<commit_before>/* Copyright 2018 Dinar Gabbasov <https://it-projects.info/team/GabbasovDinar>
 * Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
 * License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). */
odoo.define('pos_orders_history_return.screens', function (require) {
    "use strict";

    var core = require('web.core');
    var screens = require('pos_orders_history.screens');
    var models = require('pos_orders_history.models');
    var QWeb = core.qweb;
    var _t = core._t;

    screens.OrdersHistoryScreenWidget.include({
        show: function () {
            var self = this;
            this._super();
            if (this.pos.config.return_orders) {
                this.$('.actions.oe_hidden').removeClass('oe_hidden');
                this.$('.button.return').unbind('click');
                this.$('.button.return').click(function (e) {
                    var parent = $(this).parents('.order-line');
                    var id = parseInt(parent.data('id'));
                    self.click_return_order_by_id(id);
                });
            }
        },
        renderElement: function() {
            this._super();
            var self = this;
            this.$('.button.return-no-receipt').click(function (e) {
                var options = _.extend({pos: self.pos}, {});
                var order = new models.Order({}, options);
                order.temporary = true;
                order.set_mode("return_without_receipt");
                order.return_lines = [];
                self.pos.get('orders').add(order);
                self.pos.gui.back();
                self.pos.set_order(order);
            });
        },
        render_list: function(orders) {
            if (!this.pos.config.show_returned_orders) {
                orders = orders.filter(function(order) {
                    return order.returned_order !== true;
                });
            }
            this._super(orders);
        },
        click_return_order_by_id: function(id) {
            var self = this;
            var order = self.pos.db.orders_history_by_id[id];
            var uid = order.pos_reference &&
                    order.pos_reference.match(/\d{1,}-\d{1,}-\d{1,}/g) &&
                    order.pos_reference.match(/\d{1,}-\d{1,}-\d{1,}/g)[0];
            var split_sequence_number = uid.split('-');
            var sequence_number = split_sequence_number[split_sequence_number.length - 1];

            var orders = this.pos.get('orders').models;
            var exist_order = orders.find(function(o) {
                return o.uid === uid && Number(o.sequence_number) === Number(sequence_number);
            });

            if (exist_order) {
                this.pos.gui.show_popup('error',{
                    'title': _t('Warning'),
                    'body': _t('You have an unfinished return of the order. Please complete the return of the order and try again.'),
                });
                return false;
            }

            var lines = [];
            order.lines.forEach(function(line_id) {
                lines.push(self.pos.db.line_by_id[line_id]);
            });

            var product_list_widget = this.pos.chrome.screens.products.product_list_widget;

            var products = [];
            var current_products_qty_sum = 0;
            lines.forEach(function(line) {
                var product = self.pos.db.get_product_by_id(line.product_id[0]);
                if (line.price_unit !== product.price) {
                    product.old_price = line.price_unit;
                }
                current_products_qty_sum +=line.qty;
                products.push(product);
            });

            var returned_orders = this.pos.get_returned_orders_by_pos_reference(order.pos_reference);
            var exist_products_qty_sum = 0;
            returned_orders.forEach(function(o) {
                o.lines.forEach(function(line_id) {
                    var line = self.pos.db.line_by_id[line_id];
                    exist_products_qty_sum +=line.qty;
                });
            });

            if (exist_products_qty_sum + current_products_qty_sum <= 0) {
                this.pos.gui.show_popup('error',{
                    'title': _t('Error'),
                    'body': _t('All products have been returned.'),
                });
                return false;
            }

            var partner_id = order.partner_id || false;

            if (products.length > 0) {
                // create new order for return
                var json = _.extend({}, order);
                json.uid = uid;
                json.sequence_number = Number(sequence_number);
                json.lines = [];
                json.statement_ids = [];
                json.mode = "return";
                json.return_lines = lines;
                json.table_id = order.table_id[0];

                var options = _.extend({pos: this.pos}, {json: json});
                order = new models.Order({}, options);
                order.temporary = true;
                var client = null;
                if (partner_id) {
                    client = this.pos.db.get_partner_by_id(partner_id[0]);
                    if (!client) {
                        console.error('ERROR: trying to load a parner not available in the pos');
                    }
                }
                order.set_client(client);
                this.pos.get('orders').add(order);
                this.pos.gui.show_screen('products');
                this.pos.set_order(order);
                product_list_widget.set_product_list(products);
            } else {
                this.pos.gui.show_popup('error', _t('Order Is Empty'));
            }
        },
    });

    screens.ProductCategoriesWidget.include({
        renderElement: function() {
            this._super();
            var self = this;
            var order = this.pos.get_order();
            if (order && (order.get_mode() === "return" || order.get_mode() === "return_without_receipt")) {
                var returned_orders = this.pos.get_returned_orders_by_pos_reference(order.name);
                // add exist products
                var products = [];
                if (returned_orders && returned_orders.length) {
                    returned_orders.forEach(function(o) {
                        o.lines.forEach(function(line_id) {
                            var line = self.pos.db.line_by_id[line_id];
                            var product = self.pos.db.get_product_by_id(line.product_id[0]);

                            var exist_product = products.find(function(r){
                                return r.id === product.id;
                            });
                            if (exist_product) {
                                exist_product.max_return_qty += line.qty;
                            } else {
                                product.max_return_qty = line.qty;
                                if (line.price_unit !== product.price) {
                                    product.old_price = line.price_unit;
                                }
                                products.push(product);
                            }
                        });
                    });
                }
                // update max qty for current return order
                order.return_lines.forEach(function(line) {
                    var product = self.pos.db.get_product_by_id(line.product_id[0]);
                    var exist_product = products.find(function(r){
                        return r.id === product.id;
                    });
                    if (exist_product) {
                        exist_product.max_return_qty += line.qty;
                    } else {
                        product.max_return_qty = line.qty;
                        if (line.price_unit !== product.price) {
                            product.old_price = line.price_unit;
                        }
                        products.push(product);
                    }
                });
                if (products.length) {
                    this.product_list_widget.set_product_list(products);
                }
            }
        }
    });

    screens.ProductListWidget.include({
        render_product: function(product){
            var order = this.pos.get_order();
            this.return_mode = false;
            if (order && order.get_mode() === "return") {
                this.return_mode = true;
            }
            if (this.return_mode) {
                this.product_cache.clear_node(product.id);
            }
            var cached = this._super(product);
            var el = $(cached).find('.max-return-qty');
            if (el.length) {
                el.remove();
            }
            if (this.return_mode && typeof product.max_return_qty !== 'undefined') {
                var current_return_qty = order.get_current_product_return_qty(product);
                var qty = product.max_return_qty - current_return_qty;
                $(cached).find('.product-img').append('
' + qty + '
');
            }
            if (this.return_mode) {
                this.product_cache.clear_node(product.id);
            }
            return cached;
        },
    });

    return screens;
});
<commit_msg>:ambulance: table_id is undefined<commit_after>/* Copyright 2018 Dinar Gabbasov <https://it-projects.info/team/GabbasovDinar>
 * Copyright 2018 Kolushov Alexandr <https://it-projects.info/team/KolushovAlexandr>
 * License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). */
odoo.define('pos_orders_history_return.screens', function (require) {
    "use strict";

    var core = require('web.core');
    var screens = require('pos_orders_history.screens');
    var models = require('pos_orders_history.models');
    var QWeb = core.qweb;
    var _t = core._t;

    screens.OrdersHistoryScreenWidget.include({
        show: function () {
            var self = this;
            this._super();
            if (this.pos.config.return_orders) {
                this.set_return_action();
            }
        },
        set_return_action: function() {
            var self = this;
            this.$('.actions.oe_hidden').removeClass('oe_hidden');
            this.$('.button.return').unbind('click');
            this.$('.button.return').click(function (e) {
                var parent = $(this).parents('.order-line');
                var id = parseInt(parent.data('id'));
                self.click_return_order_by_id(id);
            });
        },
        renderElement: function() {
            this._super();
            var self = this;
            this.$('.button.return-no-receipt').click(function (e) {
                var options = _.extend({pos: self.pos}, {});
                var order = new models.Order({}, options);
                order.temporary = true;
                order.set_mode("return_without_receipt");
                order.return_lines = [];
                self.pos.get('orders').add(order);
                self.pos.gui.back();
                self.pos.set_order(order);
            });
        },
        render_list: function(orders) {
            if (!this.pos.config.show_returned_orders) {
                orders = orders.filter(function(order) {
                    return order.returned_order !== true;
                });
            }
            this._super(orders);
            if (this.pos.config.return_orders) {
                this.set_return_action();
            }
        },
        click_return_order_by_id: function(id) {
            var self = this;
            var order = self.pos.db.orders_history_by_id[id];
            var uid = order.pos_reference &&
                    order.pos_reference.match(/\d{1,}-\d{1,}-\d{1,}/g) &&
                    order.pos_reference.match(/\d{1,}-\d{1,}-\d{1,}/g)[0];
            var split_sequence_number = uid.split('-');
            var sequence_number = split_sequence_number[split_sequence_number.length - 1];

            var orders = this.pos.get('orders').models;
            var exist_order = orders.find(function(o) {
                return o.uid === uid && Number(o.sequence_number) === Number(sequence_number);
            });

            if (exist_order) {
                this.pos.gui.show_popup('error',{
                    'title': _t('Warning'),
                    'body': _t('You have an unfinished return of the order. Please complete the return of the order and try again.'),
                });
                return false;
            }

            var lines = [];
            order.lines.forEach(function(line_id) {
                lines.push(self.pos.db.line_by_id[line_id]);
            });

            var product_list_widget = this.pos.chrome.screens.products.product_list_widget;

            var products = [];
            var current_products_qty_sum = 0;
            lines.forEach(function(line) {
                var product = self.pos.db.get_product_by_id(line.product_id[0]);
                if (line.price_unit !== product.price) {
                    product.old_price = line.price_unit;
                }
                current_products_qty_sum +=line.qty;
                products.push(product);
            });

            var returned_orders = this.pos.get_returned_orders_by_pos_reference(order.pos_reference);
            var exist_products_qty_sum = 0;
            returned_orders.forEach(function(o) {
                o.lines.forEach(function(line_id) {
                    var line = self.pos.db.line_by_id[line_id];
                    exist_products_qty_sum +=line.qty;
                });
            });

            if (exist_products_qty_sum + current_products_qty_sum <= 0) {
                this.pos.gui.show_popup('error',{
                    'title': _t('Error'),
                    'body': _t('All products have been returned.'),
                });
                return false;
            }

            var partner_id = order.partner_id || false;

            if (products.length > 0) {
                // create new order for return
                var json = _.extend({}, order);
                json.uid = uid;
                json.sequence_number = Number(sequence_number);
                json.lines = [];
                json.statement_ids = [];
                json.mode = "return";
                json.return_lines = lines;
                if (order.table_id) {
                    json.table_id = order.table_id[0];
                }

                var options = _.extend({pos: this.pos}, {json: json});
                order = new models.Order({}, options);
                order.temporary = true;
                var client = null;
                if (partner_id) {
                    client = this.pos.db.get_partner_by_id(partner_id[0]);
                    if (!client) {
                        console.error('ERROR: trying to load a parner not available in the pos');
                    }
                }
                order.set_client(client);
                this.pos.get('orders').add(order);
                this.pos.gui.show_screen('products');
                this.pos.set_order(order);
                product_list_widget.set_product_list(products);
            } else {
                this.pos.gui.show_popup('error', _t('Order Is Empty'));
            }
        },
    });

    screens.ProductCategoriesWidget.include({
        renderElement: function() {
            this._super();
            var self = this;
            var order = this.pos.get_order();
            if (order && (order.get_mode() === "return" || order.get_mode() === "return_without_receipt")) {
                var returned_orders = this.pos.get_returned_orders_by_pos_reference(order.name);
                // add exist products
                var products = [];
                if (returned_orders && returned_orders.length) {
                    returned_orders.forEach(function(o) {
                        o.lines.forEach(function(line_id) {
                            var line = self.pos.db.line_by_id[line_id];
                            var product = self.pos.db.get_product_by_id(line.product_id[0]);

                            var exist_product = products.find(function(r){
                                return r.id === product.id;
                            });
                            if (exist_product) {
                                exist_product.max_return_qty += line.qty;
                            } else {
                                product.max_return_qty = line.qty;
                                if (line.price_unit !== product.price) {
                                    product.old_price = line.price_unit;
                                }
                                products.push(product);
                            }
                        });
                    });
                }
                // update max qty for current return order
                order.return_lines.forEach(function(line) {
                    var product = self.pos.db.get_product_by_id(line.product_id[0]);
                    var exist_product = products.find(function(r){
                        return r.id === product.id;
                    });
                    if (exist_product) {
                        exist_product.max_return_qty += line.qty;
                    } else {
                        product.max_return_qty = line.qty;
                        if (line.price_unit !== product.price) {
                            product.old_price = line.price_unit;
                        }
                        products.push(product);
                    }
                });
                if (products.length) {
                    this.product_list_widget.set_product_list(products);
                }
            }
        }
    });

    screens.ProductListWidget.include({
        render_product: function(product){
            var order = this.pos.get_order();
            this.return_mode = false;
            if (order && order.get_mode() === "return") {
                this.return_mode = true;
            }
            if (this.return_mode) {
                this.product_cache.clear_node(product.id);
            }
            var cached = this._super(product);
            var el = $(cached).find('.max-return-qty');
            if (el.length) {
                el.remove();
            }
            if (this.return_mode && typeof product.max_return_qty !== 'undefined') {
                var current_return_qty = order.get_current_product_return_qty(product);
                var qty = product.max_return_qty - current_return_qty;
                $(cached).find('.product-img').append('
' + qty + '
');
            }
            if (this.return_mode) {
                this.product_cache.clear_node(product.id);
            }
            return cached;
        },
    });

    return screens;
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import InfoLoader from './info/InfoLoader';
import * as serverAPI from '../actions/serverAPI';

import Navigation from './Navigation';
import Search from './Search';
import './PrepojeniaPage.css';

class PrepojeniaPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      entitysearch1: (props.location && props.location.query.eid1) || '',
      entitysearch2: (props.location && props.location.query.eid2) || '',
      searching: false,
    };
    this.searchConnection = this.searchConnection.bind(this);
    this.loadEntity1 = this.loadEntity1.bind(this);
    this.loadEntity2 = this.loadEntity2.bind(this);
    this.loadConnections = this.loadConnections.bind(this);
  }

  componentWillMount() {
    this.searchConnection(this.state.entitysearch1, this.state.entitysearch2);
  }

  searchConnection(entitysearch1, entitysearch2) {
    if (entitysearch1.trim() === '' || entitysearch2.trim() === '') {
      return;
    }
    browserHistory.push({
      ...this.props.location,
      query: {
        eid1: entitysearch1,
        eid2: entitysearch2,
      },
    });
    this.setState({
      entitysearch1,
      entitysearch2,
      searching: true,
      connections: [],
    }, this.loadEntity1);
  }

  loadEntity1() {
    serverAPI.searchEntity(this.state.entitysearch1, (eids1) => {
      this.setState({
        entity1: {
          name: this.state.entitysearch1,
          eids: eids1,
        },
      }, this.loadEntity2);
    });
  }

  loadEntity2() {
    serverAPI.searchEntity(this.state.entitysearch2, (eids2) => {
      this.setState({
        entity2: {
          name: this.state.entitysearch2,
          eids: eids2,
        },
      }, this.loadConnections);
    });
  }

  loadConnections() {
    serverAPI.connection(this.state.entity1.eids.map(eid => eid.eid).join(),
      this.state.entity2.eids.map(eid => eid.eid).join(),
      (conns) => {
        this.setState({
          connections: conns,
          searching: false,
        });
      });
  }

  render() {
    return (

              <Navigation />
              <Search
                entitysearch1={this.state.entitysearch1}
                entitysearch2={this.state.entitysearch2}
                searchConnection={this.searchConnection}
              />

              {this.state.searching ? (
                'Prebieha hľadanie prepojenia ...'
              ) : (
                this.state.connections && (
                  this.state.connections.length > 0 ? (

                      Dĺžka prepojenia: {this.state.connections.length - 1}.

                  ) : (

                      Prepojenie neexistuje.

                  )
                )
              )}
              {this.state.entity1 &&

                  Nájdených {this.state.entity1.eids.length} záznamov
                  pre "{this.state.entity1.name}".

              }
              {this.state.entity2 &&

                  Nájdených {this.state.entity2.eids.length} záznamov
                  pre "{this.state.entity2.name}".

              }

            {this.state.connections && this.state.connections.length > 0 ? (

                {this.state.connections.map(connEid =>
                  <InfoLoader key={connEid} eid={connEid} hasConnectLine />,
                )}

              ) : (

Zadajte dvojicu

pre začiatok vyhľadávania.

              )
            }

    );
  }
}

export default PrepojeniaPage;
<commit_msg>Issue #14: Jump to content after search<commit_after>import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import InfoLoader from './info/InfoLoader';
import * as serverAPI from '../actions/serverAPI';

import Navigation from './Navigation';
import Search from './Search';
import './PrepojeniaPage.css';

class PrepojeniaPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      entitysearch1: (props.location && props.location.query.eid1) || '',
      entitysearch2: (props.location && props.location.query.eid2) || '',
      searching: false,
    };
    this.searchConnection = this.searchConnection.bind(this);
    this.loadEntity1 = this.loadEntity1.bind(this);
    this.loadEntity2 = this.loadEntity2.bind(this);
    this.loadConnections = this.loadConnections.bind(this);
  }

  componentWillMount() {
    this.searchConnection(this.state.entitysearch1, this.state.entitysearch2);
  }

  searchConnection(entitysearch1, entitysearch2) {
    if (entitysearch1.trim() === '' || entitysearch2.trim() === '') {
      return;
    }
    browserHistory.push({
      ...this.props.location,
      query: {
        eid1: entitysearch1,
        eid2: entitysearch2,
      },
    });
    this.setState({
      entitysearch1,
      entitysearch2,
      searching: true,
      connections: [],
    }, this.loadEntity1);

    if (this.main) {
      this.main.scrollIntoView({
        behavior: 'smooth',
      });
    }
  }

  loadEntity1() {
    serverAPI.searchEntity(this.state.entitysearch1, (eids1) => {
      this.setState({
        entity1: {
          name: this.state.entitysearch1,
          eids: eids1,
        },
      }, this.loadEntity2);
    });
  }

  loadEntity2() {
    serverAPI.searchEntity(this.state.entitysearch2, (eids2) => {
      this.setState({
        entity2: {
          name: this.state.entitysearch2,
          eids: eids2,
        },
      }, this.loadConnections);
    });
  }

  loadConnections() {
    serverAPI.connection(this.state.entity1.eids.map(eid => eid.eid).join(),
      this.state.entity2.eids.map(eid => eid.eid).join(),
      (conns) => {
        this.setState({
          connections: conns,
          searching: false,
        });
      });
  }

  render() {
    return (

              <Navigation />
              <Search
                entitysearch1={this.state.entitysearch1}
                entitysearch2={this.state.entitysearch2}
                searchConnection={this.searchConnection}
              />

 { this.main = el; }}>

              {this.state.searching ? (
                'Prebieha hľadanie prepojenia ...'
              ) : (
                this.state.connections && (
                  this.state.connections.length > 0 ? (

                      Dĺžka prepojenia: {this.state.connections.length - 1}.

                  ) : (

                      Prepojenie neexistuje.

                  )
                )
              )}
              {this.state.entity1 &&

                  Nájdených {this.state.entity1.eids.length} záznamov
                  pre "{this.state.entity1.name}".

              }
              {this.state.entity2 &&

                  Nájdených {this.state.entity2.eids.length} záznamov
                  pre "{this.state.entity2.name}".

              }

            {this.state.connections && this.state.connections.length > 0 ? (

                {this.state.connections.map(connEid =>
                  <InfoLoader key={connEid} eid={connEid} hasConnectLine />,
                )}

              ) : (

Zadajte dvojicu

pre začiatok vyhľadávania.

              )
            }

    );
  }
}

