<commit_before>define(["js/core/Window", "js/html/HtmlElement", "js/lib/extension", "underscore", "require", "flow", "js/core/Bindable"], function (Window, HtmlElement, Extension, _, require, flow, Bindable) {

    /***
     * @summary An application is a Window, which gets bootstrapped and started by rAppid.js and is attached to the WindowManager.
     *
     * @description Setting up and application can be easily done via the `rappidjs create app` command. For more information about projects \
     * have a look at http://rappidjs.com/#/wiki/Project
     *
     * @see js.core.WindowManager
     */
    return Window.inherit("js.core.Application", {
        $classAttributes: [/.+/],

        _inject: function () {
            // overwrite and call inside start
        },

        _initializeDescriptors: function () {
            this.callBase();
            HtmlElement.prototype._inject.call(this);
        },

        /**
         * Starts the application after the application is bootstrapped
         *
         * @param {Object} [parameter] - parameter configuring the application
         * @param {Function} callback
         */
        start: function (parameter, callback) {
            this.show();

            this._startHistory(callback, parameter.initialHash);
        },

        /***
         *
         * @return {String} the name of the current environment
         * @private
         */
        _getEnvironment: function () {
            return this.$stage.$environmentName;
        },

        /***
         * the default namespace of the application.
         *
         * Within the application default namespace are several default directories located.
         *
         * **E.g.:**
         *
         *   +  **env** - contains for each environment an json file
         *   +  **locale** - contains for each locale a json file for translations
         *
         * the `env` directory for environments and the locale directory
         *
         * @type String
         */
        applicationDefaultNamespace: "app",

        /***
         * the `supportEnvironments` property determinate if the application has build in support for environments.
         *
         * The environment is determinated with the `_getEnvironment` method of the application and
         * returns by default the value of `environment` passed as start parameter of the application
         *
         * @wiki Environments
         */
        supportEnvironments: false,

        /***
         * Starts the history, which is responsible for navigation
         *
         * @param {Function} [callback] callback function, which is invoked after the history has started
         * @param {String} [initialHash=null] starts the history with this fragment
         * @private
         */
        _startHistory: function (callback, initialHash) {
            this.$stage.$history.start(callback, initialHash);
        },

        /***
         *
         * renders the application in the `target` Element.
         *
         * @param {Element} [target] the native Element where the rendered element will be appended
         * @return {Element} the rendered Element
         */
        render: function (target) {
            var dom = this.callBase(target);

            this.$stage.$bus.trigger('Application.Rendered');

            return dom;
        }

    }, {

        /***
         *
         * @param {js.core.Bindable} ENV - the bindable to set the environment values
         * @param {String} environmentName - the name of the environment to load
         * @param {String} applicationDefaultNamespace - the root namespace directory where to search for the env directory
         * @param {Function} callback
         */
        setupEnvironment: function (ENV, environmentName, applicationDefaultNamespace, callback) {

            var defaultEnvironment,
                environment;

            flow()
                .par(function (cb) {

                    require(["json!" + applicationDefaultNamespace + "/env/default"], function (d) {
                        defaultEnvironment = d;
                        cb();
                    }, function (err) {
                        cb(err);
                    });
                }, function (cb) {
                    if (environmentName) {
                        require(["json!" + applicationDefaultNamespace + "/env/" + environmentName], function (d) {
                            environment = d;
                            cb();
                        }, function (err) {
                            cb(err);
                        });
                    } else {
                        cb();
                    }
                })
                .exec(function (err) {
                    ENV.set(_.extend({}, defaultEnvironment, environment));
                    callback && callback(err);
                });

        }

    });
});<commit_msg>removed unused import Bindable<commit_after>define(["js/core/Window", "js/html/HtmlElement", "js/lib/extension", "underscore", "require", "flow"], function (Window, HtmlElement, Extension, _, require, flow) { //NOSONAR

    /***
     * @summary An application is a Window, which gets bootstrapped and started by rAppid.js and is attached to the WindowManager.
     *
     * @description Setting up and application can be easily done via the `rappidjs create app` command. For more information about projects \
     * have a look at http://rappidjs.com/#/wiki/Project
     *
     * @see js.core.WindowManager
     */
    return Window.inherit("js.core.Application", {
        $classAttributes: [/.+/],

        _inject: function () {
            // overwrite and call inside start
        },

        _initializeDescriptors: function () {
            this.callBase();
            HtmlElement.prototype._inject.call(this);
        },

        /**
         * Starts the application after the application is bootstrapped
         *
         * @param {Object} [parameter] - parameter configuring the application
         * @param {Function} callback
         */
        start: function (parameter, callback) {
            this.show();

            this._startHistory(callback, parameter.initialHash);
        },

        /***
         *
         * @return {String} the name of the current environment
         * @private
         */
        _getEnvironment: function () {
            return this.$stage.$environmentName;
        },

        /***
         * the default namespace of the application.
         *
         * Within the application default namespace are several default directories located.
         *
         * **E.g.:**
         *
         *   +  **env** - contains for each environment an json file
         *   +  **locale** - contains for each locale a json file for translations
         *
         * the `env` directory for environments and the locale directory
         *
         * @type String
         */
        applicationDefaultNamespace: "app",

        /***
         * the `supportEnvironments` property determinate if the application has build in support for environments.
         *
         * The environment is determinated with the `_getEnvironment` method of the application and
         * returns by default the value of `environment` passed as start parameter of the application
         *
         * @wiki Environments
         */
        supportEnvironments: false,

        /***
         * Starts the history, which is responsible for navigation
         *
         * @param {Function} [callback] callback function, which is invoked after the history has started
         * @param {String} [initialHash=null] starts the history with this fragment
         * @private
         */
        _startHistory: function (callback, initialHash) {
            this.$stage.$history.start(callback, initialHash);
        },

        /***
         *
         * renders the application in the `target` Element.
         *
         * @param {Element} [target] the native Element where the rendered element will be appended
         * @return {Element} the rendered Element
         */
        render: function (target) {
            var dom = this.callBase(target);

            this.$stage.$bus.trigger('Application.Rendered');

            return dom;
        }

    }, {

        /***
         *
         * @param {js.core.Bindable} ENV - the bindable to set the environment values
         * @param {String} environmentName - the name of the environment to load
         * @param {String} applicationDefaultNamespace - the root namespace directory where to search for the env directory
         * @param {Function} callback
         */
        setupEnvironment: function (ENV, environmentName, applicationDefaultNamespace, callback) {

            var defaultEnvironment,
                environment;

            flow()
                .par(function (cb) {

                    require(["json!" + applicationDefaultNamespace + "/env/default"], function (d) {
                        defaultEnvironment = d;
                        cb();
                    }, function (err) {
                        cb(err);
                    });
                }, function (cb) {
                    if (environmentName) {
                        require(["json!" + applicationDefaultNamespace + "/env/" + environmentName], function (d) {
                            environment = d;
                            cb();
                        }, function (err) {
                            cb(err);
                        });
                    } else {
                        cb();
                    }
                })
                .exec(function (err) {
                    ENV.set(_.extend({}, defaultEnvironment, environment));
                    callback && callback(err);
                });

        }

    });
});<|endoftext|>


<commit_before>var c = function(m){console.log(m);};
var EventsModule = {

  create_events: function() {
    var self = this;
    this.events.each(function(event) {
      var f = "on_$0".exec(event);
      self[f] = function() {
        var func = this.setting[f];
        if (func && Object.isFunction(func)) {
          func.apply(this, arguments);
        }
      }
    });

  }
};

var Widget = Class.create(EventsModule, {
  initialize: function(element, setting) {
    this.element = $(element);

    if (!Object.isElement(this.element))
      throw "Element #{e} not found.".interpolate({e: element});

    Object.extend(this.setting, setting || {});

    this.create(this.html);
    this.bind_event();
  },
  create: function() {
    var html = Translator.translate(this.setting.config);
    return html;
  },
  bind_event: function() {
    if (this.setting.on) {
      var handler = this.on.bind(this);
      this.element.observe(this.setting.on, handler);
    }
  },
  on: function(event) {
    throw "Abstract. You must implement `on` function for events";
  }
});

Widget.prototype.initialize = Widget.prototype.initialize.wrap(
    function(func) {
      this.events = $w('create destroy add remove open close');
      this.setup();
      this.create_events();
      return func.apply(this, $A(arguments).slice(1));
    }
);

<commit_msg>add feature: settion.on as Array<commit_after>var c = function(m){console.log(m);};
var EventsModule = {

  create_events: function() {
    var self = this;
    this.events.each(function(event) {
      var f = "on_$0".exec(event);
      self[f] = function() {
        var func = this.setting[f];
        if (func && Object.isFunction(func)) {
          func.apply(this, arguments);
        }
      }
    });

  }
};

var Widget = Class.create(EventsModule, {
  initialize: function(element, setting) {
    this.element = $(element);

    if (!Object.isElement(this.element))
      throw "Element #{e} not found.".interpolate({e: element});

    Object.extend(this.setting, setting || {});

    this.create(this.html);
    this.bind_event();
  },
  create: function() {
    var html = Translator.translate(this.setting.config);
    return html;
  },
  bind_event: function() {
    if (this.setting.on) {
      var handler = this.on.bind(this);

      if (Object.isArray(this.setting.on)) {
        this.setting.on.each(function(on) {
          this.element.observe(on, handler);
        }.bind(this));
      } else {
        this.element.observe(this.setting.on, handler);
      }
    }
  },
  on: function(event) {
    throw "Abstract. You must implement `on` function for events";
  }
});

Widget.prototype.initialize = Widget.prototype.initialize.wrap(
    function(func) {
      this.events = $w('create destroy add remove open close');
      this.setup();
      this.create_events();
      return func.apply(this, $A(arguments).slice(1));
    }
);

<|endoftext|>


