<commit_before>/**
 * Legacy-compatible NCList for 1.2.1 backcompat.
 * @extends
 */
function NCList_v0() {}

NCList_v0.prototype.importExisting = function(nclist, sublistIndex,
                                           lazyIndex, baseURL,
                                           lazyUrlTemplate) {
    this.topList = nclist;
    this.sublistIndex = sublistIndex;
    this.lazyIndex = lazyIndex;
    this.baseURL = baseURL;
    this.lazyUrlTemplate = lazyUrlTemplate;
};

NCList_v0.prototype.fill = function(intervals, sublistIndex) {
    //intervals: array of arrays of [start, end, ...]
    //sublistIndex: index into a [start, end] array for storing a sublist
    //              array. this is so you can use those arrays for something
    //              else, and keep the NCList_v0 bookkeeping from interfering.
    //              That's hacky, but keeping a separate copy of the intervals
    //              in the NCList_v0 seems like a waste (TODO: measure that waste).
    //half-open?
    this.sublistIndex = sublistIndex;
    var myIntervals = intervals;//.concat();
    //sort by OL
    myIntervals.sort(function(a, b) {
        if (a[0] != b[0])
            return a[0] - b[0];
        else
            return b[1] - a[1];
    });
    var sublistStack = new Array();
    var curList = new Array();
    this.topList = curList;
    curList.push(myIntervals[0]);
    var curInterval, topSublist;
    for (var i = 1, len = myIntervals.length; i < len; i++) {
        curInterval = myIntervals[i];
        //if this interval is contained in the previous interval,
        if (curInterval[1] < myIntervals[i - 1][1]) {
            //create a new sublist starting with this interval
            sublistStack.push(curList);
            curList = new Array(curInterval);
            myIntervals[i - 1][sublistIndex] = curList;
        } else {
            //find the right sublist for this interval
            while (true) {
                if (0 == sublistStack.length) {
                    curList.push(curInterval);
                    break;
                } else {
                    topSublist = sublistStack[sublistStack.length - 1];
                    if (topSublist[topSublist.length - 1][1] > curInterval[1]) {
                        //curList is the first (deepest) sublist that
                        //curInterval fits into
                        curList.push(curInterval);
                        break;
                    } else {
                        curList = sublistStack.pop();
                    }
                }
            }
        }
    }
};

NCList_v0.prototype.binarySearch = function(arr, item, itemIndex) {
    var low = -1;
    var high = arr.length;
    var mid;

    while (high - low > 1) {
        mid = (low + high) >>> 1;
        if (arr[mid][itemIndex] > item)
            high = mid;
        else
            low = mid;
    }

    //if we're iterating rightward, return the high index;
    //if leftward, the low index
    if (1 == itemIndex) return high; else return low;
};

NCList_v0.prototype.iterHelper = function(arr, from, to, fun, finish,
                                       inc, searchIndex, testIndex, path) {
    var len = arr.length;
    var i = this.binarySearch(arr, from, searchIndex);
    while ((i < len)
           && (i >= 0)
           && ((inc * arr[i][testIndex]) < (inc * to)) ) {

        if ("object" == typeof arr[i][this.lazyIndex]) {
            var ncl = this;
            // lazy node
            if (arr[i][this.lazyIndex].state) {
                if ("loading" == arr[i][this.lazyIndex].state) {
                    // node is currenly loading; finish this query once it
                    // has been loaded
                    finish.inc();
                    arr[i][this.lazyIndex].callbacks.push(
                        function(parentIndex) {
                            return function(o) {
                                ncl.iterHelper(o, from, to, fun, finish, inc,
                                               searchIndex, testIndex,
                                               path.concat(parentIndex));
                                finish.dec();
                            };
                        }(i)
                    );
                } else if ("loaded" == arr[i][this.lazyIndex].state) {
                    // just continue below
                } else {
                    console.log("unknown lazy type: " + arr[i]);
                }
            } else {
                // no "state" property means this node hasn't been loaded,
                // start loading
                arr[i][this.lazyIndex].state = "loading";
                arr[i][this.lazyIndex].callbacks = [];
                finish.inc();
                dojo.xhrGet(
                    {
                        url: this.baseURL +
                            this.lazyUrlTemplate.replace(
                                /\{chunk\}/g,
                                arr[i][this.lazyIndex].chunk
                            ),
                        handleAs: "json",
                        load: function(lazyFeat, lazyObj,
                                       sublistIndex, parentIndex) {
                            return function(o) {
                                lazyObj.state = "loaded";
                                lazyFeat[sublistIndex] = o;
                                ncl.iterHelper(o, from, to,
                                               fun, finish, inc,
                                               searchIndex, testIndex,
                                               path.concat(parentIndex));
                                for (var c = 0;
                                     c < lazyObj.callbacks.length;
                                     c++)
                                     lazyObj.callbacks[c](o);
                                finish.dec();
                            };
                        }(arr[i], arr[i][this.lazyIndex], this.sublistIndex, i),
                        error: function() {
                            finish.dec();
                        }
                    });
            }
        } else {
            fun(arr[i], path.concat(i));
        }

        if (arr[i][this.sublistIndex])
            this.iterHelper(arr[i][this.sublistIndex], from, to,
                            fun, finish, inc, searchIndex, testIndex,
                            path.concat(i));
        i += inc;
    }
};

NCList_v0.prototype.iterate = function(from, to, fun, postFun) {
    // calls the given function once for each of the
    // intervals that overlap the given interval
    //if from <= to, iterates left-to-right, otherwise iterates right-to-left

    //inc: iterate leftward or rightward
    var inc = (from > to) ? -1 : 1;
    //searchIndex: search on start or end
    var searchIndex = (from > to) ? 0 : 1;
    //testIndex: test on start or end
    var testIndex = (from > to) ? 1 : 0;
    var finish = new Finisher(postFun);
    this.iterHelper(this.topList, from, to, fun, finish,
                    inc, searchIndex, testIndex, []);
    finish.finish();
};

NCList_v0.prototype.histogram = function(from, to, numBins, callback) {
    //calls callback with a histogram of the feature density
    //in the given interval

    var result = new Array(numBins);
    var binWidth = (to - from) / numBins;
    for (var i = 0; i < numBins; i++) result[i] = 0;
    //this.histHelper(this.topList, from, to, result, numBins, (to - from) / numBins);
    this.iterate(from, to,
                 function(feat) {
	             var firstBin =
                         Math.max(0, ((feat[0] - from) / binWidth) | 0);
                     var lastBin =
                         Math.min(numBins, ((feat[1] - from) / binWidth) | 0);
	             for (var bin = firstBin; bin <= lastBin; bin++)
                         result[bin]++;
                 },
                 function() {
                     callback(result);
                 }
                 );
};

/*

Copyright (c) 2007-2009 The Evolutionary Software Foundation

Created by Mitchell Skinner <mitch_skinner@berkeley.edu>

This package and its accompanying libraries are free software; you can
redistribute it and/or modify it under the terms of the LGPL (either
version 2.1, or at your option, any later version) or the Artistic
License 2.0.  Refer to LICENSE for the full license text.

*/
<commit_msg>bugfix to backcompat-nclist url handling, references #75<commit_after>/**
 * Legacy-compatible NCList for 1.2.1 backcompat.
 * @extends
 */
function NCList_v0() {}

NCList_v0.prototype.importExisting = function(nclist, sublistIndex,
                                           lazyIndex, baseURL,
                                           lazyUrlTemplate) {
    this.topList = nclist;
    this.sublistIndex = sublistIndex;
    this.lazyIndex = lazyIndex;
    this.baseURL = baseURL;
    this.lazyUrlTemplate = lazyUrlTemplate;
};

NCList_v0.prototype.fill = function(intervals, sublistIndex) {
    //intervals: array of arrays of [start, end, ...]
    //sublistIndex: index into a [start, end] array for storing a sublist
    //              array. this is so you can use those arrays for something
    //              else, and keep the NCList_v0 bookkeeping from interfering.
    //              That's hacky, but keeping a separate copy of the intervals
    //              in the NCList_v0 seems like a waste (TODO: measure that waste).
    //half-open?
    this.sublistIndex = sublistIndex;
    var myIntervals = intervals;//.concat();
    //sort by OL
    myIntervals.sort(function(a, b) {
        if (a[0] != b[0])
            return a[0] - b[0];
        else
            return b[1] - a[1];
    });
    var sublistStack = new Array();
    var curList = new Array();
    this.topList = curList;
    curList.push(myIntervals[0]);
    var curInterval, topSublist;
    for (var i = 1, len = myIntervals.length; i < len; i++) {
        curInterval = myIntervals[i];
        //if this interval is contained in the previous interval,
        if (curInterval[1] < myIntervals[i - 1][1]) {
            //create a new sublist starting with this interval
            sublistStack.push(curList);
            curList = new Array(curInterval);
            myIntervals[i - 1][sublistIndex] = curList;
        } else {
            //find the right sublist for this interval
            while (true) {
                if (0 == sublistStack.length) {
                    curList.push(curInterval);
                    break;
                } else {
                    topSublist = sublistStack[sublistStack.length - 1];
                    if (topSublist[topSublist.length - 1][1] > curInterval[1]) {
                        //curList is the first (deepest) sublist that
                        //curInterval fits into
                        curList.push(curInterval);
                        break;
                    } else {
                        curList = sublistStack.pop();
                    }
                }
            }
        }
    }
};

NCList_v0.prototype.binarySearch = function(arr, item, itemIndex) {
    var low = -1;
    var high = arr.length;
    var mid;

    while (high - low > 1) {
        mid = (low + high) >>> 1;
        if (arr[mid][itemIndex] > item)
            high = mid;
        else
            low = mid;
    }

    //if we're iterating rightward, return the high index;
    //if leftward, the low index
    if (1 == itemIndex) return high; else return low;
};