export default PrepojeniaPage;
<|endoftext|>


<commit_before>/**
 * Use waveform for audio files in video.js player.
 */
videojs.Waveform = videojs.Component.extend({

	init: function(player, options)
    {
        videojs.Component.call(this, player, options);

        // customize controls
        console.log(this.player().options());
        if (this.player().options().autoplay)
        {
        	this.player().bigPlayButton.hide();
        }
        if (this.player().options().controls)
    	{
        	this.player().controlBar.show();
            this.player().controlBar.progressControl.hide();
    	}

        // waveform events
        this.surfer = Object.create(WaveSurfer);
        this.surfer.on('ready', this.onWaveReady.bind(this));
        this.surfer.on('error', this.onWaveError.bind(this));
        this.surfer.on('progress', this.onWaveProgress.bind(this));
        this.surfer.on('seek', this.onWaveSeek.bind(this));

        // player events
        this.player().on('firstplay', this.onFirstPlay.bind(this));
        this.player().on('play', this.onPlay.bind(this));
        this.player().on('pause', this.onPause.bind(this));
        this.player().on('volumechange', this.onVolumeChange.bind(this));
        this.player().on('timeupdate', this.onTimeUpdate.bind(this));
    },

    /**
     * Initializes the waveform.
     */
    initialize: function(opts)
    {
        // set waveform element and dimensions
        opts.container = this.el();
        opts.height = this.player().height() - (
            this.player().controlBar.height()
        );

        // customize waveform appearance
        this.surfer.init(opts);
    },

    /**
     * Start loading waveform data.
     */
    load: function(url)
    {
        this.surfer.load(url);
    },

    /**
     * Start or resume playback.
     */
    play: function()
    {
        this.surfer.play();
    },

    /**
     * Pauses playback.
     */
    pause: function()
    {
        this.surfer.pause();
    },

    /**
     * Set the current volume of the media.
     */
    setVolume: function(volume)
    {
    	this.surfer.setVolume(volume);
    },

    /**
     *
     */
    setCurrentTime: function()
    {
    	// set current time
    	var currentTime = this.formatTime(this.surfer.backend.getCurrentTime());
    	$(this.player().controlBar.currentTimeDisplay.el()).find(
    	    '.vjs-current-time-display').text(currentTime);
    },

    /**
     * Audio is loaded, decoded and the waveform is drawn.
     */
    onWaveReady: function()
    {
        // set total time
        var duration = this.formatTime(this.surfer.backend.getDuration());
        $(this.player().controlBar.durationDisplay.el()).find(
        	'.vjs-duration-display').text(duration);

        // remove loading spinner
        $(this.player().loadingSpinner.el()).remove();

        // auto-play when ready
        this.play();
    },

    /**
     * Fires continuously during audio playback.
     *
     * @param percent: Percentage played so far.
     */
    onWaveProgress: function(percent)
    {
    	this.setCurrentTime();

    	// completed playback
        if (percent >= 1)
        {
        	// pause player
        	this.player().pause();
        }
    },

    /**
     * Fires during seeking of the waveform.
     */
    onWaveSeek: function()
    {
    	this.setCurrentTime();
    },

    /**
     * Fired the first time a clip is played.
     */
    onFirstPlay: function()
    {
    	var options = this.options().options;

        // init waveform
        this.initialize(options);

        // start loading
        this.load(options.src);
    },

    /**
     * Fired whenever the media begins or resumes playback.
     */
    onPlay: function()
    {
        this.play();
    },

    /**
     * Fired whenever the media has been paused.
     */
    onPause: function()
    {
    	this.pause();
    },

    /**
     * Fired when the volume changes.
     */
    onVolumeChange: function()
    {
    	var volume = this.player().volume();
    	if (this.player().muted())
    	{
    		// muted
    		volume = 0;
    	}

    	this.setVolume(volume);
    },

    /**
     * Fired when the current playback position has changed
     *
     * During playback this is fired every 15-250 milliseconds,
     * depending on the playback technology in use.
     */
    onTimeUpdate: function()
    {
    	this.setCurrentTime();
    },

    /**
     * Waveform error.
     */
    onWaveError: function(error)
    {
        console.warn(error);
    },

    /**
    * Format seconds as a time string, H:MM:SS or M:SS
    * Supplying a guide (in seconds) will force a number of leading zeros
    * to cover the length of the guide
    * @param {Number} seconds Number of seconds to be turned into a string
    * @param {Number} guide Number (in seconds) to model the string after
    * @return {String} Time formatted as H:MM:SS or M:SS
    */
    formatTime: function(seconds, guide)
    {
      // Default to using seconds as guide
      guide = guide || seconds;
      var s = Math.floor(seconds % 60),
          m = Math.floor(seconds / 60 % 60),
          h = Math.floor(seconds / 3600),
          gm = Math.floor(guide / 60 % 60),
          gh = Math.floor(guide / 3600);

      // handle invalid times
      if (isNaN(seconds) || seconds === Infinity) {
        // '-' is false for all relational operators (e.g. <, >=) so this setting
        // will add the minimum number of fields specified by the guide
        h = m = s = '-';
      }

      // Check if we need to show hours
      h = (h > 0 || gh > 0) ? h + ':' : '';

      // If hours are showing, we may need to add a leading zero.
      // Always show at least one digit of minutes.
      m = (((h || gm >= 10) && m < 10) ? '0' + m : m) + ':';

      // Check if leading zero is need for seconds
      s = (s < 10) ? '0' + s : s;

      return h + m + s;
    }

});