<commit_before>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CoursesTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CoursesHeader");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    /*
     * Update the location dropdown list
     */
    gvm.updateLocations = function() {
        $.getJSON('/api/locations', function(data) {
            gvm.availableLocations.removeAll();
            $.each(data, function(i, item) {
                /* Put item in list */
                gvm.availableLocations.push(item);

                /* Add listener to listitem */
                $("#locbtn-" + item.id).click(function(){
                    gvm.updateTrainings(item.id);
                });
            });
        });

    }

    /*
     * Update the training data
     */
    gvm.updateTrainings = function(id) {
        $.getJSON('/api/trainings/' + id, function(data) {
            gvm.availableTrainings.removeAll();
            $.each(data, function(i, item) {
                gvm.availableTrainings.push(item);

                /* Add listener to listitem */
                $("#trainingbtn-" + item.id).click(function(){
                    gvm.updateCourses(item.id);
                });
            });
        });
    }

    /*
     * Update available courses
     */
    gvm.updateCourses = function(id) {
        $.getJSON('/api/courses/' + id, function(data) {
            gvm.availableCourses.removeAll();
            $.each(data, function(i, item) {
                gvm.availableCourses.push(item);

                /* Add listener to listitem */
                $("#coursebtn-" + item.id).click(function(){
                    alert("You selected course: " + item.name);
                });
            });
        });
    }
}

function initPage() {
    viewModel.updateLocations();
    $(".dropdown-location li a").click(function() {
        $(".btn-location").text($(this).text);
    });
}<commit_msg>courses page dropdown menu<commit_after>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CoursesTitle");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CoursesHeader");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    /*
     * Update the location dropdown list
     */
    gvm.updateLocations = function() {
        $.getJSON('/api/locations', function(data) {
            gvm.availableLocations.removeAll();
            $.each(data, function(i, item) {
                /* Put item in list */
                gvm.availableLocations.push(item);

                /* Add listener to listitem */
                $("#locbtn-" + item.id).click(function(){
                    gvm.updateTrainings(item.id);
                });
            });
        });

    }

    /*
     * Update the training data
     */
    gvm.updateTrainings = function(id) {
        $.getJSON('/api/trainings/' + id, function(data) {
            gvm.availableTrainings.removeAll();
            $.each(data, function(i, item) {
                gvm.availableTrainings.push(item);

                /* Add listener to listitem */
                $("#trainingbtn-" + item.id).click(function(){
                    gvm.updateCourses(item.id);
                });
            });
        });
    }

    /*
     * Update available courses
     */
    gvm.updateCourses = function(id) {
        $.getJSON('/api/courses/' + id, function(data) {
            gvm.availableCourses.removeAll();
            $.each(data, function(i, item) {
                gvm.availableCourses.push(item);

                /* Add listener to listitem */
                $("#coursebtn-" + item.id).click(function(){
                    alert("You selected course: " + item.name);
                });
            });
        });
    }
}

function initPage() {
    viewModel.updateLocations();
    $(".dropdown-location li a").click(function() {
        console.log("clicked");
        $(".btn-location").text($(this).text);
    });
}<|endoftext|>


<commit_before>ngapp.config(['$stateProvider', function ($stateProvider) {
    $stateProvider.state('base.start', {
        templateUrl: 'partials/start.html',
        controller: 'startController',
        url: '/start'
    });
}]);

ngapp.controller('startController', function ($scope, $rootScope, profileService, settingsService, xelibService) {
    // initialization
    profileService.validateProfiles();
    $scope.profiles = profileService.profiles;
    $scope.selectedProfile = profileService.getDefaultProfile();

    // scope functions
    $scope.getLoadOrder = function () {
        let loadOrder = xelib.GetLoadOrder().split('\r\n');
        let activePlugins = xelib.GetActivePlugins().split('\r\n');
        console.log('Load Order:\n' + loadOrder);
        console.log('Active Plugins:\n' + activePlugins);
        return loadOrder.map(function(filename) {
            let handle = xelib.LoadPluginHeader(filename);
            try {
                return {
                    filename: filename,
                    masterNames: xelib.GetMasterNames(handle),
                    active: activePlugins.indexOf(filename) > -1
                }
            } finally {
                xelib.UnloadPlugin(handle);
            }
        })
    };

    $scope.checkHardcodedDat = function() {
        let game = profileService.getGame($scope.selectedProfile.gameMode);
        let fileName = game.shortName + '.Hardcoded.dat';
        if (fh.jetpack.exists(fileName)) return true;
        alert(`Error: Required file "${fileName}" not found, please re-install the application.`);
    };

    $scope.startSession = function () {
        if (!$scope.checkHardcodedDat()) return;
        let p = $scope.selectedProfile;
        $rootScope.selectedProfile = p;
        settingsService.loadProfileSettings(p.name);
        console.log("Setting game mode to: " + p.gameMode);
        xelibService.startSession(p);
        $scope.$emit('setTitle', 'zEdit - Selecting Load Order');
        $scope.$emit('openModal', 'loadOrder', {
            loadOrder: $scope.getLoadOrder()
        });
    };

    // event listeners
    $scope.$on('settingsClick', function() {
        if ($rootScope.selectedProfile) return;
        $scope.$emit('openModal', 'profiles');
    });

    $scope.$on('profilesUpdated', function() {
        $scope.selectedProfile = profileService.getDefaultProfile();
    });
});<commit_msg>added sessionStarted event<commit_after>ngapp.config(['$stateProvider', function ($stateProvider) {
    $stateProvider.state('base.start', {
        templateUrl: 'partials/start.html',
        controller: 'startController',
        url: '/start'
    });
}]);

ngapp.controller('startController', function ($scope, $rootScope, profileService, settingsService, xelibService) {
    // initialization
    profileService.validateProfiles();
    $scope.profiles = profileService.profiles;
    $scope.selectedProfile = profileService.getDefaultProfile();

    // scope functions
    $scope.getLoadOrder = function () {
        let loadOrder = xelib.GetLoadOrder().split('\r\n');
        let activePlugins = xelib.GetActivePlugins().split('\r\n');
        console.log('Load Order:\n' + loadOrder);
        console.log('Active Plugins:\n' + activePlugins);
        return loadOrder.map(function(filename) {
            let handle = xelib.LoadPluginHeader(filename);
            try {
                return {
                    filename: filename,
                    masterNames: xelib.GetMasterNames(handle),
                    active: activePlugins.indexOf(filename) > -1
                }
            } finally {
                xelib.UnloadPlugin(handle);
            }
        })
    };

    $scope.checkHardcodedDat = function() {
        let game = profileService.getGame($scope.selectedProfile.gameMode);
        let fileName = game.shortName + '.Hardcoded.dat';
        if (fh.jetpack.exists(fileName)) return true;
        alert(`Error: Required file "${fileName}" not found, please re-install the application.`);
    };

    $scope.startSession = function () {
        if (!$scope.checkHardcodedDat()) return;
        let p = $scope.selectedProfile;
        $rootScope.selectedProfile = p;
        settingsService.loadProfileSettings(p.name);
        console.log("Setting game mode to: " + p.gameMode);
        xelibService.startSession(p);
        $scope.$emit('setTitle', 'zEdit - Selecting Load Order');
        $scope.$emit('sessionStarted', p);
        $scope.$emit('openModal', 'loadOrder', {
            loadOrder: $scope.getLoadOrder()
        });
    };

    // event listeners
    $scope.$on('settingsClick', function() {
        if ($rootScope.selectedProfile) return;
        $scope.$emit('openModal', 'profiles');
    });

    $scope.$on('profilesUpdated', function() {
        $scope.selectedProfile = profileService.getDefaultProfile();
    });
});<|endoftext|>


<commit_before>// Copyright 2020, University of Colorado Boulder

/**
 * Creates an object that has the same API as an Array, but also supports notifications and PhET-iO
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

import arrayRemove from '../../phet-core/js/arrayRemove.js';
import assertMutuallyExclusiveOptions from '../../phet-core/js/assertMutuallyExclusiveOptions.js';
import merge from '../../phet-core/js/merge.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import IOType from '../../tandem/js/types/IOType.js';
import axon from './axon.js';
import Emitter from './Emitter.js';
import NumberProperty from './NumberProperty.js';
import ValidatorDef from './ValidatorDef.js';

/**
 * @param {Object} [options]
 * @returns {[]}
 */