NCList_v0.prototype.iterHelper = function(arr, from, to, fun, finish,
                                       inc, searchIndex, testIndex, path) {
    var len = arr.length;
    var i = this.binarySearch(arr, from, searchIndex);
    while ((i < len)
           && (i >= 0)
           && ((inc * arr[i][testIndex]) < (inc * to)) ) {

        if ("object" == typeof arr[i][this.lazyIndex]) {
            var ncl = this;
            // lazy node
            if (arr[i][this.lazyIndex].state) {
                if ("loading" == arr[i][this.lazyIndex].state) {
                    // node is currenly loading; finish this query once it
                    // has been loaded
                    finish.inc();
                    arr[i][this.lazyIndex].callbacks.push(
                        function(parentIndex) {
                            return function(o) {
                                ncl.iterHelper(o, from, to, fun, finish, inc,
                                               searchIndex, testIndex,
                                               path.concat(parentIndex));
                                finish.dec();
                            };
                        }(i)
                    );
                } else if ("loaded" == arr[i][this.lazyIndex].state) {
                    // just continue below
                } else {
                    console.log("unknown lazy type: " + arr[i]);
                }
            } else {
                // no "state" property means this node hasn't been loaded,
                // start loading
                arr[i][this.lazyIndex].state = "loading";
                arr[i][this.lazyIndex].callbacks = [];
                finish.inc();
                dojo.xhrGet(
                    {
                        url: Util.resolveUrl(
                                this.baseURL,
                                this.lazyUrlTemplate.replace(
                                    /\{chunk\}/g,
                                   arr[i][this.lazyIndex].chunk
                                )
                             ),
                        handleAs: "json",
                        load: function(lazyFeat, lazyObj,
                                       sublistIndex, parentIndex) {
                            return function(o) {
                                lazyObj.state = "loaded";
                                lazyFeat[sublistIndex] = o;
                                ncl.iterHelper(o, from, to,
                                               fun, finish, inc,
                                               searchIndex, testIndex,
                                               path.concat(parentIndex));
                                for (var c = 0;
                                     c < lazyObj.callbacks.length;
                                     c++)
                                     lazyObj.callbacks[c](o);
                                finish.dec();
                            };
                        }(arr[i], arr[i][this.lazyIndex], this.sublistIndex, i),
                        error: function() {
                            finish.dec();
                        }
                    });
            }
        } else {
            fun(arr[i], path.concat(i));
        }

        if (arr[i][this.sublistIndex])
            this.iterHelper(arr[i][this.sublistIndex], from, to,
                            fun, finish, inc, searchIndex, testIndex,
                            path.concat(i));
        i += inc;
    }
};

NCList_v0.prototype.iterate = function(from, to, fun, postFun) {
    // calls the given function once for each of the
    // intervals that overlap the given interval
    //if from <= to, iterates left-to-right, otherwise iterates right-to-left

    //inc: iterate leftward or rightward
    var inc = (from > to) ? -1 : 1;
    //searchIndex: search on start or end
    var searchIndex = (from > to) ? 0 : 1;
    //testIndex: test on start or end
    var testIndex = (from > to) ? 1 : 0;
    var finish = new Finisher(postFun);
    this.iterHelper(this.topList, from, to, fun, finish,
                    inc, searchIndex, testIndex, []);
    finish.finish();
};

NCList_v0.prototype.histogram = function(from, to, numBins, callback) {
    //calls callback with a histogram of the feature density
    //in the given interval

    var result = new Array(numBins);
    var binWidth = (to - from) / numBins;
    for (var i = 0; i < numBins; i++) result[i] = 0;
    //this.histHelper(this.topList, from, to, result, numBins, (to - from) / numBins);
    this.iterate(from, to,
                 function(feat) {
	             var firstBin =
                         Math.max(0, ((feat[0] - from) / binWidth) | 0);
                     var lastBin =
                         Math.min(numBins, ((feat[1] - from) / binWidth) | 0);
	             for (var bin = firstBin; bin <= lastBin; bin++)
                         result[bin]++;
                 },
                 function() {
                     callback(result);
                 }
                 );
};

/*

Copyright (c) 2007-2009 The Evolutionary Software Foundation

Created by Mitchell Skinner <mitch_skinner@berkeley.edu>

This package and its accompanying libraries are free software; you can
redistribute it and/or modify it under the terms of the LGPL (either
version 2.1, or at your option, any later version) or the Artistic
License 2.0.  Refer to LICENSE for the full license text.

*/
<|endoftext|>


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

/**
 * Popupable trait
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrea Lin (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */

import BooleanProperty from '../../axon/js/BooleanProperty.js';
import ScreenView from '../../joist/js/ScreenView.js';
import inheritance from '../../phet-core/js/inheritance.js';
import merge from '../../phet-core/js/merge.js';
import Node from '../../scenery/js/nodes/Node.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import sun from './sun.js';

const Popupable = type => {
  assert && assert( _.includes( inheritance( type ), Node ), 'Only Node subtypes should mix Popupable' );

  class Popupable extends type {

    constructor( options, ...args ) {
      super( ...args );

      options = merge( {
        isModal: true, // {boolean} modal popups prevent interaction with the rest of the sim while open

        // {Bounds2|null} - If desired, the layoutBounds that should be used for layout
        layoutBounds: null,

        tandem: Tandem.OPTIONAL,
        phetioState: PhetioObject.DEFAULT_OPTIONS.phetioState
      }, options );

      // see https://github.com/phetsims/joist/issues/293
      assert && assert( options.isModal, 'Non-modal popups not currently supported' );

      // @public {Bounds2|null}
      this.layoutBounds = options.layoutBounds;

      // @public {Node} - The node provided to showPopup, with the transform applied
      this.popupParent = new Node( {
        children: [ this ]
      } );
      this.popupParent.show = this.show.bind( this );
      this.popupParent.hide = this.hide.bind( this );
      this.popupParent.layout = this.layout.bind( this );

      // @public {Property.<boolean>} - Whether the popup is being shown
      this.isShowingProperty = new BooleanProperty( false, {
        tandem: options.tandem.createTandem( 'isShowingProperty' ),
        phetioReadOnly: true,
        phetioState: options.phetioState // match the state transfer of the Popup
      } );

      this.isShowingProperty.lazyLink( isShowing => {
        if ( isShowing ) {
          window.phet.joist.sim.showPopup( this.popupParent, options.isModal );
        }
        else {
          window.phet.joist.sim.hidePopup( this.popupParent, options.isModal );
        }
      } );
    }

    /**
     * @public
     *
     * @param {number} width
     * @param {number} height
     */
    layout( width, height ) {
      if ( this.layoutBounds ) {
        this.popupParent.matrix = ScreenView.getLayoutMatrix( this.layoutBounds, width, height );
      }
    }

    /**
     * @public
     */
    show() {
      this.isShowingProperty.value = true;
    }

    /**
     * Hide the popup. If you create a new popup next time you show(), be sure to dispose this popup instead.
     * @public
     */
    hide() {
      this.isShowingProperty.value = false;
    }

    /**
     * Releases references
     * @public
     */
    dispose() {
      this.hide();

      this.isShowingProperty.dispose();

      super.dispose();
    }
  }

  return Popupable;
};

sun.register( 'Popupable', Popupable );

export default Popupable;<commit_msg>move hide/showPopup to an option to allow for graceful fallback if phet.joist.sim is not defined, https://github.com/phetsims/joist/issues/686<commit_after>// Copyright 2020, University of Colorado Boulder

/**
 * Popupable trait
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrea Lin (PhET Interactive Simulations)
 * @author Chris Malley (PixelZoom, Inc.)
 */

import BooleanProperty from '../../axon/js/BooleanProperty.js';
import ScreenView from '../../joist/js/ScreenView.js';
import inheritance from '../../phet-core/js/inheritance.js';
import merge from '../../phet-core/js/merge.js';
import Node from '../../scenery/js/nodes/Node.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import sun from './sun.js';

const Popupable = type => {
  assert && assert( _.includes( inheritance( type ), Node ), 'Only Node subtypes should mix Popupable' );

  class Popupable extends type {

    constructor( options, ...args ) {
      super( ...args );

      options = merge( {

        showPopup: _.hasIn( window, 'phet.joist.sim' ) && phet.joist.sim.showPopup.bind( phet.joist.sim ),
        hidePopup: _.hasIn( window, 'phet.joist.sim' ) && phet.joist.sim.hidePopup.bind( phet.joist.sim ),

        isModal: true, // {boolean} modal popups prevent interaction with the rest of the sim while open

        // {Bounds2|null} - If desired, the layoutBounds that should be used for layout
        layoutBounds: null,

        tandem: Tandem.OPTIONAL,
        phetioState: PhetioObject.DEFAULT_OPTIONS.phetioState
      }, options );

      assert && assert( typeof options.showPopup === 'function', 'showPopup is a required, and must be provided if phet.joist.sim is not available.' );
      assert && assert( typeof options.hidePopup === 'function', 'hidePopup is a required, and must be provided if phet.joist.sim is not available.' );

      // see https://github.com/phetsims/joist/issues/293
      assert && assert( options.isModal, 'Non-modal popups not currently supported' );

      // @public {Bounds2|null}
      this.layoutBounds = options.layoutBounds;

      // @public {Node} - The node provided to showPopup, with the transform applied
      this.popupParent = new Node( {
        children: [ this ]
      } );
      this.popupParent.show = this.show.bind( this );
      this.popupParent.hide = this.hide.bind( this );
      this.popupParent.layout = this.layout.bind( this );

      // @public {Property.<boolean>} - Whether the popup is being shown
      this.isShowingProperty = new BooleanProperty( false, {
        tandem: options.tandem.createTandem( 'isShowingProperty' ),
        phetioReadOnly: true,
        phetioState: options.phetioState // match the state transfer of the Popup
      } );

      this.isShowingProperty.lazyLink( isShowing => {
        if ( isShowing ) {
          options.showPopup( this.popupParent, options.isModal );
        }
        else {
          options.hidePopup( this.popupParent, options.isModal );
        }
      } );
    }

    /**
     * @public
     *
     * @param {number} width
     * @param {number} height
     */
    layout( width, height ) {
      if ( this.layoutBounds ) {
        this.popupParent.matrix = ScreenView.getLayoutMatrix( this.layoutBounds, width, height );
      }
    }

    /**
     * @public
     */
    show() {
      this.isShowingProperty.value = true;
    }

    /**
     * Hide the popup. If you create a new popup next time you show(), be sure to dispose this popup instead.
     * @public
     */
    hide() {
      this.isShowingProperty.value = false;
    }

    /**
     * Releases references
     * @public
     */
    dispose() {
      this.hide();

      this.isShowingProperty.dispose();

      super.dispose();
    }
  }

  return Popupable;
};

