<commit_before>"use strict";

var domino = require("domino");
var validateElementName = require("validate-element-name");

/**
 * The DOM object (serverComponents.dom) exposes tradition DOM objects (normally globally available
 * in browsers) such as the CustomEvent and various HTMLElement classes, for your component
 * implementations.
 */
exports.dom = domino.impl;

/**
 * Config properties holder.
 *
 * Plugins can add config on this (recommended to be use keys like
 * serverComponents.plugin_name.key). This enables easy config access without having to require
 * every plugin at the top-level that any sub-level component uses, and allows easy cross-plugin
 * config access as required.
 *
 * Individual components should not use this for config, instead providing their own APIs. This is
 * intended to allow easy access to the data for general purpose cross-component configuration.
 */
exports.config = { };

/**
 * Creates a returns a new custom HTML element prototype, extending the HTMLElement prototype.
 *
 * Note that this does *not* register the element. To do that, call serverComponents.registerElement
 * with an element name, and options (typically including the prototype returned here as your
 * 'prototype' value).
 */
exports.newElement = function newElement() {
    return Object.create(domino.impl.HTMLElement.prototype);
};

var registeredElements = {};

/**
 * Registers an element, so that it will be used when the given element name is found during parsing.
 *
 * Element names are required to contain a hyphen (to disambiguate them from existing element names),
 * be entirely lower-case, and not start with a hyphen.
 *
 * The only option currently supported is 'prototype', which sets the prototype of the given element.
 * This prototype will have its various callbacks called when it is found during document parsing,
 * and properties of the prototype will be exposed within the DOM to other elements there in turn.
 */
exports.registerElement = function registerElement(name, options) {
    var nameValidationResult = validateElementName(name);
    if (!nameValidationResult.isValid) {
        throw new Error(`Registration failed for '${name}'. ${nameValidationResult.message}`);
    }

    if (options) {
        registeredElements[name] = options.prototype;
    } else {
        registeredElements[name] = exports.newElement();
    }

    return registeredElements[name].constructor;
};

function recurseTree(rootNode, callback) {
    for (let node of rootNode.childNodes) {
        callback(node);
        recurseTree(node, callback);
    }
}

/**
 * Take a string of HTML input, and render it into a full page, handling any custom elements found
 * within, and returning a promise for the resulting string of HTML.
 */
exports.render = function render(input) {
    let doc = domino.createDocument(input);

    let createdPromises = [];

    recurseTree(doc, (node) => {
        if (node.tagName) {
            let nodeType = node.tagName.toLowerCase();
            let customElement = registeredElements[nodeType];
            if (customElement) {
                // TODO: Should probably clone node, not change prototype, for performance
                Object.setPrototypeOf(node, customElement);
                if (customElement.createdCallback) {
                    createdPromises.push(new Promise((resolve) => {
                        resolve(customElement.createdCallback.call(node));
                    }));
                }
            }
        }
    });

    return Promise.all(createdPromises).then(() => doc.documentElement.outerHTML);
};
<commit_msg>Catch another registration options edge case<commit_after>"use strict";

var domino = require("domino");
var validateElementName = require("validate-element-name");

/**
 * The DOM object (serverComponents.dom) exposes tradition DOM objects (normally globally available
 * in browsers) such as the CustomEvent and various HTMLElement classes, for your component
 * implementations.
 */
exports.dom = domino.impl;

/**
 * Config properties holder.
 *
 * Plugins can add config on this (recommended to be use keys like
 * serverComponents.plugin_name.key). This enables easy config access without having to require
 * every plugin at the top-level that any sub-level component uses, and allows easy cross-plugin
 * config access as required.
 *
 * Individual components should not use this for config, instead providing their own APIs. This is
 * intended to allow easy access to the data for general purpose cross-component configuration.
 */
exports.config = { };

/**
 * Creates a returns a new custom HTML element prototype, extending the HTMLElement prototype.
 *
 * Note that this does *not* register the element. To do that, call serverComponents.registerElement
 * with an element name, and options (typically including the prototype returned here as your
 * 'prototype' value).
 */
exports.newElement = function newElement() {
    return Object.create(domino.impl.HTMLElement.prototype);
};

var registeredElements = {};

/**
 * Registers an element, so that it will be used when the given element name is found during parsing.
 *
 * Element names are required to contain a hyphen (to disambiguate them from existing element names),
 * be entirely lower-case, and not start with a hyphen.
 *
 * The only option currently supported is 'prototype', which sets the prototype of the given element.
 * This prototype will have its various callbacks called when it is found during document parsing,
 * and properties of the prototype will be exposed within the DOM to other elements there in turn.
 */
exports.registerElement = function registerElement(name, options) {
    var nameValidationResult = validateElementName(name);
    if (!nameValidationResult.isValid) {
        throw new Error(`Registration failed for '${name}'. ${nameValidationResult.message}`);
    }

    if (options && options.prototype) {
        registeredElements[name] = options.prototype;
    } else {
        registeredElements[name] = exports.newElement();
    }

    return registeredElements[name].constructor;
};

function recurseTree(rootNode, callback) {
    for (let node of rootNode.childNodes) {
        callback(node);
        recurseTree(node, callback);
    }
}

/**
 * Take a string of HTML input, and render it into a full page, handling any custom elements found
 * within, and returning a promise for the resulting string of HTML.
 */
exports.render = function render(input) {
    let doc = domino.createDocument(input);

    let createdPromises = [];

    recurseTree(doc, (node) => {
        if (node.tagName) {
            let nodeType = node.tagName.toLowerCase();
            let customElement = registeredElements[nodeType];
            if (customElement) {
                // TODO: Should probably clone node, not change prototype, for performance
                Object.setPrototypeOf(node, customElement);
                if (customElement.createdCallback) {
                    createdPromises.push(new Promise((resolve) => {
                        resolve(customElement.createdCallback.call(node));
                    }));
                }
            }
        }
    });

    return Promise.all(createdPromises).then(() => doc.documentElement.outerHTML);
};
<|endoftext|>


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