const createArrayProxy = options => {

  assertMutuallyExclusiveOptions( options, [ 'length' ], [ 'elements' ] );

  // If the options supplied the phetioElementType, it is passed through as a phetioType to the Emitter parameter
  // const isPhetioElementTypeProvided = options && options.hasOwnProperty( 'phetioElementType' );

  options = merge( {

    // Also supports phetioType or validator options.  If both are supplied, only the phetioType is respected

    length: 0,
    elements: [],
    tandem: Tandem.OPTIONAL
  }, options );

  let emitterParameterOptions = null;
  if ( options.phetioType ) {

    assert && assert( options.phetioType.typeName.startsWith( 'ArrayProxyIO' ) );
    emitterParameterOptions = { name: 'value', phetioType: options.phetioType.parameterTypes[ 0 ] };
  }
  else if ( ValidatorDef.isValidValidator( options ) ) {
    const validator = _.pick( options, ValidatorDef.VALIDATOR_KEYS );
    emitterParameterOptions = merge( { name: 'value' }, validator );
  }
  else {
    emitterParameterOptions = merge( { name: 'value' }, { isValidValue: _.stubTrue } );
  }

  // notifies when an element has been added
  const elementAddedEmitter = new Emitter( {
    tandem: options.tandem.createTandem( 'elementAddedEmitter' ),
    parameters: [ emitterParameterOptions ]
  } );

  // notifies when an element has been removed
  const elementRemovedEmitter = new Emitter( {
    tandem: options.tandem.createTandem( 'elementRemovedEmitter' ),
    parameters: [ emitterParameterOptions ]
  } );

  // observe this, but don't set it. Updated when Array modifiers are called (except array.length=...)
  const lengthProperty = new NumberProperty( 0, {
    numberType: 'Integer',
    tandem: options.tandem.createTandem( 'lengthProperty' ),
    phetioReadOnly: true
  } );

  const targetArray = [];

  const arrayProxy = new Proxy( targetArray, {

    get: function( target, key, receiver ) {
      if ( methods.hasOwnProperty( key ) ) {
        return methods[ key ];
      }
      else {
        return Reflect.get( target, key, receiver );
      }
    },

    set: function( array, key, newValue ) {
      const oldValue = array[ key ];
      //TODO https://github.com/phetsims/axon/issues/330 dead code
      // console.log( `Changing ${key} (type===${typeof key}), from ${oldValue} to ${newValue}` );

      let removedElements = null;
      // See which items are removed
      if ( key === 'length' ) {
        removedElements = array.slice( newValue );
      }

      const returnValue = Reflect.set( array, key, newValue );
      const parsed = parseInt( key, 10 );
      if ( !isNaN( parsed ) ) {
        if ( oldValue !== undefined ) {
          elementRemovedEmitter.emit( array[ key ] );
        }
        if ( newValue !== undefined ) {
          elementAddedEmitter.emit( newValue );
        }
      }
      else if ( key === 'length' ) {
        lengthProperty.value = newValue;

        removedElements.forEach( element => elementRemovedEmitter.emit( element ) );
      }
      return returnValue;
    },

    deleteProperty: function( array, key ) {
      //TODO https://github.com/phetsims/axon/issues/330 dead code
      // console.log( `deleteProperty ${key}, ${typeof key}` );
      const parsed = parseInt( key, 10 );

      let removed;
      if ( !isNaN( parsed ) ) {
        removed = array[ key ];
      }
      const returnValue = Reflect.deleteProperty( array, key );
      if ( removed !== undefined ) {
        elementRemovedEmitter.emit( removed );
      }

      return returnValue;
    }
  } );

  // @private - Make it possible to use the targetArray in the overridden methods above.
  arrayProxy.targetArray = targetArray;

  // @public (listen only)
  arrayProxy.elementAddedEmitter = elementAddedEmitter;
  arrayProxy.elementRemovedEmitter = elementRemovedEmitter;
  arrayProxy.lengthProperty = lengthProperty;

  if ( options.length >= 0 ) {
    arrayProxy.length = options.length;
  }
  if ( options.elements.length > 0 ) {
    Array.prototype.push.apply( arrayProxy, options.elements );
  }

  // TODO https://github.com/phetsims/axon/issues/330 Move to "prototype" above or drop support
  arrayProxy.reset = () => {
    arrayProxy.length = 0;
    if ( options.length >= 0 ) {
      arrayProxy.length = options.length;
    }
    if ( options.elements.length > 0 ) {
      Array.prototype.push.apply( arrayProxy, options.elements );
    }
  };

  /******************************************
   * PhET-iO support
   *******************************************/
  if ( options.tandem.supplied ) {
    arrayProxy.phetioElementType = options.phetioType.parameterTypes[ 0 ];

    // @private - for managing state in phet-io
    // Use the same tandem and phetioState options so it can "masquerade" as the real object.  When PhetioObject is a mixin this can be changed.
    arrayProxy.arrayProxyPhetioObject = new ArrayProxyPhetioObject( arrayProxy, options );
  }

  return arrayProxy;
};

/**
 * Manages state save/load.  ArrayProxy uses Proxy and hence cannot be instrumented as a PhetioObject.  This type
 * provides that functionality.
 */
class ArrayProxyPhetioObject extends PhetioObject {

  /**
   * @param {Object} arrayProxy
   * @param {Object} [options] - same as the options to the parent ArrayProxyDef
   */
  constructor( arrayProxy, options ) {

    options = merge( {
      phetioType: ArrayProxyIO
    }, options );

    super( options );

    // @private
    this.arrayProxy = arrayProxy;
  }
}

// Methods shared by all arrayProxy instances
const methods = {

  /******************************************
   * Overridden Array methods
   *******************************************/

  // @public
  pop() {
    const initialLength = this.targetArray.length;
    const returnValue = Array.prototype.pop.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    initialLength > 0 && this.elementRemovedEmitter.emit( returnValue );
    return returnValue;
  },

  // @public
  shift() {
    const initialLength = this.targetArray.length;
    const returnValue = Array.prototype.shift.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    initialLength > 0 && this.elementRemovedEmitter.emit( returnValue );
    return returnValue;
  },
  push() {
    const returnValue = Array.prototype.push.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    for ( let i = 0; i < arguments.length; i++ ) {
      this.elementAddedEmitter.emit( arguments[ i ] );
    }
    return returnValue;
  },

  // @public
  unshift() {
    const returnValue = Array.prototype.unshift.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    for ( let i = 0; i < arguments.length; i++ ) {
      this.elementAddedEmitter.emit( arguments[ i ] );
    }
    return returnValue;
  },

  // @public
  splice() {
    const returnValue = Array.prototype.splice.apply( this.targetArray, arguments );

    // Set length first so it will be correct in elementListener callbacks
    this.lengthProperty.value = this.length;
    const deletedElements = returnValue;
    for ( let i = 2; i < arguments.length; i++ ) {
      this.elementAddedEmitter.emit( arguments[ i ] );
    }
    deletedElements.forEach( deletedElement => this.elementRemovedEmitter.emit( deletedElement ) );
    return returnValue;
  },

  // @public
  copyWithin() {
    const before = this.targetArray.slice();
    const returnValue = Array.prototype.copyWithin.apply( this.targetArray, arguments );
    reportDifference( before, this );
    return returnValue;
  },

  // @public
  fill() {
    const before = this.targetArray.slice();
    const returnValue = Array.prototype.fill.apply( this.targetArray, arguments );
    reportDifference( before, this );
    return returnValue;
  },

  /******************************************
   * For compatibility with ObservableArray
   * NOTE: consider deleting after migration
   *******************************************/

  // @public
  get: function( index ) {return this[ index ];},

  // @public
  addItemAddedListener: function( listener ) { this.elementAddedEmitter.addListener( listener ); },

  // @public
  removeItemAddedListener: function( listener ) { this.elementAddedEmitter.removeListener( listener ); },

  // @public
  addItemRemovedListener: function( listener ) { this.elementRemovedEmitter.addListener( listener ); },

  // @public
  removeItemRemovedListener: function( listener ) { this.elementRemovedEmitter.removeListener( listener ); },

  // @public
  add: function( element ) { this.push( element );},

  // @public
  addAll: function( elements ) { this.push( ...elements );},

  // @public
  remove: function( element ) { this.includes( element ) && arrayRemove( this, element );},

  // @public
  removeAll: function( elements ) {
    elements.forEach( element => this.includes( element ) && arrayRemove( this, element ) );
  },

  // @public
  clear: function() {
    while ( this.length > 0 ) {
      this.pop();
    }
  },

  // @public
  count: function( predicate ) {
    let count = 0;
    for ( let i = 0; i < this.length; i++ ) {
      if ( predicate( this[ i ] ) ) {
        count++;
      }
    }
    return count;
  },

  // @public
  find: function( predicate, fromIndex ) {
    assert && ( fromIndex !== undefined ) && assert( typeof fromIndex === 'number', 'fromIndex must be numeric, if provided' );
    assert && ( typeof fromIndex === 'number' ) && assert( fromIndex >= 0 && fromIndex < this.length,
      `fromIndex out of bounds: ${fromIndex}` );
    return _.find( this, predicate, fromIndex );
  },

  // @public
  getArrayCopy: function() {return this.slice();},

  // @public
  shuffle: function( random ) {
    assert && assert( random, 'random must be supplied' );

    // preserve the same _array reference in case any clients got a reference to it with getArray()
    const shuffled = random.shuffle( this );
    this.length = 0;
    Array.prototype.push.apply( this, shuffled );
  },

  // TODO https://github.com/phetsims/axon/issues/330 This seems important to eliminate
  // @public
  getArray: function() { return this; },

  /******************************************
   * PhET-iO
   *******************************************/

  // @public
  toStateObject: function() {
    return { array: this.map( item => this.phetioElementType.toStateObject( item ) ) };
  },

  // @public
  applyState: function( stateObject ) {
    this.length = 0;
    const elements = stateObject.array.map( paramStateObject => this.phetioElementType.fromStateObject( paramStateObject ) );
    this.push( ...elements );
  },

  // @public
  dispose: function() {
    this.elementAddedEmitter.dispose();
    this.elementRemovedEmitter.dispose();
    this.lengthProperty.dispose();
    this.arrayProxyPhetioObject && this.arrayProxyPhetioObject.dispose();
  }
};

/**
 * Black box testing is less efficient but more concise and easy to verify correctness.  Used for the rarer methods.
 * @param {Object[]} shallowCopy
 * @param {ArrayProxyDef} arrayProxy
 */
const reportDifference = ( shallowCopy, arrayProxy ) => {

  const before = shallowCopy;
  const after = arrayProxy.targetArray.slice();

  for ( let i = 0; i < before.length; i++ ) {
    const beforeElement = before[ i ];
    const afterIndex = after.indexOf( beforeElement );
    if ( afterIndex >= 0 ) {
      before.splice( i, 1 );
      after.splice( afterIndex, 1 );
      i--;
    }
  }
  before.forEach( element => arrayProxy.elementRemovedEmitter.emit( element ) );
  after.forEach( element => arrayProxy.elementAddedEmitter.emit( element ) );
};

// {Map.<cacheKey:function(new:ArrayProxyIO), function(new:ArrayProxyIO)>} - Cache each parameterized ArrayProxyIO
// based on the parameter type, so that it is only created once.
const cache = new Map();