var createWaveform = function()
{
    var props = {
        className: 'vjs-waveform',
        tabIndex: 0
    };
    return videojs.Component.prototype.createEl(null, props);
};

function wavesurferPlugin(options)
{
    // create new waveform
    this.waveform = new videojs.Waveform(this,
    {
        'el': createWaveform(),
        'options': options
    });

    // add waveform to dom
    this.el().appendChild(this.waveform.el());
};

videojs.plugin('wavesurfer', wavesurferPlugin);
<commit_msg>make duration consistent<commit_after>/**
 * Use waveform for audio files in video.js player.
 */
videojs.Waveform = videojs.Component.extend({

	init: function(player, options)
    {
        videojs.Component.call(this, player, options);

        // customize controls
        if (this.player().options().autoplay)
        {
        	this.player().bigPlayButton.hide();
        }
        if (this.player().options().controls)
    	{
        	this.player().controlBar.show();
            this.player().controlBar.progressControl.hide();
    	}

        // waveform events
        this.surfer = Object.create(WaveSurfer);
        this.surfer.on('ready', this.onWaveReady.bind(this));
        this.surfer.on('error', this.onWaveError.bind(this));
        this.surfer.on('progress', this.onWaveProgress.bind(this));
        this.surfer.on('seek', this.onWaveSeek.bind(this));

        // player events
        this.player().on('firstplay', this.onFirstPlay.bind(this));
        this.player().on('play', this.onPlay.bind(this));
        this.player().on('pause', this.onPause.bind(this));
        this.player().on('volumechange', this.onVolumeChange.bind(this));
        this.player().on('timeupdate', this.onTimeUpdate.bind(this));
    },

    /**
     * Initializes the waveform.
     */
    initialize: function(opts)
    {
        // set waveform element and dimensions
        opts.container = this.el();
        opts.height = this.player().height() - this.player().controlBar.height()

        // customize waveform appearance
        this.surfer.init(opts);
    },

    /**
     * Start loading waveform data.
     */
    load: function(url)
    {
        this.surfer.load(url);
    },

    /**
     * Start or resume playback.
     */
    play: function()
    {
        this.surfer.play();
    },

    /**
     * Pauses playback.
     */
    pause: function()
    {
        this.surfer.pause();
    },

    /**
     * Set the current volume of the media.
     */
    setVolume: function(volume)
    {
    	this.surfer.setVolume(volume);
    },

    /**
     * Updates the current time.
     */
    setCurrentTime: function()
    {
    	var currentTime = Math.min(this.surfer.backend.getDuration(),
    		this.surfer.backend.getCurrentTime());

    	// update control
    	this.player().controlBar.currentTimeDisplay.el(
    		).children[0].innerHTML = this.formatTime(currentTime, 600);
    },

    /**
     * Updates the duration time.
     */
    setDuration: function()
    {
        var duration = this.surfer.backend.getDuration();

        // update control
        this.player().controlBar.durationDisplay.el(
            ).children[0].innerHTML = this.formatTime(duration, 600);
    },

    /**
     * Audio is loaded, decoded and the waveform is drawn.
     */
    onWaveReady: function()
    {
    	// update duration
        this.setDuration();

        // remove loading spinner
        $(this.player().loadingSpinner.el()).remove();

        // auto-play when ready
        this.play();
    },

    /**
     * Fires continuously during audio playback.
     *
     * @param percent: Percentage played so far.
     */
    onWaveProgress: function(percent)
    {
    	// completed playback
        if (percent >= 1)
        {
        	if (!this.player().paused())
        	{
        		console.log('asddasdsa');

        		// pause player
            	this.player().pause();
        	}
        }
        else
        {
        	this.setCurrentTime();
        }
    },

    /**
     * Fires during seeking of the waveform.
     */
    onWaveSeek: function()
    {
    	this.setCurrentTime();
    },

    /**
     * Fired the first time a clip is played.
     */
    onFirstPlay: function()
    {
    	var options = this.options().options;

        // init waveform
        this.initialize(options);

        // start loading
        this.load(options.src);
    },

    /**
     * Fired whenever the media in the player begins or resumes playback.
     */
    onPlay: function()
    {
        this.play();
    },

    /**
     * Fired whenever the media in the player has been paused.
     */
    onPause: function()
    {
    	this.pause();
    },

    /**
     * Fired when the volume in the player changes.
     */
    onVolumeChange: function()
    {
    	var volume = this.player().volume();
    	if (this.player().muted())
    	{
    		// muted
    		volume = 0;
    	}

    	this.setVolume(volume);
    },

    /**
     * Fired when the current playback position has changed
     */
    onTimeUpdate: function()
    {
    	this.setCurrentTime();
    },

    /**
     * Waveform error.
     */
    onWaveError: function(error)
    {
        console.warn(error);
    },

    /**
    * Format seconds as a time string, H:MM:SS, M:SS or SS:MMM.
    *
    * Supplying a guide (in seconds) will force a number of leading zeros
    * to cover the length of the guide.
    *
    * @param {Number} seconds Number of seconds to be turned into a string
    * @param {Number} guide Number (in seconds) to model the string after
    * @return {String} Time formatted as H:MM:SS, M:SS or SS:MMM.
    */
    formatTime: function(seconds, guide)
    {
    	// Default to using seconds as guide
    	guide = guide || seconds;
    	var s = Math.floor(seconds % 60),
        	m = Math.floor(seconds / 60 % 60),
        	h = Math.floor(seconds / 3600),
        	gm = Math.floor(guide / 60 % 60),
        	gh = Math.floor(guide / 3600),
    	    ms = Math.floor((seconds - s) * 1000);

    	// handle invalid times
    	if (isNaN(seconds) || seconds === Infinity)
    	{
    		// '-' is false for all relational operators (e.g. <, >=) so this
    		// setting will add the minimum number of fields specified by the
    		// guide
    		h = m = s = ms = '-';
    	}

    	// Check if we need to show millseconds
    	if (s < 3)
    	{
    		if (ms < 100)
    		{
    			if (ms < 10)
    			{
    				ms = '00' + ms;
    			}
    			else
    			{
    				ms = '0' + ms;
    			}
    		}
			ms = ":" + ms;
    	}
    	else
    	{
    		ms = '';
    	}

    	// Check if we need to show hours
    	h = (h > 0 || gh > 0) ? h + ':' : '';

    	// If hours are showing, we may need to add a leading zero.
    	// Always show at least one digit of minutes.
    	m = (((h || gm >= 10) && m < 10) ? '0' + m : m) + ':';

    	// Check if leading zero is need for seconds
    	s = ((s < 10) ? '0' + s : s);

    	return h + m + s + ms;
    }

});

var createWaveform = function()
{
    var props = {
        className: 'vjs-waveform',
        tabIndex: 0
    };
    return videojs.Component.prototype.createEl(null, props);
};

function wavesurferPlugin(options)
{
    // create new waveform
    this.waveform = new videojs.Waveform(this,
    {
        'el': createWaveform(),
        'options': options
    });

    // add waveform to dom
    this.el().appendChild(this.waveform.el());
};

videojs.plugin('wavesurfer', wavesurferPlugin);
<|endoftext|>


<commit_before>var express = require('express'),
    app = express();

app.use(express.static(__dirname + '/ipsum', {maxAge: 60*60*24*7}));

module.exports.app = app;

app.get(/.*\/.*\/.*/, function(req, res) {

  res.end(go(req.url));
})

if(!String.prototype.repeat) {
  String.prototype.repeat = function(n) {
    return new Array(n+1).join(this);
  }
}

var stretch = function stretch(a, n) {
  var d = a;
  while(d.length < n) {
    d = d.concat(a.sort(function() { return Math.random() < 0.5}));
  }
  return d;
}

/* IPSUM GENERATOR */
var general = require('./general.json');
var dictionary = {
  'design': require('./design.json')
}
var normal = 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیستری را برای طراحان رایانه ای و فرهنگ پیشرو در زبان فارسی ایجاد کرد. در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها و شرایط سخت تایپ به پایان رسد وزمان مورد نیاز شامل حروفچینی دستاوردهای اصلی و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.';