sun.register( 'Popupable', Popupable );

export default Popupable;<|endoftext|>


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

/**
 * Status bar that runs along the top of a game
 *
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules

  var BackButton = require( 'SCENERY_PHET/buttons/BackButton' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var vegas = require( 'VEGAS/vegas' );

  /**
   * @param {Property} visibleBoundsProperty - for layout
   * @param {Node} messageNode - to the right of the back button, typically Text
   * @param {Node} scoreDisplay - intended to be one of the ScoreDisplay* nodes but can be any custom Node provided
   * by the client
   * @param {Object} [options]
   * @constructor
   */
  function StatusBar( visibleBoundsProperty, messageNode, scoreDisplay, options ) {

    options = _.extend( {
      backButtonListener: null,
      xMargin: 20,
      yMargin: 10,
      backgroundFill: 'rgb( 49, 117, 202 )',
      spacing: 8,
      alwaysInsideLayoutBounds: true // otherwise, moves with the edges of browser window
    }, options );

    assert && assert( !options.children, 'ScoreDisplayNumber sets children' );

    var backButton = new BackButton( { listener: options.backButtonListener } );

    var backgroundHeight = Math.max( backButton.height, messageNode.height, scoreDisplay.height ) + 2 * options.yMargin;
    var backgroundNode = new Rectangle(
      visibleBoundsProperty.get().minX,
      visibleBoundsProperty.minY,
      visibleBoundsProperty.get().maxX - visibleBoundsProperty.get().minX,
      backgroundHeight, {
        fill: options.backgroundFill
    } );

    // layout
    backButton.left = backgroundNode.left + options.xMargin;
    backButton.centerY = backgroundNode.centerY;
    messageNode.left = backButton.right + options.spacing;
    messageNode.centerY = backgroundNode.centerY;
    scoreDisplay.right = backgroundNode.right - options.xMargin;
    scoreDisplay.centerY = backgroundNode.centerY;

    var boundsListener = function( bounds ) {
      backgroundNode.setRectX( bounds.minX );
      backgroundNode.setRectWidth( bounds.maxX - bounds.minX );
      if ( !options.alwaysInsideLayoutBounds ) {
        backButton.left = backgroundNode.left + options.xMargin;
        messageNode.left = backButton.right + options.spacing;
        scoreDisplay.right = backgroundNode.right - options.xMargin;
      }
    };

    visibleBoundsProperty.link( boundsListener );

    // @private
    this.disposeStatusBar = function() {
      backButton.dispose();
      visibleBoundsProperty.unlink( boundsListener );
    };

    options.children = [ backgroundNode, backButton, messageNode, scoreDisplay ];

    Node.call( this, options );
  }

  vegas.register( 'StatusBar', StatusBar );

  return inherit( Node, StatusBar, {

    // @public
    dispose: function() {
      this.disposeStatusBar;
      Node.prototype.dispose.call( this );
    }
  } );
} );<commit_msg>Fix max calculation<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Status bar that runs along the top of a game
 *
 * @author Andrea Lin
 */