/**
 * ArrayProxyIO is the IO Type for ArrayProxyDef. It delegates most of its implementation to ArrayProxyDef.
 * Instead of being a parametric type, it leverages the phetioElementType on ArrayProxyDef.
 */
const ArrayProxyIO = parameterType => {
  if ( !cache.has( parameterType ) ) {
    cache.set( parameterType, new IOType( `ArrayProxyIO<${parameterType.typeName}>`, {
      parameterTypes: [ parameterType ],
      valueType: ArrayProxyPhetioObject,
      toStateObject: arrayProxyPhetioObject => arrayProxyPhetioObject.arrayProxy.toStateObject(),
      applyState: ( arrayProxyPhetioObject, state ) => arrayProxyPhetioObject.arrayProxy.applyState( state )
    } ) );
  }
  return cache.get( parameterType );
};

// @public
createArrayProxy.ArrayProxyIO = ArrayProxyIO;

axon.register( 'createArrayProxy', createArrayProxy );
export default createArrayProxy;<commit_msg>Remove dead code, see https://github.com/phetsims/axon/issues/330<commit_after>// Copyright 2020, University of Colorado Boulder

/**
 * Creates an object that has the same API as an Array, but also supports notifications and PhET-iO
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

import arrayRemove from '../../phet-core/js/arrayRemove.js';
import assertMutuallyExclusiveOptions from '../../phet-core/js/assertMutuallyExclusiveOptions.js';
import merge from '../../phet-core/js/merge.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import IOType from '../../tandem/js/types/IOType.js';
import axon from './axon.js';
import Emitter from './Emitter.js';
import NumberProperty from './NumberProperty.js';
import ValidatorDef from './ValidatorDef.js';

/**
 * @param {Object} [options]
 * @returns {[]}
 */
const createArrayProxy = options => {

  assertMutuallyExclusiveOptions( options, [ 'length' ], [ 'elements' ] );

  // If the options supplied the phetioElementType, it is passed through as a phetioType to the Emitter parameter
  // const isPhetioElementTypeProvided = options && options.hasOwnProperty( 'phetioElementType' );

  options = merge( {

    // Also supports phetioType or validator options.  If both are supplied, only the phetioType is respected

    length: 0,
    elements: [],
    tandem: Tandem.OPTIONAL
  }, options );

  let emitterParameterOptions = null;
  if ( options.phetioType ) {

    assert && assert( options.phetioType.typeName.startsWith( 'ArrayProxyIO' ) );
    emitterParameterOptions = { name: 'value', phetioType: options.phetioType.parameterTypes[ 0 ] };
  }
  else if ( ValidatorDef.isValidValidator( options ) ) {
    const validator = _.pick( options, ValidatorDef.VALIDATOR_KEYS );
    emitterParameterOptions = merge( { name: 'value' }, validator );
  }
  else {
    emitterParameterOptions = merge( { name: 'value' }, { isValidValue: _.stubTrue } );
  }

  // notifies when an element has been added
  const elementAddedEmitter = new Emitter( {
    tandem: options.tandem.createTandem( 'elementAddedEmitter' ),
    parameters: [ emitterParameterOptions ]
  } );

  // notifies when an element has been removed
  const elementRemovedEmitter = new Emitter( {
    tandem: options.tandem.createTandem( 'elementRemovedEmitter' ),
    parameters: [ emitterParameterOptions ]
  } );

  // observe this, but don't set it. Updated when Array modifiers are called (except array.length=...)
  const lengthProperty = new NumberProperty( 0, {
    numberType: 'Integer',
    tandem: options.tandem.createTandem( 'lengthProperty' ),
    phetioReadOnly: true
  } );

  const targetArray = [];

  const arrayProxy = new Proxy( targetArray, {

    get: function( target, key, receiver ) {
      if ( methods.hasOwnProperty( key ) ) {
        return methods[ key ];
      }
      else {
        return Reflect.get( target, key, receiver );
      }
    },

    set: function( array, key, newValue ) {
      const oldValue = array[ key ];

      let removedElements = null;

      // See which items are removed
      if ( key === 'length' ) {
        removedElements = array.slice( newValue );
      }

      const returnValue = Reflect.set( array, key, newValue );
      const parsed = parseInt( key, 10 );
      if ( !isNaN( parsed ) ) {
        if ( oldValue !== undefined ) {
          elementRemovedEmitter.emit( array[ key ] );
        }
        if ( newValue !== undefined ) {
          elementAddedEmitter.emit( newValue );
        }
      }
      else if ( key === 'length' ) {
        lengthProperty.value = newValue;

        removedElements.forEach( element => elementRemovedEmitter.emit( element ) );
      }
      return returnValue;
    },

    deleteProperty: function( array, key ) {
      const parsed = parseInt( key, 10 );

      let removed;
      if ( !isNaN( parsed ) ) {
        removed = array[ key ];
      }
      const returnValue = Reflect.deleteProperty( array, key );
      if ( removed !== undefined ) {
        elementRemovedEmitter.emit( removed );
      }

      return returnValue;
    }
  } );

  // @private - Make it possible to use the targetArray in the overridden methods above.
  arrayProxy.targetArray = targetArray;

  // @public (listen only)
  arrayProxy.elementAddedEmitter = elementAddedEmitter;
  arrayProxy.elementRemovedEmitter = elementRemovedEmitter;
  arrayProxy.lengthProperty = lengthProperty;

  if ( options.length >= 0 ) {
    arrayProxy.length = options.length;
  }
  if ( options.elements.length > 0 ) {
    Array.prototype.push.apply( arrayProxy, options.elements );
  }

  // TODO https://github.com/phetsims/axon/issues/330 Move to "prototype" above or drop support
  arrayProxy.reset = () => {
    arrayProxy.length = 0;
    if ( options.length >= 0 ) {
      arrayProxy.length = options.length;
    }
    if ( options.elements.length > 0 ) {
      Array.prototype.push.apply( arrayProxy, options.elements );
    }
  };

  /******************************************
   * PhET-iO support
   *******************************************/
  if ( options.tandem.supplied ) {
    arrayProxy.phetioElementType = options.phetioType.parameterTypes[ 0 ];

    // @private - for managing state in phet-io
    // Use the same tandem and phetioState options so it can "masquerade" as the real object.  When PhetioObject is a mixin this can be changed.
    arrayProxy.arrayProxyPhetioObject = new ArrayProxyPhetioObject( arrayProxy, options );
  }

  return arrayProxy;
};

/**
 * Manages state save/load.  ArrayProxy uses Proxy and hence cannot be instrumented as a PhetioObject.  This type
 * provides that functionality.
 */
class ArrayProxyPhetioObject extends PhetioObject {

  /**
   * @param {Object} arrayProxy
   * @param {Object} [options] - same as the options to the parent ArrayProxyDef
   */
  constructor( arrayProxy, options ) {

    options = merge( {
      phetioType: ArrayProxyIO
    }, options );

    super( options );

    // @private
    this.arrayProxy = arrayProxy;
  }
}

// Methods shared by all arrayProxy instances
const methods = {

  /******************************************
   * Overridden Array methods
   *******************************************/

  // @public
  pop() {
    const initialLength = this.targetArray.length;
    const returnValue = Array.prototype.pop.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    initialLength > 0 && this.elementRemovedEmitter.emit( returnValue );
    return returnValue;
  },

  // @public
  shift() {
    const initialLength = this.targetArray.length;
    const returnValue = Array.prototype.shift.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    initialLength > 0 && this.elementRemovedEmitter.emit( returnValue );
    return returnValue;
  },
  push() {
    const returnValue = Array.prototype.push.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    for ( let i = 0; i < arguments.length; i++ ) {
      this.elementAddedEmitter.emit( arguments[ i ] );
    }
    return returnValue;
  },

  // @public
  unshift() {
    const returnValue = Array.prototype.unshift.apply( this.targetArray, arguments );
    this.lengthProperty.value = this.length;
    for ( let i = 0; i < arguments.length; i++ ) {
      this.elementAddedEmitter.emit( arguments[ i ] );
    }
    return returnValue;
  },

  // @public
  splice() {
    const returnValue = Array.prototype.splice.apply( this.targetArray, arguments );

    // Set length first so it will be correct in elementListener callbacks
    this.lengthProperty.value = this.length;
    const deletedElements = returnValue;
    for ( let i = 2; i < arguments.length; i++ ) {
      this.elementAddedEmitter.emit( arguments[ i ] );
    }
    deletedElements.forEach( deletedElement => this.elementRemovedEmitter.emit( deletedElement ) );
    return returnValue;
  },

  // @public
  copyWithin() {
    const before = this.targetArray.slice();
    const returnValue = Array.prototype.copyWithin.apply( this.targetArray, arguments );
    reportDifference( before, this );
    return returnValue;
  },

  // @public
  fill() {
    const before = this.targetArray.slice();
    const returnValue = Array.prototype.fill.apply( this.targetArray, arguments );
    reportDifference( before, this );
    return returnValue;
  },

  /******************************************
   * For compatibility with ObservableArray
   * NOTE: consider deleting after migration
   *******************************************/

  // @public
  get: function( index ) {return this[ index ];},

  // @public
  addItemAddedListener: function( listener ) { this.elementAddedEmitter.addListener( listener ); },

  // @public
  removeItemAddedListener: function( listener ) { this.elementAddedEmitter.removeListener( listener ); },

  // @public
  addItemRemovedListener: function( listener ) { this.elementRemovedEmitter.addListener( listener ); },

  // @public
  removeItemRemovedListener: function( listener ) { this.elementRemovedEmitter.removeListener( listener ); },

  // @public
  add: function( element ) { this.push( element );},

  // @public
  addAll: function( elements ) { this.push( ...elements );},

  // @public
  remove: function( element ) { this.includes( element ) && arrayRemove( this, element );},

  // @public
  removeAll: function( elements ) {
    elements.forEach( element => this.includes( element ) && arrayRemove( this, element ) );
  },

  // @public
  clear: function() {
    while ( this.length > 0 ) {
      this.pop();
    }
  },

  // @public
  count: function( predicate ) {
    let count = 0;
    for ( let i = 0; i < this.length; i++ ) {
      if ( predicate( this[ i ] ) ) {
        count++;
      }
    }
    return count;
  },

  // @public
  find: function( predicate, fromIndex ) {
    assert && ( fromIndex !== undefined ) && assert( typeof fromIndex === 'number', 'fromIndex must be numeric, if provided' );
    assert && ( typeof fromIndex === 'number' ) && assert( fromIndex >= 0 && fromIndex < this.length,
      `fromIndex out of bounds: ${fromIndex}` );
    return _.find( this, predicate, fromIndex );
  },

  // @public
  getArrayCopy: function() {return this.slice();},

  // @public
  shuffle: function( random ) {
    assert && assert( random, 'random must be supplied' );

    // preserve the same _array reference in case any clients got a reference to it with getArray()
    const shuffled = random.shuffle( this );
    this.length = 0;
    Array.prototype.push.apply( this, shuffled );
  },

  // TODO https://github.com/phetsims/axon/issues/330 This seems important to eliminate
  // @public
  getArray: function() { return this; },

  /******************************************
   * PhET-iO
   *******************************************/

  // @public
  toStateObject: function() {
    return { array: this.map( item => this.phetioElementType.toStateObject( item ) ) };
  },

  // @public
  applyState: function( stateObject ) {
    this.length = 0;
    const elements = stateObject.array.map( paramStateObject => this.phetioElementType.fromStateObject( paramStateObject ) );
    this.push( ...elements );
  },

  // @public
  dispose: function() {
    this.elementAddedEmitter.dispose();
    this.elementRemovedEmitter.dispose();
    this.lengthProperty.dispose();
    this.arrayProxyPhetioObject && this.arrayProxyPhetioObject.dispose();
  }
};