/**
 * Tandem is a general instance registry that can be used to track creation/disposal of instances in PhET Simulations.
 * It is used for phetio.js instrumentation for PhET-iO support.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var tandemNamespace = require( 'TANDEM/tandemNamespace' );
  var toCamelCase = require( 'PHET_CORE/toCamelCase' );

  // text
  var packageString = require( 'text!REPOSITORY/package.json' );

  // constants
  var packageJSON = JSON.parse( packageString );
  var PHET_IO_ENABLED = !!(window.phet && window.phet.phetio);

  // variables
  var launched = false;

  // increment names of required tandems to avoid collisions for uninstrumented sims with phetioValidateTandems=false
  var requiredTandemIndex = 0;

  // increment names of optional tandems to avoid collisions for uninstrumented sims with phetioValidateTandems=false
  var optionalTandemIndex = 0;

  // increment names of uninstrumented common code tandems to avoid collisions for uninstrumented sims with phetioValidateTandems=false
  var uninstrumentedCodeIndex = 0;

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @param {Object} [options]
   * @constructor
   */
  function Tandem( id, options ) {

    // @private - these options are stored on the instance so they can be passed through the super type inheritance chain.
    // Note: Make sure that added options here are also added to options for inheritance (createSupertypeTandem)
    // and/or for composition (createTandem) as they make sense.
    this.options = _.extend( {

      // Enabled tandems notify listeners when they are added. Disabled tandems do not notify listeners,
      // but children of a disabled tandem may be enabled.
      enabled: true,

      supplied: true, // if the tandem is not supplied and required, an error will be thrown.
      required: true // require === false means it is an optional tandem
    }, options );

    // @public (read-only)
    this.id = (id !== undefined) ? id : '';
    this.required = this.options.required;
    this.supplied = this.options.supplied;

    // @private (read-only)
    this.enabled = this.options.enabled;
  }

  var bufferedInstances = [];

  tandemNamespace.register( 'Tandem', Tandem );

  // Listeners that will be notified when items are registered/deregistered
  var instanceListeners = [];

  inherit( Object, Tandem, {

    /**
     * Adds an instance of any type.  For example, it could be an axon Property, scenery Node or Sun button.  Each
     * item should only be added to the registry once, but that is not enforced here in Tandem.  For PhET-iO, phetio.js
     * enforces one entry per ID in phetio.addInstance
     *
     * This is used to register instances with PhET-iO.
     * @param {Object} instance - the instance to add
     * @param {function} type - the PhET-iO type function, such as TString or TProperty(TNumber)
     * @param {Object} options
     * @public
     */
    addInstance: function( instance, type, options ) {

      if ( PHET_IO_ENABLED && this.enabled ) {

        // Throw an error if the tandem is tandemRequired() but not supplied
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( !(this.required && !this.supplied), 'Tandem was required but not supplied' );
        }

        // ValidateTandems is false and printMissingTandems flag is present for a tandem that is required but not supplied.
        if ( phet.phetio.queryParameters.printMissingTandems && (this.required && !this.supplied) ) {
          console.log( 'Required Tandem not supplied.\n' +
                       'this.id = ' + this.id + '\n' +
                       'Stack trace: ' + new Error().stack );
        }

        // ifphetio returns a no-op function, so to test whether a valid "T" wrapper type was passed, we search for the typeName
        assert && assert( type && type.typeName, 'type must be specified and have a typeName for ' + this.id );

        // If tandem is tandemOptional, then don't add the instance
        if ( !this.required && !this.supplied ) {
          if ( phet.phetio.queryParameters.printMissingTandems ) {
            var stackTrace = new Error().stack;

            // Generally PhETFont is not desired because there are so many untandemized instances.
            if ( stackTrace.indexOf( 'PhetFont' ) === -1 ) {
              console.log( 'Optional Tandem not supplied.\n' +
                           'this.id = ' + this.id + '\n' +
                           'Stack trace: ' + stackTrace );
            }
          }

          // For optionally instrumented types that are not provided tandems, the instance isn't really "added"
          // but likewise, it in not an error
          return;
        }

        if ( !launched ) {
          bufferedInstances.push( { tandem: this, instance: instance, type: type, options: options } );
        }
        else {
          for ( var i = 0; i < instanceListeners.length; i++ ) {
            instanceListeners[ i ].addInstance( this.id, instance, type, options );
          }
        }
      }
    },

    /**
     * Removes an instance from the
     * @param {Object} instance - the instance to remove
     * @public
     */
    removeInstance: function( instance ) {
      if ( !this.required && !this.supplied ) {
        return;
      }

      // Only active when running as phet-io
      if ( PHET_IO_ENABLED && this.enabled ) {
        for ( var i = 0; i < instanceListeners.length; i++ ) {
          instanceListeners[ i ].removeInstance( this.id, instance );
        }
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @param {Object} [options]
     * @returns {Tandem}
     * @public
     */
    createTandem: function( id, options ) {

      // Make sure the id was provided
      assert && assert( typeof id === 'string' && id.length > 0, 'id must be defined' );

      var string = (this.id.length > 0) ? (this.id + '.' + id) : id;

      // Any child of something should be passed these inherited options.
      options = _.extend( {
        enabled: this.enabled,
        supplied: this.supplied,
        required: this.required
      }, options );

      return new Tandem( string, options );
    },

    /**
     * Creates a group tandem for creating multiple indexed child tandems, such as:
     * sim.screen.model.electron_0
     * sim.screen.model.electron_1
     *
     * In this case, 'sim.screen.model.electron' is the group tandem id.
     *
     * Used for arrays, observable arrays, or when many elements of the same type are created and they do not otherwise
     * have unique identifiers.
     * @param id
     * @returns {GroupTandem}
     */
    createGroupTandem: function( id ) {

      // Unfortunately we must resort to globals here since loading through the namespace would create a cycle
      return new GroupTandem( this.id + '.' + id );
    },

    /**
     * Get the last part of the tandem (after the last .), used in Joist for creating button names dynamically based
     * on screen names
     * @returns {string} the tail of the tandem
     */
    get tail() {
      assert && assert( this.id.indexOf( '.' ) >= 0, 'tandem ID does not have a tail' );

      var lastIndexOfDot = this.id.lastIndexOf( '.' );
      var tail = this.id.substring( lastIndexOfDot + 1 );
      assert && assert( tail.length > 0, 'tandem ID did not have a tail' );
      return tail;
    },

    /**
     * Returns a Tandem for everything except the tail.
     * @returns {Tandem}
     */
    get parentTandem() {
      assert && assert( this.id.indexOf( '.' ) >= 0, 'tandem ID does not have a tail' );

      var lastIndexOfDot = this.id.lastIndexOf( '.' );
      var headID = this.id.substring( 0, lastIndexOfDot );

      return new Tandem( headID, {
        required: this.required,
        supplied: this.supplied,
        enabled: this.enabled
      } );
    },

    /**
     * When using subtyping, the instance listeners must only be notified once rather than once for every level
     * in the inheritance hierarchy.  When a subtype constructor has a tandem.addInstance call, it should
     * pass a supertype tandem to the parent constructor so that it won't try to register the item twice.
     * @returns {SupertypeTandem}
     */
    createSupertypeTandem: function() {
      return new SupertypeTandem( this.id, this.options );
    },

    /**
     * Return true if this tandem is legal and can be used by the phet-io system.
     * @returns {boolean}
     */
    isLegalAndUsable: function() {

      // If we are not in phet-io mode, then the tandem is not legal and usable.
      if ( !PHET_IO_ENABLED ) {
        return false;
      }

      // A tandem is legal if it has been supplied or, if it hasn't been supplied, if it is optional.
      return this.supplied || (this.optional && !this.supplied);
    }
  }, {

    /**
     * Some common code (such as CheckBox or RadioButton) must always be instrumented and hence requires a tandem to be
     * passed in.  The options hash indicates this with {tandem: Tandem.tandemRequired()}
     * @returns {Tandem}
     */
    tandemRequired: function() {
      return rootTandem.createTandem( 'requiredTandem' + (requiredTandemIndex++), {
        required: true,
        supplied: false
      } );
    },

    /**
     *
     * Used to indicate a common code component that supports tandem, but doesn't not require it.
     * If a tandem is not passed through to this instance, then it will not be instrumented.
     * @returns {Tandem}
     */
    tandemOptional: function() {
      return rootTandem.createTandem( 'optionalTandem' + (optionalTandemIndex++), {
        required: false,
        supplied: false
      } );
    },

    /**
     * Adds a listener that will be notified when items are registered/deregistered
     * Listeners have the form
     * {
     *   addInstance(id,instance),
     *   removeInstance(id,instance)
     * }
     * where id is of type {string} and instance is of type {Object}
     *
     * @param {Object} instanceListener - described above
     * @public
     * @static
     */
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    },

    /**
     * Create a tandem based on the name of the running simulation.
     * @returns {Tandem}
     */
    createRootTandem: function() {
      return new Tandem( toCamelCase( packageJSON.name ) );
    },

    /**
     * Create a child of the root tandem.
     * @param {string} name
     * @returns {Tandem}
     */
    createStaticTandem: function( name ) {
      return Tandem.createRootTandem().createTandem( name );
    },

    /**
     * When all listeners are listening, all buffered instances are registered.
     */
    launch: function() {
      assert && assert( !launched, 'Tandem was launched twice' );
      launched = true;
      while ( bufferedInstances.length > 0 ) {
        var instance = bufferedInstances.shift();
        instance.tandem.addInstance( instance.instance, instance.type, instance.options );
      }
    },

    /**
     * Catch cases where tandem is being supplied to a class that doesn't support tandem.
     * @param options
     */
    disallowTandem: function( options ) {

      if ( Tandem.validationEnabled() ) {
        assert && assert( !options.tandem, 'tandem is not allowed' );
      }
    },

    /**
     * When running in PhET-iO brand, some code (such as user interface components) must be instrumented for PhET-iO.
     * Uninstrumented files should call this function to indicate they still need to be instrumented, so they aren't
     * missed.  See https://github.com/phetsims/phet-io/issues/668
     */
    indicateUninstrumentedCode: function() {

      // Guard against undefined errors
      if ( PHET_IO_ENABLED ) {

        // Assert if validating tandems
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( false, 'Uninstrumented code detected' );
        }

        // Print stack trace if query parameter supplied
        if ( phet.phetio.queryParameters.printMissingTandems ) {
          var stackTrace = new Error().stack;
          console.log( 'Uninstrumented Code! Tandem not supplied: ' + (uninstrumentedCodeIndex++) + '.\n' +
                       'Stack trace: ' + stackTrace );
        }

      }
    },

    /**
     * Determine whether or not tandem validation is turned on for the sim.
     * @returns {Boolean} If tandems are being validated or not.
     */
    validationEnabled: function() {
      return PHET_IO_ENABLED && phet.phetio.queryParameters.phetioValidateTandems;
    }
  } );

  var rootTandem = Tandem.createRootTandem();

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   * @private create with Tandem.createGroupTandem
   * Declared in the same file to avoid circular reference errors in module loading.
   */
  function GroupTandem( id ) {

    Tandem.call( this, id );

    // @private for generating indices from a pool
    this.groupElementIndex = 0;
  }

  tandemNamespace.register( 'Tandem.GroupTandem', GroupTandem );

  inherit( Tandem, GroupTandem, {

    // @public
    createNextTandem: function() {
      return new Tandem( this.id + '_' + (this.groupElementIndex++) );
    }
  } );

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @param {Object} options
   * @constructor
   * @private create with Tandem.createSupertypeTandem
   */
  function SupertypeTandem( id, options ) {
    Tandem.call( this, id, options );
  }

  tandemNamespace.register( 'Tandem.SupertypeTandem', SupertypeTandem );

  inherit( Tandem, SupertypeTandem, {

    // @public - This method overrides the method from Tandem to make no-op, see Tandem.createSupertypeTandem
    addInstance: function( instance, type, options ) {},

    // @public - This method overrides the method from Tandem to make no-op, see Tandem.createSupertypeTandem
    removeInstance: function( instance ) {}
  } );

  return Tandem;
} );