function loremipsum(data) {
  var method = data[0],
      unit = data[1],
      amount = +data[2];

  if(method == 'normal') {
    switch(unit) {
      case 'c':
        return normal.slice(0, amount);
      case 'p':
        return normal.repeat(amount);
      case 'w':
        return normal.split(' ').slice(0, amount).join(' ');
    }
  }

  var r = dictionary[method].concat(general);
  r.sort(function() {
    return Math.floor(Math.random()*3-1);
  });

  switch(unit) {
    case 'c':
      r = stretch(r, amount/2);
      return r.slice(0, amount/2).join(' ').slice(0, amount + (amount/4-1));
    case 'w':
      r = stretch(r, amount);
      return r.slice(0, amount).join(' ');
    case 'p':
      r = stretch(r, 15*(Math.random()+1));
      var s = r.join(' ') + '.
';
      for(var i = 1; i < amount; i++) {
        r = r.sort(function() { return Math.floor(Math.random()*3-1); });
        r = stretch(r, 15*(Math.random()*3+2));

        s += r.join(' ') + '.
';
      }
      return s;
  }
}
function go(url) {
  var req = url.split('/');
  return loremipsum(req.slice(1));
}
<commit_msg>Linted<commit_after>var express = require('express'),
    app = express();

app.use(express.static(__dirname + '/ipsum', {maxAge: 60*60*24*7}));

module.exports.app = app;

app.get(/.*\/.*\/.*/, function(req, res) {

  res.end(go(req.url));
});

if(!String.prototype.repeat) {
  String.prototype.repeat = function(n) {
    return new Array(n+1).join(this);
  };
}

function randomize() {
  return Math.floor(Math.random()*3-1);
}

var stretch = function stretch(a, n) {
  var d = a;
  while(d.length < n) {
    d = d.concat(a.sort(randomize));
  }
  return d;
};

/* IPSUM GENERATOR */
var general = require('./general.json');
var dictionary = {
  'design': require('./design.json')
};
var normal = 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیستری را برای طراحان رایانه ای و فرهنگ پیشرو در زبان فارسی ایجاد کرد. در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها و شرایط سخت تایپ به پایان رسد وزمان مورد نیاز شامل حروفچینی دستاوردهای اصلی و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.';

function loremipsum(data) {
  var method = data[0],
      unit = data[1],
      amount = +data[2];

  if(method == 'normal') {
    switch(unit) {
      case 'c':
        return normal.slice(0, amount);
      case 'p':
        return normal.repeat(amount);
      case 'w':
        return normal.split(' ').slice(0, amount).join(' ');
    }
  }

  var r = dictionary[method].concat(general);
  r.sort(randomize);

  switch(unit) {
    case 'c':
      r = stretch(r, amount/2);
      return r.slice(0, amount/2).join(' ').slice(0, amount + (amount/4-1));
    case 'w':
      r = stretch(r, amount);
      return r.slice(0, amount).join(' ');
    case 'p':
      r = stretch(r, 15*(Math.random()+1));
      var s = r.join(' ') + '.
';
      for(var i = 1; i < amount; i++) {
        r = r.sort(randomize);
        r = stretch(r, 15*(Math.random()*3+2));

        s += r.join(' ') + '.
';
      }
      return s;
  }
}
function go(url) {
  var req = url.split('/');
  return loremipsum(req.slice(1));
}
<|endoftext|>


<commit_before>/**
 * Created by andreas on 04.05.14.
 */

import TrackData from './trackdata';
import GpsData from './gpsdata';
import RouteData from './routedata';
import Formatter from '../util/formatter';
import NavCompute from './navcompute';
import navobjects from './navobjects';
import globalStore from '../util/globalstore.jsx';
import keys,{KeyHelper} from '../util/keys.jsx';
import PropertyHandler from '../util/propertyhandler';
import RouteEdit,{StateHelper} from './routeeditor.js';
import assign from 'object-assign';

const activeRoute=new RouteEdit(RouteEdit.MODES.ACTIVE);

class Callback{
    constructor(callback){
        this.callback=callback;
    }
    dataChanged(keys){
        this.callback(keys);
    }
}

/**
 *
 * @constructor
 */
const NavData=function(){

    /**
     * @private
     * @type {Formatter}
     */
    this.formatter=Formatter;
    /** @type {GpsData}
     * @private
     */
    this.gpsdata=new GpsData();
        /**
     * @private
     * @type {TrackData}
     */
    this.trackHandler=new TrackData();
    /**
     * @type {AisData|exports|module.exports}
     */
    this.routeHandler=new RouteData();

    this.aisMode=navobjects.AisCenterMode.GPS;

    let self=this;
    this.changeCallback=new Callback((keys)=>{self.computeValues();});
    globalStore.register(this.changeCallback,
        KeyHelper.flattenedKeys(activeRoute.getStoreKeys())
            .concat(
                KeyHelper.flattenedKeys(this.gpsdata.getStoreKeys()),
                [keys.map.centerPosition]
            ));
};

/**
 * compute the raw and formtted valued
 * @private
 */
NavData.prototype.computeValues=function() {
    let data={
        centerCourse:0,
        centerDistance:0,
        centerMarkerCourse:0,
        centerMarkerDistance:0,
        markerCourse:0,
        markerDistance:0,
        markerVmg:0,
        markerEta:null,
        markerXte: 0,
        markerWp:new navobjects.WayPoint(0,0,"Marker"),
        /* data for the active route */
        routeName: undefined,
        routeNumPoints: 0,
        routeLen: 0,
        routeRemain: 0,
        routeEta: null,
        routeNextCourse: 0,
        routeNextWp: undefined,
        /* data for the route we are editing */
        edRouteName: undefined,
        edRouteNumPoints: 0,
        edRouteLen: 0,
        /* the next 2 will only be filled when the editing route is the current */
        edRouteRemain: 0,
        edRouteEta:0,
        anchorWatchDistance: undefined,
        anchorDistance: 0,
        anchorDirection: 0
    };
    let gps = globalStore.getMultiple(GpsData.getStoreKeys());
    //copy the marker to data to make it available extern
    data.markerWp = activeRoute.getCurrentTarget();
    data.routeNextWp = activeRoute.getNextWaypoint();
    let maplatlon=globalStore.getData(keys.map.centerPosition,new navobjects.Point(0,0));
    let rstart = activeRoute.getCurrentFrom();
    if (gps.valid) {
        if (activeRoute.hasActiveTarget()) {
            let legData = NavCompute.computeLegInfo(data.markerWp, gps, rstart);
            assign(data, legData);
        }
        else {
            data.markerCourse = undefined;
            data.markerDistance = undefined;
            data.markerEta = undefined;
            data.markerXte = undefined;
        }
        let centerdst = NavCompute.computeDistance(gps, maplatlon);
        data.centerCourse = centerdst.course;
        data.centerDistance = centerdst.dts;
        if (activeRoute.anchorWatch() !== undefined) {
            let anchor = activeRoute.getCurrentFrom();
            data.anchorWatchDistance = activeRoute.anchorWatch();
            if (anchor) {
                let aleginfo = NavCompute.computeLegInfo(anchor, gps);
                data.anchorDistance = aleginfo.markerDistance;
                data.anchorDirection = aleginfo.markerCourse;
            }
            else {
                data.anchorDistance = 0;
                data.anchorDirection = 0;
                data.anchorWatchDistance = undefined;
            }
        }
        else {
            data.anchorWatchDistance = undefined;
        }
    }
    else {
        data.centerCourse = 0;
        data.centerDistance = 0;
        data.markerCourse = 0;
        data.markerDistance = 0;
        data.markerEta = null;
        data.markerXte = undefined;
        data.anchorDistance = 0;
        data.anchorDirection = 0;
        data.anchorWatchDistance = undefined;
    }

    //distance between marker and center
    if (data.markerWp) {
        let mcdst = NavCompute.computeDistance(data.markerWp, maplatlon);
        data.centerMarkerCourse = mcdst.course;
        data.centerMarkerDistance = mcdst.dts;
    }
    else {
        data.centerMarkerCourse = undefined;
        data.centerMarkerDistance = undefined;
    }
    //route data
    let curRoute = activeRoute.hasActiveTarget() ? activeRoute.getRoute() : undefined;
    data.isApproaching = activeRoute.isApproaching();
    if (curRoute) {
        data.routeName = curRoute.name;
        data.routeNumPoints = curRoute.points.length;
        data.routeLen = curRoute.computeLength(0, curRoute);
        let currentIndex = curRoute.getIndexFromPoint(data.markerWp);
        if (currentIndex < 0) currentIndex = 0;
        data.routeRemain = curRoute.computeLength(currentIndex) + data.markerDistance;
        let routetime = gps.rtime ? gps.rtime.getTime() : 0;
        if (data.markerVmg && data.markerVmg > 0) {
            routetime += data.routeRemain / data.markerVmg * 3600 * 1000; //time in ms
            let routeDate = new Date(Math.round(routetime));
            data.routeEta = routeDate;
        }
        else {
            data.routeEta = undefined;
        }
        data.routeNextCourse = undefined;
        if (gps.valid) {
            if (data.routeNextWp) {
                let dst = NavCompute.computeDistance(gps, data.routeNextWp);
                data.routeNextCourse = dst.course;
            }
        }
        else {
            data.routeRemain = 0;
            data.routeEta = undefined;
            data.routeNextCourse = undefined;
        }
    }
    else {
        data.routeName = undefined;
        data.routeNumPoints = 0;
        data.routeLen = 0;
        data.routeRemain = 0;
        data.routeEta = undefined;
        data.routeNextCourse = undefined;
    }
    let self=this;
    data.wpName=data.markerWp ? data.markerWp.name : '';
    //store the data asynchronously to avoid any locks
    window.setTimeout(()=> {
        globalStore.storeMultiple(data, {
            centerCourse: keys.nav.center.course,
            centerDistance: keys.nav.center.distance,
            markerCourse: keys.nav.wp.course,
            markerDistance: keys.nav.wp.distance,
            markerEta: keys.nav.wp.eta,
            markerXte: keys.nav.wp.xte,
            markerVmg: keys.nav.wp.vmg,
            markerWp: keys.nav.wp.position,
            anchorDirection: keys.nav.anchor.direction,
            anchorDistance: keys.nav.anchor.distance,
            anchorWatchDistance: keys.nav.anchor.watchDistance,
            centerMarkerCourse: keys.nav.center.markerCourse,
            centerMarkerDistance: keys.nav.center.markerDistance,
            routeName: keys.nav.route.name,
            routeNumPoints: keys.nav.route.numPoints,
            routeLen: keys.nav.route.len,
            routeRemain: keys.nav.route.remain,
            routeEta: keys.nav.route.eta,
            routeNextCourse: keys.nav.route.nextCourse,
            isApproaching: keys.nav.route.isApproaching,
            wpName:keys.nav.wp.name
        },self.changeCallback);
    },0);
};

/**
 * get the center for AIS queries
 * @returns {navobjects.Point}
 */