/**
 * Black box testing is less efficient but more concise and easy to verify correctness.  Used for the rarer methods.
 * @param {Object[]} shallowCopy
 * @param {ArrayProxyDef} arrayProxy
 */
const reportDifference = ( shallowCopy, arrayProxy ) => {

  const before = shallowCopy;
  const after = arrayProxy.targetArray.slice();

  for ( let i = 0; i < before.length; i++ ) {
    const beforeElement = before[ i ];
    const afterIndex = after.indexOf( beforeElement );
    if ( afterIndex >= 0 ) {
      before.splice( i, 1 );
      after.splice( afterIndex, 1 );
      i--;
    }
  }
  before.forEach( element => arrayProxy.elementRemovedEmitter.emit( element ) );
  after.forEach( element => arrayProxy.elementAddedEmitter.emit( element ) );
};

// {Map.<cacheKey:function(new:ArrayProxyIO), function(new:ArrayProxyIO)>} - Cache each parameterized ArrayProxyIO
// based on the parameter type, so that it is only created once.
const cache = new Map();

/**
 * ArrayProxyIO is the IO Type for ArrayProxyDef. It delegates most of its implementation to ArrayProxyDef.
 * Instead of being a parametric type, it leverages the phetioElementType on ArrayProxyDef.
 */
const ArrayProxyIO = parameterType => {
  if ( !cache.has( parameterType ) ) {
    cache.set( parameterType, new IOType( `ArrayProxyIO<${parameterType.typeName}>`, {
      parameterTypes: [ parameterType ],
      valueType: ArrayProxyPhetioObject,
      toStateObject: arrayProxyPhetioObject => arrayProxyPhetioObject.arrayProxy.toStateObject(),
      applyState: ( arrayProxyPhetioObject, state ) => arrayProxyPhetioObject.arrayProxy.applyState( state )
    } ) );
  }
  return cache.get( parameterType );
};

// @public
createArrayProxy.ArrayProxyIO = ArrayProxyIO;

axon.register( 'createArrayProxy', createArrayProxy );
export default createArrayProxy;<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var _ = require('../lib/')._;
var log = require('../lib/').bows('SegmentUtil');

var keysToOmit = ['id', 'start', 'end', 'vizType'];

function SegmentUtil(data) {
  var actuals = [];
  var undelivereds = [];
  var overlaps = [];

  function addToActuals(e) {
    actuals.push(_.extend({}, e, {vizType: 'actual'}));
  }

  function addToUndelivered(e) {
    undelivereds.push(_.extend({}, e, {vizType: 'undelivered'}));
  }

  function processElement(e) {
    if (e.deliveryType === 'temp' || e.deliveryType === 'scheduled') {
      if (actuals.length === 0) {
        addToActuals(e);
      } else {
        var lastActual = actuals[actuals.length - 1];
        if (e.start === lastActual.end) {
          if (_.isEqual(_.omit(e, keysToOmit), _.omit(lastActual, keysToOmit))) {
            lastActual.end = e.end;
          } else {
            addToActuals(e);
          }
        } else if (e.start < lastActual.end) {
          // It is overlapping, so let's see how we should deal with it.

          if (e.start < lastActual.start) {
            // The current element is completely newer than the last actual, so we have to rewind a bit.
            var removedActual = actuals.pop();
            processElement(e);
            processElement(removedActual);
          } else if (e.deliveryType === 'temp') {
            // It's a temp, which wins no matter what it was before.
            // Start by setting up shared adjustments to the segments (clone lastActual and reshape it)
            var undeliveredClone = _.clone(lastActual);
            lastActual.end = e.start;

            if (e.end >= undeliveredClone.end) {
              // The temp segment is longer than the current, throw away the rest of the current
              undeliveredClone.start = e.start;
              addToUndelivered(undeliveredClone);
              addToActuals(e);
            } else {
              // The current exceeds the temp, so replace the current "chunk" and re-attach the schedule
              var endingSegment = _.clone(undeliveredClone);
              undeliveredClone.start = e.start;
              undeliveredClone.end = e.end;
              addToUndelivered(undeliveredClone);
              addToActuals(_.clone(e));

              // Re-attach the end of the schedule
              endingSegment.start = e.end;
              addToActuals(endingSegment);
            }
          } else {
            // e.deliveryType === 'scheduled'
            if (lastActual.deliveryType === 'scheduled') {
              // Scheduled overlapping a scheduled, this should not happen.
              overlaps.push([lastActual, e]);
              actuals.pop();
            } else {
              // Scheduled overlapping a temp, this can happen and the schedule should be skipped

              var undeliveredClone = _.clone(e);

              if (e.end > lastActual.end) {
                // Scheduled is longer than the temp, so preserve the tail
                var deliveredClone = _.clone(e);
                undeliveredClone.end = lastActual.end;
                deliveredClone.start = lastActual.end;
                addToUndelivered(undeliveredClone);
                addToActuals(deliveredClone);
              } else {
                // Scheduled is shorter than the temp, so completely skip it
                addToUndelivered(undeliveredClone);
              }
            }
          }
        } else {
          // e.start > lastActual.end, this means that we have a gap in the segments, act like this is
          // the first event we saw and keep going.
          addToActuals(e);
        }
      }
    }
  }

  data.forEach(processElement);

  log(overlaps.length, 'instances of scheduled overlapping a scheduled.');
  if (overlaps.length > 0) {
    log('First example', overlaps[0][0], overlaps[0][1]);
  }

  this.actual = actuals;
  this.undelivered = undelivereds;
  this.all = this.actual.concat(this.undelivered);

  return this;
}

module.exports = SegmentUtil;
<commit_msg>Fix smooshing<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2014, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var _ = require('../lib/')._;
var log = require('../lib/').bows('SegmentUtil');

var keysForEquality = ['type', 'deliveryType', 'value', 'deviceId', 'scheduleName', 'source'];

function SegmentUtil(data) {
  var actuals = [];
  var undelivereds = [];
  var overlaps = [];

  function addToActuals(e) {
    actuals.push(_.extend({}, e, {vizType: 'actual'}));
  }

  function addToUndelivered(e) {
    undelivereds.push(_.extend({}, e, {vizType: 'undelivered'}));
    }

  function processElement(e) {
    if (e.deliveryType === 'temp' || e.deliveryType === 'scheduled') {
      if (actuals.length === 0) {
        addToActuals(e);
      } else {
        var lastActual = actuals[actuals.length - 1];
        if (e.start === lastActual.end) {
          if (_.isEqual(_.pick(e, keysForEquality), _.pick(lastActual, keysForEquality))) {
            lastActual.end = e.end;
          } else {
            addToActuals(e);
          }
        } else if (e.start < lastActual.end) {
          // It is overlapping, so let's see how we should deal with it.

          if (e.start < lastActual.start) {
            // The current element is completely newer than the last actual, so we have to rewind a bit.
            var removedActual = actuals.pop();
            processElement(e);
            processElement(removedActual);
          } else if (e.deliveryType === 'temp') {
            // It's a temp, which wins no matter what it was before.
            // Start by setting up shared adjustments to the segments (clone lastActual and reshape it)
            var undeliveredClone = _.clone(lastActual);
            lastActual.end = e.start;

            if (e.end >= undeliveredClone.end) {
              // The temp segment is longer than the current, throw away the rest of the current
              undeliveredClone.start = e.start;
              addToUndelivered(undeliveredClone);
              addToActuals(e);
            } else {
              // The current exceeds the temp, so replace the current "chunk" and re-attach the schedule
              var endingSegment = _.clone(undeliveredClone);
              undeliveredClone.start = e.start;
              undeliveredClone.end = e.end;
              addToUndelivered(undeliveredClone);
              addToActuals(_.clone(e));

              // Re-attach the end of the schedule
              endingSegment.start = e.end;
              addToActuals(endingSegment);
            }
          } else {
            // e.deliveryType === 'scheduled'
            if (lastActual.deliveryType === 'scheduled') {
              // Scheduled overlapping a scheduled, this should not happen.
              overlaps.push([lastActual, e]);
              actuals.pop();
            } else {
              // Scheduled overlapping a temp, this can happen and the schedule should be skipped

              var undeliveredClone = _.clone(e);

              if (e.end > lastActual.end) {
                // Scheduled is longer than the temp, so preserve the tail
                var deliveredClone = _.clone(e);
                undeliveredClone.end = lastActual.end;
                deliveredClone.start = lastActual.end;
                addToUndelivered(undeliveredClone);
                addToActuals(deliveredClone);
              } else {
                // Scheduled is shorter than the temp, so completely skip it
                addToUndelivered(undeliveredClone);
              }
            }
          }
        } else {
          // e.start > lastActual.end, this means that we have a gap in the segments, act like this is
          // the first event we saw and keep going.
          addToActuals(e);
        }
      }
    }
  }

  data.forEach(processElement);

  log(overlaps.length, 'instances of scheduled overlapping a scheduled.');
  if (overlaps.length > 0) {
    log('First example', overlaps[0][0], overlaps[0][1]);
  }

  this.actual = actuals;
  this.undelivered = undelivereds;
  this.all = this.actual.concat(this.undelivered);

  return this;
}