<commit_msg>Use singletons for tandemOptional and tandemRequired, see https://github.com/phetsims/phet-io/issues/1254<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * Tandem is a general instance registry that can be used to track creation/disposal of instances in PhET Simulations.
 * It is used for phetio.js instrumentation for PhET-iO support.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var tandemNamespace = require( 'TANDEM/tandemNamespace' );
  var toCamelCase = require( 'PHET_CORE/toCamelCase' );

  // text
  var packageString = require( 'text!REPOSITORY/package.json' );

  // constants
  var packageJSON = JSON.parse( packageString );
  var PHET_IO_ENABLED = !!(window.phet && window.phet.phetio);

  // variables
  var launched = false;

  // increment names of uninstrumented common code tandems to avoid collisions for uninstrumented sims with phetioValidateTandems=false
  var uninstrumentedCodeIndex = 0;

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @param {Object} [options]
   * @constructor
   */
  function Tandem( id, options ) {

    // @private - these options are stored on the instance so they can be passed through the super type inheritance chain.
    // Note: Make sure that added options here are also added to options for inheritance (createSupertypeTandem)
    // and/or for composition (createTandem) as they make sense.
    this.options = _.extend( {

      // Enabled tandems notify listeners when they are added. Disabled tandems do not notify listeners,
      // but children of a disabled tandem may be enabled.
      enabled: true,

      supplied: true, // if the tandem is not supplied and required, an error will be thrown.
      required: true // require === false means it is an optional tandem
    }, options );

    // @public (read-only)
    this.id = (id !== undefined) ? id : '';
    this.required = this.options.required;
    this.supplied = this.options.supplied;

    // @private (read-only)
    this.enabled = this.options.enabled;
  }

  var bufferedInstances = [];

  tandemNamespace.register( 'Tandem', Tandem );

  // Listeners that will be notified when items are registered/deregistered
  var instanceListeners = [];

  inherit( Object, Tandem, {

    /**
     * Adds an instance of any type.  For example, it could be an axon Property, scenery Node or Sun button.  Each
     * item should only be added to the registry once, but that is not enforced here in Tandem.  For PhET-iO, phetio.js
     * enforces one entry per ID in phetio.addInstance
     *
     * This is used to register instances with PhET-iO.
     * @param {Object} instance - the instance to add
     * @param {function} type - the PhET-iO type function, such as TString or TProperty(TNumber)
     * @param {Object} options
     * @public
     */
    addInstance: function( instance, type, options ) {

      if ( PHET_IO_ENABLED && this.enabled ) {

        // Throw an error if the tandem is tandemRequired() but not supplied
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( !(this.required && !this.supplied), 'Tandem was required but not supplied' );
        }

        // ValidateTandems is false and printMissingTandems flag is present for a tandem that is required but not supplied.
        if ( phet.phetio.queryParameters.printMissingTandems && (this.required && !this.supplied) ) {
          console.log( 'Required Tandem not supplied.\n' +
                       'this.id = ' + this.id + '\n' +
                       'Stack trace: ' + new Error().stack );
        }

        // ifphetio returns a no-op function, so to test whether a valid "T" wrapper type was passed, we search for the typeName
        assert && assert( type && type.typeName, 'type must be specified and have a typeName for ' + this.id );

        // If tandem is tandemOptional, then don't add the instance
        if ( !this.required && !this.supplied ) {
          if ( phet.phetio.queryParameters.printMissingTandems ) {
            var stackTrace = new Error().stack;

            // Generally PhETFont is not desired because there are so many untandemized instances.
            if ( stackTrace.indexOf( 'PhetFont' ) === -1 ) {
              console.log( 'Optional Tandem not supplied.\n' +
                           'this.id = ' + this.id + '\n' +
                           'Stack trace: ' + stackTrace );
            }
          }

          // For optionally instrumented types that are not provided tandems, the instance isn't really "added"
          // but likewise, it in not an error
          return;
        }

        if ( !launched ) {
          bufferedInstances.push( { tandem: this, instance: instance, type: type, options: options } );
        }
        else {
          for ( var i = 0; i < instanceListeners.length; i++ ) {
            instanceListeners[ i ].addInstance( this.id, instance, type, options );
          }
        }
      }
    },

    /**
     * Removes an instance from the
     * @param {Object} instance - the instance to remove
     * @public
     */
    removeInstance: function( instance ) {
      if ( !this.required && !this.supplied ) {
        return;
      }

      // Only active when running as phet-io
      if ( PHET_IO_ENABLED && this.enabled ) {
        for ( var i = 0; i < instanceListeners.length; i++ ) {
          instanceListeners[ i ].removeInstance( this.id, instance );
        }
      }
    },

    /**
     * Create a new Tandem by appending the given id
     * @param {string} id
     * @param {Object} [options]
     * @returns {Tandem}
     * @public
     */
    createTandem: function( id, options ) {

      // Make sure the id was provided
      assert && assert( typeof id === 'string' && id.length > 0, 'id must be defined' );

      var string = (this.id.length > 0) ? (this.id + '.' + id) : id;

      // Any child of something should be passed these inherited options.
      options = _.extend( {
        enabled: this.enabled,
        supplied: this.supplied,
        required: this.required
      }, options );

      return new Tandem( string, options );
    },

    /**
     * Creates a group tandem for creating multiple indexed child tandems, such as:
     * sim.screen.model.electron_0
     * sim.screen.model.electron_1
     *
     * In this case, 'sim.screen.model.electron' is the group tandem id.
     *
     * Used for arrays, observable arrays, or when many elements of the same type are created and they do not otherwise
     * have unique identifiers.
     * @param id
     * @returns {GroupTandem}
     */
    createGroupTandem: function( id ) {

      // Unfortunately we must resort to globals here since loading through the namespace would create a cycle
      return new GroupTandem( this.id + '.' + id );
    },

    /**
     * Get the last part of the tandem (after the last .), used in Joist for creating button names dynamically based
     * on screen names
     * @returns {string} the tail of the tandem
     */
    get tail() {
      assert && assert( this.id.indexOf( '.' ) >= 0, 'tandem ID does not have a tail' );

      var lastIndexOfDot = this.id.lastIndexOf( '.' );
      var tail = this.id.substring( lastIndexOfDot + 1 );
      assert && assert( tail.length > 0, 'tandem ID did not have a tail' );
      return tail;
    },

    /**
     * Returns a Tandem for everything except the tail.
     * @returns {Tandem}
     */
    get parentTandem() {
      assert && assert( this.id.indexOf( '.' ) >= 0, 'tandem ID does not have a tail' );

      var lastIndexOfDot = this.id.lastIndexOf( '.' );
      var headID = this.id.substring( 0, lastIndexOfDot );

      return new Tandem( headID, {
        required: this.required,
        supplied: this.supplied,
        enabled: this.enabled
      } );
    },

    /**
     * When using subtyping, the instance listeners must only be notified once rather than once for every level
     * in the inheritance hierarchy.  When a subtype constructor has a tandem.addInstance call, it should
     * pass a supertype tandem to the parent constructor so that it won't try to register the item twice.
     * @returns {SupertypeTandem}
     */
    createSupertypeTandem: function() {
      return new SupertypeTandem( this.id, this.options );
    },

    /**
     * Return true if this tandem is legal and can be used by the phet-io system.
     * @returns {boolean}
     */
    isLegalAndUsable: function() {

      // If we are not in phet-io mode, then the tandem is not legal and usable.
      if ( !PHET_IO_ENABLED ) {
        return false;
      }

      // A tandem is legal if it has been supplied or, if it hasn't been supplied, if it is optional.
      return this.supplied || (this.optional && !this.supplied);
    }
  }, {

    /**
     * Some common code (such as CheckBox or RadioButton) must always be instrumented and hence requires a tandem to be
     * passed in.  The options hash indicates this with {tandem: Tandem.tandemRequired()}
     * @returns {Tandem}
     */
    tandemRequired: function() {
      return requiredTandem;
    },

    /**
     *
     * Used to indicate a common code component that supports tandem, but doesn't not require it.
     * If a tandem is not passed through to this instance, then it will not be instrumented.
     * @returns {Tandem}
     */
    tandemOptional: function() {
      return optionalTandem;
    },

    /**
     * Adds a listener that will be notified when items are registered/deregistered
     * Listeners have the form
     * {
     *   addInstance(id,instance),
     *   removeInstance(id,instance)
     * }
     * where id is of type {string} and instance is of type {Object}
     *
     * @param {Object} instanceListener - described above
     * @public
     * @static
     */
    addInstanceListener: function( instanceListener ) {
      instanceListeners.push( instanceListener );
    },

    /**
     * Create a tandem based on the name of the running simulation.
     * @returns {Tandem}
     */
    createRootTandem: function() {
      return new Tandem( toCamelCase( packageJSON.name ) );
    },

    /**
     * Create a child of the root tandem.
     * @param {string} name
     * @returns {Tandem}
     */
    createStaticTandem: function( name ) {
      return Tandem.createRootTandem().createTandem( name );
    },

    /**
     * When all listeners are listening, all buffered instances are registered.
     */
    launch: function() {
      assert && assert( !launched, 'Tandem was launched twice' );
      launched = true;
      while ( bufferedInstances.length > 0 ) {
        var instance = bufferedInstances.shift();
        instance.tandem.addInstance( instance.instance, instance.type, instance.options );
      }
    },

    /**
     * Catch cases where tandem is being supplied to a class that doesn't support tandem.
     * @param options
     */
    disallowTandem: function( options ) {

      if ( Tandem.validationEnabled() ) {
        assert && assert( !options.tandem, 'tandem is not allowed' );
      }
    },

    /**
     * When running in PhET-iO brand, some code (such as user interface components) must be instrumented for PhET-iO.
     * Uninstrumented files should call this function to indicate they still need to be instrumented, so they aren't
     * missed.  See https://github.com/phetsims/phet-io/issues/668
     */
    indicateUninstrumentedCode: function() {

      // Guard against undefined errors
      if ( PHET_IO_ENABLED ) {

        // Assert if validating tandems
        if ( phet.phetio.queryParameters.phetioValidateTandems ) {
          assert && assert( false, 'Uninstrumented code detected' );
        }

        // Print stack trace if query parameter supplied
        if ( phet.phetio.queryParameters.printMissingTandems ) {
          var stackTrace = new Error().stack;
          console.log( 'Uninstrumented Code! Tandem not supplied: ' + (uninstrumentedCodeIndex++) + '.\n' +
                       'Stack trace: ' + stackTrace );
        }

      }
    },

    /**
     * Determine whether or not tandem validation is turned on for the sim.
     * @returns {Boolean} If tandems are being validated or not.
     */
    validationEnabled: function() {
      return PHET_IO_ENABLED && phet.phetio.queryParameters.phetioValidateTandems;
    }
  } );

  var rootTandem = Tandem.createRootTandem();

  var optionalTandem = rootTandem.createTandem( 'optionalTandem', {
    required: false,
    supplied: false
  } );

  var requiredTandem = rootTandem.createTandem( 'requiredTandem', {
    required: true,
    supplied: false
  } );

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @constructor
   * @private create with Tandem.createGroupTandem
   * Declared in the same file to avoid circular reference errors in module loading.
   */
  function GroupTandem( id ) {

    Tandem.call( this, id );

    // @private for generating indices from a pool
    this.groupElementIndex = 0;
  }

  tandemNamespace.register( 'Tandem.GroupTandem', GroupTandem );

  inherit( Tandem, GroupTandem, {

    // @public
    createNextTandem: function() {
      return new Tandem( this.id + '_' + (this.groupElementIndex++) );
    }
  } );

  /**
   * @param {string} id - id as a string (or '' for a root id)
   * @param {Object} options
   * @constructor
   * @private create with Tandem.createSupertypeTandem
   */
  function SupertypeTandem( id, options ) {
    Tandem.call( this, id, options );
  }

  tandemNamespace.register( 'Tandem.SupertypeTandem', SupertypeTandem );

  inherit( Tandem, SupertypeTandem, {

    // @public - This method overrides the method from Tandem to make no-op, see Tandem.createSupertypeTandem
    addInstance: function( instance, type, options ) {},

    // @public - This method overrides the method from Tandem to make no-op, see Tandem.createSupertypeTandem
    removeInstance: function( instance ) {}
  } );

  return Tandem;
} );