define( function( require ) {
  'use strict';

  // modules

  var BackButton = require( 'SCENERY_PHET/buttons/BackButton' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var vegas = require( 'VEGAS/vegas' );

  /**
   * @param {Property} visibleBoundsProperty - for layout
   * @param {Node} messageNode - to the right of the back button, typically Text
   * @param {Node} scoreDisplay - intended to be one of the ScoreDisplay* nodes but can be any custom Node provided
   * by the client
   * @param {Object} [options]
   * @constructor
   */
  function StatusBar( visibleBoundsProperty, messageNode, scoreDisplay, options ) {

    options = _.extend( {
      backButtonListener: null,
      xMargin: 20,
      yMargin: 10,
      backgroundFill: 'rgb( 49, 117, 202 )',
      spacing: 8,
      alwaysInsideLayoutBounds: true // otherwise, moves with the edges of browser window
    }, options );

    assert && assert( !options.children, 'ScoreDisplayNumber sets children' );

    var backButton = new BackButton( { listener: options.backButtonListener } );

    var backgroundHeight = _.max( [ backButton.height, messageNode.height, scoreDisplay.height ] ) + 2 * options.yMargin;
    var backgroundNode = new Rectangle(
      visibleBoundsProperty.get().minX,
      visibleBoundsProperty.minY,
      visibleBoundsProperty.get().maxX - visibleBoundsProperty.get().minX,
      backgroundHeight, {
        fill: options.backgroundFill
    } );

    // layout
    backButton.left = backgroundNode.left + options.xMargin;
    backButton.centerY = backgroundNode.centerY;
    messageNode.left = backButton.right + options.spacing;
    messageNode.centerY = backgroundNode.centerY;
    scoreDisplay.right = backgroundNode.right - options.xMargin;
    scoreDisplay.centerY = backgroundNode.centerY;

    var boundsListener = function( bounds ) {
      backgroundNode.setRectX( bounds.minX );
      backgroundNode.setRectWidth( bounds.maxX - bounds.minX );
      if ( !options.alwaysInsideLayoutBounds ) {
        backButton.left = backgroundNode.left + options.xMargin;
        messageNode.left = backButton.right + options.spacing;
        scoreDisplay.right = backgroundNode.right - options.xMargin;
      }
    };

    visibleBoundsProperty.link( boundsListener );

    // @private
    this.disposeStatusBar = function() {
      backButton.dispose();
      visibleBoundsProperty.unlink( boundsListener );
    };

    options.children = [ backgroundNode, backButton, messageNode, scoreDisplay ];

    Node.call( this, options );
  }

  vegas.register( 'StatusBar', StatusBar );

  return inherit( Node, StatusBar, {

    // @public
    dispose: function() {
      this.disposeStatusBar;
      Node.prototype.dispose.call( this );
    }
  } );
} );<|endoftext|>


<commit_before>// Copyright 2014-2018, University of Colorado Boulder

/**
 * Shows a readout of the elapsed time, with play and pause buttons.  By default there are no units (which could be used
 * if all of a simulations time units are in 'seconds'), or you can specify a selection of units to choose from.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Anton Ulyanov (Mlearner)
 */
define( function( require ) {
  'use strict';

  // modules
  var Bounds2 = require( 'DOT/Bounds2' );
  var BooleanRectangularToggleButton = require( 'SUN/buttons/BooleanRectangularToggleButton' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PauseIconShape = require( 'SCENERY_PHET/PauseIconShape' );
  var PlayIconShape = require( 'SCENERY_PHET/PlayIconShape' );
  var RectangularPushButton = require( 'SUN/buttons/RectangularPushButton' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
  var ShadedRectangle = require( 'SCENERY_PHET/ShadedRectangle' );
  var Tandem = require( 'TANDEM/Tandem' );
  var TimerReadoutNode = require( 'SCENERY_PHET/TimerReadoutNode' );
  var UTurnArrowShape = require( 'SCENERY_PHET/UTurnArrowShape' );
  var VBox = require( 'SCENERY/nodes/VBox' );

  /**
   * @param {Property.<number>} timeProperty
   * @param {Property.<boolean>} runningProperty
   * @param {Object} [options]
   * @constructor
   */
  function TimerNode( timeProperty, runningProperty, options ) {

    options = _.extend( {

      // See also options that pass through to TimerReadoutNode
      touchAreaDilation: 10,
      cursor: 'pointer',
      iconHeight: 10,
      iconFill: 'black',
      iconLineWidth: 1,
      backgroundBaseColor: 'rgb(  80, 130, 230  )',
      buttonBaseColor: '#DFE0E1',
      xSpacing: 6, // horizontal space between the buttons
      ySpacing: 6, // vertical space between readout and buttons
      xMargin: 8,
      yMargin: 8,

      // {number} the maximum time value, in seconds. See TimerReadoutNode options.maxValue
      maxValue: TimerReadoutNode.DEFAULT_MAX_VALUE,

      // options propagated to TimerReadoutNode
      timerReadoutNodeOptions: null,

      // Tandem is required to make sure the buttons are instrumented
      tandem: Tandem.required
    }, options );

    assert && assert( options.xSpacing >= 0, 'Buttons cannot overlap' );
    assert && assert( options.ySpacing >= 0, 'Buttons cannot overlap the readout' );

    // fill in timerReadoutNodeOptions defaults
    assert && assert( !options.timerReadoutNodeOptions || options.timerReadoutNodeOptions.maxValue === undefined,
      'TimerNode sets maxValue' );
    options.timerReadoutNodeOptions = options.timerReadoutNodeOptions || {};
    options.timerReadoutNodeOptions.maxValue = options.maxValue;

    // Create the TimerReadoutNode.  If we need more flexibility for this part, consider inversion of control
    var timerReadoutNode = new TimerReadoutNode( timeProperty, options.timerReadoutNodeOptions );

    // Buttons ----------------------------------------------------------------------------

    var resetPath = new Path( new UTurnArrowShape( options.iconHeight ), {
      fill: options.iconFill
    } );

    var playIconHeight = resetPath.height;
    var playIconWidth = 0.8 * playIconHeight;
    var playPath = new Path( new PlayIconShape( playIconWidth, playIconHeight ), {
      fill: options.iconFill
    } );

    var pausePath = new Path( new PauseIconShape( 0.75 * playIconWidth, playIconHeight ), {
      fill: options.iconFill
    } );

    var playPauseButton = new BooleanRectangularToggleButton( pausePath, playPath, runningProperty, {
      baseColor: options.buttonBaseColor,
      tandem: options.tandem.createTandem( 'playPauseButton' )
    } );

    var resetButton = new RectangularPushButton( {
      listener: function resetTimer() {
        runningProperty.set( false );
        timeProperty.set( 0 );
      },
      content: resetPath,
      baseColor: options.buttonBaseColor,
      tandem: options.tandem.createTandem( 'resetButton' )
    } );

    var contents = new VBox( {
      spacing: options.ySpacing,
      children: [
        timerReadoutNode,
        new HBox( {
          spacing: options.xSpacing,
          children: [ resetButton, playPauseButton ]
        } )
      ]
    } );

    // Background panel ----------------------------------------------------------------------------

    var backgroundNode = new ShadedRectangle( new Bounds2( 0, 0,
      contents.width + 2 * options.xMargin, contents.height + 2 * options.yMargin ), {
      baseColor: options.backgroundBaseColor
    } );
    backgroundNode.touchArea = backgroundNode.localBounds.dilated( options.touchAreaDilation );
    contents.center = backgroundNode.center;

    assert && assert( !options.children, 'TimerNode sets children' );
    options.children = [ backgroundNode, contents ];

    Node.call( this, options );

    // @public (read-only) - Target for drag listeners
    this.dragTarget = backgroundNode;

    // Disable the reset button when time is zero.
    var timeListener = function( time ) {
      resetButton.enabled = time > 0;
      playPauseButton.enabled = time < options.maxValue;
      if ( time >= options.maxValue ) {
        runningProperty.value = false;
      }
    };
    timeProperty.link( timeListener );

    // @private
    this.disposeTimerNode = function() {
      timerReadoutNode.dispose();
      timeProperty.unlink( timeListener );
      resetButton.dispose();
      playPauseButton.dispose();
    };
  }

  sceneryPhet.register( 'TimerNode', TimerNode );

  return inherit( Node, TimerNode, {

    /**
     * Release resources when no longer be used.
     * @public
     */
    dispose: function() {
      this.disposeTimerNode();
      Node.prototype.dispose.call( this );
    }
  } );
} );<commit_msg>delete TimerNode options.touchAreaDilation, https://github.com/phetsims/scenery-phet/issues/497<commit_after>// Copyright 2014-2018, University of Colorado Boulder

/**
 * Shows a readout of the elapsed time, with play and pause buttons.  By default there are no units (which could be used
 * if all of a simulations time units are in 'seconds'), or you can specify a selection of units to choose from.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Anton Ulyanov (Mlearner)
 */
define( function( require ) {
  'use strict';

  // modules
  var Bounds2 = require( 'DOT/Bounds2' );
  var BooleanRectangularToggleButton = require( 'SUN/buttons/BooleanRectangularToggleButton' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PauseIconShape = require( 'SCENERY_PHET/PauseIconShape' );
  var PlayIconShape = require( 'SCENERY_PHET/PlayIconShape' );
  var RectangularPushButton = require( 'SUN/buttons/RectangularPushButton' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
  var ShadedRectangle = require( 'SCENERY_PHET/ShadedRectangle' );
  var Tandem = require( 'TANDEM/Tandem' );
  var TimerReadoutNode = require( 'SCENERY_PHET/TimerReadoutNode' );
  var UTurnArrowShape = require( 'SCENERY_PHET/UTurnArrowShape' );
  var VBox = require( 'SCENERY/nodes/VBox' );

  /**
   * @param {Property.<number>} timeProperty
   * @param {Property.<boolean>} runningProperty
   * @param {Object} [options]
   * @constructor
   */
  function TimerNode( timeProperty, runningProperty, options ) {

    options = _.extend( {

      // See also options that pass through to TimerReadoutNode
      cursor: 'pointer',
      iconHeight: 10,
      iconFill: 'black',
      iconLineWidth: 1,
      backgroundBaseColor: 'rgb(  80, 130, 230  )',
      buttonBaseColor: '#DFE0E1',
      xSpacing: 6, // horizontal space between the buttons
      ySpacing: 6, // vertical space between readout and buttons
      xMargin: 8,
      yMargin: 8,

      // {number} the maximum time value, in seconds. See TimerReadoutNode options.maxValue
      maxValue: TimerReadoutNode.DEFAULT_MAX_VALUE,

      // options propagated to TimerReadoutNode
      timerReadoutNodeOptions: null,

      // Tandem is required to make sure the buttons are instrumented
      tandem: Tandem.required
    }, options );

    assert && assert( options.xSpacing >= 0, 'Buttons cannot overlap' );
    assert && assert( options.ySpacing >= 0, 'Buttons cannot overlap the readout' );

    // fill in timerReadoutNodeOptions defaults
    assert && assert( !options.timerReadoutNodeOptions || options.timerReadoutNodeOptions.maxValue === undefined,
      'TimerNode sets maxValue' );
    options.timerReadoutNodeOptions = options.timerReadoutNodeOptions || {};
    options.timerReadoutNodeOptions.maxValue = options.maxValue;

    // Create the TimerReadoutNode.  If we need more flexibility for this part, consider inversion of control
    var timerReadoutNode = new TimerReadoutNode( timeProperty, options.timerReadoutNodeOptions );

    // Buttons ----------------------------------------------------------------------------

    var resetPath = new Path( new UTurnArrowShape( options.iconHeight ), {
      fill: options.iconFill
    } );

    var playIconHeight = resetPath.height;
    var playIconWidth = 0.8 * playIconHeight;
    var playPath = new Path( new PlayIconShape( playIconWidth, playIconHeight ), {
      fill: options.iconFill
    } );

    var pausePath = new Path( new PauseIconShape( 0.75 * playIconWidth, playIconHeight ), {
      fill: options.iconFill
    } );

    var playPauseButton = new BooleanRectangularToggleButton( pausePath, playPath, runningProperty, {
      baseColor: options.buttonBaseColor,
      tandem: options.tandem.createTandem( 'playPauseButton' )
    } );

    var resetButton = new RectangularPushButton( {
      listener: function resetTimer() {
        runningProperty.set( false );
        timeProperty.set( 0 );
      },
      content: resetPath,
      baseColor: options.buttonBaseColor,
      tandem: options.tandem.createTandem( 'resetButton' )
    } );

    var contents = new VBox( {
      spacing: options.ySpacing,
      children: [
        timerReadoutNode,
        new HBox( {
          spacing: options.xSpacing,
          children: [ resetButton, playPauseButton ]
        } )
      ]
    } );

    // Background panel ----------------------------------------------------------------------------

    var backgroundNode = new ShadedRectangle( new Bounds2( 0, 0,
      contents.width + 2 * options.xMargin, contents.height + 2 * options.yMargin ), {
      baseColor: options.backgroundBaseColor
    } );
    contents.center = backgroundNode.center;

    assert && assert( !options.children, 'TimerNode sets children' );
    options.children = [ backgroundNode, contents ];

    Node.call( this, options );

    // @public (read-only) - Target for drag listeners
    this.dragTarget = backgroundNode;

    // Disable the reset button when time is zero.
    var timeListener = function( time ) {
      resetButton.enabled = time > 0;
      playPauseButton.enabled = time < options.maxValue;
      if ( time >= options.maxValue ) {
        runningProperty.value = false;
      }
    };
    timeProperty.link( timeListener );

    // @private
    this.disposeTimerNode = function() {
      timerReadoutNode.dispose();
      timeProperty.unlink( timeListener );
      resetButton.dispose();
      playPauseButton.dispose();
    };
  }

  sceneryPhet.register( 'TimerNode', TimerNode );

  return inherit( Node, TimerNode, {

    /**
     * Release resources when no longer be used.
     * @public
     */
    dispose: function() {
      this.disposeTimerNode();
      Node.prototype.dispose.call( this );
    }
  } );
} );<|endoftext|>


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

ga('create', '{{ site.google_analytics }}', 'auto');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
<commit_msg>Removing unused JS<commit_after><|endoftext|>


<commit_before>'use strict';
define(
    [
        'app/config',
        'three',
        'stats',
        'app/InputHandler',
        'app/classes/Debug',
        'app/classes/Camera',
        'app/classes/GameObjectManager',
        'app/classes/Planet',
        'app/classes/Star',
        'app/classes/SpaceShip',
        'app/classes/Grid'
    ],
    function(config, THREE, Stats, InputHandler, Debug, Camera, GameObjectManager, Planet, Star, SpaceShip, Grid) {
        let stats = new Stats();
        stats.showPanel(0);
        document.body.appendChild(stats.dom);

        let scene = new THREE.Scene();
        window.scene = scene;

        let renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(config.canvasWidth, config.canvasHeight);
        document.getElementById('game').appendChild(renderer.domElement);

        let camera = new Camera(
            scene,
            renderer,
            config.camera.fov,
            config.canvasWidth / config.canvasHeight,
            0.1,
            1000,
            new THREE.Vector3(0, 0, 50),
            new THREE.Vector3(0, 0, 0)
        );

        scene.add(new THREE.AmbientLight( 0x101010 ));

        GameObjectManager.add([
            new Grid(scene, 'grid', new THREE.Vector3(0, 0, 0), 750, 750, 60, true),

            new Planet(scene, 'redPlanet',    3.301,   20, new THREE.Vector3( 0, 18, 0), true, 0xff3333),
            new Planet(scene, 'homePlanet',   48.690,  100, new THREE.Vector3(25,  0, 0), true, 0x33ff33),

            new Star(  scene, 'sol',        1.9984E8, 1400, new THREE.Vector3( 0,  0, 0),       0xffff00),

            new SpaceShip(scene, 'player', 40.0, new THREE.Vector3(0, 50, 0))
        ]);

        GameObjectManager.get('redPlanet').velocity.setX(0.2);
        GameObjectManager.get('redPlanet').velocity.setZ(0.3);

        GameObjectManager.get('homePlanet').velocity.setZ(0.03);
        GameObjectManager.get('homePlanet').velocity.setY(-0.3);

        GameObjectManager.get('player').velocity.setX(.2);
        GameObjectManager.get('player').velocity.setY(0);

        config.maxAnisotropy = renderer.getMaxAnisotropy();

        let lastFrameTime    = 0;
        let lastDeltaTValues = [];
        let smoothDeltaT     = 0;

        function update(currentFrameTime) {
            stats.begin();
            Debug.clear();

            let deltaT = currentFrameTime - lastFrameTime;
            lastFrameTime = currentFrameTime;

            // Ugly hack to prevent "jumps" when the tab lost focus
            if(deltaT > 32) deltaT = 1000/60;

            // Smooth deltaT
            while(lastDeltaTValues.length >= config.framesToSmoothDeltaT) {
                lastDeltaTValues.splice(0, 1);
            }
            lastDeltaTValues.push(deltaT);
            smoothDeltaT = lastDeltaTValues.reduce(function(prev, cur) { return prev + cur;}) / lastDeltaTValues.length;

            // Update controls
            camera.controls.update();

            // Handle user input
            InputHandler.checkInput(camera);

            // Update all the objects' positions
            GameObjectManager.updatePositions(deltaT, smoothDeltaT);

            // Update all the objects
            GameObjectManager.update(deltaT, smoothDeltaT);

            // Render the scene
            renderer.render(scene, camera.camera);

            stats.end();
            requestAnimationFrame(update);
        }

        requestAnimationFrame(update);
    }
);<commit_msg>Removing statement making scene global<commit_after>'use strict';
define(
    [
        'app/config',
        'three',
        'stats',
        'app/InputHandler',
        'app/classes/Debug',
        'app/classes/Camera',
        'app/classes/GameObjectManager',
        'app/classes/Planet',
        'app/classes/Star',
        'app/classes/SpaceShip',
        'app/classes/Grid'
    ],
    function(config, THREE, Stats, InputHandler, Debug, Camera, GameObjectManager, Planet, Star, SpaceShip, Grid) {
        let stats = new Stats();
        stats.showPanel(0);
        document.body.appendChild(stats.dom);

        let scene = new THREE.Scene();

        let renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(config.canvasWidth, config.canvasHeight);
        document.getElementById('game').appendChild(renderer.domElement);

        let camera = new Camera(
            scene,
            renderer,
            config.camera.fov,
            config.canvasWidth / config.canvasHeight,
            0.1,
            1000,
            new THREE.Vector3(0, 0, 50),
            new THREE.Vector3(0, 0, 0)
        );

        scene.add(new THREE.AmbientLight( 0x101010 ));

        GameObjectManager.add([
            new Grid(scene, 'grid', new THREE.Vector3(0, 0, 0), 750, 750, 60, true),

            new Planet(scene, 'redPlanet',    3.301,   20, new THREE.Vector3( 0, 18, 0), true, 0xff3333),
            new Planet(scene, 'homePlanet',   48.690,  100, new THREE.Vector3(25,  0, 0), true, 0x33ff33),

            new Star(  scene, 'sol',        1.9984E8, 1400, new THREE.Vector3( 0,  0, 0),       0xffff00),

            new SpaceShip(scene, 'player', 40.0, new THREE.Vector3(0, 50, 0))
        ]);

        GameObjectManager.get('redPlanet').velocity.setX(0.2);
        GameObjectManager.get('redPlanet').velocity.setZ(0.3);

        GameObjectManager.get('homePlanet').velocity.setZ(0.03);
        GameObjectManager.get('homePlanet').velocity.setY(-0.3);

        GameObjectManager.get('player').velocity.setX(.2);
        GameObjectManager.get('player').velocity.setY(0);

        config.maxAnisotropy = renderer.getMaxAnisotropy();

        let lastFrameTime    = 0;
        let lastDeltaTValues = [];
        let smoothDeltaT     = 0;

        function update(currentFrameTime) {
            stats.begin();
            Debug.clear();

            let deltaT = currentFrameTime - lastFrameTime;
            lastFrameTime = currentFrameTime;

            // Ugly hack to prevent "jumps" when the tab lost focus
            if(deltaT > 32) deltaT = 1000/60;

            // Smooth deltaT
            while(lastDeltaTValues.length >= config.framesToSmoothDeltaT) {
                lastDeltaTValues.splice(0, 1);
            }
            lastDeltaTValues.push(deltaT);
            smoothDeltaT = lastDeltaTValues.reduce(function(prev, cur) { return prev + cur;}) / lastDeltaTValues.length;

            // Update controls
            camera.controls.update();

            // Handle user input
            InputHandler.checkInput(camera);

            // Update all the objects' positions
            GameObjectManager.updatePositions(deltaT, smoothDeltaT);

            // Update all the objects
            GameObjectManager.update(deltaT, smoothDeltaT);

            // Render the scene
            renderer.render(scene, camera.camera);

            stats.end();
            requestAnimationFrame(update);
        }

        requestAnimationFrame(update);
    }
);<|endoftext|>


<commit_before>$(document).ready(function(){
	app.c.init();
	app.v.init();
	app.c.listeners();
})
/////////////////////////////////////////////////////////////////////////////////

var app={m:{},v:{},c:{}};

/////////////////////////////////////////////////////////////////////////////////

app.m.colors={};
app.m.colors.primary="#f37";
app.m.colors.secondary="#f67";
app.m.colors.grey="#555";

/////////////////////////////////////////////////////////////////////////////////

app.c.init=function(){
	app.m.metadata={"name":"Ziph","version":"0.0.1"};
};

app.c.listeners=function(){

$("input#count").click(function(){
	var input=$("#input").val();
	var count=$("input[name=count]:checked").val();
	var division=$("input[name=division]:checked").val();
	if (parseInt(division)==1){
		division=true;
	}else{
		division=false;
	}
	console.log(division);
	input=app.c.ziph(input,parseInt(count),division);
	var sortable=[];
	for (key in input){sortable.push([key,input[key].count]);}
	sortable.sort(function(a,b){return b[1]-a[1];});
	var d="";
	d+="
";
	d+="
sample length: "+app.m.sampleLength+"
";
	for (var i=0;i<sortable.length;i++){
		var rowClass="odd";
		if (i%2==0){rowClass="even";}
		d+="
"+sortable[i][1]+"	"+sortable[i][0]+"
";
	}
	d+="
";
	$("#output").html(d);
});

};

app.c.ziph=function(sample,n,spaces){
	var spaces=spaces||false;
	var n=n||1;
	var lex={};
	var sample=sample.toLowerCase();
	if (spaces==true){
		sample=sample.split(" ");
	}
	else{
		sample=sample.split("");
	}

	app.m.sampleLength=sample.length;

	for (var i=0;i<=(sample.length-n);i++){
		//then populate the lexicon
			var compilation=[];
			for (var j=0;j<n;j++){
				compilation.push(sample[i+j])
			}
			if (spaces==true){
				compilation=compilation.join(" ");
			}
			else{
				compilation=compilation.join("");
			}

		if (!lex[compilation]){
			lex[compilation]={};
			lex[compilation].count=1;
		}
		else{
			lex[compilation].count++;
		}
	}
	return lex;
};

///////////////////////////////////////////

app.v.init=function(){
	app.v.style();
	var d="";
	d+="

";
		d+="
ziph
";
		d+="
";
		d+="<input type='radio' value='1' name='count' checked>count by singletons
";
		d+="<input type='radio' value='2' name='count'>count by doubles
";
		d+="<input type='radio' value='3' name='count'>count by triples
";
		d+="<input type='radio' value='4' name='count'>count by quadruples
";
		d+="
";
		d+="<input type='radio' value='1' name='division' checked>count by words
";
		d+="<input type='radio' value='0' name='division'>count by characters
";
		d+="<textarea rows='10' cols='5' id='input' autofocus></textarea>";
		d+="<input type='button' value='count' id='count'></input>";
	d+="	";
	d+="

";
	$("body").html(d);
};

app.v.style=function(){
	davis.style("body",{
		"width":"100%",
		"margin":"0px",
		"padding":"0px",
		"color":"#555",
		"font-size":"3em",
		"font-family":"sans-serif"
	});
	davis.style("div",{
		"padding":"0",
		"font-size":"1.5em",
		"margin":"30px"
	});
	davis.style("h1",{
		"text-align":"left",
		"font-size":"7em",
		"margin-bottom":"30px",
		"color":app.m.colors.primary
	});
	davis.style("input[type=button]",{
		"width":"100%",
		"font-size":"2em",
		"background":app.m.colors.primary,
		"border":"2px solid "+app.m.colors.grey,
		"cursor":"pointer",
		"color":"#fff"
	});
	davis.style("textarea",{
		"width":"100%",
		"font-size":"0.8em",
		"font-family":"arial sans-serif",
		"border":"2px solid "+app.m.colors.grey,
		"margin":"0",
		"margin-top":"30px"
	});
	davis.style("table",{
		"width":"100%"
	});
	davis.style("table#layout",{
		"height":"100%",
		"table-layout":"fixed"
	});
	davis.style("td",{
		"padding":"30px",
		"margin":"0px",
		"vertical-align":"top",
		"text-align":"left"
	});
	davis.style("td#output",{
		"background":app.m.colors.primary,
		"text-align":"left",
		"padding":"0"
	});
	davis.style("td#output td",{
		"color":"#fff",
		"padding":"3px",
		"margin":"0",
	});
	davis.style("tr.odd td",{
		"background":app.m.colors.secondary
	});
	davis.style("td#output td:hover",{
		"background":"#555"
	});
};<commit_msg>fixed the html parsing problem for output<commit_after>$(document).ready(function(){
	app.c.init();
	app.v.init();
	app.c.listeners();
})
/////////////////////////////////////////////////////////////////////////////////

var app={m:{},v:{},c:{}};

/////////////////////////////////////////////////////////////////////////////////

app.m.colors={};
app.m.colors.primary="#f37";
app.m.colors.secondary="#f67";
app.m.colors.grey="#555";

/////////////////////////////////////////////////////////////////////////////////

app.c.init=function(){
	app.m.metadata={"name":"Ziph","version":"0.0.1"};
};

app.c.listeners=function(){

$("input#count").click(function(){
	var input=$("#input").val();
	var count=$("input[name=count]:checked").val();
	var division=$("input[name=division]:checked").val();
	if (parseInt(division)==1){
		division=true;
	}else{
		division=false;
	}
	console.log(division);
	input=app.c.ziph(input,parseInt(count),division);
	var sortable=[];
	for (key in input){sortable.push([key,input[key].count]);}
	sortable.sort(function(a,b){return b[1]-a[1];});
	var d="";
	d+="
";
	d+="
sample length: "+app.m.sampleLength+"
";
	for (var i=0;i<sortable.length;i++){
		var rowClass="odd";
		if (i%2==0){rowClass="even";}
		d+="
"+sortable[i][1]+"	"+sortable[i][0].replace(/</gi,"<")+"
";
	}
	d+="
";
	$("#output").html(d);
});

};

app.c.ziph=function(sample,n,spaces){
	var spaces=spaces||false;
	var n=n||1;
	var lex={};
	var sample=sample.toLowerCase();
	if (spaces==true){
		sample=sample.split(" ");
	}
	else{
		sample=sample.split("");
	}

	app.m.sampleLength=sample.length;

	for (var i=0;i<=(sample.length-n);i++){
		//then populate the lexicon
			var compilation=[];
			for (var j=0;j<n;j++){
				compilation.push(sample[i+j])
			}
			if (spaces==true){
				compilation=compilation.join(" ");
			}
			else{
				compilation=compilation.join("");
			}

		if (!lex[compilation]){
			lex[compilation]={};
			lex[compilation].count=1;
		}
		else{
			lex[compilation].count++;
		}
	}
	return lex;
};

///////////////////////////////////////////

app.v.init=function(){
	app.v.style();
	var d="";
	d+="

";
		d+="
ziph
";
		d+="
";
		d+="<input type='radio' value='1' name='count' checked>count by singletons
";
		d+="<input type='radio' value='2' name='count'>count by doubles
";
		d+="<input type='radio' value='3' name='count'>count by triples
";
		d+="<input type='radio' value='4' name='count'>count by quadruples
";
		d+="
";
		d+="<input type='radio' value='1' name='division' checked>count by words
";
		d+="<input type='radio' value='0' name='division'>count by characters
";
		d+="<textarea rows='10' cols='5' id='input' autofocus></textarea>";
		d+="<input type='button' value='count' id='count'></input>";
	d+="	";
	d+="

";
	$("body").html(d);
};

app.v.style=function(){
	davis.style("body",{
		"width":"100%",
		"margin":"0px",
		"padding":"0px",
		"color":"#555",
		"font-size":"3em",
		"font-family":"sans-serif"
	});
	davis.style("div",{
		"padding":"0",
		"font-size":"1.5em",
		"margin":"30px"
	});
	davis.style("h1",{
		"text-align":"left",
		"font-size":"7em",
		"margin-bottom":"30px",
		"color":app.m.colors.primary
	});
	davis.style("input[type=button]",{
		"width":"100%",
		"font-size":"2em",
		"background":app.m.colors.primary,
		"border":"2px solid "+app.m.colors.grey,
		"cursor":"pointer",
		"color":"#fff"
	});
	davis.style("textarea",{
		"width":"100%",
		"font-size":"0.8em",
		"font-family":"arial sans-serif",
		"border":"2px solid "+app.m.colors.grey,
		"margin":"0",
		"margin-top":"30px"
	});
	davis.style("table",{
		"width":"100%"
	});
	davis.style("table#layout",{
		"height":"100%",
		"table-layout":"fixed"
	});
	davis.style("td",{
		"padding":"30px",
		"margin":"0px",
		"vertical-align":"top",
		"text-align":"left"
	});
	davis.style("td#output",{
		"background":app.m.colors.primary,
		"text-align":"left",
		"padding":"0"
	});
	davis.style("td#output td",{
		"color":"#fff",
		"padding":"3px",
		"margin":"0",
	});
	davis.style("tr.odd td",{
		"background":app.m.colors.secondary
	});
	davis.style("td#output td:hover",{
		"background":"#555"
	});
};<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const binance = require ('./binance.js');

// ---------------------------------------------------------------------------

module.exports = class binanceje extends binance {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'binanceje',
            'name': 'Binance Jersey',
            'countries': [ 'JE' ], // Jersey
            'certified': false,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/54874009-d526eb00-4df3-11e9-928c-ce6a2b914cd1.jpg',
                'api': {
                    'ws': {
                        'spot': 'wss://stream.binance.je:9443/ws',
                    },
                    'web': 'https://www.binance.je',
                    'wapi': 'https://api.binance.je/wapi/v3',
                    'public': 'https://api.binance.je/api/v1',
                    'private': 'https://api.binance.je/api/v3',
                    'v3': 'https://api.binance.je/api/v3',
                    'v1': 'https://api.binance.je/api/v1',
                },
                'www': 'https://www.binance.je',
                'referral': 'https://www.binance.je/?ref=35047921',
                'doc': 'https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md',
                'fees': 'https://www.binance.je/fees.html',
            },
            'fees': {
                'trading': {
                    'tierBased': false,
                    'percentage': true,
                    'taker': 0.0005,
                    'maker': 0.0005,
                },
                // should be deleted, these are outdated and inaccurate
                'funding': {
                    'tierBased': false,
                    'percentage': false,
                    'withdraw': {
                        'BTC': 0.0005,
                        'ETH': 0.01,
                    },
                    'deposit': {},
                },
            },
        });
    }
};
<commit_msg>binanceje shutdown<commit_after><|endoftext|>


<commit_before>'use strict';

// ---------------------------------------------------------------------------

const bitfinex = require ('./bitfinex.js');
const { ExchangeError, NotSupported, InsufficientFunds } = require ('./base/errors');

// ---------------------------------------------------------------------------

module.exports = class bitfinex2 extends bitfinex {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bitfinex2',
            'name': 'Bitfinex v2',
            'countries': 'VG',
            'version': 'v2',
            // new metainfo interface
            'has': {
                'CORS': true,
                'createOrder': false,
                'createMarketOrder': false,
                'createLimitOrder': false,
                'editOrder': false,
                'fetchMyTrades': false,
                'fetchOHLCV': true,
                'fetchTickers': true,
                'fetchOrder': true,
                'fetchOpenOrders': false,
                'fetchClosedOrders': false,
                'withdraw': true,
                'deposit': false,
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '3h': '3h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1D',
                '1w': '7D',
                '2w': '14D',
                '1M': '1M',
            },
            'rateLimit': 1500,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27766244-e328a50c-5ed2-11e7-947b-041416579bb3.jpg',
                'api': 'https://api.bitfinex.com',
                'www': 'https://www.bitfinex.com',
                'doc': [
                    'https://bitfinex.readme.io/v2/docs',
                    'https://github.com/bitfinexcom/bitfinex-api-node',
                ],
                'fees': 'https://www.bitfinex.com/fees',
            },
            'api': {
                'v1': {
                    'get': [
                        'symbols',
                        'symbols_details',
                    ],
                },
                'public': {
                    'get': [
                        'platform/status',
                        'tickers',
                        'ticker/{symbol}',
                        'trades/{symbol}/hist',
                        'book/{symbol}/{precision}',
                        'book/{symbol}/P0',
                        'book/{symbol}/P1',
                        'book/{symbol}/P2',
                        'book/{symbol}/P3',
                        'book/{symbol}/R0',
                        'stats1/{key}:{size}:{symbol}/{side}/{section}',
                        'stats1/{key}:{size}:{symbol}/long/last',
                        'stats1/{key}:{size}:{symbol}/long/hist',
                        'stats1/{key}:{size}:{symbol}/short/last',
                        'stats1/{key}:{size}:{symbol}/short/hist',
                        'candles/trade:{timeframe}:{symbol}/{section}',
                        'candles/trade:{timeframe}:{symbol}/last',
                        'candles/trade:{timeframe}:{symbol}/hist',
                    ],
                    'post': [
                        'calc/trade/avg',
                    ],
                },
                'private': {
                    'post': [
                        'auth/r/wallets',
                        'auth/r/orders/{symbol}',
                        'auth/r/orders/{symbol}/new',
                        'auth/r/orders/{symbol}/hist',
                        'auth/r/order/{symbol}:{id}/trades',
                        'auth/r/trades/{symbol}/hist',
                        'auth/r/positions',
                        'auth/r/funding/offers/{symbol}',
                        'auth/r/funding/offers/{symbol}/hist',
                        'auth/r/funding/loans/{symbol}',
                        'auth/r/funding/loans/{symbol}/hist',
                        'auth/r/funding/credits/{symbol}',
                        'auth/r/funding/credits/{symbol}/hist',
                        'auth/r/funding/trades/{symbol}/hist',
                        'auth/r/info/margin/{key}',
                        'auth/r/info/funding/{key}',
                        'auth/r/movements/{currency}/hist',
                        'auth/r/stats/perf:{timeframe}/hist',
                        'auth/r/alerts',
                        'auth/w/alert/set',
                        'auth/w/alert/{type}:{symbol}:{price}/del',
                        'auth/calc/order/avail',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.1 / 100,
                    'taker': 0.2 / 100,
                },
                'funding': {
                    'withdraw': {
                        'BTC': 0.0005,
                        'BCH': 0.0005,
                        'ETH': 0.01,
                        'EOS': 0.1,
                        'LTC': 0.001,
                        'OMG': 0.1,
                        'IOT': 0.0,
                        'NEO': 0.0,
                        'ETC': 0.01,
                        'XRP': 0.02,
                        'ETP': 0.01,
                        'ZEC': 0.001,
                        'BTG': 0.0,
                        'DASH': 0.01,
                        'XMR': 0.04,
                        'QTM': 0.01,
                        'EDO': 0.5,
                        'DAT': 1.0,
                        'AVT': 0.5,
                        'SAN': 0.1,
                        'USDT': 5.0,
                        'SPK': 9.2784,
                        'BAT': 9.0883,
                        'GNT': 8.2881,
                        'SNT': 14.303,
                        'QASH': 3.2428,
                        'YYW': 18.055,
                    },
                },
            },
        });
    }

    isFiat (code) {
        let fiat = {
            'USD': 'USD',
            'EUR': 'EUR',
        };
        return (code in fiat);
    }

    getCurrencyId (code) {
        let isFiat = this.isFiat (code);
        let prefix = isFiat ? 'f' : 't';
        return prefix + code;
    }

    async fetchMarkets () {
        let markets = await this.v1GetSymbolsDetails ();
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let market = markets[p];
            let id = market['pair'].toUpperCase ();
            let baseId = id.slice (0, 3);
            let quoteId = id.slice (3, 6);
            let base = this.commonCurrencyCode (baseId);
            let quote = this.commonCurrencyCode (quoteId);
            let symbol = base + '/' + quote;
            id = 't' + id;
            baseId = this.getCurrencyId (baseId);
            quoteId = this.getCurrencyId (quoteId);
            let precision = {
                'price': market['price_precision'],
                'amount': market['price_precision'],
            };
            let limits = {
                'amount': {
                    'min': parseFloat (market['minimum_order_size']),
                    'max': parseFloat (market['maximum_order_size']),
                },
                'price': {
                    'min': Math.pow (10, -precision['price']),
                    'max': Math.pow (10, precision['price']),
                },
            };
            limits['cost'] = {
                'min': limits['amount']['min'] * limits['price']['min'],
                'max': undefined,
            };
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': true,
                'precision': precision,
                'limits': limits,
                'lot': Math.pow (10, -precision['amount']),
                'info': market,
            });
        }
        return result;
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let response = await this.privatePostAuthRWallets ();
        let balanceType = this.safeString (params, 'type', 'exchange');
        let result = { 'info': response };
        for (let b = 0; b < response.length; b++) {
            let balance = response[b];
            let accountType = balance[0];
            let currency = balance[1];
            let total = balance[2];
            let available = balance[4];
            if (accountType === balanceType) {
                if (currency[0] === 't')
                    currency = currency.slice (1);
                let uppercase = currency.toUpperCase ();
                uppercase = this.commonCurrencyCode (uppercase);
                let account = this.account ();
                account['free'] = available;
                account['total'] = total;
                if (account['free'])
                    account['used'] = account['total'] - account['free'];
                result[uppercase] = account;
            }
        }
        return this.parseBalance (result);
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetBookSymbolPrecision (this.extend ({
            'symbol': this.marketId (symbol),
            'precision': 'R0',
        }, params));
        let timestamp = this.milliseconds ();
        let result = {
            'bids': [],
            'asks': [],
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
        };
        for (let i = 0; i < orderbook.length; i++) {
            let order = orderbook[i];
            let price = order[1];
            let amount = order[2];
            let side = (amount > 0) ? 'bids' : 'asks';
            amount = Math.abs (amount);
            result[side].push ([ price, amount ]);
        }
        result['bids'] = this.sortBy (result['bids'], 0, true);
        result['asks'] = this.sortBy (result['asks'], 0);
        return result;
    }

    parseTicker (ticker, market = undefined) {
        let timestamp = this.milliseconds ();
        let symbol = undefined;
        if (market)
            symbol = market['symbol'];
        let length = ticker.length;
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': ticker[length - 2],
            'low': ticker[length - 1],
            'bid': ticker[length - 10],
            'ask': ticker[length - 8],
            'vwap': undefined,
            'open': undefined,
            'close': undefined,
            'first': undefined,
            'last': ticker[length - 4],
            'change': ticker[length - 6],
            'percentage': ticker[length - 5],
            'average': undefined,
            'baseVolume': ticker[length - 3],
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        let tickers = await this.publicGetTickers (this.extend ({
            'symbols': this.ids.join (','),
        }, params));
        let result = {};
        for (let i = 0; i < tickers.length; i++) {
            let ticker = tickers[i];
            let id = ticker[0];
            let market = this.markets_by_id[id];
            let symbol = market['symbol'];
            result[symbol] = this.parseTicker (ticker, market);
        }
        return result;
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.markets[symbol];
        let ticker = await this.publicGetTickerSymbol (this.extend ({
            'symbol': market['id'],
        }, params));
        return this.parseTicker (ticker, market);
    }

    parseTrade (trade, market) {
        let [ id, timestamp, amount, price ] = trade;
        let side = (amount < 0) ? 'sell' : 'buy';
        if (amount < 0) {
            amount = -amount;
        }
        return {
            'id': id.toString (),
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'type': undefined,
            'side': side,
            'price': price,
            'amount': amount,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = 120, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
            'sort': 1,
            'limit': limit, // default = max = 120
        };
        if (typeof since !== 'undefined')
            request['start'] = since;
        let response = await this.publicGetTradesSymbolHist (this.extend (request, params));
        let trades = this.sortBy (response, 1);
        return this.parseTrades (trades, market, undefined, limit);
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = 100, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
            'timeframe': this.timeframes[timeframe],
            'sort': 1,
            'limit': limit,
        };
        if (typeof since !== 'undefined')
            request['start'] = since;
        request = this.extend (request, params);
        let response = await this.publicGetCandlesTradeTimeframeSymbolHist (request);
        return this.parseOHLCVs (response, market, timeframe, since, limit);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        throw new NotSupported (this.id + ' createOrder not implemented yet');
    }

    cancelOrder (id, symbol = undefined, params = {}) {
        throw new NotSupported (this.id + ' cancelOrder not implemented yet');
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        throw new NotSupported (this.id + ' fetchOrder not implemented yet');
    }

    async withdraw (currency, amount, address, tag = undefined, params = {}) {
        throw new NotSupported (this.id + ' withdraw not implemented yet');
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = 25, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
            'limit': limit,
            'end': this.seconds (),
        };
        if (typeof since !== 'undefined')
            request['start'] = parseInt (since / 1000);
        let response = await this.privatePostAuthRTradesSymbolHist (this.extend (request, params));
        // return this.parseTrades (response, market, since, limit); // not implemented yet for bitfinex v2
        return response;
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (api === 'v1')
            request = api + request;
        else
            request = this.version + request;
        let url = this.urls['api'] + '/' + request;
        if (api === 'public') {
            if (Object.keys (query).length) {
                url += '?' + this.urlencode (query);
            }
        }
        if (api === 'private') {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ().toString ();
            body = this.json (query);
            let auth = '/api' + '/' + request + nonce + body;
            let signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha384');
            headers = {
                'bfx-nonce': nonce,
                'bfx-apikey': this.apiKey,
                'bfx-signature': signature,
                'Content-Type': 'application/json',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        if (response) {
            if ('message' in response) {
                if (response['message'].indexOf ('not enough exchange balance') >= 0)
                    throw new InsufficientFunds (this.id + ' ' + this.json (response));
                throw new ExchangeError (this.id + ' ' + this.json (response));
            }
            return response;
        } else if (response === '') {
            throw new ExchangeError (this.id + ' returned empty response');
        }
        return response;
    }
};
<commit_msg>bitfinex2 fetchTicker consistency<commit_after>'use strict';