module.exports = SegmentUtil;
<|endoftext|>


<commit_before>const Router = require('express').Router;
const Trail = require(__dirname + '/../models/trail');
const bodyParser = require('body-parser').json();
const trailRouter = module.exports = new Router();
const jwtAuth = require(__dirname + '/../lib/jwt_auth');
const errorHandler = require(__dirname + '/../lib/db_error_handler');

trailRouter.get('/', (req, res) => {
  res.status(200).json({ msg: 'Howdy Pardner!!' });
});

trailRouter.get('/trail', jwtAuth, (req, res) => {
  Trail.find({ userId: req.user._id }, (err, data) => {
    if (err) errorHandler(err, res);

    res.status(200).json(data);
  });
});

trailRouter.post('/trail', jwtAuth, bodyParser, (req, res) => {
  var newTrail = new Trail(req.body);
  newTrail.userId = req.user._id;
  newTrail.save((err, data) => {
    if (err) errorHandler();

    res.status(200).json(data);
  });
});

trailRouter.put('/trail/:id', bodyParser, (req, res) => {
  var trailData = req.body;
  delete trailData._id;
  Trail.update({ _id: req.params.id }, trailData, (err) => {
    if (err) errorHandler();

    res.status(200).json({ msg: 'You have changed trail information' });
  });
});

trailRouter.delete('/trail/:id', (req, res) => {
  Trail.remove({ _id: req.params.id }, (err) => {
    if (err) errorHandler();

    res.status(200).json({ msg: 'Trail Deleted' });
  });
});
<commit_msg>revise trail_routes.js<commit_after>const Router = require('express').Router;
const Trail = require(__dirname + '/../models/trail');
const bodyParser = require('body-parser').json();
const trailRouter = module.exports = new Router();
const jwtAuth = require(__dirname + '/../lib/jwt_auth');
const errorHandler = require(__dirname + '/../lib/db_error_handler');

trailRouter.get('/', (req, res) => {
  res.status(200).json({ msg: 'Howdy Pardner!!' });
});

trailRouter.get('/trails', jwtAuth, (req, res) => {
  Trail.find({ userId: req.user._id }, (err, data) => {
    if (err) return errorHandler(err, res);

    res.status(200).json(data);
  });
});

trailRouter.post('/trails', jwtAuth, bodyParser, (req, res) => {
  var newTrail = new Trail(req.body);
  newTrail.userId = req.user._id;
  newTrail.save((err, data) => {
    if (err) return errorHandler(err, res);

    res.status(200).json(data);
  });
});

trailRouter.put('/trails/:id', bodyParser, (req, res) => {
  var trailData = req.body;
  delete trailData._id;
  Trail.update({ _id: req.params.id }, trailData, (err) => {
    if (err) return errorHandler(err, res);

    res.status(200).json({ msg: 'You have changed trail information' });
  });
});

trailRouter.delete('/trails/:id', (req, res) => {
  Trail.remove({ _id: req.params.id }, (err) => {
    if (err) return errorHandler(err, res);

    res.status(200).json({ msg: 'Trail Deleted' });
  });
});
<|endoftext|>


<commit_before>const Resolver = require('./resolver')
const defaults = require('./defaults')
const rescue = require('rescue')
const fs = require('fs').promises

const { Interrupt } = require('interrupt')

class Mingle {
    static Kubernetes = class {
        static Error = Interrupt.create('Mingle.Kubernetes.Error', {
            'FILE_NOT_FOUND': '%(fileType)s file not found'
        })
    }
}

async function load (file, type) {
    return await Mingle.Kubernetes.Error.resolve(fs.readFile(file, 'utf8'), 'FILE_NOT_FOUND', { file, type })
}

exports.create = async function (destructible, properties) {
    const options = defaults(properties, process.env)
    options.token = (await load(options.token, 'token')).replace(/\n$/, '')
    options.ca = (await load(options.ca, 'ca'))
    return new Resolver(options)
}
<commit_msg>Fix for Interrupt export.<commit_after>const Resolver = require('./resolver')
const defaults = require('./defaults')
const rescue = require('rescue')
const fs = require('fs').promises

const Interrupt = require('interrupt')

class Mingle {
    static Kubernetes = class {
        static Error = Interrupt.create('Mingle.Kubernetes.Error', {
            'FILE_NOT_FOUND': '%(fileType)s file not found'
        })
    }
}

async function load (file, type) {
    return await Mingle.Kubernetes.Error.resolve(fs.readFile(file, 'utf8'), 'FILE_NOT_FOUND', { file, type })
}

exports.create = async function (destructible, properties) {
    const options = defaults(properties, process.env)
    options.token = (await load(options.token, 'token')).replace(/\n$/, '')
    options.ca = (await load(options.ca, 'ca'))
    return new Resolver(options)
}
<|endoftext|>


<commit_before>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
* jQuery Simple Websocket
* https://github.com/jbloemendal/jquery-simple-websocket
*/