<|endoftext|>


<commit_before>goog.provide('prototype_claudia');
//TEST ob Repository funktioniert
goog.provide('lime.Label');
goog.provide('lime.Renderer.CANVAS.LABEL');
goog.provide('lime.Renderer.DOM.LABEL');
goog.require('lime.Renderer.CANVAS.SPRITE');
goog.require('lime.Renderer.DOM.SPRITE');
goog.require('lime.Sprite');
goog.require('goog.style');

goog.require('lime.Director');
goog.require('lime.Scene');
goog.require('lime.Layer');
goog.require('lime.Circle');
goog.require('lime.animation.Sequence');
goog.require('lime.animation.ScaleTo');
goog.require('lime.animation.MoveBy');
goog.require('lime.animation.RotateBy');
goog.require('lime.animation.Loop');
goog.require('lime.RoundedRect');
goog.require('lime.Sprite');

goog.require('lime');
goog.require('lime.Node');
goog.require('lime.fill.Color');
goog.require('lime.fill.Stroke');
goog.require('lime.fill.Fill');
goog.require('lime.fill.Image');

var VIEWPORT_WIDTH = 1280;
var VIEWPORT_HEIGHT = 720

//////////
/* INIT */
//////////

prototype_claudia.start = function(){

	var director = new lime.Director(document.body, VIEWPORT_WIDTH, VIEWPORT_HEIGHT),

        scene = new lime.Scene(),
        background = new lime.Sprite().setSize(VIEWPORT_WIDTH,VIEWPORT_HEIGHT).setFill('images/wiese/Verlauf_Wiese.jpg').setPosition(0,0).setAnchorPoint(0,0),
        erde = new lime.Sprite().setSize(1470,1470).setFill('images/wiese/Erde_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        landschaft1 = new lime.Sprite().setSize(1590,1590).setFill('images/wiese/Landschaft1_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        landschaft2 = new lime.Sprite().setSize(1680,1680).setFill('images/wiese/Landschaft2_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        himmel = new lime.Sprite().setSize(1750,1750).setFill('images/wiese/Himmel_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        planet_bottom = new lime.Circle().setSize(1475,1475).setFill('#232323').setAnchorPoint(0.5,0.5).setPosition(0,0),
        hindernis1 = new lime.RoundedRect().setSize(100, 100).setFill(160,270,280).setAnchorPoint(0.5, 0.5).setPosition(0, -1480),
        hindernis2 = new lime.RoundedRect().setSize(100, 160).setFill(160,270,280).setAnchorPoint(0.5, 0.5).setPosition(0, 1480),
        hindernis3 = new lime.RoundedRect().setSize(75, 120).setFill(160,270,280).setAnchorPoint(0.5, 0.5).setPosition(1600, 0),
        character = new lime.Circle().setSize(100, 150).setPosition(100, 535).setAnchorPoint(0.5, 1).setFill('#d5622f'),
        jumpArea =  new lime.Node().setSize(VIEWPORT_WIDTH / 2, VIEWPORT_HEIGHT / 2).setPosition(0,0).setAnchorPoint(0,0),
        crouchArea = new lime.Node().setSize(VIEWPORT_WIDTH / 2, VIEWPORT_HEIGHT / 2).setPosition(0, VIEWPORT_HEIGHT / 2).setAnchorPoint(0,0),

        // LAYER_1 – OBJECTS //
        layer_1 = new lime.Layer().setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT),

        // LAYER_2 – INTERACTION //
        layer_2 = new lime.Layer().setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);

    //planet_bottom.appendChild(hindernis1);
	//planet_bottom.appendChild(hindernis2);
    //planet_bottom.appendChild(hindernis3);
    //layer_1.appendChild(planet_bottom);
    //layer_1.appendChild(planet_top);
	layer_1.appendChild(background);
	layer_1.appendChild(himmel);
	layer_1.appendChild(landschaft2);
	layer_1.appendChild(landschaft1);
	layer_1.appendChild(erde);
    layer_1.appendChild(character);
    layer_2.appendChild(jumpArea);
    layer_2.appendChild(crouchArea);

    //background.qualityRenderer = true;

    scene.appendChild(layer_1);
    scene.appendChild(layer_2);

	director.makeMobileWebAppCapable();

///////////////
/* ANIMATION */
///////////////

    var turnLandschaft1 = new lime.animation.Loop(
        new lime.animation.RotateBy(360).setDuration(60).setEasing(lime.animation.Easing.LINEAR)
    );

    var turnLandschaft2 = new lime.animation.Loop(
        new lime.animation.RotateBy(360).setDuration(65).setEasing(lime.animation.Easing.LINEAR)
    );

    var turnHimmel = new lime.animation.Loop(
        new lime.animation.RotateBy(360).setDuration(100).setEasing(lime.animation.Easing.LINEAR)
    );

    var jumpUp = new lime.animation.MoveBy(0, -280).setDuration(0.2).setEasing(lime.animation.Easing.EASEOUT);
    var jumpDown = jumpUp.reverse().setDuration(0.35).setEasing(lime.animation.Easing.EASEIN);
    var jump = new lime.animation.Sequence(jumpUp, jumpDown);

    var crouch = new lime.animation.ScaleTo(1.6, 0.5).setDuration(0.1);
    var standUp = new lime.animation.ScaleTo(1, 1).setDuration(0.1);

    landschaft1.runAction(turnLandschaft1);
    landschaft2.runAction(turnLandschaft2);
    erde.runAction(turnLandschaft1);
    himmel.runAction(turnHimmel);

////////////////////
/* EVENTHANDLING */
////////////////////

	var isCrouching = false;

    goog.events.listen(jumpArea,['mousedown','touchstart'], function(e) {
        character.runAction(jump);
    });
    goog.events.listen(crouchArea,['mousedown','touchstart'], function(e) {
        character.runAction(crouch);

        e.swallow(['mouseup','touchend'],function(){
			character.runAction(standUp);
        });
    });

	/*
    var touchStartY;
    var touchMoveY;
    var touchEndY;
    var isCrouching = false;

    goog.events.listen(swipeArea, 'touchstart', function(e) {
        touchStartY = Math.round(e.position.y);
    });

    goog.events.listen(swipeArea, 'touchend', function(e) {
        touchEndY = Math.round(e.position.y);

        if (touchEndY < touchStartY) {
            character.runAction(jump);
        }
        if (isCrouching == true) {
            character.runAction(standUp);
            isCrouching = false;
        } else {
            return;
        }
    });

    goog.events.listen(swipeArea, 'touchmove', function(e) {
        touchMoveY = Math.round(e.position.y);

        if (isCrouching == false && touchStartY < touchMoveY) {
            character.runAction(crouch);
            isCrouching = true;
        } else {
            return;
        }
    }); */

	director.replaceScene(scene);
}