NavData.prototype.getAisCenter=function(){
    if (this.aisMode == navobjects.AisCenterMode.NONE) return undefined;
    if (this.aisMode == navobjects.AisCenterMode.GPS) {
        if (globalStore.getData(keys.nav.gps.valid)) return globalStore.getData(keys.nav.gps.position);
        return undefined;
    }
    return globalStore.getData(keys.map.centerPosition);
};

/**
 * set the mode for the AIS query
 * @param {navobjects.AisCenterMode} mode
 */
NavData.prototype.setAisCenterMode=function(mode){
    this.aisMode=mode;
};

/**
 * get the routing handler
 * @returns {RouteData|*}
 */
NavData.prototype.getRoutingHandler=function(){
    return this.routeHandler;
};

/**
 * get the gps data handler
 * @returns {GpsData}
 */
NavData.prototype.getGpsHandler=function(){
    return this.gpsdata;
};

NavData.prototype.resetTrack=function(){
    return this.trackHandler.resetTrack();
};

NavData.prototype.getCurrentPosition=function(){
    if (globalStore.getData(keys.nav.gps.valid)){
        return globalStore.getData(keys.nav.gps.position);
    }
};

module.exports=new NavData();

<commit_msg>compute route eta correctly<commit_after>/**
 * Created by andreas on 04.05.14.
 */

import TrackData from './trackdata';
import GpsData from './gpsdata';
import RouteData from './routedata';
import Formatter from '../util/formatter';
import NavCompute from './navcompute';
import navobjects from './navobjects';
import globalStore from '../util/globalstore.jsx';
import keys,{KeyHelper} from '../util/keys.jsx';
import PropertyHandler from '../util/propertyhandler';
import RouteEdit,{StateHelper} from './routeeditor.js';
import assign from 'object-assign';

const activeRoute=new RouteEdit(RouteEdit.MODES.ACTIVE);

class Callback{
    constructor(callback){
        this.callback=callback;
    }
    dataChanged(keys){
        this.callback(keys);
    }
}

/**
 *
 * @constructor
 */
const NavData=function(){

    /**
     * @private
     * @type {Formatter}
     */
    this.formatter=Formatter;
    /** @type {GpsData}
     * @private
     */
    this.gpsdata=new GpsData();
        /**
     * @private
     * @type {TrackData}
     */
    this.trackHandler=new TrackData();
    /**
     * @type {AisData|exports|module.exports}
     */
    this.routeHandler=new RouteData();

    this.aisMode=navobjects.AisCenterMode.GPS;

    let self=this;
    this.changeCallback=new Callback((keys)=>{self.computeValues();});
    globalStore.register(this.changeCallback,
        KeyHelper.flattenedKeys(activeRoute.getStoreKeys())
            .concat(
                KeyHelper.flattenedKeys(this.gpsdata.getStoreKeys()),
                [keys.map.centerPosition]
            ));
};

/**
 * compute the raw and formtted valued
 * @private
 */
NavData.prototype.computeValues=function() {
    let data={
        centerCourse:0,
        centerDistance:0,
        centerMarkerCourse:0,
        centerMarkerDistance:0,
        markerCourse:0,
        markerDistance:0,
        markerVmg:0,
        markerEta:null,
        markerXte: 0,
        markerWp:new navobjects.WayPoint(0,0,"Marker"),
        /* data for the active route */
        routeName: undefined,
        routeNumPoints: 0,
        routeLen: 0,
        routeRemain: 0,
        routeEta: null,
        routeNextCourse: 0,
        routeNextWp: undefined,
        anchorWatchDistance: undefined,
        anchorDistance: 0,
        anchorDirection: 0
    };
    let gps = globalStore.getMultiple(GpsData.getStoreKeys());
    //copy the marker to data to make it available extern
    data.markerWp = activeRoute.getCurrentTarget();
    data.routeNextWp = activeRoute.getNextWaypoint();
    let maplatlon=globalStore.getData(keys.map.centerPosition,new navobjects.Point(0,0));
    let rstart = activeRoute.getCurrentFrom();
    if (gps.valid) {
        if (activeRoute.hasActiveTarget()) {
            let legData = NavCompute.computeLegInfo(data.markerWp, gps, rstart);
            assign(data, legData);
        }
        else {
            data.markerCourse = undefined;
            data.markerDistance = undefined;
            data.markerEta = undefined;
            data.markerXte = undefined;
        }
        let centerdst = NavCompute.computeDistance(gps, maplatlon);
        data.centerCourse = centerdst.course;
        data.centerDistance = centerdst.dts;
        if (activeRoute.anchorWatch() !== undefined) {
            let anchor = activeRoute.getCurrentFrom();
            data.anchorWatchDistance = activeRoute.anchorWatch();
            if (anchor) {
                let aleginfo = NavCompute.computeLegInfo(anchor, gps);
                data.anchorDistance = aleginfo.markerDistance;
                data.anchorDirection = aleginfo.markerCourse;
            }
            else {
                data.anchorDistance = 0;
                data.anchorDirection = 0;
                data.anchorWatchDistance = undefined;
            }
        }
        else {
            data.anchorWatchDistance = undefined;
        }
    }
    else {
        data.centerCourse = 0;
        data.centerDistance = 0;
        data.markerCourse = 0;
        data.markerDistance = 0;
        data.markerEta = null;
        data.markerXte = undefined;
        data.anchorDistance = 0;
        data.anchorDirection = 0;
        data.anchorWatchDistance = undefined;
    }

    //distance between marker and center
    if (data.markerWp) {
        let mcdst = NavCompute.computeDistance(data.markerWp, maplatlon);
        data.centerMarkerCourse = mcdst.course;
        data.centerMarkerDistance = mcdst.dts;
    }
    else {
        data.centerMarkerCourse = undefined;
        data.centerMarkerDistance = undefined;
    }
    //route data
    let curRoute = activeRoute.hasActiveTarget() ? activeRoute.getRoute() : undefined;
    data.isApproaching = activeRoute.isApproaching();
    if (curRoute) {
        data.routeName = curRoute.name;
        data.routeNumPoints = curRoute.points.length;
        data.routeLen = curRoute.computeLength(0);
        let currentIndex = curRoute.getIndexFromPoint(data.markerWp);
        if (currentIndex < 0) currentIndex = 0;
        data.routeRemain = curRoute.computeLength(currentIndex) + data.markerDistance;
        let routetime = gps.rtime ? gps.rtime.getTime() : 0;
        if (data.markerVmg && data.markerVmg > 0) {
            routetime += data.routeRemain / data.markerVmg  * 1000; //time in ms
            let routeDate = new Date(Math.round(routetime));
            data.routeEta = routeDate;
        }
        else {
            data.routeEta = undefined;
        }
        data.routeNextCourse = undefined;
        if (gps.valid) {
            if (data.routeNextWp) {
                let dst = NavCompute.computeDistance(gps, data.routeNextWp);
                data.routeNextCourse = dst.course;
            }
        }
        else {
            data.routeRemain = 0;
            data.routeEta = undefined;
            data.routeNextCourse = undefined;
        }
    }
    else {
        data.routeName = undefined;
        data.routeNumPoints = 0;
        data.routeLen = 0;
        data.routeRemain = 0;
        data.routeEta = undefined;
        data.routeNextCourse = undefined;
    }
    let self=this;
    data.wpName=data.markerWp ? data.markerWp.name : '';
    //store the data asynchronously to avoid any locks
    window.setTimeout(()=> {
        globalStore.storeMultiple(data, {
            centerCourse: keys.nav.center.course,
            centerDistance: keys.nav.center.distance,
            markerCourse: keys.nav.wp.course,
            markerDistance: keys.nav.wp.distance,
            markerEta: keys.nav.wp.eta,
            markerXte: keys.nav.wp.xte,
            markerVmg: keys.nav.wp.vmg,
            markerWp: keys.nav.wp.position,
            anchorDirection: keys.nav.anchor.direction,
            anchorDistance: keys.nav.anchor.distance,
            anchorWatchDistance: keys.nav.anchor.watchDistance,
            centerMarkerCourse: keys.nav.center.markerCourse,
            centerMarkerDistance: keys.nav.center.markerDistance,
            routeName: keys.nav.route.name,
            routeNumPoints: keys.nav.route.numPoints,
            routeLen: keys.nav.route.len,
            routeRemain: keys.nav.route.remain,
            routeEta: keys.nav.route.eta,
            routeNextCourse: keys.nav.route.nextCourse,
            isApproaching: keys.nav.route.isApproaching,
            wpName:keys.nav.wp.name
        },self.changeCallback);
    },0);
};

/**
 * get the center for AIS queries
 * @returns {navobjects.Point}
 */
NavData.prototype.getAisCenter=function(){
    if (this.aisMode == navobjects.AisCenterMode.NONE) return undefined;
    if (this.aisMode == navobjects.AisCenterMode.GPS) {
        if (globalStore.getData(keys.nav.gps.valid)) return globalStore.getData(keys.nav.gps.position);
        return undefined;
    }
    return globalStore.getData(keys.map.centerPosition);
};

/**
 * set the mode for the AIS query
 * @param {navobjects.AisCenterMode} mode
 */
NavData.prototype.setAisCenterMode=function(mode){
    this.aisMode=mode;
};

/**
 * get the routing handler
 * @returns {RouteData|*}
 */
NavData.prototype.getRoutingHandler=function(){
    return this.routeHandler;
};

/**
 * get the gps data handler
 * @returns {GpsData}
 */
NavData.prototype.getGpsHandler=function(){
    return this.gpsdata;
};

NavData.prototype.resetTrack=function(){
    return this.trackHandler.resetTrack();
};

NavData.prototype.getCurrentPosition=function(){
    if (globalStore.getData(keys.nav.gps.valid)){
        return globalStore.getData(keys.nav.gps.position);
    }
};

module.exports=new NavData();

<|endoftext|>


<commit_before>'use strict';

const mongo = require('mongo');
const co = require('co');
const dataCollection = mongo.connect().then(db => db.collection('data'));

const defaultSearchEmOptions = {
    limit: 1e3,
    resolution: 1e6
};
const searchEm = co.wrap(function* em(value, options) {
    if (typeof value !== 'number') {
        throw new Error('value must be a number');
    }
    options = Object.assign({}, defaultSearchEmOptions, options);

    if (options.limit > 1e4) options.limit = 1e4;
    if (options.limit < 1) options.limit = 1;

    let error;
    if (options.accuracy) { // accuracy is in ppm
        error = value / 1e6 * options.accuracy;
    } else {
        error = value / options.resolution;
    }

    const data = yield dataCollection;
    const searchBottom = data.find({em: {$lte: value, $gte: value - error}}).sort({em: -1}).limit(options.limit).project({'ocl.id': 1, mf: 1, em: 1}).toArray();
    const searchTop = data.find({em: {$gt: value, $lte: value + error}}).sort({em: 1}).limit(options.limit).project({'ocl.id': 1, mf: 1, em: 1}).toArray();
    const results = yield Promise.all([searchBottom, searchTop]);

    const uniqueMFs = new Map();
    results.forEach(function treatResult(result) {
        for (const resultValue of result) {
            let element = uniqueMFs.get(resultValue.mf);
            if (!element) {
                element = {
                    mf: resultValue.mf,
                    em: resultValue.em,
                    ppm: Math.round(Math.abs(resultValue.em - value) / value * 1e6),
                    molecules: []
                };
                uniqueMFs.set(resultValue.mf, element);
            }
            element.molecules.push({
                id: resultValue._id,
                oclID: resultValue.ocl.id,
            });
        }
    });

    const finalResult = Array.from(uniqueMFs.values());
    finalResult.forEach(line => {
        line.total = line.molecules.length
    });
    finalResult.sort((a, b) => a.ppm - b.ppm);
    return finalResult;
});