(function (factory) {
  if ('object' === typeof module && typeof 'object' === module.exports) {
      module.exports = factory(jQuery);
  } else {
      factory(jQuery);
  }
}(function($) {

    var SimpleWebSocket = function(opt) {
        if (!this._isNotEmpty(opt, 'url')) {
            throw new Error('Missing argument, example usage: $.simpleWebSocket({ url: "ws://127.0.0.1:3000" }); ');
        }
        this._opt = opt;

        this._ws = null;
        this._reConnectTries = 60;
        this._reConnectDeferred = null;
        this._dataType = this._prop(this._opt, 'dataType', 'json');

        this._listeners = [];

        var self = this;
        this._api = (function() {
            return {
                connect: function() {
                    return $.extend(self._api, self._reConnect.apply(self, []));
                },

                isConnected: function(callback) {
                    if (callback) {
                        callback.apply(this, [self._isConnected.apply(self, [])]);
                        return self._api;
                    } else {
                        return self._isConnected.apply(self, []);
                    }
                },

                send: function(data) {
                    return $.extend(self._api, self._send.apply(self, [data]));
                },

                listen: function(listener) {
                    return $.extend(self._api, self._listenReconnect.apply(self, [listener]));
                },

                remove: function(listener) {
                    self._remove.apply(self, [listener]);
                    return self._api;
                },

                removeAll: function() {
                    self._removeAll.apply(self, []);
                    return self._api;
                },

                close: function() {
                    self._close.apply(self, []);
                    self._reset.apply(self, []);
                    return self._api;
                }
            };
        })();

        return this._api;
    };

    SimpleWebSocket.prototype = {

        _createWebSocket: function(opt) {
            var ws;
            if (opt.protocols) {
                ws = ('undefined' !== typeof window.MozWebSocket) ? new MozWebSocket(opt.url, opt.protocols) : window.WebSocket ? new WebSocket(opt.url, opt.protocols) : null;
            } else {
                ws = ('undefined' !== typeof window.MozWebSocket) ? new MozWebSocket(opt.url) : window.WebSocket ? new WebSocket(opt.url) : null;
            }

            if (!ws) {
                throw new Error('Error, websocket could not be initialized.');
            }
            return ws;
        },

        _bindSocketEvents: function(ws, opt) {
            var self = this;
            $(ws).bind('open', opt.open)
            .bind('close', opt.close)
            .bind('message', function(event) {
                try {
                    if ('function' === typeof opt.message) {
                        if (self._dataType && 'json' === self._dataType.toLowerCase()) {
                            var json = JSON.parse(event.originalEvent.data);
                            opt.message.call(this, json);
                        } else if (self._dataType && 'xml' === self._dataType.toLowerCase()) {
                            var domParser = new DOMParser();
                            var dom = domParser.parseFromString(event.originalEvent.data, 'text/xml');
                            opt.message.call(this, dom);
                        } else {
                            opt.message.call(this, event.originalEvent.data);
                        }
                    }
                } catch (exception) {
                    if ('function' === typeof opt.error) {
                      opt.error.call(this, exception);
                    }
                }
            }).bind('error', function(exception) {
                if ('function' === typeof opt.error) {
                    opt.error.call(this, exception);
                }
            });
        },

        _webSocket: function(opt) {
           var ws = this._createWebSocket(opt);
           this._bindSocketEvents(ws, opt);

           return ws;
        },

        _getSocketEventHandler: function(attempt) {
            var self = this;
            return {
                open: function(e) {
                    var sock = this;
                    if (attempt) {
                        attempt.resolve(sock);
                    }
                },
                close: function(e) {
                    if (attempt) {
                        attempt.rejectWith(e);
                    }
                },
                message: function(message) {
                    for (var i=0, len=self._listeners.length; i<len; i++) {
                        try {
                            self._listeners[i].deferred.notify.apply(self, [message]);
                        } catch (error) {
                        }
                    }
                },
                error: function(e) {
                    self._ws = null;
                    for (var i=0, len=self._listeners.length; i<len; i++) {
                        self._listeners[i].deferred.reject.apply(self, [e]);
                    }
                    if (attempt) {
                        attempt.rejectWith.apply(self, [e]);
                    }
                }
            };
        },

        _connect: function() {
            var attempt = $.Deferred();

            if (this._ws) {
                if (2 === this._ws.readyState || 3 === this._ws.readyState) {
                    // close previous socket
                    this._ws.close();
                } else if (0 === this._ws.readyState) {
                    return attempt.promise();
                } else if (1 === this._ws.readyState) {
                    attempt.resolve(this._ws);
                    return attempt.promise();
                }
            }

            this._ws = this._webSocket($.extend(this._opt, this._getSocketEventHandler(attempt)));

            return attempt.promise();
        },

        _reset: function() {
            this._reConnectTries = this._prop(this._opt, 'attempts', 60); // default 10min
            this._reConnectDeferred = $.Deferred();
        },

        _close: function() {
            if (this._ws) {
                this._ws.close();
                this._ws = null;
            }
        },

        _isConnected: function() {
            return this._ws !== null && this._ws.readyState === 1;
        },

        _reConnectTry: function() {
            var self = this;
            this._connect().done(function() {
                self._reConnectDeferred.resolve.apply(self, [self._ws]);
            }).fail(function(e) {
                self._reConnectTries--;
                if (self._reConnectTries > 0) {
                    window.setTimeout(function() {
                        self._reConnect.apply(self, []);
                    }, self._prop.apply(self, [self._opt, 'timeout', 10000]));
                } else {
                    self._reConnectDeferred.rejectWith.apply(self, [e]);
                }
            });
        },

        _reConnect: function() {
            var self = this;
            if (!this._reConnectDeferred || 'pending' !== this._reConnectDeferred.state()) {
                this._reset();
            }

            if (this._ws && this._ws.readyState === 1) {
                this._reConnectDeferred.resolve(this._ws);
            } else {
                this._reConnectTry();
            }

            return self._reConnectDeferred.promise.apply(self, []);
        },

        _preparePayload: function(data) {
            var payload;
            if (this._opt.dataType && 'text' === this._opt.dataType.toLowerCase()) {
                payload = data;
            } else if (this._opt.dataType && 'xml' === this._opt.dataType.toLowerCase()) {
                payload = data;
            } else if (this._opt.dataType && 'json' === this._opt.dataType.toLowerCase()) {
                payload = JSON.stringify(data);
            } else {
                payload = JSON.stringify(data); // default
            }
            return payload;
        },

        _send: function(data) {
            var self = this;
            var attempt = $.Deferred();

            (function(json) {
                self._reConnect.apply(self, []).done(function(ws) {
                    ws.send(json);
                    attempt.resolve.apply(self, [self._api]);
                }).fail(function(e) {
                    attempt.rejectWith.apply(self, [e]);
                });
            })(this._preparePayload(data));

            return attempt.promise();
        },

        _indexOfListener: function(listener) {
            for (var i=0, len=this._listeners.length; i<len; i++) {
                if (this._listeners[i].listener === listener) {
                    return i;
                }
            }
            return -1;
        },

         _isNotEmpty: function(obj, property) {
            return typeof 'undefined' !== obj &&
                null !== obj &&
                'undefined' !== typeof property &&
                null !== property &&
                '' !== property &&
                'undefined' !== typeof obj[property] &&
                null !== obj[property] &&
                '' !== obj[property];
         },

        _prop: function(obj, property, defaultValue) {
            if (this._isNotEmpty(obj, property)) {
               return obj[property];
            }
            return defaultValue;
        },

        _listen: function(listener) {
            var self = this;
            var dInternal = $.Deferred();
             self._reConnect.apply(self, []).done(function() {
                 dInternal.progress(function() {
                     listener.apply(this, arguments);
                 });
                 self._remove.apply(self, [listener]);
                 self._listeners.push({ 'deferred': dInternal, 'listener': listener });
             }).fail(function(e) {
                 dInternal.reject(e);
             });
             return dInternal.promise();
        },

        _listenReconnect: function(listener) {
            var dExternal = $.Deferred();

            var self = this;
            this._listen(listener)
            .fail(function() {
                dExternal.notify(arguments);
                self._listenReconnect.apply(self, [listener]);
            }).done(function() {
                dExternal.resolve();
            });

            return dExternal.promise();
        },

        _remove: function(listener) {
            var index = this._indexOfListener(listener);
            if (index !== -1) {
                this._listeners[index].deferred.resolve();
                this._listeners.splice(index, 1);
            }
        },

        _removeAll: function() {
           for (var i=0, len=this._listeners.length; i<len; i++) {
               this._listeners[i].deferred.resolve();
           }
           this._listeners = [];
        }
     };

    $.extend({
        simpleWebSocket: function(opt) {
            return new SimpleWebSocket(opt);
        }
    });

    return $.simpleWebSocket;
}));
<commit_msg>refactoring<commit_after>/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
* jQuery Simple Websocket
* https://github.com/jbloemendal/jquery-simple-websocket
*/

(function (factory) {
  if ('object' === typeof module && typeof 'object' === module.exports) {
      module.exports = factory(jQuery);
  } else {
      factory(jQuery);
  }
}(function($) {

    var SimpleWebSocket = function(opt) {
        if (!this._isNotEmpty(opt, 'url')) {
            throw new Error('Missing argument, example usage: $.simpleWebSocket({ url: "ws://127.0.0.1:3000" }); ');
        }
        this._opt = opt;

        this._ws = null;
        this._reConnectTries = 60;
        this._reConnectDeferred = null;
        this._dataType = this._prop(this._opt, 'dataType', 'json');

        this._listeners = [];

        var self = this;
        this._api = (function() {
            return {
                connect: function() {
                    return $.extend(self._api, self._reConnect.apply(self, []));
                },

                isConnected: function(callback) {
                    if (callback) {
                        callback.apply(this, [self._isConnected.apply(self, [])]);
                        return self._api;
                    } else {
                        return self._isConnected.apply(self, []);
                    }
                },

                send: function(data) {
                    return $.extend(self._api, self._send.apply(self, [data]));
                },

                listen: function(listener) {
                    return $.extend(self._api, self._listenReconnect.apply(self, [listener]));
                },

                remove: function(listener) {
                    self._remove.apply(self, [listener]);
                    return self._api;
                },

                removeAll: function() {
                    self._removeAll.apply(self, []);
                    return self._api;
                },

                close: function() {
                    self._close.apply(self, []);
                    self._reset.apply(self, []);
                    return self._api;
                }
            };
        })();

        return this._api;
    };

    SimpleWebSocket.prototype = {

        _createWebSocket: function(opt) {
            var ws = null;
            if (opt.protocols) {
                if ('undefined' === typeof window.MozWebSocket) {
                    ws = (window.WebSocket ? new WebSocket(opt.url, opt.protocols) : null);
                } else {
                    ws = new MozWebSocket(opt.url, opt.protocols);
                }
            } else {
                if ('undefined' === typeof window.MozWebSocket) {
                    if (window.WebSocket) {
                        ws =  new WebSocket(opt.url);
                    } else {
                        throw new Error('Error, websocket could not be initialized.');
                    }
                } else {
                    ws = new MozWebSocket(opt.url);
                }
            }
            return ws;
        },

        _bindSocketEvents: function(ws, opt) {
            var self = this;
            $(ws).bind('open', opt.open)
            .bind('close', opt.close)
            .bind('message', function(event) {
                try {
                    if ('function' === typeof opt.message) {
                        if (self._dataType && 'json' === self._dataType.toLowerCase()) {
                            var json = JSON.parse(event.originalEvent.data);
                            opt.message.call(this, json);
                        } else if (self._dataType && 'xml' === self._dataType.toLowerCase()) {
                            var domParser = new DOMParser();
                            var dom = domParser.parseFromString(event.originalEvent.data, 'text/xml');
                            opt.message.call(this, dom);
                        } else {
                            opt.message.call(this, event.originalEvent.data);
                        }
                    }
                } catch (exception) {
                    if ('function' === typeof opt.error) {
                      opt.error.call(this, exception);
                    }
                }
            }).bind('error', function(exception) {
                if ('function' === typeof opt.error) {
                    opt.error.call(this, exception);
                }
            });
        },

        _webSocket: function(opt) {
           var ws = this._createWebSocket(opt);
           this._bindSocketEvents(ws, opt);

           return ws;
        },

        _getSocketEventHandler: function(attempt) {
            var self = this;
            return {
                open: function(e) {
                    var sock = this;
                    if (attempt) {
                        attempt.resolve(sock);
                    }
                },
                close: function(e) {
                    if (attempt) {
                        attempt.rejectWith(e);
                    }
                },
                message: function(message) {
                    for (var i=0, len=self._listeners.length; i<len; i++) {
                        try {
                            self._listeners[i].deferred.notify.apply(self, [message]);
                        } catch (error) {
                        }
                    }
                },
                error: function(e) {
                    self._ws = null;
                    for (var i=0, len=self._listeners.length; i<len; i++) {
                        self._listeners[i].deferred.reject.apply(self, [e]);
                    }
                    if (attempt) {
                        attempt.rejectWith.apply(self, [e]);
                    }
                }
            };
        },

        _connect: function() {
            var attempt = $.Deferred();

            if (this._ws) {
                if (2 === this._ws.readyState || 3 === this._ws.readyState) {
                    // close previous socket
                    this._ws.close();
                } else if (0 === this._ws.readyState) {
                    return attempt.promise();
                } else if (1 === this._ws.readyState) {
                    attempt.resolve(this._ws);
                    return attempt.promise();
                }
            }

            this._ws = this._webSocket($.extend(this._opt, this._getSocketEventHandler(attempt)));

            return attempt.promise();
        },

        _reset: function() {
            this._reConnectTries = this._prop(this._opt, 'attempts', 60); // default 10min
            this._reConnectDeferred = $.Deferred();
        },

        _close: function() {
            if (this._ws) {
                this._ws.close();
                this._ws = null;
            }
        },

        _isConnected: function() {
            return this._ws !== null && this._ws.readyState === 1;
        },

        _reConnectTry: function() {
            var self = this;
            this._connect().done(function() {
                self._reConnectDeferred.resolve.apply(self, [self._ws]);
            }).fail(function(e) {
                self._reConnectTries--;
                if (self._reConnectTries > 0) {
                    window.setTimeout(function() {
                        self._reConnect.apply(self, []);
                    }, self._prop.apply(self, [self._opt, 'timeout', 10000]));
                } else {
                    self._reConnectDeferred.rejectWith.apply(self, [e]);
                }
            });
        },

        _reConnect: function() {
            var self = this;
            if (!this._reConnectDeferred || 'pending' !== this._reConnectDeferred.state()) {
                this._reset();
            }

            if (this._ws && this._ws.readyState === 1) {
                this._reConnectDeferred.resolve(this._ws);
            } else {
                this._reConnectTry();
            }

            return self._reConnectDeferred.promise.apply(self, []);
        },

        _preparePayload: function(data) {
            var payload;
            if (this._opt.dataType && 'text' === this._opt.dataType.toLowerCase()) {
                payload = data;
            } else if (this._opt.dataType && 'xml' === this._opt.dataType.toLowerCase()) {
                payload = data;
            } else if (this._opt.dataType && 'json' === this._opt.dataType.toLowerCase()) {
                payload = JSON.stringify(data);
            } else {
                payload = JSON.stringify(data); // default
            }
            return payload;
        },

        _send: function(data) {
            var self = this;
            var attempt = $.Deferred();

            (function(json) {
                self._reConnect.apply(self, []).done(function(ws) {
                    ws.send(json);
                    attempt.resolve.apply(self, [self._api]);
                }).fail(function(e) {
                    attempt.rejectWith.apply(self, [e]);
                });
            })(this._preparePayload(data));

            return attempt.promise();
        },

        _indexOfListener: function(listener) {
            for (var i=0, len=this._listeners.length; i<len; i++) {
                if (this._listeners[i].listener === listener) {
                    return i;
                }
            }
            return -1;
        },

         _isNotEmpty: function(obj, property) {
            return typeof 'undefined' !== obj &&
                null !== obj &&
                'undefined' !== typeof property &&
                null !== property &&
                '' !== property &&
                'undefined' !== typeof obj[property] &&
                null !== obj[property] &&
                '' !== obj[property];
         },

        _prop: function(obj, property, defaultValue) {
            if (this._isNotEmpty(obj, property)) {
               return obj[property];
            }
            return defaultValue;
        },

        _listen: function(listener) {
            var self = this;
            var dInternal = $.Deferred();
             self._reConnect.apply(self, []).done(function() {
                 dInternal.progress(function() {
                     listener.apply(this, arguments);
                 });
                 self._remove.apply(self, [listener]);
                 self._listeners.push({ 'deferred': dInternal, 'listener': listener });
             }).fail(function(e) {
                 dInternal.reject(e);
             });
             return dInternal.promise();
        },

        _listenReconnect: function(listener) {
            var dExternal = $.Deferred();

            var self = this;
            this._listen(listener)
            .fail(function() {
                dExternal.notify(arguments);
                self._listenReconnect.apply(self, [listener]);
            }).done(function() {
                dExternal.resolve();
            });

            return dExternal.promise();
        },

        _remove: function(listener) {
            var index = this._indexOfListener(listener);
            if (index !== -1) {
                this._listeners[index].deferred.resolve();
                this._listeners.splice(index, 1);
            }
        },

        _removeAll: function() {
           for (var i=0, len=this._listeners.length; i<len; i++) {
               this._listeners[i].deferred.resolve();
           }
           this._listeners = [];
        }
     };

    $.extend({
        simpleWebSocket: function(opt) {
            return new SimpleWebSocket(opt);
        }
    });

    return $.simpleWebSocket;
}));
<|endoftext|>