//this is required for outside access after code is compiled in ADVANCED_COMPILATIONS mode
goog.exportSymbol('prototype_claudia.start', prototype_claudia.start);
<commit_msg>Fließender Hintergrund<commit_after>goog.provide('prototype_claudia');

goog.require('lime.Renderer.CANVAS.SPRITE');
goog.require('lime.Renderer.DOM.SPRITE');
goog.require('lime.Sprite');
goog.require('goog.style');

goog.require('lime.Director');
goog.require('lime.Scene');
goog.require('lime.Layer');
goog.require('lime.Circle');
goog.require('lime.animation.Sequence');
goog.require('lime.animation.ScaleTo');
goog.require('lime.animation.MoveBy');
goog.require('lime.animation.RotateBy');
goog.require('lime.animation.RotateTo');
goog.require('lime.animation.Loop');
goog.require('lime.animation.Sequence');
goog.require('lime.RoundedRect');
goog.require('lime.Sprite');

goog.require('lime');
goog.require('lime.Node');
goog.require('lime.fill.Color');
goog.require('lime.fill.Stroke');
goog.require('lime.fill.Fill');
goog.require('lime.fill.Image');

var VIEWPORT_WIDTH = 1280;
var VIEWPORT_HEIGHT = 720

//////////
/* INIT */
//////////

prototype_claudia.start = function(){

	var director = new lime.Director(document.body, VIEWPORT_WIDTH, VIEWPORT_HEIGHT),

        scene = new lime.Scene(),

        background = new lime.Sprite().setSize(VIEWPORT_WIDTH,VIEWPORT_HEIGHT).setFill('images/wiese/Verlauf_Wiese.jpg').setPosition(0,0).setAnchorPoint(0,0),
        himmel1 = new lime.Sprite().setSize(1750,1750).setFill('images/wiese/Himmel_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        himmel2 = new lime.Sprite().setSize(1750,1750).setFill('images/wiese/Himmel_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1).setRotation(90),
        landschaftHinten1 = new lime.Sprite().setSize(1680,1680).setFill('images/wiese/Landschaft2_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        landschaftHinten2 = new lime.Sprite().setSize(1680,1680).setFill('images/wiese/Landschaft2_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1).setRotation(90),
        landschaftVorne1 = new lime.Sprite().setSize(1590,1590).setFill('images/wiese/Landschaft1_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        landschaftVorne2 = new lime.Sprite().setSize(1590,1590).setFill('images/wiese/Landschaft1_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1).setRotation(90),
        erde1 = new lime.Sprite().setSize(1470,1470).setFill('images/wiese/Erde_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1),
        erde2 = new lime.Sprite().setSize(1470,1470).setFill('images/wiese/Erde_Wiese.png').setPosition(0,1960).setAnchorPoint(0,1).setRotation(90),

        //hindernis1 = new lime.RoundedRect().setSize(100, 100).setFill(160,270,280).setAnchorPoint(0.5, 0.5).setPosition(0, -1480),
        //hindernis2 = new lime.RoundedRect().setSize(100, 160).setFill(160,270,280).setAnchorPoint(0.5, 0.5).setPosition(0, 1480),
        //hindernis3 = new lime.RoundedRect().setSize(75, 120).setFill(160,270,280).setAnchorPoint(0.5, 0.5).setPosition(1600, 0),
        character = new lime.Circle().setSize(100, 150).setPosition(100, 535).setAnchorPoint(0.5, 1).setFill('#d5622f'),
        jumpArea =  new lime.Node().setSize(VIEWPORT_WIDTH / 2, VIEWPORT_HEIGHT / 2).setPosition(0,0).setAnchorPoint(0,0),
        crouchArea = new lime.Node().setSize(VIEWPORT_WIDTH / 2, VIEWPORT_HEIGHT / 2).setPosition(0, VIEWPORT_HEIGHT / 2).setAnchorPoint(0,0),

        // LAYER_1 – OBJECTS //
        layer_1 = new lime.Layer().setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT),

        // LAYER_2 – INTERACTION //
        layer_2 = new lime.Layer().setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);

		layer_1.appendChild(background);
		layer_1.appendChild(himmel2);
		layer_1.appendChild(himmel1);
		layer_1.appendChild(landschaftHinten2);
		layer_1.appendChild(landschaftHinten1);
		layer_1.appendChild(landschaftVorne2);
		layer_1.appendChild(landschaftVorne1);
		layer_1.appendChild(erde1);
		layer_1.appendChild(erde2);
	    layer_1.appendChild(character);

	    layer_2.appendChild(jumpArea);
	    layer_2.appendChild(crouchArea);

	    //background.qualityRenderer = true;

	    scene.appendChild(layer_1);
	    scene.appendChild(layer_2);

		director.makeMobileWebAppCapable();

///////////////
/* ANIMATION */
///////////////

    var drehungErde1 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(90).setDuration(20).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(20).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungErde2 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(20).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(90).setDuration(20).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungLandschaftVorne1 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(90).setDuration(20).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(20).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungLandschaftVorne2 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(20).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(90).setDuration(20).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungLandschaftHinten1 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(90).setDuration(35).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(35).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungLandschaftHinten2 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(35).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(90).setDuration(35).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungHimmel1 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(90).setDuration(50).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(50).setEasing(lime.animation.Easing.LINEAR)
            )
    );

    var drehungHimmel2 = new lime.animation.Loop(
    	    new lime.animation.Sequence(
    	      new lime.animation.RotateTo(180).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
        	  new lime.animation.RotateTo(270).setDuration(0).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(360).setDuration(50).setEasing(lime.animation.Easing.LINEAR),
              new lime.animation.RotateTo(90).setDuration(50).setEasing(lime.animation.Easing.LINEAR)
            )
    );
    erde1.runAction(drehungErde1);
    erde2.runAction(drehungErde2);
    landschaftHinten1.runAction(drehungLandschaftHinten1);
    landschaftHinten2.runAction(drehungLandschaftHinten2);
    landschaftVorne1.runAction(drehungLandschaftVorne1);
    landschaftVorne2.runAction(drehungLandschaftVorne2);
    himmel1.runAction(drehungHimmel1);
    himmel2.runAction(drehungHimmel2);

    var jumpUp = new lime.animation.MoveBy(0, -280).setDuration(0.2).setEasing(lime.animation.Easing.EASEOUT);
    var jumpDown = jumpUp.reverse().setDuration(0.35).setEasing(lime.animation.Easing.EASEIN);
    var jump = new lime.animation.Sequence(jumpUp, jumpDown);

    var crouch = new lime.animation.ScaleTo(1.6, 0.5).setDuration(0.1);
    var standUp = new lime.animation.ScaleTo(1, 1).setDuration(0.1);

////////////////////
/* EVENTHANDLING */
////////////////////

	var isCrouching = false;

    goog.events.listen(jumpArea,['mousedown','touchstart'], function(e) {
        character.runAction(jump);
    });
    goog.events.listen(crouchArea,['mousedown','touchstart'], function(e) {
        character.runAction(crouch);

        e.swallow(['mouseup','touchend'],function(){
			character.runAction(standUp);
        });
    });

	director.replaceScene(scene);
}

//this is required for outside access after code is compiled in ADVANCED_COMPILATIONS mode
goog.exportSymbol('prototype_claudia.start', prototype_claudia.start);
<|endoftext|>


<commit_before>const Harvest = require('harvest').default;
const async = require('async').default;
const moment = require('moment');
const qs = require('qs');
const debug = require('debug')('revenue-core');
const dbInit = require('./db');
const getInvoicesList = require('./api/invoices');

module.exports = function(options, configurator, callback) {
	var clioptions = options;

	debug('options: %j', clioptions);
	return dbInit(configurator).then(db => {
		const CONFIG = db
			.get('config')
			.first()
			.value();

		const DATE_FORMAT = 'YYYY-DD-MM HH:mm:ss';
		const MIN_INTERVAL = 30 * 60;
		debug('config: %o', CONFIG);
		const harvest = new Harvest(CONFIG);

		let last_update;

		if (db.has('updates').value()) {
			const update = db
				.get('updates')
				.first()
				.value();
			if (update) {
				last_update = update.updated_since;
			}
		}

		if (
			clioptions.force ||
			clioptions.year != undefined ||
			!db.get('payments').exists()
		) {
			last_update = undefined;
		}
		debug('last update: %s', last_update);

		if (
			!last_update ||
			moment().unix() - moment(last_update).unix() > MIN_INTERVAL
		) {
			debug('fetching form server');
			getInvoicesList(harvest, db, last_update, () => {
				debug('rendering');
				var now = moment
					.utc()
					.subtract(10, 'minutes')
					.toISOString();

				db.get('updates')
					.upsert({
						id: 0,
						updated_since: now
					})
					.write();
				debug('updated %s', now);
				callback(db, now, clioptions);
			});
		} else {
			debug('rendering');
			callback(db, last_update, clioptions);
		}
	});
};
<commit_msg>fixed cache from cli<commit_after>const Harvest = require('harvest').default;
const async = require('async').default;
const moment = require('moment');
const qs = require('qs');
const debug = require('debug')('revenue-core');
const dbInit = require('./db');
const getInvoicesList = require('./api/invoices');