exports.search = {
    em: searchEm
};
<commit_msg>faster search by em<commit_after>'use strict';

const mongo = require('mongo');
const co = require('co');
const dataCollection = mongo.connect().then(db => db.collection('data'));

const defaultSearchEmOptions = {
    limit: 1e3,
    resolution: 1e6
};
const searchEm = co.wrap(function* em(value, options) {
    if (typeof value !== 'number') {
        throw new Error('value must be a number');
    }
    options = Object.assign({}, defaultSearchEmOptions, options);

    if (options.limit > 1e4) options.limit = 1e4;
    if (options.limit < 1) options.limit = 1;

    let error;
    if (options.accuracy) { // accuracy is in ppm
        error = value / 1e6 * options.accuracy;
    } else {
        error = value / options.resolution;
    }

    const data = yield dataCollection;
    const searchBottom = data.find({em: {$lte: value, $gte: value - error}}).sort({em: -1}).limit(options.limit).project({_id: -1, em: 1, mf: 1}).toArray();
    const searchTop = data.find({em: {$gt: value, $lte: value + error}}).sort({em: 1}).limit(options.limit).project({_id: -1, em: 1, mf: 1}).toArray();
    const results = yield Promise.all([searchBottom, searchTop]);

    const uniqueMFs = new Map();
    results.forEach(function treatResult(result) {
        for (const resultValue of result) {
            let element = uniqueMFs.get(resultValue.mf);
            if (!element) {
                element = {
                    mf: resultValue.mf,
                    em: resultValue.em,
                    ppm: Math.abs(resultValue.em - value) / value * 1e6,
                    total: 0
                };
                uniqueMFs.set(resultValue.mf, element);
            }
            element.total++;
        }
    });

    const finalResult = Array.from(uniqueMFs.values());
    finalResult.sort((a, b) => a.ppm - b.ppm);
    return finalResult;
});

exports.search = {
    em: searchEm
};
<|endoftext|>


<commit_before>/*global TWEEN:true*/

// extends src/nodes/time.js which extends src/node-box-native-view.js

$(function(){

  var template =
    // '<canvas id="canvas-<%= id %>" class="canvas" width="180" height="100" style="max-width:100%;" />'+
    '<img id="view-<%= id %>" class="tween-view" width="180" height="100" style="max-width:100%;" />'+
    '

'+
    '
from:, to:, duration:
'+
    '

'+
    '

';

  Iframework.NativeNodes["time-tween"] = Iframework.NativeNodes["time"].extend({

    template: _.template(template),
    info: {
      title: "tween",
      description: "interpolate between two values over time"
    },
    initializeModule: function(){
      var self = this;
      if (window.TWEEN) {
        // this.setupTween();
      } else {
        yepnope({
          load: "libs/Tween.js",
          complete: function () {
            self.initializeModule();
          }
        });
      }
      // this.progressbar(".progressbar");
    },
    _tween: null,
    _tweenVals: {},
    setupTween: function(){
      var ease = this._ease;
      if (this._type === "Linear" && this._ease !== "None") {
        ease = "None";
      }
      if (!!window.TWEEN && TWEEN.Easing.hasOwnProperty(this._type) && TWEEN.Easing[this._type].hasOwnProperty(ease)) {
        // Restart tween if currently playing
        var restart = false;
        if (this._tween && this._tween.playing) {
          // Stop if exists
          this.inputstop();
          restart = true;
        }

        var tweeningFunction = TWEEN.Easing[this._type][ease];

        this.$(".function").text(this._type+"."+ease);
        this.$(".tween-in").text(this._from);
        this.$(".tween-out").text(this._to);
        this.$(".tween-duration").text(this._duration);
        this.$(".tween-view").attr({src:"libs/Tween/"+this._type+"."+ease+".png"});

        this._tweenVals.x = this._reversing ? this._to : this._from;
        var self = this;
        this._tween = new TWEEN.Tween( self._tweenVals )
          .to( { x: (self._reversing ? self._from : self._to) }, self._duration*1000 )
          .easing( tweeningFunction )
          .onComplete( function () {
            self.send("complete", "!");
            self.inputstop();
            // Reverse or loop if set
            self.loop();
          });

        if (restart) {
          // Restart
          this.inputstart();
        }
      }
    },
    _reversing: false,
    reverse: function(){
      this._reversing = !this._reversing;
      this.setupTween();
      this.inputstart();
    },
    loop: function(){
      // Reverse, loop, or stop
      if (this._pingpong) {
        this.reverse();
      } else if (this._loop) {
        this.inputstart();
      }
    },
    _deferStart: false,
    inputstart: function(){
      if (!window.TWEEN) {
        this._deferStart = true;
        return;
      }
      if (!this._tween) {
        this.setupTween();
      }
      if (this._tween) {
        // Reset
        this._tweenVals.x = this._reversing ? this._to : this._from;
        this._tween.start();
        this._tween.playing = true;
      }
    },
    inputstop: function(){
      if (this._tween) {
        this._tween.stop();
        this._tween.playing = false;
      }
    },
    inputpingpong: function(boo){
      this._pingpong = boo;
      if (boo) {
        this.$(".loop").text("(pingpong)");
      } else {
        this.$(".loop").text(this._loop ? "(loop)" : "");
      }
    },
    inputloop: function(boo){
      this._loop = boo;
      if (!this._pingpong) {
        if (boo) {
          this.$(".loop").text("(loop)");
        } else {
          this.$(".loop").text("");
        }
      }
    },
    _lastDisplay: "",
    redraw: function(){
      // Only display to .00001
      var display = Math.round(this._tweenVals.x*100000)/100000;
      if (display !== this._lastDisplay) {
        this.$(".tween-value").text(display);
        this._lastDisplay = display;
      }
    },
    renderAnimationFrame: function (timestamp) {
      // Get a tick from GraphView.renderAnimationFrame()
      // this._valueChanged is set by NodeBox.receive()
      if (this._triggerRedraw) {
        // Changing settings sets up a new tween
        if (window.TWEEN) {
          this._triggerRedraw = false;
          this.setupTween();
          if (this._deferStart) {
            this._deferStart = false;
            this.inputstart();
          }
        }
      }
      if (!!window.TWEEN && this._tween && this._tween.playing) {
        this._tween.update(timestamp);
        if (this._lastValue !== this._tweenVals.x) {
          this.send("value", this._tweenVals.x);
          this.redraw();
        }
        this._lastValue = this._tweenVals.x;
      }
    },
    inputs: {
      from: {
        type: "float",
        description: "start value",
        "default": 0.0
      },
      to: {
        type: "float",
        description: "end value",
        "default": 1.0
      },
      duration: {
        type: "float",
        description: "number of seconds",
        "default": 5.0
      },
      type: {
        type: "string",
        description: "Linear Quadratic Cubic Quartic Quintic Sinusoidal Exponential Circular Elastic Back Bounce. For a visual explanation see: http://sole.github.com/tween.js/examples/03_graphs.html",
        options: "Linear Quadratic Cubic Quartic Quintic Sinusoidal Exponential Circular Elastic Back Bounce".split(" "),
        "default": "Sinusoidal"
      },
      ease: {
        type: "string",
        description: "In, Out, or InOut for all except Linear, which is None. For a visual explanation see: http://sole.github.com/tween.js/examples/03_graphs.html",
        options: "None In Out InOut".split(" "),
        "default": "InOut"
      },
      loop: {
        type: "boolean",
        description: "restart the tween on completion"
      },
      pingpong: {
        type: "boolean",
        description: "reverse the tween on completion"
      },
      start: {
        type: "bang",
        description: "start tween"
      },
      stop: {
        type: "bang",
        description: "stop tween"
      }
    },
    outputs: {
      complete: {
        type: "bang"
      },
      value: {
        type: "float"
      }
    }

  });

});
<commit_msg>change from linear and back<commit_after>/*global TWEEN:true*/

// extends src/nodes/time.js which extends src/node-box-native-view.js