// ---------------------------------------------------------------------------

const bitfinex = require ('./bitfinex.js');
const { ExchangeError, NotSupported, InsufficientFunds } = require ('./base/errors');

// ---------------------------------------------------------------------------

module.exports = class bitfinex2 extends bitfinex {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bitfinex2',
            'name': 'Bitfinex v2',
            'countries': 'VG',
            'version': 'v2',
            // new metainfo interface
            'has': {
                'CORS': true,
                'createOrder': false,
                'createMarketOrder': false,
                'createLimitOrder': false,
                'editOrder': false,
                'fetchMyTrades': false,
                'fetchOHLCV': true,
                'fetchTickers': true,
                'fetchOrder': true,
                'fetchOpenOrders': false,
                'fetchClosedOrders': false,
                'withdraw': true,
                'deposit': false,
            },
            'timeframes': {
                '1m': '1m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '3h': '3h',
                '6h': '6h',
                '12h': '12h',
                '1d': '1D',
                '1w': '7D',
                '2w': '14D',
                '1M': '1M',
            },
            'rateLimit': 1500,
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27766244-e328a50c-5ed2-11e7-947b-041416579bb3.jpg',
                'api': 'https://api.bitfinex.com',
                'www': 'https://www.bitfinex.com',
                'doc': [
                    'https://bitfinex.readme.io/v2/docs',
                    'https://github.com/bitfinexcom/bitfinex-api-node',
                ],
                'fees': 'https://www.bitfinex.com/fees',
            },
            'api': {
                'v1': {
                    'get': [
                        'symbols',
                        'symbols_details',
                    ],
                },
                'public': {
                    'get': [
                        'platform/status',
                        'tickers',
                        'ticker/{symbol}',
                        'trades/{symbol}/hist',
                        'book/{symbol}/{precision}',
                        'book/{symbol}/P0',
                        'book/{symbol}/P1',
                        'book/{symbol}/P2',
                        'book/{symbol}/P3',
                        'book/{symbol}/R0',
                        'stats1/{key}:{size}:{symbol}/{side}/{section}',
                        'stats1/{key}:{size}:{symbol}/long/last',
                        'stats1/{key}:{size}:{symbol}/long/hist',
                        'stats1/{key}:{size}:{symbol}/short/last',
                        'stats1/{key}:{size}:{symbol}/short/hist',
                        'candles/trade:{timeframe}:{symbol}/{section}',
                        'candles/trade:{timeframe}:{symbol}/last',
                        'candles/trade:{timeframe}:{symbol}/hist',
                    ],
                    'post': [
                        'calc/trade/avg',
                    ],
                },
                'private': {
                    'post': [
                        'auth/r/wallets',
                        'auth/r/orders/{symbol}',
                        'auth/r/orders/{symbol}/new',
                        'auth/r/orders/{symbol}/hist',
                        'auth/r/order/{symbol}:{id}/trades',
                        'auth/r/trades/{symbol}/hist',
                        'auth/r/positions',
                        'auth/r/funding/offers/{symbol}',
                        'auth/r/funding/offers/{symbol}/hist',
                        'auth/r/funding/loans/{symbol}',
                        'auth/r/funding/loans/{symbol}/hist',
                        'auth/r/funding/credits/{symbol}',
                        'auth/r/funding/credits/{symbol}/hist',
                        'auth/r/funding/trades/{symbol}/hist',
                        'auth/r/info/margin/{key}',
                        'auth/r/info/funding/{key}',
                        'auth/r/movements/{currency}/hist',
                        'auth/r/stats/perf:{timeframe}/hist',
                        'auth/r/alerts',
                        'auth/w/alert/set',
                        'auth/w/alert/{type}:{symbol}:{price}/del',
                        'auth/calc/order/avail',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.1 / 100,
                    'taker': 0.2 / 100,
                },
                'funding': {
                    'withdraw': {
                        'BTC': 0.0005,
                        'BCH': 0.0005,
                        'ETH': 0.01,
                        'EOS': 0.1,
                        'LTC': 0.001,
                        'OMG': 0.1,
                        'IOT': 0.0,
                        'NEO': 0.0,
                        'ETC': 0.01,
                        'XRP': 0.02,
                        'ETP': 0.01,
                        'ZEC': 0.001,
                        'BTG': 0.0,
                        'DASH': 0.01,
                        'XMR': 0.04,
                        'QTM': 0.01,
                        'EDO': 0.5,
                        'DAT': 1.0,
                        'AVT': 0.5,
                        'SAN': 0.1,
                        'USDT': 5.0,
                        'SPK': 9.2784,
                        'BAT': 9.0883,
                        'GNT': 8.2881,
                        'SNT': 14.303,
                        'QASH': 3.2428,
                        'YYW': 18.055,
                    },
                },
            },
        });
    }

    isFiat (code) {
        let fiat = {
            'USD': 'USD',
            'EUR': 'EUR',
        };
        return (code in fiat);
    }

    getCurrencyId (code) {
        let isFiat = this.isFiat (code);
        let prefix = isFiat ? 'f' : 't';
        return prefix + code;
    }

    async fetchMarkets () {
        let markets = await this.v1GetSymbolsDetails ();
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let market = markets[p];
            let id = market['pair'].toUpperCase ();
            let baseId = id.slice (0, 3);
            let quoteId = id.slice (3, 6);
            let base = this.commonCurrencyCode (baseId);
            let quote = this.commonCurrencyCode (quoteId);
            let symbol = base + '/' + quote;
            id = 't' + id;
            baseId = this.getCurrencyId (baseId);
            quoteId = this.getCurrencyId (quoteId);
            let precision = {
                'price': market['price_precision'],
                'amount': market['price_precision'],
            };
            let limits = {
                'amount': {
                    'min': parseFloat (market['minimum_order_size']),
                    'max': parseFloat (market['maximum_order_size']),
                },
                'price': {
                    'min': Math.pow (10, -precision['price']),
                    'max': Math.pow (10, precision['price']),
                },
            };
            limits['cost'] = {
                'min': limits['amount']['min'] * limits['price']['min'],
                'max': undefined,
            };
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': true,
                'precision': precision,
                'limits': limits,
                'lot': Math.pow (10, -precision['amount']),
                'info': market,
            });
        }
        return result;
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let response = await this.privatePostAuthRWallets ();
        let balanceType = this.safeString (params, 'type', 'exchange');
        let result = { 'info': response };
        for (let b = 0; b < response.length; b++) {
            let balance = response[b];
            let accountType = balance[0];
            let currency = balance[1];
            let total = balance[2];
            let available = balance[4];
            if (accountType === balanceType) {
                if (currency[0] === 't')
                    currency = currency.slice (1);
                let uppercase = currency.toUpperCase ();
                uppercase = this.commonCurrencyCode (uppercase);
                let account = this.account ();
                account['free'] = available;
                account['total'] = total;
                if (account['free'])
                    account['used'] = account['total'] - account['free'];
                result[uppercase] = account;
            }
        }
        return this.parseBalance (result);
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetBookSymbolPrecision (this.extend ({
            'symbol': this.marketId (symbol),
            'precision': 'R0',
        }, params));
        let timestamp = this.milliseconds ();
        let result = {
            'bids': [],
            'asks': [],
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
        };
        for (let i = 0; i < orderbook.length; i++) {
            let order = orderbook[i];
            let price = order[1];
            let amount = order[2];
            let side = (amount > 0) ? 'bids' : 'asks';
            amount = Math.abs (amount);
            result[side].push ([ price, amount ]);
        }
        result['bids'] = this.sortBy (result['bids'], 0, true);
        result['asks'] = this.sortBy (result['asks'], 0);
        return result;
    }

    parseTicker (ticker, market = undefined) {
        let timestamp = this.milliseconds ();
        let symbol = undefined;
        if (market)
            symbol = market['symbol'];
        let length = ticker.length;
        let last = ticker[length - 4];
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': ticker[length - 2],
            'low': ticker[length - 1],
            'bid': ticker[length - 10],
            'bidVolume': undefined,
            'ask': ticker[length - 8],
            'askVolume': undefined,
            'vwap': undefined,
            'open': undefined,
            'close': last,
            'last': last,
            'previousClose': undefined,
            'change': ticker[length - 6],
            'percentage': ticker[length - 5],
            'average': undefined,
            'baseVolume': ticker[length - 3],
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        let tickers = await this.publicGetTickers (this.extend ({
            'symbols': this.ids.join (','),
        }, params));
        let result = {};
        for (let i = 0; i < tickers.length; i++) {
            let ticker = tickers[i];
            let id = ticker[0];
            let market = this.markets_by_id[id];
            let symbol = market['symbol'];
            result[symbol] = this.parseTicker (ticker, market);
        }
        return result;
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.markets[symbol];
        let ticker = await this.publicGetTickerSymbol (this.extend ({
            'symbol': market['id'],
        }, params));
        return this.parseTicker (ticker, market);
    }

    parseTrade (trade, market) {
        let [ id, timestamp, amount, price ] = trade;
        let side = (amount < 0) ? 'sell' : 'buy';
        if (amount < 0) {
            amount = -amount;
        }
        return {
            'id': id.toString (),
            'info': trade,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'type': undefined,
            'side': side,
            'price': price,
            'amount': amount,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = 120, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
            'sort': 1,
            'limit': limit, // default = max = 120
        };
        if (typeof since !== 'undefined')
            request['start'] = since;
        let response = await this.publicGetTradesSymbolHist (this.extend (request, params));
        let trades = this.sortBy (response, 1);
        return this.parseTrades (trades, market, undefined, limit);
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = 100, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
            'timeframe': this.timeframes[timeframe],
            'sort': 1,
            'limit': limit,
        };
        if (typeof since !== 'undefined')
            request['start'] = since;
        request = this.extend (request, params);
        let response = await this.publicGetCandlesTradeTimeframeSymbolHist (request);
        return this.parseOHLCVs (response, market, timeframe, since, limit);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        throw new NotSupported (this.id + ' createOrder not implemented yet');
    }

    cancelOrder (id, symbol = undefined, params = {}) {
        throw new NotSupported (this.id + ' cancelOrder not implemented yet');
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        throw new NotSupported (this.id + ' fetchOrder not implemented yet');
    }

    async withdraw (currency, amount, address, tag = undefined, params = {}) {
        throw new NotSupported (this.id + ' withdraw not implemented yet');
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = 25, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'symbol': market['id'],
            'limit': limit,
            'end': this.seconds (),
        };
        if (typeof since !== 'undefined')
            request['start'] = parseInt (since / 1000);
        let response = await this.privatePostAuthRTradesSymbolHist (this.extend (request, params));
        // return this.parseTrades (response, market, since, limit); // not implemented yet for bitfinex v2
        return response;
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (api === 'v1')
            request = api + request;
        else
            request = this.version + request;
        let url = this.urls['api'] + '/' + request;
        if (api === 'public') {
            if (Object.keys (query).length) {
                url += '?' + this.urlencode (query);
            }
        }
        if (api === 'private') {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ().toString ();
            body = this.json (query);
            let auth = '/api' + '/' + request + nonce + body;
            let signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha384');
            headers = {
                'bfx-nonce': nonce,
                'bfx-apikey': this.apiKey,
                'bfx-signature': signature,
                'Content-Type': 'application/json',
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let response = await this.fetch2 (path, api, method, params, headers, body);
        if (response) {
            if ('message' in response) {
                if (response['message'].indexOf ('not enough exchange balance') >= 0)
                    throw new InsufficientFunds (this.id + ' ' + this.json (response));
                throw new ExchangeError (this.id + ' ' + this.json (response));
            }
            return response;
        } else if (response === '') {
            throw new ExchangeError (this.id + ' returned empty response');
        }
        return response;
    }
};
<|endoftext|>