module.exports = function(options, configurator, callback) {
	var clioptions = options;

	debug('options: %j', clioptions);
	return dbInit(configurator).then(db => {
		const CONFIG = db
			.get('config')
			.first()
			.value();

		const DATE_FORMAT = 'YYYY-DD-MM HH:mm:ss';
		const MIN_INTERVAL = 30 * 60;
		debug('config: %o', CONFIG);
		const harvest = new Harvest(CONFIG);

		let last_update;

		if (db.has('updates').value()) {
			const update = db
				.get('updates')
				.first()
				.value();
			if (update) {
				last_update = update.updated_since;
			}
		}

		if (
			clioptions.force ||
			(clioptions.year != undefined &&
				clioptions.year != new Date().getFullYear()) ||
			!db.get('payments').exists()
		) {
			last_update = undefined;
		}
		debug('last update: %s', last_update);

		if (
			!last_update ||
			moment().unix() - moment(last_update).unix() > MIN_INTERVAL
		) {
			debug('fetching form server');
			getInvoicesList(harvest, db, last_update, () => {
				debug('rendering');
				var now = moment
					.utc()
					.subtract(10, 'minutes')
					.toISOString();

				db.get('updates')
					.upsert({
						id: 0,
						updated_since: now
					})
					.write();
				debug('updated %s', now);
				callback(db, now, clioptions);
			});
		} else {
			debug('rendering');
			callback(db, last_update, clioptions);
		}
	});
};
<|endoftext|>


<commit_before>var ImageSequence = function (target, options) {

  target.imagesequence = this;
  this.target = target;
  this.options = options;

  this.parseOptions();

  this.init();

  if(this.autoplay){
    this.run();
  }
};

ImageSequence.prototype.parseOptions = function () {
  this.src = this.options.src;
  this.width = this.options.width;
  this.height = this.options.height;
  this.currentFrame = 0;
  this.image = new Image();
  this.step = 1;
  this.loop = false;
  this.running = false;
  if (this.options.loop) {
    this.loop = true;
  }
  this.autoplay = false;
  if (this.options.autoplay) {
    this.autoplay = true;
  }
  if (this.options.rewind) {
    this.step = -1;
  }
  this.shouldPlay = this.autoplay;

  this.afterAnimation = false;
  if(this.options.afterAnimation !== undefined){
    this.afterAnimation = true;
    this.animationEnded = this.options.afterAnimation;
  }

  this.path = this.options.path;
  this.indexTo = 0;
  if (this.options.indexTo) {
    this.indexTo = this.options.indexTo;
  }
  this.indexFrom = 0;
  if (this.options.indexFrom) {
    this.indexFrom = this.options.indexFrom;
  }
  this.extension = this.options.extension;
  this.images = [];
  this.mode = 'sprite';
  if(this.options.path) {
    this.mode = 'sequence';
  }

  $(this.target.selector).prepend('<canvas id="' + this.target.selector + '"></canvas>');
  this.canvas = document.getElementById(this.target.selector);
  this.context = this.canvas.getContext('2d');

};

ImageSequence.prototype.init = function () {
  if(this.mode === 'sequence') {
    this.preloader();
    if(!this.shouldPlay) {
      this.drawCanvas(this.images[0]);
    }
  } else {
    this.image.src = this.src;
    this.target.html(this.image);
  }
  this.target.css('overflow','hidden');
};

ImageSequence.prototype.run = function () {
  this.running = true;
  var _this = this;
  setTimeout(function () {
    if(_this.shouldPlay){
      _this.nextFrame();
      _this.run();
    }
  }, 40);
};

ImageSequence.prototype.preloader = function () {
  for(var i = this.indexFrom; i <= this.indexTo; i++) {
    var img = new Image();
    var imageName = this.path + '/' + i + this.extension;
    img.src = imageName;
    this.images.push(img);
  }
};

ImageSequence.prototype.play = function () {
  this.step = 1;
  this.shouldPlay = true;
  if(this.running === false) {
    this.run();
  }
};

ImageSequence.prototype.pause = function () {
  this.step = 0;
};

ImageSequence.prototype.rewind = function () {
  this.step = -1;
  this.shouldPlay = true;
  if(this.running === false) {
    this.run();
  }
};

ImageSequence.prototype.drawCanvas = function (src) {

  var img = new Image();
      img.src = src.src;

  var targetWidth = this.target.width();
  var targetHeight = this.target.height();

  var scaleX = targetWidth / img.width;
  var scaleY = targetHeight / img.height;
  var scale = Math.max(scaleX, scaleY);

  var frameWidth = img.width * scale;
  var frameHeight = img.height * scale;

  var windowWidth     = $(window).outerWidth(),
      windowHeight    = $(window).outerHeight();
  // Set the canvas width
  this.canvas.width = targetWidth;
  this.canvas.height = windowHeight;

  this.context.clearRect( 0, 0, this.context.canvas.width, this.context.canvas.height );

  this.context.drawImage(
    img, // The image source
    (this.canvas.width - frameWidth) / 2, // X position - center it in the canvas
    (this.canvas.height - frameHeight) / 2, // Y position - 0px from the top
    frameWidth, // The width of the image - grab the scaled frameWidth
    frameHeight // Height of the image - grab the scaled frameHeight
  );

  window.onresize = function(){
    this.context.drawImage(
      img, // The image source
      (this.canvas.width - frameWidth) / 2, // X position - center it in the canvas
      (this.canvas.height - frameHeight) / 2, // Y position - 0px from the top
      frameWidth, // The width of the image - grab the scaled frameWidth
      frameHeight // Height of the image - grab the scaled frameHeight
    );
  };

};

ImageSequence.prototype.drawCurrentFrame = function () {

  if(this.mode === 'sequence') {

    var counter = _this.currentFrame;
    this.drawCanvas(this.images[counter]);

  } else {

    var targetWidth = this.target.width();
    var targetHeight = this.target.height();

    var scaleX = targetWidth / this.width;
    var scaleY = targetHeight / this.height;
    var scale = Math.max(scaleX, scaleY);

    var frameWidth = this.width * scale;
    var frameHeight = this.height * scale;

    var x = (targetWidth - frameWidth) / 2;
    var y = (targetHeight - frameHeight) / 2;

    // Animation
    x -= this.currentFrame * frameWidth;

    $(this.image).css({
      'transform' : "translate3d(" + x + "px,"+ y +"px,0) scale(" + scale + ", " + scale + ")",
      'transform-origin' : 'left top'
    });
  }
};

/*
Not necessarily 1, 2, 3...
Can be 8, 7, 6...
Could also be 0, 5, 10, 15...
*/
ImageSequence.prototype.nextFrame = function () {
  this.currentFrame = this.currentFrame + this.step;
  if (this.currentFrame >= this.countFrames()) {
    if(this.afterAnimation){
      this.animationEnded();
    }
    // On the right, end of sequence
    if (this.loop) {
      this.currentFrame -= this.countFrames();
    } else {
      this.currentFrame = this.countFrames() - 1;
      this.shouldPlay = false;
      this.running = false;
    }
  } else if (this.currentFrame < 0) {
    // On the left, beginning of sequence
    if(this.loop){
      this.currentFrame += this.countFrames();
    } else {
      this.currentFrame = 0;
      this.shouldPlay = false;
      this.running = false;
    }
  }
  this.drawCurrentFrame();
};

ImageSequence.prototype.countFrames = function () {
  if(this.mode === 'sequence') {
    return this.indexTo - this.indexFrom;
  } else {
    return this.image.naturalWidth / this.width;
  }
};

// Add method to jquery objects
if($) {
  $.fn.imagesequence = function (options) {
    return new ImageSequence(this, options);
  };
}
<commit_msg>Latest 'this' fixes.<commit_after>var ImageSequence = function (target, options) {

  target.imagesequence = this;
  this.target = target;
  this.options = options;

  this.parseOptions();

  this.init();

  if(this.autoplay){
    this.run();
  }
};

ImageSequence.prototype.parseOptions = function () {
  this.src = this.options.src;
  this.width = this.options.width;
  this.height = this.options.height;
  this.currentFrame = 0;
  this.image = new Image();
  this.step = 1;
  this.loop = false;
  this.running = false;
  if (this.options.loop) {
    this.loop = true;
  }
  this.autoplay = false;
  if (this.options.autoplay) {
    this.autoplay = true;
  }
  if (this.options.rewind) {
    this.step = -1;
  }
  this.shouldPlay = this.autoplay;

  this.afterAnimation = false;
  if(this.options.afterAnimation !== undefined){
    this.afterAnimation = true;
    this.animationEnded = this.options.afterAnimation;
  }

  this.path = this.options.path;
  this.indexTo = 0;
  if (this.options.indexTo) {
    this.indexTo = this.options.indexTo;
  }
  this.indexFrom = 0;
  if (this.options.indexFrom) {
    this.indexFrom = this.options.indexFrom;
  }
  this.extension = this.options.extension;
  this.images = [];
  this.mode = 'sprite';
  if(this.options.path) {
    this.mode = 'sequence';
  }

  $(this.target.selector).prepend('<canvas id="' + this.target.selector + '"></canvas>');
  this.canvas = document.getElementById(this.target.selector);
  this.context = this.canvas.getContext('2d');

};