$(function(){

  var template =
    // '<canvas id="canvas-<%= id %>" class="canvas" width="180" height="100" style="max-width:100%;" />'+
    '<img id="view-<%= id %>" class="tween-view" width="180" height="100" style="max-width:100%;" />'+
    '

'+
    '
from:, to:, duration:
'+
    '

'+
    '

';

  Iframework.NativeNodes["time-tween"] = Iframework.NativeNodes["time"].extend({

    template: _.template(template),
    info: {
      title: "tween",
      description: "interpolate between two values over time"
    },
    initializeModule: function(){
      var self = this;
      if (window.TWEEN) {
        // this.setupTween();
      } else {
        yepnope({
          load: "libs/Tween.js",
          complete: function () {
            self.initializeModule();
          }
        });
      }
      // this.progressbar(".progressbar");
    },
    _tween: null,
    _tweenVals: {},
    setupTween: function(){
      var ease = this._ease;
      if (this._type === "Linear" && this._ease !== "None") {
        ease = "None";
      }
      if (this._type !== "Linear" && this._ease === "None") {
        ease = "InOut";
      }
      if (!!window.TWEEN && TWEEN.Easing.hasOwnProperty(this._type) && TWEEN.Easing[this._type].hasOwnProperty(ease)) {
        // Restart tween if currently playing
        var restart = false;
        if (this._tween && this._tween.playing) {
          // Stop if exists
          this.inputstop();
          restart = true;
        }

        var tweeningFunction = TWEEN.Easing[this._type][ease];

        this.$(".function").text(this._type+"."+ease);
        this.$(".tween-in").text(this._from);
        this.$(".tween-out").text(this._to);
        this.$(".tween-duration").text(this._duration);
        this.$(".tween-view").attr({src:"libs/Tween/"+this._type+"."+ease+".png"});

        this._tweenVals.x = this._reversing ? this._to : this._from;
        var self = this;
        this._tween = new TWEEN.Tween( self._tweenVals )
          .to( { x: (self._reversing ? self._from : self._to) }, self._duration*1000 )
          .easing( tweeningFunction )
          .onComplete( function () {
            self.send("complete", "!");
            self.inputstop();
            // Reverse or loop if set
            self.loop();
          });

        if (restart) {
          // Restart
          this.inputstart();
        }
      }
    },
    _reversing: false,
    reverse: function(){
      this._reversing = !this._reversing;
      this.setupTween();
      this.inputstart();
    },
    loop: function(){
      // Reverse, loop, or stop
      if (this._pingpong) {
        this.reverse();
      } else if (this._loop) {
        this.inputstart();
      }
    },
    _deferStart: false,
    inputstart: function(){
      if (!window.TWEEN) {
        this._deferStart = true;
        return;
      }
      if (!this._tween) {
        this.setupTween();
      }
      if (this._tween) {
        // Reset
        this._tweenVals.x = this._reversing ? this._to : this._from;
        this._tween.start();
        this._tween.playing = true;
      }
    },
    inputstop: function(){
      if (this._tween) {
        this._tween.stop();
        this._tween.playing = false;
      }
    },
    inputpingpong: function(boo){
      this._pingpong = boo;
      if (boo) {
        this.$(".loop").text("(pingpong)");
      } else {
        this.$(".loop").text(this._loop ? "(loop)" : "");
      }
    },
    inputloop: function(boo){
      this._loop = boo;
      if (!this._pingpong) {
        if (boo) {
          this.$(".loop").text("(loop)");
        } else {
          this.$(".loop").text("");
        }
      }
    },
    _lastDisplay: "",
    redraw: function(){
      // Only display to .00001
      var display = Math.round(this._tweenVals.x*100000)/100000;
      if (display !== this._lastDisplay) {
        this.$(".tween-value").text(display);
        this._lastDisplay = display;
      }
    },
    renderAnimationFrame: function (timestamp) {
      // Get a tick from GraphView.renderAnimationFrame()
      // this._valueChanged is set by NodeBox.receive()
      if (this._triggerRedraw) {
        // Changing settings sets up a new tween
        if (window.TWEEN) {
          this._triggerRedraw = false;
          this.setupTween();
          if (this._deferStart) {
            this._deferStart = false;
            this.inputstart();
          }
        }
      }
      if (!!window.TWEEN && this._tween && this._tween.playing) {
        this._tween.update(timestamp);
        if (this._lastValue !== this._tweenVals.x) {
          this.send("value", this._tweenVals.x);
          this.redraw();
        }
        this._lastValue = this._tweenVals.x;
      }
    },
    inputs: {
      from: {
        type: "float",
        description: "start value",
        "default": 0.0
      },
      to: {
        type: "float",
        description: "end value",
        "default": 1.0
      },
      duration: {
        type: "float",
        description: "number of seconds",
        "default": 5.0
      },
      type: {
        type: "string",
        description: "Linear Quadratic Cubic Quartic Quintic Sinusoidal Exponential Circular Elastic Back Bounce. For a visual explanation see: http://sole.github.com/tween.js/examples/03_graphs.html",
        options: "Linear Quadratic Cubic Quartic Quintic Sinusoidal Exponential Circular Elastic Back Bounce".split(" "),
        "default": "Sinusoidal"
      },
      ease: {
        type: "string",
        description: "In, Out, or InOut for all except Linear, which is None. For a visual explanation see: http://sole.github.com/tween.js/examples/03_graphs.html",
        options: "None In Out InOut".split(" "),
        "default": "InOut"
      },
      loop: {
        type: "boolean",
        description: "restart the tween on completion"
      },
      pingpong: {
        type: "boolean",
        description: "reverse the tween on completion"
      },
      start: {
        type: "bang",
        description: "start tween"
      },
      stop: {
        type: "bang",
        description: "stop tween"
      }
    },
    outputs: {
      complete: {
        type: "bang"
      },
      value: {
        type: "float"
      }
    }

  });

});
<|endoftext|>


<commit_before>const en = require("../src/i18n/strings/en_EN");
const de = require("../src/i18n/strings/de_DE");

module.exports = jest.fn((opts, cb) => {
    const url = opts.url || opts.uri;
    if (url && url.endsWith("languages.json")) {
        cb(undefined, {status: 200}, JSON.stringify({
            "en": {
                "fileName": "en_EN.json",
                "label": "English",
            },
            "de": {
                "fileName": "de_DE.json",
                "label": "German",
            },
        }));
    } else if (url && url.endsWith("en_EN.json")) {
        cb(undefined, {status: 200}, JSON.stringify(en));
    } else if (url && url.endsWith("de_DE.json")) {
        cb(undefined, {status: 200}, JSON.stringify(de));
    } else {
        cb(true, {status: 404}, "");
    }
});
<commit_msg>add comments<commit_after>const en = require("../src/i18n/strings/en_EN");
const de = require("../src/i18n/strings/de_DE");

// Mock the browser-request for the languageHandler tests to return
// Fake languages.json containing references to en_EN and de_DE
// en_EN.json
// de_DE.json
module.exports = jest.fn((opts, cb) => {
    const url = opts.url || opts.uri;
    if (url && url.endsWith("languages.json")) {
        cb(undefined, {status: 200}, JSON.stringify({
            "en": {
                "fileName": "en_EN.json",
                "label": "English",
            },
            "de": {
                "fileName": "de_DE.json",
                "label": "German",
            },
        }));
    } else if (url && url.endsWith("en_EN.json")) {
        cb(undefined, {status: 200}, JSON.stringify(en));
    } else if (url && url.endsWith("de_DE.json")) {
        cb(undefined, {status: 200}, JSON.stringify(de));
    } else {
        cb(true, {status: 404}, "");
    }
});
<|endoftext|>


<commit_before>  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-64951930-1', 'auto');
  ga('send', 'pageview');
<commit_msg>Corrected ga code according to new eu law<commit_after>var gaProperty = 'UA-64951930-1';
var disableStr = 'ga-disable-' + gaProperty;
if (document.cookie.indexOf(disableStr + '=true') > -1) {
  window[disableStr] = true;
}
function gaOptout() {
  document.cookie = disableStr + '=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/';
  window[disableStr] = true;
  alert('Das Tracking ist jetzt deaktiviert');
}
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-64951930-1', 'auto');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
<|endoftext|>


<commit_before>var GitHub = require('github-api'),
    log = require('../lib/logger')('github.js');

module.exports = function(context, config) {

  config = config || {};
  var username = config.username || 'moravianlibrary';
  var reponame = config.reponame || 'mapseries-data';
  var workBranch = config.workBranch || 'work';

  var github = null;
  var upstream = null;
  var origin = null;

  function getGitHub() {
    if (github) {
      return github;
    }
    github = new GitHub({
      token: context.storage.get('github_token'),
    });

    return github;
  }

  function getUpstream() {
    if (upstream) {
      return upstream;
    }
    var github = getGitHub();
    upstream = github.getRepo(username, reponame);
    return upstream;
  }

  function getOrigin() {
    if (origin) {
      return origin;
    }
    var github = getGitHub();
    origin = github.getRepo(context.storage.get('github_username'), reponame);
    return origin;
  }

  function hasFork() {
    log.debug('Calling hasFork()')
    var repo = getOrigin();

    return new Promise(function(resolve, reject) {
      repo.getContents('master', "")
      .then(() => { log.debug('hasFork returned true'); resolve(true) })
      .catch(() => { log.debug('hasFork returned false'); resolve(false) })
    });
  }

  function fork() {
    log.debug('Calling fork()')
    var timer = null;

    return new Promise((resolve, reject) => {
      timer = window.setInterval(() => {
        log.debug('window.setInterval')

        hasFork().then((result) => {
          if (result) {
            window.clearInterval(timer);
            resolve();
          }
        })
      }, 1000);

      var repo = getUpstream();
      repo.fork()
      .catch((err) => {
        window.clearInterval(timer);
        reject(err);
      });
    });
  }

  function hasWork() {
    log.debug('Calling hasWork()')
    var repo = getOrigin();

    return new Promise((resolve, reject) => {
      repo.getRef('heads/' + workBranch)
      .then(() => { log.debug('hasWork returned true'); resolve(true) })
      .catch(() => { log.debug('hasWork returned false'); resolve(false) })
    });
  }

  function initWork() {
    log.debug('Calling initWork()')

    return hasWork()
    .then((result) => {
      if (result) {
        return new Promise((resolve, reject) => { resolve() })
      } else {
        var repo = getOrigin();
        return repo.createBranch('master', workBranch);
      }
    });

  }

  function isDirty() {
    log.debug('Calling isDirty()')
    var origin = getOrigin(),
        masterSha = null;

    return origin.getRef('heads/master')
    .then((res) => {
      masterSha = res;
      return origin.getRef('heads/' + workBranch);
    })
    .then((workSha) => {
      var result = masterSha.data.object.sha != workSha.data.object.sha;
      log.debug('isDirty returned ' + result)
      return new Promise((resolve, reject) => { resolve(result) });
    });

  }

  function isSynced() {
    log.debug('Calling isSynced()')
    var origin = getOrigin(),
        upstream = getUpstream(),
        originSha = null;

    return origin.getRef('heads/master')
    .then((res) => {
      originSha = res;
      return upstream.getRef('heads/master');
    })
    .then((upstreamSha) => {
      var result = originSha.data.object.sha == upstreamSha.data.object.sha;
      log.debug('isSynced returned ' + result)
      return new Promise((resolve, reject) => { resolve(result) });
    });

  }

  function createPullBranch() {
    log.debug('Calling createPullBranch()')
    var repo = getOrigin();
    var branchName;

    return new Promise((resolve, reject) => {

      repo.listBranches()
      .then((branches) => {
        var maxNum = 0;
        var regex = /^pull(\d+)$/;
        branches.data.forEach(function(branch) {
          var match = regex.exec(branch.name);
          if (match) {
            maxNum = Math.max(maxNum, parseInt(match[1]));
          }
        });
        branchName = 'pull' + (maxNum + 1);

        return repo.createBranch(workBranch, branchName);
      })
      .then(() => { resolve(branchName) })
      .catch((err) => { reject(err) });

    });
  }

  function init() {
    log.debug('Calling init()')

    return hasFork()
    .then((forked) => {
      if (!forked) {
        return fork();
      } else {
        return new Promise((resolve, reject) => { resolve() });
      }
    })
    .then(() => {
      return hasWork();
    })
    .then((work) => {
      if (!work) {
        return initWork();
      } else {
        return new Promise((resolve, reject) => { resolve() });
      }
    })
    .then(() => {
      return isDirty();
    })
    .then((dirty) => {
      if (dirty) {
        context.dispatch.init_dirty();
        return new Promise((resolve, reject) => { resolve() });
      } else {
        return isSynced()
        .then((synced) => {
          if (synced) {
            return new Promise((resolve, reject) => { resolve() });
          } else {
            var repo = getOrigin();
            return repo.deleteRepo()
            .then(() => {
              return fork()
            })
            .then(() => {
              return initWork();
            })
          }
        });
      }
    })
  }

  function lsPath(path, callback) {
    log.debug('Calling lsPath()')
    var repo = getOrigin();
    return repo.contents(workBranch, path);
  }

  function getTreeSha(treeSha, name) {
    log.debug('Calling getTreeSha()')

    var repo = getOrigin();

    return new Promise((resolve, reject) => {
      repo.getTree(treeSha)
      .then((tree) => {
        var resolved = false;
        tree.data.tree.forEach((t) => {
          if (t.path == name) {
            resolved = true;
            resolve(t.sha);
            return;
          }
        });
        if (!resolved) {
          reject(name + ' was not found in ' + tree);
        }
      })
      .catch((err) => { reject(err) });
    });
  }

  function readFile(path, treeSha) {
    log.debug('Calling readFile()')

    var repo = getOrigin(),
        paths = null;

    if (typeof path === "string") {
      paths = path.split('/')
    } else {
      paths = path;
    }

    if (paths.length > 0) {
      let p = paths[0];

      if (!treeSha) {

        return repo.getRef('heads/' + workBranch)
        .then((sha) => {

          return getTreeSha(sha.data.object.sha, p)
          .then((sha) => { return readFile(paths.slice(1), sha) })

        });

      } else {

        return getTreeSha(treeSha, p)
        .then((sha) => { return readFile(paths.slice(1), sha) })

      }

    } else {
      return repo.getBlob(treeSha)
      .then((data) => {
        return new Promise((resolve, reject) => { resolve(data.data) })
      })
    }
  }

  function writeFiles(files, message, blobs) {
    log.debug('Calling writeFiles()')
    var repo = getOrigin(),
        workRef = 'heads/' + workBranch;

    if (files.length) {
      var file = files.pop();

      return repo.createBlob({content: file.content})
      .then((sha) => {
        blobs = blobs || [];
        blobs.push({path: file.path, sha: sha.data.sha});
        return writeFiles(files, message, blobs);
      });

    } else {

      var commitSha = null,
          commit = null,
          treeSha = null;

      return repo.getRef(workRef)
      .then((res) => {
        commitSha = res.data.object.sha;
        return repo.getCommit(commitSha);
      })
      .then((res) => {
        commit = res.data;
        var tree = [];
        blobs.forEach(function(blob) {
          tree.push({
            path: blob.path,
            mode: '100644',
            type: 'blob',
            sha: blob.sha
          });
        });
        return repo.createTree(tree, commit.tree.sha);
      })
      .then((res) => {
        treeSha = res.data.sha;
        return repo.commit(commitSha, treeSha, message);
      })
      .then((commit) => {
        return repo.updateHead(workRef, commit.data.sha, false);
      });
    }
  }

  function pullRequest(title) {
    log.debug('Calling pullRequest()')

    return createPullBranch()
    .then((branch) => {
      var pull = {
        body: 'Generated by geojson.io',
        base: 'master',
        head: context.storage.get('github_username') + ':' + branch,
        title: title
      };
      var repo = getUpstream();
      return repo.createPullRequest(pull);
    })
    .then(() => {
      return discardWork();
    });
  }

  function discardWork() {
    log.debug('Calling discardWork()')
    var origin = getOrigin();

    return origin.deleteRef('heads/' + workBranch)
    .then(() => {
      return origin.createBranch('master', workBranch);
    })
    .then(() => {
      context.dispatch.discardWork();
      return new Promise((resolve, reject) => { resolve() });
    });
  }

  return {
    init: init,
    lsPath: lsPath,
    readFile: readFile,
    writeFiles: writeFiles,
    pullRequest: pullRequest,
    discardWork: discardWork
  };
};
<commit_msg>Bug fix<commit_after>var GitHub = require('github-api'),
    log = require('../lib/logger')('github.js');