<commit_before>var matchFBO     = require('../../lib/match-fbo')
var drawTriangle = require('a-big-triangle')
var throttle     = require('frame-debounce')
var fit          = require('canvas-fit')
var getContext   = require('gl-context')
var compare      = require('gl-compare')
var createShader = require('glslify')
var now          = require('right-now')
var fs           = require('fs')

var container  = document.getElementById('container')
var canvas     = container.appendChild(document.createElement('canvas'))
var readme     = fs.readFileSync(__dirname + '/README.md', 'utf8')
var gl         = getContext(canvas, render)
var comparison = compare(gl, actual, expected)

comparison.mode = 'slide'
comparison.amount = 0.5

require('../common')({
    description: readme
  , compare: comparison
  , canvas: canvas
  , test: matchFBO(comparison, 0.99)
})

window.addEventListener('resize', fit(canvas), false)

var actualShader = createShader({
  vertex: "attribute vec2 uv;void main() {gl_Position = vec4(uv,0,1);}",
  fragment: [
"precision mediump float;",
"uniform vec2 screenSize, boxLo, boxHi;",
"#pragma glslify: inBox=require(" + process.env.file_box_glsl + ")",
"void main() {",
  "vec2 q = (gl_FragCoord.xy / screenSize);",
  "if(inBox(boxLo, boxHi, q)) {",
    "gl_FragColor = vec4(1,1,1,1);",
  "} else {",
    "gl_FragColor = vec4(0,0,0,1);",
  "}",
"}"].join("\n"),
  inline: true
})(gl)

var expectedShader = createShader({
    frag: './shaders/fragment.glsl'
  , vert: './shaders/vertex.glsl'
})(gl)

var boxLo = [0,0]
var boxHi = [0,0]

function render() {
  var t = 0.0001 * now()
  boxLo = [ 0.5*(1.0+0.8*Math.cos(2*t)), 0.5*(1.0+0.8*Math.cos(t + 1.37)) ]
  boxHi = [ boxLo[0] + 0.25*(1.0+0.8*Math.cos(0.9*t + 7)), boxLo[1]+0.25*(1.0+0.8*Math.cos(3*t - 1)) ]

  comparison.run()
  comparison.render()
}

function actual(fbo) {
  fbo.shape = [canvas.height, canvas.width]
  fbo.bind()
  actualShader.bind()
  actualShader.uniforms.screenSize = [canvas.width, canvas.height]
  expectedShader.uniforms.boxLo = boxLo
  expectedShader.uniforms.boxHi = boxHi
  drawTriangle(gl)
}

function expected(fbo) {
  fbo.shape = [canvas.height, canvas.width]
  fbo.bind()
  expectedShader.bind()
  expectedShader.uniforms.screenSize = [canvas.width, canvas.height]
  expectedShader.uniforms.boxLo = boxLo
  expectedShader.uniforms.boxHi = boxHi
  drawTriangle(gl)
}<commit_msg>fixed typo<commit_after>var matchFBO     = require('../../lib/match-fbo')
var drawTriangle = require('a-big-triangle')
var throttle     = require('frame-debounce')
var fit          = require('canvas-fit')
var getContext   = require('gl-context')
var compare      = require('gl-compare')
var createShader = require('glslify')
var now          = require('right-now')
var fs           = require('fs')

var container  = document.getElementById('container')
var canvas     = container.appendChild(document.createElement('canvas'))
var readme     = fs.readFileSync(__dirname + '/README.md', 'utf8')
var gl         = getContext(canvas, render)
var comparison = compare(gl, actual, expected)

comparison.mode = 'slide'
comparison.amount = 0.5

require('../common')({
    description: readme
  , compare: comparison
  , canvas: canvas
  , test: matchFBO(comparison, 0.99)
})

window.addEventListener('resize', fit(canvas), false)

var actualShader = createShader({
  vertex: "attribute vec2 uv;void main() {gl_Position = vec4(uv,0,1);}",
  fragment: [
"precision mediump float;",
"uniform vec2 screenSize, boxLo, boxHi;",
"#pragma glslify: inBox=require(" + process.env.file_box_glsl + ")",
"void main() {",
  "vec2 q = (gl_FragCoord.xy / screenSize);",
  "if(inBox(boxLo, boxHi, q)) {",
    "gl_FragColor = vec4(1,1,1,1);",
  "} else {",
    "gl_FragColor = vec4(0,0,0,1);",
  "}",
"}"].join("\n"),
  inline: true
})(gl)

var expectedShader = createShader({
    frag: './shaders/fragment.glsl'
  , vert: './shaders/vertex.glsl'
})(gl)

var boxLo = [0,0]
var boxHi = [0,0]

function render() {
  var t = 0.0001 * now()
  boxLo = [ 0.5*(1.0-0.8*Math.cos(2*t)), 0.5*(1.0+0.8*Math.cos(t + 1.37)) ]
  boxHi = [ boxLo[0] + 0.25*(1.0+0.8*Math.cos(0.9*t + 7)), boxLo[1]+0.25*(1.0+0.8*Math.cos(3*t - 1)) ]

  comparison.run()
  comparison.render()
}

function actual(fbo) {
  fbo.shape = [canvas.height, canvas.width]
  fbo.bind()
  actualShader.bind()
  actualShader.uniforms.screenSize = [canvas.width, canvas.height]
  actualShader.uniforms.boxLo = boxLo
  actualShader.uniforms.boxHi = boxHi
  drawTriangle(gl)
}

function expected(fbo) {
  fbo.shape = [canvas.height, canvas.width]
  fbo.bind()
  expectedShader.bind()
  expectedShader.uniforms.screenSize = [canvas.width, canvas.height]
  expectedShader.uniforms.boxLo = boxLo
  expectedShader.uniforms.boxHi = boxHi
  drawTriangle(gl)
}<|endoftext|>