ImageSequence.prototype.init = function () {
  if(this.mode === 'sequence') {
    this.preloader();
    if(!this.shouldPlay) {
      this.drawCanvas(this.images[0]);
    }
  } else {
    this.image.src = this.src;
    this.target.html(this.image);
  }
  this.target.css('overflow','hidden');
};

ImageSequence.prototype.run = function () {
  this.running = true;
  var _this = this;
  setTimeout(function () {
    if(_this.shouldPlay){
      _this.nextFrame();
      _this.run();
    }
  }, 40);
};

ImageSequence.prototype.preloader = function () {
  for(var i = this.indexFrom; i <= this.indexTo; i++) {
    var img = new Image();
    var imageName = this.path + '/' + i + this.extension;
    img.src = imageName;
    this.images.push(img);
  }
};

ImageSequence.prototype.play = function () {
  this.step = 1;
  this.shouldPlay = true;
  if(this.running === false) {
    this.run();
  }
};

ImageSequence.prototype.pause = function () {
  this.step = 0;
};

ImageSequence.prototype.rewind = function () {
  this.step = -1;
  this.shouldPlay = true;
  if(this.running === false) {
    this.run();
  }
};

ImageSequence.prototype.drawCanvas = function (src) {

  var img = new Image();
      img.src = src.src;

  var targetWidth = this.target.width();
  var targetHeight = this.target.height();

  var scaleX = targetWidth / img.width;
  var scaleY = targetHeight / img.height;
  var scale = Math.max(scaleX, scaleY);

  var frameWidth = img.width * scale;
  var frameHeight = img.height * scale;

  var windowWidth     = $(window).outerWidth(),
      windowHeight    = $(window).outerHeight();
  // Set the canvas width
  this.canvas.width = targetWidth;
  this.canvas.height = windowHeight;

  this.context.clearRect( 0, 0, this.context.canvas.width, this.context.canvas.height );

  this.context.drawImage(
    img, // The image source
    (this.canvas.width - frameWidth) / 2, // X position - center it in the canvas
    (this.canvas.height - frameHeight) / 2, // Y position - 0px from the top
    frameWidth, // The width of the image - grab the scaled frameWidth
    frameHeight // Height of the image - grab the scaled frameHeight
  );

  window.onresize = function(){
    this.context.drawImage(
      img, // The image source
      (this.canvas.width - frameWidth) / 2, // X position - center it in the canvas
      (this.canvas.height - frameHeight) / 2, // Y position - 0px from the top
      frameWidth, // The width of the image - grab the scaled frameWidth
      frameHeight // Height of the image - grab the scaled frameHeight
    );
  };

};

ImageSequence.prototype.drawCurrentFrame = function () {

  if(this.mode === 'sequence') {

    var counter = this.currentFrame;
    this.drawCanvas(this.images[counter]);

  } else {

    var targetWidth = this.target.width();
    var targetHeight = this.target.height();

    var scaleX = targetWidth / this.width;
    var scaleY = targetHeight / this.height;
    var scale = Math.max(scaleX, scaleY);

    var frameWidth = this.width * scale;
    var frameHeight = this.height * scale;

    var x = (targetWidth - frameWidth) / 2;
    var y = (targetHeight - frameHeight) / 2;

    // Animation
    x -= this.currentFrame * frameWidth;

    $(this.image).css({
      'transform' : "translate3d(" + x + "px,"+ y +"px,0) scale(" + scale + ", " + scale + ")",
      'transform-origin' : 'left top'
    });
  }
};

/*
Not necessarily 1, 2, 3...
Can be 8, 7, 6...
Could also be 0, 5, 10, 15...
*/
ImageSequence.prototype.nextFrame = function () {
  this.currentFrame = this.currentFrame + this.step;
  if (this.currentFrame >= this.countFrames()) {
    if(this.afterAnimation){
      this.animationEnded();
    }
    // On the right, end of sequence
    if (this.loop) {
      this.currentFrame -= this.countFrames();
    } else {
      this.currentFrame = this.countFrames() - 1;
      this.shouldPlay = false;
      this.running = false;
    }
  } else if (this.currentFrame < 0) {
    // On the left, beginning of sequence
    if(this.loop){
      this.currentFrame += this.countFrames();
    } else {
      this.currentFrame = 0;
      this.shouldPlay = false;
      this.running = false;
    }
  }
  this.drawCurrentFrame();
};

ImageSequence.prototype.countFrames = function () {
  if(this.mode === 'sequence') {
    return this.indexTo - this.indexFrom;
  } else {
    return this.image.naturalWidth / this.width;
  }
};

// Add method to jquery objects
if($) {
  $.fn.imagesequence = function (options) {
    return new ImageSequence(this, options);
  };
}
<|endoftext|>