module.exports = function(context, config) {

  config = config || {};
  var username = config.username || 'moravianlibrary';
  var reponame = config.reponame || 'mapseries-data';
  var workBranch = config.workBranch || 'work';

  var github = null;
  var upstream = null;
  var origin = null;

  function getGitHub() {
    if (github) {
      return github;
    }
    github = new GitHub({
      token: context.storage.get('github_token'),
    });

    return github;
  }

  function getUpstream() {
    if (upstream) {
      return upstream;
    }
    var github = getGitHub();
    upstream = github.getRepo(username, reponame);
    return upstream;
  }

  function getOrigin() {
    if (origin) {
      return origin;
    }
    var github = getGitHub();
    origin = github.getRepo(context.storage.get('github_username'), reponame);
    return origin;
  }

  function hasFork() {
    log.debug('Calling hasFork()')
    var repo = getOrigin();

    return new Promise(function(resolve, reject) {
      repo.getContents('master', "")
      .then(() => { log.debug('hasFork returned true'); resolve(true) })
      .catch(() => { log.debug('hasFork returned false'); resolve(false) })
    });
  }

  function fork() {
    log.debug('Calling fork()')
    var timer = null;

    return new Promise((resolve, reject) => {
      timer = window.setInterval(() => {
        log.debug('window.setInterval')

        hasFork().then((result) => {
          if (result) {
            window.clearInterval(timer);
            resolve();
          }
        })
      }, 1000);

      var repo = getUpstream();
      repo.fork()
      .then((forked_repo) => {
        var new_reponame = forked_repo.data['name']
        var github = getGitHub();
        var origin = github.getRepo(context.storage.get('github_username'), new_reponame);
        return origin.updateRepository({name : 'mapseries-data'})
      })
      .catch((err) => {
        window.clearInterval(timer);
        reject(err);
      });
    });
  }

  function hasWork() {
    log.debug('Calling hasWork()')
    var repo = getOrigin();

    return new Promise((resolve, reject) => {
      repo.getRef('heads/' + workBranch)
      .then(() => { log.debug('hasWork returned true'); resolve(true) })
      .catch(() => { log.debug('hasWork returned false'); resolve(false) })
    });
  }

  function initWork() {
    log.debug('Calling initWork()')

    return hasWork()
    .then((result) => {
      if (result) {
        return new Promise((resolve, reject) => { resolve() })
      } else {
        var repo = getOrigin();
        return repo.createBranch('master', workBranch);
      }
    });

  }

  function isDirty() {
    log.debug('Calling isDirty()')
    var origin = getOrigin(),
        masterSha = null;

    return origin.getRef('heads/master')
    .then((res) => {
      masterSha = res;
      return origin.getRef('heads/' + workBranch);
    })
    .then((workSha) => {
      var result = masterSha.data.object.sha != workSha.data.object.sha;
      log.debug('isDirty returned ' + result)
      return new Promise((resolve, reject) => { resolve(result) });
    });

  }

  function isSynced() {
    log.debug('Calling isSynced()')
    var origin = getOrigin(),
        upstream = getUpstream(),
        originSha = null;

    return origin.getRef('heads/master')
    .then((res) => {
      originSha = res;
      return upstream.getRef('heads/master');
    })
    .then((upstreamSha) => {
      var result = originSha.data.object.sha == upstreamSha.data.object.sha;
      log.debug('isSynced returned ' + result)
      return new Promise((resolve, reject) => { resolve(result) });
    });

  }

  function createPullBranch() {
    log.debug('Calling createPullBranch()')
    var repo = getOrigin();
    var branchName;

    return new Promise((resolve, reject) => {

      repo.listBranches()
      .then((branches) => {
        var maxNum = 0;
        var regex = /^pull(\d+)$/;
        branches.data.forEach(function(branch) {
          var match = regex.exec(branch.name);
          if (match) {
            maxNum = Math.max(maxNum, parseInt(match[1]));
          }
        });
        branchName = 'pull' + (maxNum + 1);

        return repo.createBranch(workBranch, branchName);
      })
      .then(() => { resolve(branchName) })
      .catch((err) => { reject(err) });

    });
  }

  function init() {
    log.debug('Calling init()')

    return hasFork()
    .then((forked) => {
      if (!forked) {
        return fork();
      } else {
        return new Promise((resolve, reject) => { resolve() });
      }
    })
    .then(() => {
      return hasWork();
    })
    .then((work) => {
      if (!work) {
        return initWork();
      } else {
        return new Promise((resolve, reject) => { resolve() });
      }
    })
    .then(() => {
      return isDirty();
    })
    .then((dirty) => {
      if (dirty) {
        context.dispatch.init_dirty();
        return new Promise((resolve, reject) => { resolve() });
      } else {
        return isSynced()
        .then((synced) => {
          if (synced) {
            return new Promise((resolve, reject) => { resolve() });
          } else {
            var repo = getOrigin();
            return repo.deleteRepo()
            .then(() => {
              return fork()
            })
            .then(() => {
              return initWork();
            })
          }
        });
      }
    })
  }

  function lsPath(path, callback) {
    log.debug('Calling lsPath()')
    var repo = getOrigin();
    return repo.contents(workBranch, path);
  }

  function getTreeSha(treeSha, name) {
    log.debug('Calling getTreeSha()')

    var repo = getOrigin();

    return new Promise((resolve, reject) => {
      repo.getTree(treeSha)
      .then((tree) => {
        var resolved = false;
        tree.data.tree.forEach((t) => {
          if (t.path == name) {
            resolved = true;
            resolve(t.sha);
            return;
          }
        });
        if (!resolved) {
          reject(name + ' was not found in ' + tree);
        }
      })
      .catch((err) => { reject(err) });
    });
  }

  function readFile(path, treeSha) {
    log.debug('Calling readFile()')

    var repo = getOrigin(),
        paths = null;

    if (typeof path === "string") {
      paths = path.split('/')
    } else {
      paths = path;
    }

    if (paths.length > 0) {
      let p = paths[0];

      if (!treeSha) {

        return repo.getRef('heads/' + workBranch)
        .then((sha) => {

          return getTreeSha(sha.data.object.sha, p)
          .then((sha) => { return readFile(paths.slice(1), sha) })

        });

      } else {

        return getTreeSha(treeSha, p)
        .then((sha) => { return readFile(paths.slice(1), sha) })

      }

    } else {
      return repo.getBlob(treeSha)
      .then((data) => {
        return new Promise((resolve, reject) => { resolve(data.data) })
      })
    }
  }

  function writeFiles(files, message, blobs) {
    log.debug('Calling writeFiles()')
    var repo = getOrigin(),
        workRef = 'heads/' + workBranch;

    if (files.length) {
      var file = files.pop();

      return repo.createBlob({content: file.content})
      .then((sha) => {
        blobs = blobs || [];
        blobs.push({path: file.path, sha: sha.data.sha});
        return writeFiles(files, message, blobs);
      });

    } else {

      var commitSha = null,
          commit = null,
          treeSha = null;

      return repo.getRef(workRef)
      .then((res) => {
        commitSha = res.data.object.sha;
        return repo.getCommit(commitSha);
      })
      .then((res) => {
        commit = res.data;
        var tree = [];
        blobs.forEach(function(blob) {
          tree.push({
            path: blob.path,
            mode: '100644',
            type: 'blob',
            sha: blob.sha
          });
        });
        return repo.createTree(tree, commit.tree.sha);
      })
      .then((res) => {
        treeSha = res.data.sha;
        return repo.commit(commitSha, treeSha, message);
      })
      .then((commit) => {
        return repo.updateHead(workRef, commit.data.sha, false);
      });
    }
  }

  function pullRequest(title) {
    log.debug('Calling pullRequest()')

    return createPullBranch()
    .then((branch) => {
      var pull = {
        body: 'Generated by geojson.io',
        base: 'master',
        head: context.storage.get('github_username') + ':' + branch,
        title: title
      };
      var repo = getUpstream();
      return repo.createPullRequest(pull);
    })
    .then(() => {
      return discardWork();
    });
  }

  function discardWork() {
    log.debug('Calling discardWork()')
    var origin = getOrigin();

    return origin.deleteRef('heads/' + workBranch)
    .then(() => {
      return origin.createBranch('master', workBranch);
    })
    .then(() => {
      context.dispatch.discardWork();
      return new Promise((resolve, reject) => { resolve() });
    });
  }

  return {
    init: init,
    lsPath: lsPath,
    readFile: readFile,
    writeFiles: writeFiles,
    pullRequest: pullRequest,
    discardWork: discardWork
  };
};
<|endoftext|>