<commit_before>function Delegator(config) {
	var w = config.writer;

	var del = {};

	/**
	 * @memberOf del
	 * @param params
	 * @param callback
	 */
	del.lookupEntity = function(params, callback) {
		var type = params.type;
		var query = params.query;
		var lookupService = params.lookupService;

		if (lookupService == 'project') {
			$.ajax({
				url: cwrc_params['entities_search_callback']+ '/' + query,
				dataType: 'json',
				success: function(data, status, xhr) {
					if ($.isPlainObject(data)) data = [data];
					if (data != null) {
						callback.call(w, data);
					} else {
						callback.call(w, []);
					}
				},
				error: function(xhr, status, error) {
					if (status == 'parsererror') {
						var lines = xhr.responseText.split(/\n/);
						if (lines[lines.length-1] == '') {
							lines.pop();
						}
						var string = lines.join(',');
						var data = $.parseJSON('['+string+']');
						callback.call(w, data);
					} else {
						callback.call(w, null);
					}
				}
			});
		} else if (lookupService == 'viaf') {
			$.ajax({
				url: 'http://viaf.org/viaf/AutoSuggest',
				data: {
					query: query
				},
				dataType: 'jsonp',
				success: function(data, status, xhr) {
					if (data != null && data.result != null) {
						callback.call(w, data.result);
					} else {
						callback.call(w, []);
					}
				},
				error: function() {
					callback.call(w, null);
				}
			});
		}
	};

	del.validate = function(callback) {
		console.log('hit delegator validate document');
		var docText = w.fm.getDocumentContent(false);
		var schemaUrl = w.schemas[w.schemaId].url;

		var valid = 'pass';
		callback.call(w, valid);

//		$.ajax({
//			url: w.baseUrl+'services/validator/validate.html',
//			type: 'POST',
//			dataType: 'XML',
//			data: {
//				sch: schemaUrl,
//				type: 'RNG_XML',
//				content: docText
//			},
//			success: function(data, status, xhr) {
//				if (callback) {
//					var valid = $('status', data).text() == 'pass';
//					callback.call(w, valid);
//				} else {
//					w.validation.showValidationResult(data, docText);
//				}
//			},
//			error: function() {
////				 $.ajax({
////					url : 'xml/validation.xml',
////					success : function(data, status, xhr) {
////						if (callback) {
////							var valid = $('status', data).text() == 'pass';
////							callback(valid);
////						} else {
////							w.validation.showValidationResult(data, docText);
////						}
////					}
////				});
//				w.dialogs.show('message', {
//					title: 'Error',
//					msg: 'An error occurred while trying to validate the document.',
//					type: 'error'
//				});
//			}
//		});
	};

	/**
	 * Loads a document based on the currentDocId
	 * TODO Move currentDocId system out of CWRCWriter
	 * @param docName
	 */
	del.loadDocument = function(callback) {
		console.log('hit delegator load document');
	    var baseUrl = window.location.protocol+'//'+window.location.host;

		$.ajax({
			url: baseUrl+Drupal.settings.basePath+'islandora/object/' + PID + '/datastream/CWRC/view',
			type: 'GET',
			dataType: 'xml',
			success: function(doc, status, xhr) {
				window.location.hash = '#'+w.currentDocId;
				//w.fm.loadDocumentFromXml(doc);
				callback.call(w, doc);
				writer.layout.enableResizable("east");
			    writer.layout.options.east.resizable = true;
			},
			error: function(xhr, status, error) {
				w.dialogs.show('message', {
					title: 'Error',
					msg: 'An error ('+status+') occurred and '+w.currentDocId+' was not loaded.',
					type: 'error'
				});
				w.currentDocId = null;
			}
		});
	};

	/**
	 * Performs the server call to save the document.
	 * @param callback Called with one boolean parameter: true for successful save, false otherwise
	 */
	del.saveDocument = function(callback) {
		w.mode == w.XMLRDF;
		console.log('hit delegator save document');
		var docText = w.fm.getDocumentContent(true);
		console.log('doctext: ');
		console.log(docText);
		console.log('writer triples');
		console.log(w.triples);
		$.ajax({
			url : window.parent.Drupal.settings.basePath + 'islandora/cwrcwriter/save_data/' + PID,
			type: 'POST',
			dataType: 'text',
			data: {
				"text": docText
			},
			success: function(data, status, xhr) {
				w.editor.isNotDirty = 1; // force clean state
				w.dialogs.show('message', {
					title: 'Document Saved',
					msg: w.currentDocId+' was saved successfully.'
				});
				window.location.hash = '#'+w.currentDocId;
				if (callback) {
					callback.call(w, true);
				}
			},
			error: function() {
				w.dialogs.show('message', {
					title: 'Error',
					msg: 'An error occurred and '+w.currentDocId+' was not saved.',
					type: 'error'
				});
				if (callback) {
					callback.call(w, false);
				}
			}
		});
	};

	del.getHelp = function(tagName) {
		return w.u.getDocumentationForTag(tagName);
	};

	return del;
}<commit_msg>Implemented default implementation of validator. Needs validation.<commit_after>function Delegator(config) {
	var w = config.writer;

	var del = {};

	/**
	 * @memberOf del
	 * @param params
	 * @param callback
	 */
	del.lookupEntity = function(params, callback) {
		var type = params.type;
		var query = params.query;
		var lookupService = params.lookupService;

		if (lookupService == 'project') {
			$.ajax({
				url: cwrc_params['entities_search_callback']+ '/' + query,
				dataType: 'json',
				success: function(data, status, xhr) {
					if ($.isPlainObject(data)) data = [data];
					if (data != null) {
						callback.call(w, data);
					} else {
						callback.call(w, []);
					}
				},
				error: function(xhr, status, error) {
					if (status == 'parsererror') {
						var lines = xhr.responseText.split(/\n/);
						if (lines[lines.length-1] == '') {
							lines.pop();
						}
						var string = lines.join(',');
						var data = $.parseJSON('['+string+']');
						callback.call(w, data);
					} else {
						callback.call(w, null);
					}
				}
			});
		} else if (lookupService == 'viaf') {
			$.ajax({
				url: 'http://viaf.org/viaf/AutoSuggest',
				data: {
					query: query
				},
				dataType: 'jsonp',
				success: function(data, status, xhr) {
					if (data != null && data.result != null) {
						callback.call(w, data.result);
					} else {
						callback.call(w, []);
					}
				},
				error: function() {
					callback.call(w, null);
				}
			});
		}
	};

	del.validate = function(callback) {
		console.log('hit delegator validate document');
		var docText = w.fm.getDocumentContent(false);
		var schemaUrl = w.schemas[w.schemaId].url;
//
//		var valid = 'pass';
//		callback.call(w, valid);

		$.ajax({
			url: 'http://apps.testing.cwrc.ca/services/validator/validate.html',
			type: 'POST',
			dataType: 'XML',
			data: {
				sch: schemaUrl,
				type: 'RNG_XML',
				content: docText
			},
			success: function(data, status, xhr) {
				if (callback) {
					var valid = $('status', data).text() == 'pass';
					callback.call(w, valid);
				} else {
					w.validation.showValidationResult(data, docText);
				}
			},
			error: function() {
				 $.ajax({
					url : 'xml/validation.xml',
					success : function(data, status, xhr) {
						if (callback) {
							var valid = $('status', data).text() == 'pass';
							callback(valid);
						} else {
							w.validation.showValidationResult(data, docText);
						}
					}
				});
				w.dialogs.show('message', {
					title: 'Error',
					msg: 'An error occurred while trying to validate the document.',
					type: 'error'
				});
			}
		});
	};

	/**
	 * Loads a document based on the currentDocId
	 * TODO Move currentDocId system out of CWRCWriter
	 * @param docName
	 */
	del.loadDocument = function(callback) {
		console.log('hit delegator load document');
	    var baseUrl = window.location.protocol+'//'+window.location.host;

		$.ajax({
			url: baseUrl+Drupal.settings.basePath+'islandora/object/' + PID + '/datastream/CWRC/view',
			type: 'GET',
			dataType: 'xml',
			success: function(doc, status, xhr) {
				window.location.hash = '#'+w.currentDocId;
				//w.fm.loadDocumentFromXml(doc);
				callback.call(w, doc);
				writer.layout.enableResizable("east");
			    writer.layout.options.east.resizable = true;
			},
			error: function(xhr, status, error) {
				w.dialogs.show('message', {
					title: 'Error',
					msg: 'An error ('+status+') occurred and '+w.currentDocId+' was not loaded.',
					type: 'error'
				});
				w.currentDocId = null;
			}
		});
	};

	/**
	 * Performs the server call to save the document.
	 * @param callback Called with one boolean parameter: true for successful save, false otherwise
	 */
	del.saveDocument = function(callback) {
		w.mode == w.XMLRDF;
		console.log('hit delegator save document');
		var docText = w.fm.getDocumentContent(true);
		console.log('doctext: ');
		console.log(docText);
		console.log('writer triples');
		console.log(w.triples);
		$.ajax({
			url : window.parent.Drupal.settings.basePath + 'islandora/cwrcwriter/save_data/' + PID,
			type: 'POST',
			dataType: 'text',
			data: {
				"text": docText
			},
			success: function(data, status, xhr) {
				w.editor.isNotDirty = 1; // force clean state
				w.dialogs.show('message', {
					title: 'Document Saved',
					msg: w.currentDocId+' was saved successfully.'
				});
				window.location.hash = '#'+w.currentDocId;
				if (callback) {
					callback.call(w, true);
				}
			},
			error: function() {
				w.dialogs.show('message', {
					title: 'Error',
					msg: 'An error occurred and '+w.currentDocId+' was not saved.',
					type: 'error'
				});
				if (callback) {
					callback.call(w, false);
				}
			}
		});
	};

	del.getHelp = function(tagName) {
		return w.u.getDocumentationForTag(tagName);
	};

	return del;
}<|endoftext|>


<commit_before>import {calculateSavings} from './utils/fuelSavingsCalculator';
import {getCalculations, deleteCalculation} from './api/api';
import './index.css';

const getById = (id) => global.document.getElementById(id);

// Populate table of previous calculations via API call.
getCalculations().then(result => {
  let calculationsBody = "";

  result.forEach(calculation => {
    calculationsBody+= `

      Delete
      ${calculation.newMpg}
      ${calculation.tradeMpg}
      ${calculation.pricePerGallon}
      ${calculation.milesDrivenPerMonth}

`
  });

  getById('calculations').innerHTML = calculationsBody;

  const deleteLinks = global.document.getElementsByClassName('deleteCalc');

  // Must use array.prototype here since getElementsByClassname only returns an "array like" object
  Array.prototype.forEach.call(deleteLinks, link => {
    link.onclick = function(event) {
      const element = event.target;
      event.preventDefault();
      deleteCalculation(element.attributes["data-id"].value);
      const row = element.parentNode.parentNode;
      row.parentNode.removeChild(row);
    };
  });
});

const resultTd = getById('result');

const inputs = [
  getById('newMpg'),
  getById('tradeMpg'),
  getById('pricePerGallon'),
  getById('milesDrivenPerMonth')
];

inputs.map(input => {
  input.onkeyup = () => {
    var inputValues = {};
    inputs.forEach(input => inputValues[input.id] = parseFloat(input.value));
    displayResults(inputValues);
  }
});

function displayResults(inputValues) {
  const savingsOrLoss = calculateSavings(inputValues);
  resultTd.innerHTML = savingsOrLoss ? savingsOrLoss + ' per month' : '';
}
<commit_msg>Comment reformat<commit_after>import {calculateSavings} from './utils/fuelSavingsCalculator';
import {getCalculations, deleteCalculation} from './api/api';
import './index.css';

const getById = (id) => global.document.getElementById(id);

// Populate table of previous calculations via API call.
getCalculations().then(result => {
  let calculationsBody = "";

  result.forEach(calculation => {
    calculationsBody+= `

      Delete
      ${calculation.newMpg}
      ${calculation.tradeMpg}
      ${calculation.pricePerGallon}
      ${calculation.milesDrivenPerMonth}

`
  });

  getById('calculations').innerHTML = calculationsBody;

  const deleteLinks = global.document.getElementsByClassName('deleteCalc');

  // Must use array.prototype here
  // getElementsByClassname only returns an "array like" object
  Array.prototype.forEach.call(deleteLinks, link => {
    link.onclick = function(event) {
      const element = event.target;
      event.preventDefault();
      deleteCalculation(element.attributes["data-id"].value);
      const row = element.parentNode.parentNode;
      row.parentNode.removeChild(row);
    };
  });
});

const resultTd = getById('result');

const inputs = [
  getById('newMpg'),
  getById('tradeMpg'),
  getById('pricePerGallon'),
  getById('milesDrivenPerMonth')
];

inputs.map(input => {
  input.onkeyup = () => {
    var inputValues = {};
    inputs.forEach(input => inputValues[input.id] = parseFloat(input.value));
    displayResults(inputValues);
  }
});

function displayResults(inputValues) {
  const savingsOrLoss = calculateSavings(inputValues);
  resultTd.innerHTML = savingsOrLoss ? savingsOrLoss + ' per month' : '';
}
<|endoftext|>