<commit_before>/*

 Copyright (c) 2017 Jirtdan Team and other collaborators

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 */

"use strict";
/*jshint esversion: 6*/
import {ConnectionLine} from './controls/ConnectionLine.js'

//FIXME: Draft
//TODO: Dependency from raphael needs to be removed.
export class Board {
    constructor(paper) {
        this.paper = paper;
        this.connections = [];
        this.controls = [];
        this.isConnecting = false;
    }

    addControl(control) {
        //TODO:
        this.controls.push(control);
    }

    startConnection(pin) {
        //TODO:
        this.isConnecting = true;
        this.inputPin = pin;
    }

    startFinishConnection(pin) {
        if (!this.isConnecting) {
            this.startConnection(pin);
            return;
        }
        this.finishConnection(pin);
    }

    finishConnection(pin) {
        console.log(pin);
        if (!this.isConnecting) return;
        if (this.inputPin == pin) return;

        if (this.inputPin.canConnect(pin)) {
            this.createConnection(this.inputPin, pin);
        }
        this.isConnecting = false;
    }

    /**
     * Create new connection and add it to the list.
     */
    createConnection(pin1, pin2) {
        this.connections.push(new ConnectionLine(this, pin1, pin2));
    }

    /**
     * Translate all connections depending on pins they connect to.
     * This method is fired on drag-drop of the control.
     */
    translateConnections(pin, x, y) {
        for (var i = 0; i < this.connections.length; i++) {
            this.connections[i].onPinTranslate(pin, x, y);
        }
    }
}
<commit_msg>[Board] Remove unnecessary logging<commit_after>/*

 Copyright (c) 2017 Jirtdan Team and other collaborators

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 */

"use strict";
/*jshint esversion: 6*/
import {ConnectionLine} from './controls/ConnectionLine.js'

//FIXME: Draft
//TODO: Dependency from raphael needs to be removed.
export class Board {
    constructor(paper) {
        this.paper = paper;
        this.connections = [];
        this.controls = [];
        this.isConnecting = false;
    }

    addControl(control) {
        //TODO:
        this.controls.push(control);
    }

    startConnection(pin) {
        //TODO:
        this.isConnecting = true;
        this.inputPin = pin;
    }

    startFinishConnection(pin) {
        if (!this.isConnecting) {
            this.startConnection(pin);
            return;
        }
        this.finishConnection(pin);
    }

    finishConnection(pin) {
        if (!this.isConnecting) return;
        if (this.inputPin == pin) return;

        if (this.inputPin.canConnect(pin)) {
            this.createConnection(this.inputPin, pin);
        }
        this.isConnecting = false;
    }

    /**
     * Create new connection and add it to the list.
     */
    createConnection(pin1, pin2) {
        this.connections.push(new ConnectionLine(this, pin1, pin2));
    }

    /**
     * Translate all connections depending on pins they connect to.
     * This method is fired on drag-drop of the control.
     */
    translateConnections(pin, x, y) {
        for (var i = 0; i < this.connections.length; i++) {
            this.connections[i].onPinTranslate(pin, x, y);
        }
    }
}
<|endoftext|>


<commit_before>/**
 * Created by ivar on 21.11.15.
 */

define([
    'config/stateConfig',
    'config/global',
    'angular-ui-router',
    'angular-messages',
    'angular-sanitize',
    'ui-bootstrap',
    'angular-storage',
    'angular-animate',
    'angular-scroll',
    'angular-scroll-glue',
    'angular-ui-select',
    'angular-vertilize'
], function (stateConfig, globalConf/*etTranslations, $ocLazyLoad*/) {

    var app = angular.module('myApp', [
        'ui.router',
        'ui.bootstrap',
        'ui.select',
        'ngCookies',
        'ngResource',
        'ngStorage',
        'ngAnimate',
        'ngSanitize',
        'ngMessages',
        'duScroll',
        'angular.vertilize',
        'luegg.directives',
        'angularSpinners'
    ]);

    app.constant('config', globalConf);

    app.config(function($animateProvider) {
        $animateProvider.classNameFilter(/angular-animate/);
    });

    app.config(function(uiSelectConfig) {
        uiSelectConfig.theme = 'bootstrap';
    });

    app.config(function ($provide, $httpProvider) {

  	  // Intercept http calls.
  	  $provide.factory('MyHttpInterceptor', function ($q) {
  	    return {
  	      // On request success
  	      request: function (config) {
  	        // console.log(config); // Contains the data about the request before it is sent.
  	        // Return the config or wrap it in a promise if blank.
  	        return config || $q.when(config);
  	      },

  	      // On request failure
  	      requestError: function (rejection) {
  	        // console.log(rejection); // Contains the data about the error on the request.
  	        console.log('requestError');
  	        // Return the promise rejection.
  	        return $q.reject(rejection);
  	      },

  	      // On response success
  	      response: function (response) {
  	        // console.log(response); // Contains the data from the response.
  	        // Return the response or promise.
  	        return response || $q.when(response);
  	      },

  	      // On response failure
  	      responseError: function (rejection) {
  	        // console.log(rejection); // Contains the data about the error.
  	    	 console.log('wnwbApi responseError');

  	    	  if (rejection.status == 500){
  	    		 alert('Sorry, something went wrong.'
  	    				 + "\n" + rejection.status + ' ' + rejection.statusText
  	    				 + "\n" + rejection.config.url);
  	    	  }
  	    	 else if (rejection.status == 401){

  	    		 alert('Please login first.'
  	    				 + "\n" + rejection.status + ' ' + rejection.statusText
  	    				 + "\n" + rejection.config.url);
  	    	  }
  	    	  else if (rejection.status == 404){

  	    		 alert('Sorry, something went wrong.'
  	    				 + "\n" + rejection.status + ' ' + rejection.statusText
  	    				 + "\n" + rejection.config.url);
  	    	  }

  	        // Return the promise rejection.
  	        return $q.reject(rejection);
  	      }
  	    };
  	  });
  	  // Intercept http calls.

  	  // Add the interceptor to the $httpProvider.
  	  $httpProvider.interceptors.push('MyHttpInterceptor');

  	});
    var defaultResponseTransformer = function (data, headersGetter) {
        return JSON.parse(data).results;
    };

    app.factory('wnwbApi', ['config', '$resource', function(config, $resource) {
        return {
            Version: $resource(config.API_URL+'version/', {}, {}, {stripTrailingSlashes: false}),
            sensereltype: $resource(config.API_URL+'sensereltype/:id/', {}, {}, {stripTrailingSlashes: false}),
            Authorization: $resource(config.API_AUTH_URL, {}, {
                auth: {
                    method: 'POST',
                    params: {

                    }
                }
            }, {stripTrailingSlashes: false}),
            Lexicon: $resource(config.API_URL+'lexicon/:id/', {}, {
                get: {
                    method: 'GET',
                    isArray: false
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            Sense: $resource(config.API_URL+'sense/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                },
                remove: {
                	method: 'DELETE'
                }
            }, {stripTrailingSlashes: false}),
            SynSet: $resource(config.API_URL+'synset/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                },
                remove: {
                	method: 'DELETE'
                }
            }, {stripTrailingSlashes: false}),
            HyperonymRelTree: $resource(config.API_URL+'hypers/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            HyponymRelTree: $resource(config.API_URL+'hypos/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SiblingRelTree: $resource(config.API_URL+'sibs/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            OtherRelTree: $resource(config.API_URL+'rels/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SenseRel: $resource(config.API_URL+'senserel/:id/', {}, {}, {stripTrailingSlashes: false}),
            SynSetRel: $resource(config.API_URL+'synsetrel/:id/', {}, {}, {stripTrailingSlashes: false}),
            SenseRelType: $resource(config.API_URL+'sensereltype/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SenseStyle: $resource(config.API_URL+'refcode/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SynSetRelType: $resource(config.API_URL+'synsetreltype/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            ExtRelType: $resource(config.API_URL+'extreltype/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            ExtSystem: $resource(config.API_URL+'extsystem/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            LexicalEntry: $resource(config.API_URL+'lexentry/', {}, {
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            Statistics: $resource(config.API_URL+'stats/', {}, {
                query: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            Principal: $resource(config.API_URL+'users/?principal', {}, {
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false})
        };
    }]);

    return app;
});<commit_msg>LexicalEntryUsage<commit_after>/**
 * Created by ivar on 21.11.15.
 */

define([
    'config/stateConfig',
    'config/global',
    'angular-ui-router',
    'angular-messages',
    'angular-sanitize',
    'ui-bootstrap',
    'angular-storage',
    'angular-animate',
    'angular-scroll',
    'angular-scroll-glue',
    'angular-ui-select',
    'angular-vertilize'
], function (stateConfig, globalConf/*etTranslations, $ocLazyLoad*/) {

    var app = angular.module('myApp', [
        'ui.router',
        'ui.bootstrap',
        'ui.select',
        'ngCookies',
        'ngResource',
        'ngStorage',
        'ngAnimate',
        'ngSanitize',
        'ngMessages',
        'duScroll',
        'angular.vertilize',
        'luegg.directives',
        'angularSpinners'
    ]);

    app.constant('config', globalConf);

    app.config(function($animateProvider) {
        $animateProvider.classNameFilter(/angular-animate/);
    });

    app.config(function(uiSelectConfig) {
        uiSelectConfig.theme = 'bootstrap';
    });

    app.config(function ($provide, $httpProvider) {

  	  // Intercept http calls.
  	  $provide.factory('MyHttpInterceptor', function ($q) {
  	    return {
  	      // On request success
  	      request: function (config) {
  	        // console.log(config); // Contains the data about the request before it is sent.
  	        // Return the config or wrap it in a promise if blank.
  	        return config || $q.when(config);
  	      },

  	      // On request failure
  	      requestError: function (rejection) {
  	        // console.log(rejection); // Contains the data about the error on the request.
  	        console.log('requestError');
  	        // Return the promise rejection.
  	        return $q.reject(rejection);
  	      },

  	      // On response success
  	      response: function (response) {
  	        // console.log(response); // Contains the data from the response.
  	        // Return the response or promise.
  	        return response || $q.when(response);
  	      },

  	      // On response failure
  	      responseError: function (rejection) {
  	        // console.log(rejection); // Contains the data about the error.
  	    	 console.log('wnwbApi responseError');

  	    	  if (rejection.status == 500){
  	    		 alert('Sorry, something went wrong.'
  	    				 + "\n" + rejection.status + ' ' + rejection.statusText
  	    				 + "\n" + rejection.config.url);
  	    	  }
  	    	 else if (rejection.status == 401){

  	    		 alert('Please login first.'
  	    				 + "\n" + rejection.status + ' ' + rejection.statusText
  	    				 + "\n" + rejection.config.url);
  	    	  }
  	    	  else if (rejection.status == 404){

  	    		 alert('Sorry, something went wrong.'
  	    				 + "\n" + rejection.status + ' ' + rejection.statusText
  	    				 + "\n" + rejection.config.url);
  	    	  }

  	        // Return the promise rejection.
  	        return $q.reject(rejection);
  	      }
  	    };
  	  });
  	  // Intercept http calls.

  	  // Add the interceptor to the $httpProvider.
  	  $httpProvider.interceptors.push('MyHttpInterceptor');

  	});
    var defaultResponseTransformer = function (data, headersGetter) {
        return JSON.parse(data).results;
    };

    app.factory('wnwbApi', ['config', '$resource', function(config, $resource) {
        return {
            Version: $resource(config.API_URL+'version/', {}, {}, {stripTrailingSlashes: false}),
            sensereltype: $resource(config.API_URL+'sensereltype/:id/', {}, {}, {stripTrailingSlashes: false}),
            Authorization: $resource(config.API_AUTH_URL, {}, {
                auth: {
                    method: 'POST',
                    params: {

                    }
                }
            }, {stripTrailingSlashes: false}),
            Lexicon: $resource(config.API_URL+'lexicon/:id/', {}, {
                get: {
                    method: 'GET',
                    isArray: false
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            Sense: $resource(config.API_URL+'sense/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                },
                remove: {
                	method: 'DELETE'
                }
            }, {stripTrailingSlashes: false}),
            SynSet: $resource(config.API_URL+'synset/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                },
                remove: {
                	method: 'DELETE'
                }
            }, {stripTrailingSlashes: false}),
            HyperonymRelTree: $resource(config.API_URL+'hypers/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            HyponymRelTree: $resource(config.API_URL+'hypos/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SiblingRelTree: $resource(config.API_URL+'sibs/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            OtherRelTree: $resource(config.API_URL+'rels/', {}, {
                get: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SenseRel: $resource(config.API_URL+'senserel/:id/', {}, {}, {stripTrailingSlashes: false}),
            SynSetRel: $resource(config.API_URL+'synsetrel/:id/', {}, {}, {stripTrailingSlashes: false}),
            SenseRelType: $resource(config.API_URL+'sensereltype/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SenseStyle: $resource(config.API_URL+'refcode/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            SynSetRelType: $resource(config.API_URL+'synsetreltype/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            ExtRelType: $resource(config.API_URL+'extreltype/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            ExtSystem: $resource(config.API_URL+'extsystem/:id/', {}, {
                update: {
                    method: 'PUT'
                },
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            LexicalEntry: $resource(config.API_URL+'lexentry/', {}, {
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
             LexicalEntryUsage: $resource(config.API_URL+'lexentryusage/', {}, {
                query: {
                    method: 'GET',
                    //transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            Statistics: $resource(config.API_URL+'stats/', {}, {
                query: {
                    method: 'GET',
                    isArray: true
                }
            }, {stripTrailingSlashes: false}),
            Principal: $resource(config.API_URL+'users/?principal', {}, {
                query: {
                    method: 'GET',
                    transformResponse: [defaultResponseTransformer],
                    isArray: true
                }
            }, {stripTrailingSlashes: false})
        };
    }]);

    return app;
});<|endoftext|>


<commit_before>import React from 'react';

import Icon from 'common/Icon';
import { formatPercentage, formatThousands } from 'common/format';
import Tooltip from 'common/Tooltip';

import Analyzer from 'parser/core/Analyzer';

import { STATISTIC_ORDER } from 'interface/others/SmallStatisticBox';
import StatisticWrapper from 'interface/others/StatisticWrapper';

const debug = false;

class DistanceMoved extends Analyzer {
  lastPositionUpdate = null;
  lastPositionChange = null;
  totalDistanceMoved = 0;
  timeSpentMoving = 0;

  // Events
  on_cast(event) {
    if (this.owner.byPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  on_damage(event) {
    if (this.owner.toPlayer(event)) {
      // Damage coordinates are for the target, so they are only accurate when done TO player
      this.updatePlayerPosition(event);
    }
  }

  on_energize(event) {
    if (this.owner.toPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  on_heal(event) {
    if (this.owner.toPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  on_absorbed(event) {
    if (this.owner.toPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  timeSinceLastMovement() {
    return this.owner.currentTimestamp - this.lastPositionChange.timestamp;
  }

  // Data parsing
  calculateDistance(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / 100;
  }

  updateTotalDistance(event) {
    if (!this.lastPositionUpdate) {
      return;
    }
    const distanceMoved = this.calculateDistance(this.lastPositionUpdate.x, this.lastPositionUpdate.y, event.x, event.y);
    if (distanceMoved !== 0) {
      this.timeSpentMoving += event.timestamp - this.lastPositionUpdate.timestamp;
      this.totalDistanceMoved += distanceMoved;
    }
  }

  updatePlayerPosition(event) {
    if (!event.x || !event.y) {
      return;
    }
    this.updateTotalDistance(event);
    if (!this.lastPositionChange || event.x !== this.lastPositionChange.x || event.y !== this.lastPositionChange.y) {
      this.lastPositionChange = event;
    }
    this.lastPositionUpdate = event;
  }

  statistic() {
    const dist_value = `≈${formatThousands(this.totalDistanceMoved)} yards`;
    const dist_label = 'Distance moved';
    const dist_tooltip = `≈${formatThousands(this.totalDistanceMoved / (this.owner.fightDuration / 1000) * 60)} yards per minute. Consider this when analyzing the fight, as some fights require more movement than others. Unnecessary movement can result in a DPS/HPS loss.`;
    const dist_icon = <Icon icon="spell_fire_burningspeed" />;

    const timeMoving_value = `≈${formatPercentage(this.timeSpentMoving / (this.owner.fightDuration))}%`;
    const timeMoving_label = 'Time spent moving';
    const timeMoving_tooltip = `In ≈${formatThousands(this.timeSpentMoving / 1000)} seconds of movement you moved ≈${formatThousands(this.totalDistanceMoved)} yards. This statistic is not entirely accurate and may be overstated for fights with lots of problems.`;
    const timeMoving_icon = <Icon icon="inv_misc_pocketwatch_02" />;

    debug && console.log(`Time spent moving: ${this.timeSpentMoving / 1000} s, Total distance moved: ${this.totalDistanceMoved} yds`);

    return (
      <StatisticWrapper position={STATISTIC_ORDER.UNIMPORTANT()}>

                {dist_icon} {dist_label}

                {/*{dist_tooltip ? <dfn data-tip={dist_tooltip}>{dist_value}</dfn> : dist_value}*/}
                {dist_tooltip ? <Tooltip content={dist_tooltip}>{dist_value}</Tooltip> : dist_value}

                {timeMoving_icon} {timeMoving_label}

                {timeMoving_tooltip ? <dfn data-tip={timeMoving_tooltip}>{timeMoving_value}</dfn> : timeMoving_value}

      </StatisticWrapper>
    );
  }
}

export default DistanceMoved;
<commit_msg>Cleanup DistanceMoved<commit_after>import React from 'react';

import Icon from 'common/Icon';
import { formatPercentage, formatThousands } from 'common/format';
import Tooltip from 'common/Tooltip';

import Analyzer from 'parser/core/Analyzer';

import { STATISTIC_ORDER } from 'interface/others/SmallStatisticBox';
import StatisticWrapper from 'interface/others/StatisticWrapper';

const debug = false;

class DistanceMoved extends Analyzer {
  lastPositionUpdate = null;
  lastPositionChange = null;
  totalDistanceMoved = 0;
  timeSpentMoving = 0;

  // Events
  on_cast(event) {
    if (this.owner.byPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  on_damage(event) {
    if (this.owner.toPlayer(event)) {
      // Damage coordinates are for the target, so they are only accurate when done TO player
      this.updatePlayerPosition(event);
    }
  }

  on_energize(event) {
    if (this.owner.toPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  on_heal(event) {
    if (this.owner.toPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  on_absorbed(event) {
    if (this.owner.toPlayer(event)) {
      this.updatePlayerPosition(event);
    }
  }

  timeSinceLastMovement() {
    return this.owner.currentTimestamp - this.lastPositionChange.timestamp;
  }

  // Data parsing
  calculateDistance(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) / 100;
  }

  updateTotalDistance(event) {
    if (!this.lastPositionUpdate) {
      return;
    }
    const distanceMoved = this.calculateDistance(this.lastPositionUpdate.x, this.lastPositionUpdate.y, event.x, event.y);
    if (distanceMoved !== 0) {
      this.timeSpentMoving += event.timestamp - this.lastPositionUpdate.timestamp;
      this.totalDistanceMoved += distanceMoved;
    }
  }

  updatePlayerPosition(event) {
    if (!event.x || !event.y) {
      return;
    }
    this.updateTotalDistance(event);
    if (!this.lastPositionChange || event.x !== this.lastPositionChange.x || event.y !== this.lastPositionChange.y) {
      this.lastPositionChange = event;
    }
    this.lastPositionUpdate = event;
  }

  statistic() {
    debug && console.log(`Time spent moving: ${this.timeSpentMoving / 1000} s, Total distance moved: ${this.totalDistanceMoved} yds`);

    return (
      <StatisticWrapper position={STATISTIC_ORDER.UNIMPORTANT()}>

                <Icon icon="spell_fire_burningspeed" /> Distance moved

                <Tooltip content={`≈${formatThousands(this.totalDistanceMoved / (this.owner.fightDuration / 1000) * 60)} yards per minute. Consider this when analyzing the fight, as some fights require more movement than others. Unnecessary movement can result in a DPS/HPS loss.`}>
                  ≈ {formatThousands(this.totalDistanceMoved)} yards
                </Tooltip>

                <Icon icon="inv_misc_pocketwatch_02" /> Time spent moving

                <Tooltip content={`In ≈${formatThousands(this.timeSpentMoving / 1000)} seconds of movement you moved ≈${formatThousands(this.totalDistanceMoved)} yards. This statistic is not entirely accurate and may be overstated for fights with lots of problems.`}>
                  ≈ {formatPercentage(this.timeSpentMoving / (this.owner.fightDuration))} %
                </Tooltip>

      </StatisticWrapper>
    );
  }
}

export default DistanceMoved;
<|endoftext|>


<commit_before>document.getElementById("formatButton").addEventListener("click", format, false);
document.getElementById("selectAllButton").addEventListener("click", selectAll, false);
function format() {
    var input = document.getElementById("json-input").value;
    try {
        input = JSON.parse(input);
        input = JSON.stringify(input, null, 4);
        document.getElementById("json-input").value = input;
        notifyCompletion("done");
    } catch (error) {
        notifyCompletion("failed");
        document.getElementById("errorOut").innerHTML = error;
    }
}
function selectAll() {
    document.getElementById("json-input").select();
}
function notifyCompletion(status) {
    if (status == "done") {
        document.getElementById("notification-area").innerHTML = "JSON formatted! Your JSON is perfectly valid.";
        $("#notification-area").fadeTo("fast", 1);
        setTimeout(function () {
            $("#notification-area").fadeTo("slow", 0);
        }, 4500);
    } else if (status == "failed") {
        document.getElementById("notification-area").innerHTML = "Something went wrong, see below for details. Your JSON is invalid.";
        $("#notification-area").fadeTo("fast", 1);
        setTimeout(function () {
            $("#notification-area").fadeTo("slow", 0);
            $("#errorOut").fadeTo("slow", 0);
        }, 10000);
    }
}
<commit_msg>Update formatter.js<commit_after>document.getElementById("formatButton").addEventListener("click", format, false);
document.getElementById("selectAllButton").addEventListener("click", selectAll, false);
function format() {
    var input = document.getElementById("json-input").value;
    try {
        input = JSON.parse(input);
        input = JSON.stringify(input, null, 4);
        document.getElementById("json-input").value = input;
        notifyCompletion("done");
    } catch (error) {
        notifyCompletion("failed", error);
    }
}
function selectAll() {
    document.getElementById("json-input").select();
}
function notifyCompletion(status, err) {
    if (status == "done") {
        document.getElementById("notification-area").innerHTML = "JSON formatted! Your JSON is perfectly valid.";
        $("#notification-area").fadeTo("fast", 1);
        setTimeout(function () {
            $("#notification-area").fadeTo("slow", 0);
        }, 4500);
    } else if (status == "failed") {
        document.getElementById("notification-area").innerHTML = "" + err + "";
        $("#notification-area").fadeTo("fast", 1);
        setTimeout(function () {
            $("#notification-area").fadeTo("slow", 0);
            $("#errorOut").fadeTo("slow", 0);
        }, 10000);
    }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
var options = require('../../src/lib/cmd')("Load MARC21 bibliographic records", {
        'match': {
            alias: 'm',
            describe: 'Criterion for matching (index:field)'
        },
        'map': {
            describe: 'Remap a field using the CSV file. Specified as 500$a:file.csv'
        },
        'overlay': {
            alias: 'o',
            default: true,
            boolean: true,
            describe: 'Overlay matching records'
        },
        'skip': {
            boolean: true,
            describe: 'Skip matching records'
        },
        'reject': {
            default: 'import.rej',
            describe: 'File name in which to store rejected records'
        },
        'recordclass': {
            describe: 'Record class to use for records (overrides LDR/06)'
        },
        'commit': {
            default: 1000,
            describe: 'Number of records to process between commits'
        }
    }),
    environment = require('../../src/lib/environment'),
    JSONImporter = require('bn-importers/lib/json'),
    graphstore = require('../../src/lib/environment').graphstore,
    models = require('../../src/models'),
    Record = models.Record,
    MARCRecord = require('marcrecord'),
    util = require('util'),
    fs = require('fs'),
    Q = require('q');
var inspect = require('eyes').inspector({maxLength: false});

graphstore.autocommit = false;

var importer = new JSONImporter({
    files: options._,
    commit: options.commit,
    pause: (options.map ? true : false)
});

var maps = { };

if (options.map) {
    var csv = require('csv');
    var mappromises = [ ];
    if (util.isArray(options.map)) {
        options.map.forEach(function (map) {
            var prom = Q.defer();
            addMap(map, prom);
            mappromises.push(prom.promise);
        });
    } else {
        var prom = Q.defer();
        addMap(options.map, prom);
        mappromises.push(prom.promise);
    }
    Q.all(mappromises).done(function () {
        importer.start();
    });
}

var linkcount = 0;
var recordcount = 0;
var mainrecordcount = 0;
var rejects = [ ];

var linklookup = { };

importer.on('record', function (record, mypromise) {
    var rec;
    var recordclass;
    if (options.recordclass) {
        recordclass = options.recordclass;
    } else {
        if (record.leader.charAt(6) === 'z') {
            recordclass = 'auth';
        } else if (record.leader.charAt(6) === 'w') {
            recordclass = 'classification';
        } else if (record.leader.charAt(6) === 'q') {
            recordclass = 'communityinfo';
        } else if (record.leader.charAt(6).match('[uvxy]')) {
            recordclass = 'holdings';
        } else {
            recordclass = 'biblio';
        }
    }
    mainrecordcount++;
    if (options.match) {
        var matchre = /^([^:]*):(...)(.*)?$/;
        var parts = matchre.exec(options.match);
        var marc = new MARCRecord(record);
        var matchpoint = { };
        var matchrec = function (field) {
            matchpoint[parts[1]] = field.string(parts[3]);
            return Record.findOne(matchpoint);
        };
        if (util.isArray(marc['f' + parts[2]])) {
            for (var ii = 0; ii < marc['f' + parts[2]].length; ii++) {
                if ( (rec = matchrec(marc['f' + parts[2]][ii])) ) break;
            }
        } else if (marc['f' + parts[2]]) {
            rec = matchrec(marc['f' + parts[2]]);
        }
    }
    if (options.map) {
        var tag, subf;
        for (var ii = 0; ii < record.fields.length; ii++) {
            tag = Object.keys(record.fields[ii])[0];
            if (typeof maps[tag] !== 'undefined') {
                for (var jj = 0; jj < record.fields[ii][tag].subfields.length; jj++) {
                    subf = Object.keys(record.fields[ii][tag].subfields[jj])[0];
                    if (typeof maps[tag][subf] !== 'undefined' && typeof maps[tag][subf][record.fields[ii][tag].subfields[jj][subf]] !== 'undefined') {
                        record.fields[ii][tag].subfields[jj][subf] = maps[tag][subf][record.fields[ii][tag].subfields[jj][subf]];
                    }
                }
            }
        }
    }
    if (!rec) {
        rec = new Record({ format: 'marc21', data: record, recordclass: recordclass });
    } else if (options.overlay) {
        rec.format = 'marc21';
        rec.data = record;
    } else {
        mypromise.resolve();
        return;
    }
    try {
        rec.save();
        var links = rec.getLinks();
        links.forEach(function (link) {
            var target = (link.match ? linklookup[JSON.stringify(link.match)] : undefined)
                         || linklookup[link.key];
            if (typeof target === 'undefined' && link.match) {
                target = Record.findOne(link.match);
            }
            if (typeof target === 'undefined') {
                target = Record.findOne({ key: link.key });
            }
            if (typeof target === 'undefined' && typeof link.vivify === 'object') {
                target = new Record(link.vivify);
                target.save();
                recordcount++;
            }
            if (typeof target !== 'undefined') {
                linklookup[link.key] = linklookup[link.key] || target.id;
                if (link.match) {
                    linklookup[JSON.stringify(link.match)] = linklookup[link.key];
                }
                rec.link(link.label, target, link.properties);
                linkcount++;
            }
        });
        recordcount++;
    } catch (e) {
        console.log(e, e.stack);
        mypromise.reject(record);
    }
    mypromise.resolve(record);
});

importer.on('commit', function (promise) {
    graphstore.db.commitSync();
    promise.resolve(true);
});

importer.on('done', function (rejects) {
    console.log('Processed ' + mainrecordcount + ' and created ' + recordcount + ' records/' + linkcount + ' links');
    if (rejects.length > 0) {
        fs.writeFileSync(options.reject, rejects.join('\n'));
    }
    process.exit();
});

function addMap(map, promise) {
    var map = map.match(/^([0-9]{3})(.):(.*)$/);
    maps[map[1]] = maps[map[1]] || { };
    maps[map[1]][map[2]] = maps[map[1]][map[2]] || { };
    csv().from.path(map[3]).to.array(function (rows) {
        rows.forEach(function (row, index) {
            if (index > 0) {
                maps[map[1]][map[2]][row[0]] = row[1];
            }
        });
        promise.resolve(true);
    });
}
<commit_msg>Remove obsolete MARC21 importer<commit_after><|endoftext|>


<commit_before>import Immutable from 'immutable';
import alt from '../alt';
import data from '../data';
import FundStore from './FundStore';
import CartActions from '../actions/CartActions';
import CartStore from './CartStore';

// Initial state of product so we can reuse it,
// when the CartActions dispatches `clear`
const initial = Immutable.fromJS(data);
// A snapshot of the product each time it is checked out.
// The snapshot allows us to restore to the data after
// a checkout when the cart is cleared.
var snapshot;

class ProductStore {
  constructor() {
    this.products = initial;
    this.bindActions(CartActions);

    // We'll expose this store's getter for CartStore's use
    this.exportPublicMethods({ getProductIndex: this.getProductIndex.bind(this) });
  }

  onAdd(id) {
    // Let the cart get a stock first ;)
    this.waitFor([CartStore, FundStore]);
    var funds = FundStore.getState().funds;

    try {
      var index = this.getProductIndex(id);
    } catch(e) {
      return false;
    }

    var product = this.products.get(index);
    var stock = product.get('stock');
    var diff = funds - product.get('price');

    // OFC, We won't update anything when
    // the stock is already replenished!
    if ( stock == 0 || diff < 0 ) {
      return false;
    }

    this.products = this.products.update(index, (product) => {
      return product.update('stock', v => v - 1);
    });
  }

  onClear() {
    // Simply reassign our `products` state
    // to `_products` since we created a snapshot
    // of its init state on the class constructor
    this.products = snapshot !== undefined
      ? snapshot
      : initial;
  }

  onCheckout() {
    // Save the snapshot of the current product
    // for later usage (to be used to restore)
    // when cleared
    snapshot = this.products;

    // We're not updating anything.
    return false;
  }

  /**
   * Get the product with the given id
   *
   * @param {int} id ID the of the given product
   * @throws Error
   * @return {Object}
   */
  getProductIndex(id) {
    const index = this.products
      .findIndex(product => product.get('id') === id);

    // Throw an error if the product does not exist
    // >> `findIndex` returns -1 when an index was not found
    if ( index == -1 ) {
      throw new Error(`Product with the id ${id} does not exist`);
    }

    return index;
  }
}

export default alt.createStore(ProductStore);
<commit_msg>Added remove product handler<commit_after>import Immutable from 'immutable';
import alt from '../alt';
import data from '../data';
import FundStore from './FundStore';
import CartActions from '../actions/CartActions';
import CartStore from './CartStore';

// Initial state of product so we can reuse it,
// when the CartActions dispatches `clear`
const initial = Immutable.fromJS(data);
// A snapshot of the product each time it is checked out.
// The snapshot allows us to restore to the data after
// a checkout when the cart is cleared.
var snapshot;

class ProductStore {
  constructor() {
    this.products = initial;
    this.bindActions(CartActions);

    // We'll expose this store's getter for CartStore's use
    this.exportPublicMethods({ getProductIndex: this.getProductIndex.bind(this) });
  }

  onAdd(id) {
    // Let the cart get a stock first ;)
    this.waitFor([CartStore, FundStore]);
    var funds = FundStore.getState().funds;

    try {
      var index = this.getProductIndex(id);
    } catch(e) {
      return false;
    }

    var product = this.products.get(index);
    var stock = product.get('stock');
    var diff = funds - product.get('price');

    // OFC, We won't update anything when
    // the stock is already replenished!
    if ( stock == 0 || diff < 0 ) {
      return false;
    }

    this.products = this.products.update(index, (product) => {
      return product.update('stock', v => v - 1);
    });
  }

  onClear() {
    // Simply reassign our `products` state
    // to `_products` since we created a snapshot
    // of its init state on the class constructor
    this.products = snapshot !== undefined
      ? snapshot
      : initial;
  }

  onCheckout() {
    // Save the snapshot of the current product
    // for later usage (to be used to restore)
    // when cleared
    snapshot = this.products;

    // We're not updating anything.
    return false;
  }

  onRemove(id) {
    this.products = this.products
      .update(this.getProductIndex(id), (product) => {
        return product.set('quantity', product.get('quantity') + 1);
      });
  }

  /**
   * Get the product with the given id
   *
   * @param {int} id ID the of the given product
   * @throws Error
   * @return {Object}
   */
  getProductIndex(id) {
    const index = this.products
      .findIndex(product => product.get('id') === id);

    // Throw an error if the product does not exist
    // >> `findIndex` returns -1 when an index was not found
    if ( index == -1 ) {
      throw new Error(`Product with the id ${id} does not exist`);
    }

    return index;
  }
}

export default alt.createStore(ProductStore);
<|endoftext|>


<commit_before>const { Client } = require('discord.js');
const ClientUtil = require('./ClientUtil');
const CommandHandler = require('./CommandHandler');
const InhibitorHandler = require('./InhibitorHandler');
const ListenerHandler = require('./ListenerHandler');

/**
 * Options used to determine how the framework behaves.
 * @typedef {Object} AkairoOptions
 * @prop {string|string[]} [ownerID=''] - Discord ID of the client owner(s).
 * @prop {boolean} [selfbot=false] - Whether or not this bot is a selfbot.
 * @prop {string} [commandDirectory] - Directory to commands.
 * @prop {string|string[]|PrefixFunction} [prefix='!'] - Default command prefix(es).
 * @prop {boolean|AllowMentionFunction} [allowMention=true] - Whether or not to allow mentions to the client user as a prefix.
 * @prop {boolean} [handleEdits=false] - Whether or not to handle edited messages.
 * @prop {boolean} [commandUtil=false] - Whether or not to assign `message.util`.
 * Set to `true` by default if `handleEdits` is on.
 * @prop {number} [commandUtilLifetime=0] - Milliseconds a command util should last before it is removed.
 * If 0, command utils will never be removed.
 * @prop {boolean} [fetchMembers=false] - Whether or not to fetch member on each message from a guild.
 * @prop {number} [defaultCooldown=0] - The default cooldown for commands.
 * @prop {ArgumentPromptOptions} [defaultPrompt] - The default prompt options.
 * @prop {string} [inhibitorDirectory] - Directory to inhibitors.
 * @prop {boolean} [blockNotSelf=true] - Whether or not to block others, if a selfbot.
 * @prop {boolean} [blockClient=true] - Whether or not to block self, if not a selfbot.
 * @prop {boolean} [blockBots=true] - Whether or not to block bots.
 * @prop {string} [listenerDirectory] - Directory to listeners.
 * @prop {Object} [emitters={}] - Emitters to load onto the listener handler.
 * @prop {boolean} [automateCategories=false] - Whether or not to set each module's category to it's parent directory name
 */

/**
 * A function that returns the prefix(es) to use.
 * @typedef {Function} PrefixFunction
 * @param {Message} message - Message to get prefix for.
 * @returns {string|string[]}
 */

/**
 * A function that returns whether mentions can be used as a prefix.
 * @typedef {Function} AllowMentionFunction
 * @param {Message} message - Message to option for.
 * @returns {boolean}
 */

class AkairoClient extends Client {
    /**
     * The Akairo framework client.
     * Creates the handlers and sets them up.
     * @param {AkairoOptions} [options={}] - Options to use for the framework.
     * @param {ClientOptions} [clientOptions] - Options for Discord JS client.
     * If not specified, the previous options parameter is used instead.
     */
    constructor(options = {}, clientOptions) {
        super(clientOptions || options);

        /**
         * The ID of the owner.
         * @type {string}
         */
        this.ownerID = options.ownerID;

        /**
         * Whether or not this is a selfbot.
         * @type {boolean}
         */
        this.selfbot = !!options.selfbot;

        /**
         * An empty object.
         * Useful for storing things.
         * @type {Object}
         */
        this.mem = {};

        /**
         * Utility methods.
         * @type {ClientUtil}
         */
        this.util = new ClientUtil(this);

        /**
         * Databases added.
         * @type {Object}
         */
        this.databases = {};

        /**
         * Options for the framework.
         * @type {AkairoOptions}
         */
        this.akairoOptions = options;

        this._built = false;
        this._loaded = false;
    }

    /**
     * Adds a database that will be initialized once ready.
     * @param {string} name - Name of database.
     * @param {SQLiteHandler} database - The database.
     * @returns {AkairoClient}
     */
    addDatabase(name, database) {
        this.databases[name] = database;
        Object.defineProperty(database, 'client', {
            value: this
        });

        if (!this.akairoOptions.emitters) this.akairoOptions.emitters = {};
        this.akairoOptions.emitters[name] = database;

        return this;
    }

    /**
     * Logins the client, creates message listener, and initialize databases.
     * Resolves once client is ready.
     * @param {string} token - Client token.
     * @returns {Promise<string>}
     */
    login(token) {
        return new Promise((resolve, reject) => {
            if (!this._built) this.build();
            if (!this._loaded) this.loadAll();

            super.login(token).catch(reject);

            this.once('ready', () => {
                const promises = [];

                for (const key of Object.keys(this.databases)) {
                    const db = this.databases[key];
                    const ids = (db.init && db.init(this)) || [];
                    promises.push(db.load ? db.load(ids) : Promise.resolve());
                }

                Promise.all(promises).then(() => {
                    if (this.commandHandler) {
                        this.on('message', m => {
                            this.commandHandler.handle(m, false);
                        });

                        if (this.commandHandler.handleEdits) {
                            this.on('messageUpdate', (o, m) => {
                                if (o.content === m.content) return;
                                if (this.commandHandler.handleEdits) this.commandHandler.handle(m, true);
                            });
                        }
                    }

                    return resolve(token);
                }).catch(reject);
            });
        });
    }

    /**
     * Builds the client by creating the handlers.
     * @returns {AkairoClient}
     */
    build() {
        if (this._built) {
            throw new Error('Client handlers can only be built once.');
        }

        this._built = true;

        if (this.akairoOptions.commandDirectory && !this.commandHandler) {
            /**
             * The command handler.
             * @type {CommandHandler}
             */
            this.commandHandler = new CommandHandler(this, this.akairoOptions);
        }

        if (this.akairoOptions.inhibitorDirectory && !this.inhibitorHandler) {
            /**
             * The inhibitor handler.
             * @type {InhibitorHandler}
             */
            this.inhibitorHandler = new InhibitorHandler(this, this.akairoOptions);
        }

        if (this.akairoOptions.listenerDirectory && !this.listenerHandler) {
            /**
             * The listener handler.
             * @type {ListenerHandler}
             */
            this.listenerHandler = new ListenerHandler(this, this.akairoOptions);
        }

        return this;
    }

    /**
     * Calls `loadAll()` on the handlers.
     * @returns {void}
     */
    loadAll() {
        if (this._loaded) {
            throw new Error('Client modules can only be loaded once.');
        }

        this._loaded = true;

        if (this.listenerHandler) this.listenerHandler.loadAll();
        if (this.commandHandler) this.commandHandler.loadAll();
        if (this.inhibitorHandler) this.inhibitorHandler.loadAll();
    }
}

module.exports = AkairoClient;
<commit_msg>Deprecate more things<commit_after>const { Client } = require('discord.js');
const ClientUtil = require('./ClientUtil');
const CommandHandler = require('./CommandHandler');
const InhibitorHandler = require('./InhibitorHandler');
const ListenerHandler = require('./ListenerHandler');

/**
 * Options used to determine how the framework behaves.
 * @typedef {Object} AkairoOptions
 * @prop {string|string[]} [ownerID=''] - Discord ID of the client owner(s).
 * @prop {boolean} [selfbot=false] - Whether or not this bot is a selfbot.
 * @prop {string} [commandDirectory] - Directory to commands.
 * @prop {string|string[]|PrefixFunction} [prefix='!'] - Default command prefix(es).
 * @prop {boolean|AllowMentionFunction} [allowMention=true] - Whether or not to allow mentions to the client user as a prefix.
 * @prop {boolean} [handleEdits=false] - Whether or not to handle edited messages.
 * @prop {boolean} [commandUtil=false] - Whether or not to assign `message.util`.
 * Set to `true` by default if `handleEdits` is on.
 * @prop {number} [commandUtilLifetime=0] - Milliseconds a command util should last before it is removed.
 * If 0, command utils will never be removed.
 * @prop {boolean} [fetchMembers=false] - Whether or not to fetch member on each message from a guild.
 * @prop {number} [defaultCooldown=0] - The default cooldown for commands.
 * @prop {ArgumentPromptOptions} [defaultPrompt] - The default prompt options.
 * @prop {string} [inhibitorDirectory] - Directory to inhibitors.
 * @prop {boolean} [blockNotSelf=true] - Whether or not to block others, if a selfbot.
 * @prop {boolean} [blockClient=true] - Whether or not to block self, if not a selfbot.
 * @prop {boolean} [blockBots=true] - Whether or not to block bots.
 * @prop {string} [listenerDirectory] - Directory to listeners.
 * @prop {Object} [emitters={}] - Emitters to load onto the listener handler.
 * @prop {boolean} [automateCategories=false] - Whether or not to set each module's category to it's parent directory name
 */

/**
 * A function that returns the prefix(es) to use.
 * @typedef {Function} PrefixFunction
 * @param {Message} message - Message to get prefix for.
 * @returns {string|string[]}
 */

/**
 * A function that returns whether mentions can be used as a prefix.
 * @typedef {Function} AllowMentionFunction
 * @param {Message} message - Message to option for.
 * @returns {boolean}
 */

class AkairoClient extends Client {
    /**
     * The Akairo framework client.
     * Creates the handlers and sets them up.
     * @param {AkairoOptions} [options={}] - Options to use for the framework.
     * @param {ClientOptions} [clientOptions] - Options for Discord JS client.
     * If not specified, the previous options parameter is used instead.
     */
    constructor(options = {}, clientOptions) {
        super(clientOptions || options);

        /**
         * The ID of the owner.
         * @type {string}
         */
        this.ownerID = options.ownerID;

        /**
         * Whether or not this is a selfbot.
         * @type {boolean}
         */
        this.selfbot = !!options.selfbot;

        /**
         * An empty object.
         * Useful for storing things.
         * @deprecated
         * @type {Object}
         */
        this.mem = {};

        /**
         * Utility methods.
         * @type {ClientUtil}
         */
        this.util = new ClientUtil(this);

        /**
         * Databases added.
         * @deprecated
         * @type {Object}
         */
        this.databases = {};

        /**
         * Options for the framework.
         * @type {AkairoOptions}
         */
        this.akairoOptions = options;

        this._built = false;
        this._loaded = false;
    }

    /**
     * Adds a database that will be initialized once ready.
     * @deprecated
     * @param {string} name - Name of database.
     * @param {SQLiteHandler} database - The database.
     * @returns {AkairoClient}
     */
    addDatabase(name, database) {
        this.databases[name] = database;
        Object.defineProperty(database, 'client', {
            value: this
        });

        if (!this.akairoOptions.emitters) this.akairoOptions.emitters = {};
        this.akairoOptions.emitters[name] = database;

        return this;
    }

    /**
     * Logins the client, creates message listener, and initialize databases.
     * Resolves once client is ready.
     * @param {string} token - Client token.
     * @returns {Promise<string>}
     */
    login(token) {
        return new Promise((resolve, reject) => {
            if (!this._built) this.build();
            if (!this._loaded) this.loadAll();

            super.login(token).catch(reject);

            this.once('ready', () => {
                const promises = [];

                for (const key of Object.keys(this.databases)) {
                    const db = this.databases[key];
                    const ids = (db.init && db.init(this)) || [];
                    promises.push(db.load ? db.load(ids) : Promise.resolve());
                }

                Promise.all(promises).then(() => {
                    if (this.commandHandler) {
                        this.on('message', m => {
                            this.commandHandler.handle(m, false);
                        });

                        if (this.commandHandler.handleEdits) {
                            this.on('messageUpdate', (o, m) => {
                                if (o.content === m.content) return;
                                if (this.commandHandler.handleEdits) this.commandHandler.handle(m, true);
                            });
                        }
                    }

                    return resolve(token);
                }).catch(reject);
            });
        });
    }

    /**
     * Builds the client by creating the handlers.
     * @returns {AkairoClient}
     */
    build() {
        if (this._built) {
            throw new Error('Client handlers can only be built once.');
        }

        this._built = true;

        if (this.akairoOptions.commandDirectory && !this.commandHandler) {
            /**
             * The command handler.
             * @type {CommandHandler}
             */
            this.commandHandler = new CommandHandler(this, this.akairoOptions);
        }

        if (this.akairoOptions.inhibitorDirectory && !this.inhibitorHandler) {
            /**
             * The inhibitor handler.
             * @type {InhibitorHandler}
             */
            this.inhibitorHandler = new InhibitorHandler(this, this.akairoOptions);
        }

        if (this.akairoOptions.listenerDirectory && !this.listenerHandler) {
            /**
             * The listener handler.
             * @type {ListenerHandler}
             */
            this.listenerHandler = new ListenerHandler(this, this.akairoOptions);
        }

        return this;
    }

    /**
     * Calls `loadAll()` on the handlers.
     * @returns {void}
     */
    loadAll() {
        if (this._loaded) {
            throw new Error('Client modules can only be loaded once.');
        }

        this._loaded = true;

        if (this.listenerHandler) this.listenerHandler.loadAll();
        if (this.commandHandler) this.commandHandler.loadAll();
        if (this.inhibitorHandler) this.inhibitorHandler.loadAll();
    }
}

module.exports = AkairoClient;
<|endoftext|>


<commit_before>const Generator = require('yeoman-generator');
const {toId, toAppId, toName, isValidAppId} = require('./utilities.js');

const PROJECT_TYPES = [{
  name: 'JavaScript App',
  value: 'js'
}, {
  name: 'TypeScript App',
  value: 'ts'
}];

const IDE_TYPES = [{
  name: 'None',
  value: 'none'
}, {
  name: 'Visual Studio Code',
  value: 'vsc'
}];

module.exports = class extends Generator {

  prompting() {
    return this.prompt([
      {
        type: 'input',
        name: 'name',
        message: 'Your project name',
        default: this.appname, // defaults to current working dir
        filter: toId
      }, {
        type: 'input',
        name: 'version',
        message: 'Initial version',
        default: '0.1.0'
      }, {
        type: 'list',
        name: 'proj_type',
        message: 'Type of project',
        choices: PROJECT_TYPES
      }, {
        type: 'input',
        name: 'app_id',
        message: 'App ID',
        default: answers => 'example.' + toAppId(answers.name),
        validate: input => isValidAppId(input) ||
          'Invalid App ID, use alphanumeric characters and periods only, EG: com.domain.app'
      }, {
        type: 'input',
        name: 'app_name',
        message: 'App name',
        default: answers => toName(answers.name)
      }, {
        type: 'input',
        name: 'app_description',
        message: 'App description',
        default: 'Example Tabris.js App'
      }, {
        type: 'input',
        name: 'author_name',
        message: 'Author',
        default: this.user.git.name
      }, {
        type: 'input',
        name: 'author_email',
        message: 'Email',
        default: this.user.git.email
      }, {
        type: 'list',
        name: 'ide_type',
        message: 'Configure for IDE',
        choices: IDE_TYPES
      }
    ]).then(answers => {
      let main = answers.proj_type === 'js' ? 'src/app.js' : 'dist/app.js';
      this._props = Object.assign(answers, {main});
    });
  }

  writing() {
    this.fs.copyTpl(
      this.templatePath('_package.json'),
      this.destinationPath('package.json'),
      this._props
    );
    this.fs.copyTpl(
      this.templatePath('cordova'),
      this.destinationPath('cordova'),
      this._props
    );
    if (this._props.proj_type === 'ts') {
      this.fs.copyTpl(
        this.templatePath('ts/_gitignore'),
        this.destinationPath('.gitignore')
      );
      this.fs.copyTpl(
        this.templatePath('ts/src'),
        this.destinationPath('src'),
        this._props
      );
      this.fs.copyTpl(
        this.templatePath('ts/tsconfig.json'),
        this.destinationPath('tsconfig.json')
      );
      this.fs.copyTpl(
        this.templatePath('ts/tslint.json'),
        this.destinationPath('tslint.json')
      );
    } else if (this._props.proj_type === 'js') {
      this.fs.copyTpl(
        this.templatePath('js/_gitignore'),
        this.destinationPath('.gitignore')
      );
      this.fs.copyTpl(
        this.templatePath('js/.eslintrc'),
        this.destinationPath('.eslintrc')
      );
      this.fs.copyTpl(
        this.templatePath('js/src'),
        this.destinationPath('src'),
        this._props
      );
    }
    if (this._props.ide_type === 'vsc') {
      this.fs.copyTpl(
        this.templatePath('.vscode'),
        this.destinationPath('.vscode')
      );
    }
  }

  install() {
    this.npmInstall(['tabris@2.0.0-rc1'], {
      save: true
    });
    if (this._props.proj_type === 'js') {
      this.npmInstall(['eslint'], {
        saveDev: true
      });
    } else if (this._props.proj_type === 'ts') {
      this.npmInstall(['typescript', 'tslint', 'npm-run-all'], {
        saveDev: true
      });
    }
  }

};
<commit_msg>Add numbers to multiple choice questions<commit_after>const Generator = require('yeoman-generator');
const {toId, toAppId, toName, isValidAppId} = require('./utilities.js');

const PROJECT_TYPES = [{
  name: '1 - JavaScript App',
  value: 'js'
}, {
  name: '2 - TypeScript App',
  value: 'ts'
}];

const IDE_TYPES = [{
  name: '1 - None',
  value: 'none'
}, {
  name: '2 - Visual Studio Code',
  value: 'vsc'
}];

module.exports = class extends Generator {

  prompting() {
    return this.prompt([
      {
        type: 'input',
        name: 'name',
        message: 'Your project name',
        default: this.appname, // defaults to current working dir
        filter: toId
      }, {
        type: 'input',
        name: 'version',
        message: 'Initial version',
        default: '0.1.0'
      }, {
        type: 'list',
        name: 'proj_type',
        message: 'Type of project',
        choices: PROJECT_TYPES
      }, {
        type: 'input',
        name: 'app_id',
        message: 'App ID',
        default: answers => 'example.' + toAppId(answers.name),
        validate: input => isValidAppId(input) ||
          'Invalid App ID, use alphanumeric characters and periods only, EG: com.domain.app'
      }, {
        type: 'input',
        name: 'app_name',
        message: 'App name',
        default: answers => toName(answers.name)
      }, {
        type: 'input',
        name: 'app_description',
        message: 'App description',
        default: 'Example Tabris.js App'
      }, {
        type: 'input',
        name: 'author_name',
        message: 'Author',
        default: this.user.git.name
      }, {
        type: 'input',
        name: 'author_email',
        message: 'Email',
        default: this.user.git.email
      }, {
        type: 'list',
        name: 'ide_type',
        message: 'Configure for IDE',
        choices: IDE_TYPES
      }
    ]).then(answers => {
      let main = answers.proj_type === 'js' ? 'src/app.js' : 'dist/app.js';
      this._props = Object.assign(answers, {main});
    });
  }

  writing() {
    this.fs.copyTpl(
      this.templatePath('_package.json'),
      this.destinationPath('package.json'),
      this._props
    );
    this.fs.copyTpl(
      this.templatePath('cordova'),
      this.destinationPath('cordova'),
      this._props
    );
    if (this._props.proj_type === 'ts') {
      this.fs.copyTpl(
        this.templatePath('ts/_gitignore'),
        this.destinationPath('.gitignore')
      );
      this.fs.copyTpl(
        this.templatePath('ts/src'),
        this.destinationPath('src'),
        this._props
      );
      this.fs.copyTpl(
        this.templatePath('ts/tsconfig.json'),
        this.destinationPath('tsconfig.json')
      );
      this.fs.copyTpl(
        this.templatePath('ts/tslint.json'),
        this.destinationPath('tslint.json')
      );
    } else if (this._props.proj_type === 'js') {
      this.fs.copyTpl(
        this.templatePath('js/_gitignore'),
        this.destinationPath('.gitignore')
      );
      this.fs.copyTpl(
        this.templatePath('js/.eslintrc'),
        this.destinationPath('.eslintrc')
      );
      this.fs.copyTpl(
        this.templatePath('js/src'),
        this.destinationPath('src'),
        this._props
      );
    }
    if (this._props.ide_type === 'vsc') {
      this.fs.copyTpl(
        this.templatePath('.vscode'),
        this.destinationPath('.vscode')
      );
    }
  }

  install() {
    this.npmInstall(['tabris@2.0.0-rc1'], {
      save: true
    });
    if (this._props.proj_type === 'js') {
      this.npmInstall(['eslint'], {
        saveDev: true
      });
    } else if (this._props.proj_type === 'ts') {
      this.npmInstall(['typescript', 'tslint', 'npm-run-all'], {
        saveDev: true
      });
    }
  }

};
<|endoftext|>


<commit_before>import {Path} from './Path';
import * as Util from '../../core/Util';
import * as LineUtil from '../../geometry/LineUtil';
import {LatLng, toLatLng} from '../../geo/LatLng';
import {LatLngBounds} from '../../geo/LatLngBounds';
import {Bounds} from '../../geometry/Bounds';
import {Point} from '../../geometry/Point';

/*
 * @class Polyline
 * @aka L.Polyline
 * @inherits Path
 *
 * A class for drawing polyline overlays on a map. Extends `Path`.
 *
 * @example
 *
 * ```js
 * // create a red polyline from an array of LatLng points
 * var latlngs = [
 * 	[45.51, -122.68],
 * 	[37.77, -122.43],
 * 	[34.04, -118.2]
 * ];
 *
 * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
 *
 * // zoom the map to the polyline
 * map.fitBounds(polyline.getBounds());
 * ```
 *
 * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
 *
 * ```js
 * // create a red polyline from an array of arrays of LatLng points
 * var latlngs = [
 * 	[[45.51, -122.68],
 * 	 [37.77, -122.43],
 * 	 [34.04, -118.2]],
 * 	[[40.78, -73.91],
 * 	 [41.83, -87.62],
 * 	 [32.76, -96.72]]
 * ];
 * ```
 */

export var Polyline = Path.extend({

	// @section
	// @aka Polyline options
	options: {
		// @option smoothFactor: Number = 1.0
		// How much to simplify the polyline on each zoom level. More means
		// better performance and smoother look, and less means more accurate representation.
		smoothFactor: 1.0,

		// @option noClip: Boolean = false
		// Disable polyline clipping.
		noClip: false
	},

	initialize: function (latlngs, options) {
		Util.setOptions(this, options);
		this._setLatLngs(latlngs);
	},

	// @method getLatLngs(): LatLng[]
	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
	getLatLngs: function () {
		return this._latlngs;
	},

	// @method setLatLngs(latlngs: LatLng[]): this
	// Replaces all the points in the polyline with the given array of geographical points.
	setLatLngs: function (latlngs) {
		this._setLatLngs(latlngs);
		return this.redraw();
	},

	// @method isEmpty(): Boolean
	// Returns `true` if the Polyline has no LatLngs.
	isEmpty: function () {
		return !this._latlngs.length;
	},

	closestLayerPoint: function (p) {
		var minDistance = Infinity,
		    minPoint = null,
		    closest = LineUtil._sqClosestPointOnSegment,
		    p1, p2;

		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
			var points = this._parts[j];

			for (var i = 1, len = points.length; i < len; i++) {
				p1 = points[i - 1];
				p2 = points[i];

				var sqDist = closest(p, p1, p2, true);

				if (sqDist < minDistance) {
					minDistance = sqDist;
					minPoint = closest(p, p1, p2);
				}
			}
		}
		if (minPoint) {
			minPoint.distance = Math.sqrt(minDistance);
		}
		return minPoint;
	},

	// @method getCenter(): LatLng
	// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
	getCenter: function () {
		// throws error when not yet added to map as this center calculation requires projected coordinates
		if (!this._map) {
			throw new Error('Must add layer to map before using getCenter()');
		}

		var i, halfDist, segDist, dist, p1, p2, ratio,
		    points = this._rings[0],
		    len = points.length;

		if (!len) { return null; }

		// polyline centroid algorithm; only uses the first ring if there are multiple

		for (i = 0, halfDist = 0; i < len - 1; i++) {
			halfDist += points[i].distanceTo(points[i + 1]) / 2;
		}

		// The line is so small in the current view that all points are on the same pixel.
		if (halfDist === 0) {
			return this._map.layerPointToLatLng(points[0]);
		}

		for (i = 0, dist = 0; i < len - 1; i++) {
			p1 = points[i];
			p2 = points[i + 1];
			segDist = p1.distanceTo(p2);
			dist += segDist;

			if (dist > halfDist) {
				ratio = (dist - halfDist) / segDist;
				return this._map.layerPointToLatLng([
					p2.x - ratio * (p2.x - p1.x),
					p2.y - ratio * (p2.y - p1.y)
				]);
			}
		}
	},

	// @method getBounds(): LatLngBounds
	// Returns the `LatLngBounds` of the path.
	getBounds: function () {
		return this._bounds;
	},

	// @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this
	// Adds a given point to the polyline. By default, adds to the first ring of
	// the polyline in case of a multi-polyline, but can be overridden by passing
	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
	addLatLng: function (latlng, latlngs) {
		latlngs = latlngs || this._defaultShape();
		latlng = toLatLng(latlng);
		latlngs.push(latlng);
		this._bounds.extend(latlng);
		return this.redraw();
	},

	_setLatLngs: function (latlngs) {
		this._bounds = new LatLngBounds();
		this._latlngs = this._convertLatLngs(latlngs);
	},

	_defaultShape: function () {
		return LineUtil.isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
	},

	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
	_convertLatLngs: function (latlngs) {
		var result = [],
		    flat = LineUtil.isFlat(latlngs);

		for (var i = 0, len = latlngs.length; i < len; i++) {
			if (flat) {
				result[i] = toLatLng(latlngs[i]);
				this._bounds.extend(result[i]);
			} else {
				result[i] = this._convertLatLngs(latlngs[i]);
			}
		}

		return result;
	},

	_project: function () {
		var pxBounds = new Bounds();
		this._rings = [];
		this._projectLatlngs(this._latlngs, this._rings, pxBounds);

		var w = this._clickTolerance(),
		    p = new Point(w, w);

		if (this._bounds.isValid() && pxBounds.isValid()) {
			pxBounds.min._subtract(p);
			pxBounds.max._add(p);
			this._pxBounds = pxBounds;
		}
	},

	// recursively turns latlngs into a set of rings with projected coordinates
	_projectLatlngs: function (latlngs, result, projectedBounds) {
		var flat = latlngs[0] instanceof LatLng,
		    len = latlngs.length,
		    i, ring;

		if (flat) {
			ring = [];
			for (i = 0; i < len; i++) {
				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
				projectedBounds.extend(ring[i]);
			}
			result.push(ring);
		} else {
			for (i = 0; i < len; i++) {
				this._projectLatlngs(latlngs[i], result, projectedBounds);
			}
		}
	},

	// clip polyline by renderer bounds so that we have less to render for performance
	_clipPoints: function () {
		var bounds = this._renderer._bounds;

		this._parts = [];
		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
			return;
		}

		if (this.options.noClip) {
			this._parts = this._rings;
			return;
		}

		var parts = this._parts,
		    i, j, k, len, len2, segment, points;

		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
			points = this._rings[i];

			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
				segment = LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);

				if (!segment) { continue; }

				parts[k] = parts[k] || [];
				parts[k].push(segment[0]);

				// if segment goes out of screen, or it's the last one, it's the end of the line part
				if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
					parts[k].push(segment[1]);
					k++;
				}
			}
		}
	},

	// simplify each clipped part of the polyline for performance
	_simplifyPoints: function () {
		var parts = this._parts,
		    tolerance = this.options.smoothFactor;

		for (var i = 0, len = parts.length; i < len; i++) {
			parts[i] = LineUtil.simplify(parts[i], tolerance);
		}
	},

	_update: function () {
		if (!this._map) { return; }

		this._clipPoints();
		this._simplifyPoints();
		this._updatePath();
	},

	_updatePath: function () {
		this._renderer._updatePoly(this);
	},

	// Needed by the `Canvas` renderer for interactivity
	_containsPoint: function (p, closed) {
		var i, j, k, len, len2, part,
		    w = this._clickTolerance();

		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }

		// hit detection for polylines
		for (i = 0, len = this._parts.length; i < len; i++) {
			part = this._parts[i];

			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
				if (!closed && (j === 0)) { continue; }

				if (LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
					return true;
				}
			}
		}
		return false;
	}
});

// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
// Instantiates a polyline object given an array of geographical points and
// optionally an options object. You can create a `Polyline` object with
// multiple separate lines (`MultiPolyline`) by passing an array of arrays
// of geographic points.
export function polyline(latlngs, options) {
	return new Polyline(latlngs, options);
}

// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.
Polyline._flat = LineUtil._flat;
<commit_msg>Add documentation for PolyLine.closestLayerPoint (#5701)<commit_after>import {Path} from './Path';
import * as Util from '../../core/Util';
import * as LineUtil from '../../geometry/LineUtil';
import {LatLng, toLatLng} from '../../geo/LatLng';
import {LatLngBounds} from '../../geo/LatLngBounds';
import {Bounds} from '../../geometry/Bounds';
import {Point} from '../../geometry/Point';

/*
 * @class Polyline
 * @aka L.Polyline
 * @inherits Path
 *
 * A class for drawing polyline overlays on a map. Extends `Path`.
 *
 * @example
 *
 * ```js
 * // create a red polyline from an array of LatLng points
 * var latlngs = [
 * 	[45.51, -122.68],
 * 	[37.77, -122.43],
 * 	[34.04, -118.2]
 * ];
 *
 * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
 *
 * // zoom the map to the polyline
 * map.fitBounds(polyline.getBounds());
 * ```
 *
 * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
 *
 * ```js
 * // create a red polyline from an array of arrays of LatLng points
 * var latlngs = [
 * 	[[45.51, -122.68],
 * 	 [37.77, -122.43],
 * 	 [34.04, -118.2]],
 * 	[[40.78, -73.91],
 * 	 [41.83, -87.62],
 * 	 [32.76, -96.72]]
 * ];
 * ```
 */

export var Polyline = Path.extend({

	// @section
	// @aka Polyline options
	options: {
		// @option smoothFactor: Number = 1.0
		// How much to simplify the polyline on each zoom level. More means
		// better performance and smoother look, and less means more accurate representation.
		smoothFactor: 1.0,

		// @option noClip: Boolean = false
		// Disable polyline clipping.
		noClip: false
	},

	initialize: function (latlngs, options) {
		Util.setOptions(this, options);
		this._setLatLngs(latlngs);
	},

	// @method getLatLngs(): LatLng[]
	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
	getLatLngs: function () {
		return this._latlngs;
	},

	// @method setLatLngs(latlngs: LatLng[]): this
	// Replaces all the points in the polyline with the given array of geographical points.
	setLatLngs: function (latlngs) {
		this._setLatLngs(latlngs);
		return this.redraw();
	},

	// @method isEmpty(): Boolean
	// Returns `true` if the Polyline has no LatLngs.
	isEmpty: function () {
		return !this._latlngs.length;
	},

	// @method closestLayerPoint: Point
	// Returns the point closest to `p` on the Polyline.
	closestLayerPoint: function (p) {
		var minDistance = Infinity,
		    minPoint = null,
		    closest = LineUtil._sqClosestPointOnSegment,
		    p1, p2;

		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
			var points = this._parts[j];

			for (var i = 1, len = points.length; i < len; i++) {
				p1 = points[i - 1];
				p2 = points[i];

				var sqDist = closest(p, p1, p2, true);

				if (sqDist < minDistance) {
					minDistance = sqDist;
					minPoint = closest(p, p1, p2);
				}
			}
		}
		if (minPoint) {
			minPoint.distance = Math.sqrt(minDistance);
		}
		return minPoint;
	},

	// @method getCenter(): LatLng
	// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
	getCenter: function () {
		// throws error when not yet added to map as this center calculation requires projected coordinates
		if (!this._map) {
			throw new Error('Must add layer to map before using getCenter()');
		}

		var i, halfDist, segDist, dist, p1, p2, ratio,
		    points = this._rings[0],
		    len = points.length;

		if (!len) { return null; }

		// polyline centroid algorithm; only uses the first ring if there are multiple

		for (i = 0, halfDist = 0; i < len - 1; i++) {
			halfDist += points[i].distanceTo(points[i + 1]) / 2;
		}

		// The line is so small in the current view that all points are on the same pixel.
		if (halfDist === 0) {
			return this._map.layerPointToLatLng(points[0]);
		}

		for (i = 0, dist = 0; i < len - 1; i++) {
			p1 = points[i];
			p2 = points[i + 1];
			segDist = p1.distanceTo(p2);
			dist += segDist;

			if (dist > halfDist) {
				ratio = (dist - halfDist) / segDist;
				return this._map.layerPointToLatLng([
					p2.x - ratio * (p2.x - p1.x),
					p2.y - ratio * (p2.y - p1.y)
				]);
			}
		}
	},

	// @method getBounds(): LatLngBounds
	// Returns the `LatLngBounds` of the path.
	getBounds: function () {
		return this._bounds;
	},

	// @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this
	// Adds a given point to the polyline. By default, adds to the first ring of
	// the polyline in case of a multi-polyline, but can be overridden by passing
	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
	addLatLng: function (latlng, latlngs) {
		latlngs = latlngs || this._defaultShape();
		latlng = toLatLng(latlng);
		latlngs.push(latlng);
		this._bounds.extend(latlng);
		return this.redraw();
	},

	_setLatLngs: function (latlngs) {
		this._bounds = new LatLngBounds();
		this._latlngs = this._convertLatLngs(latlngs);
	},

	_defaultShape: function () {
		return LineUtil.isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
	},

	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
	_convertLatLngs: function (latlngs) {
		var result = [],
		    flat = LineUtil.isFlat(latlngs);

		for (var i = 0, len = latlngs.length; i < len; i++) {
			if (flat) {
				result[i] = toLatLng(latlngs[i]);
				this._bounds.extend(result[i]);
			} else {
				result[i] = this._convertLatLngs(latlngs[i]);
			}
		}

		return result;
	},

	_project: function () {
		var pxBounds = new Bounds();
		this._rings = [];
		this._projectLatlngs(this._latlngs, this._rings, pxBounds);

		var w = this._clickTolerance(),
		    p = new Point(w, w);

		if (this._bounds.isValid() && pxBounds.isValid()) {
			pxBounds.min._subtract(p);
			pxBounds.max._add(p);
			this._pxBounds = pxBounds;
		}
	},

	// recursively turns latlngs into a set of rings with projected coordinates
	_projectLatlngs: function (latlngs, result, projectedBounds) {
		var flat = latlngs[0] instanceof LatLng,
		    len = latlngs.length,
		    i, ring;

		if (flat) {
			ring = [];
			for (i = 0; i < len; i++) {
				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
				projectedBounds.extend(ring[i]);
			}
			result.push(ring);
		} else {
			for (i = 0; i < len; i++) {
				this._projectLatlngs(latlngs[i], result, projectedBounds);
			}
		}
	},

	// clip polyline by renderer bounds so that we have less to render for performance
	_clipPoints: function () {
		var bounds = this._renderer._bounds;

		this._parts = [];
		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
			return;
		}

		if (this.options.noClip) {
			this._parts = this._rings;
			return;
		}

		var parts = this._parts,
		    i, j, k, len, len2, segment, points;

		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
			points = this._rings[i];

			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
				segment = LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);

				if (!segment) { continue; }

				parts[k] = parts[k] || [];
				parts[k].push(segment[0]);

				// if segment goes out of screen, or it's the last one, it's the end of the line part
				if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
					parts[k].push(segment[1]);
					k++;
				}
			}
		}
	},

	// simplify each clipped part of the polyline for performance
	_simplifyPoints: function () {
		var parts = this._parts,
		    tolerance = this.options.smoothFactor;

		for (var i = 0, len = parts.length; i < len; i++) {
			parts[i] = LineUtil.simplify(parts[i], tolerance);
		}
	},

	_update: function () {
		if (!this._map) { return; }

		this._clipPoints();
		this._simplifyPoints();
		this._updatePath();
	},

	_updatePath: function () {
		this._renderer._updatePoly(this);
	},

	// Needed by the `Canvas` renderer for interactivity
	_containsPoint: function (p, closed) {
		var i, j, k, len, len2, part,
		    w = this._clickTolerance();

		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }

		// hit detection for polylines
		for (i = 0, len = this._parts.length; i < len; i++) {
			part = this._parts[i];

			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
				if (!closed && (j === 0)) { continue; }

				if (LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
					return true;
				}
			}
		}
		return false;
	}
});

// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
// Instantiates a polyline object given an array of geographical points and
// optionally an options object. You can create a `Polyline` object with
// multiple separate lines (`MultiPolyline`) by passing an array of arrays
// of geographic points.
export function polyline(latlngs, options) {
	return new Polyline(latlngs, options);
}

// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.
Polyline._flat = LineUtil._flat;
<|endoftext|>


<commit_before>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 * ***************************************************************************

    In this file we extend the standard Blockly library with application-specific functionality
    that seems to be core enough to become core extension.
 */

/**
 * Returns the list of all blocks currently inserted&chained into a slot specified by slotName.
 *
 * It is way easier to iterate this way (just one call, and you always get a list, even if empty).
 */
Blockly.Block.prototype.getSlotContentsList = function(slotName) {
    var slotContentsList = [];

    var next = this.getInputTargetBlock(slotName);

    while(next) {
        slotContentsList.push( next );
        next = next.getNextBlock();
    }

    return slotContentsList;
};

/**
 * Returns the list of all statement inputs (slots) available in a block.
 */
Blockly.Block.prototype.getStatementInputNames = function() {
    var statementInputNames = [];

    for (var i = 0, input; input = this.inputList[i]; i++) {
        if(input.type == Blockly.NEXT_STATEMENT) {
            statementInputNames.push(input.name);
        }
    }

    return statementInputNames;
}

//function to toggle hide/show optiFields
function optiField_setter(newState) {
	var checkBoxFieldName=this.name.split("_checkbox")[0]; //the name of the checkbox's dummyInput

	var sourceBlock=this.sourceBlock_;
	var it = 0;
	var iplist=sourceBlock.inputList;

        //find out at which position of the inputList of sourceBlock the checkbox is present.
    while(iplist[it].name != checkBoxFieldName) {
        it++;
    }

    //if the input field has fieldRow of length, then it means that it's a single level optiField with no special label (label of the attibute/element itself is used)
    /* fieldRow indices:
     * 0 : The tree path made of unicode table-building characters
     * 1 : The checkbox
     * 2 : The text label for the field
     * 3 : The text/dropdown field
     */

    if(iplist[it].fieldRow.length == 4) {   // currently that's the way to detect a single-row optifield (bit risky)
        iplist[it].fieldRow[3].setVisible(newState);
    } else {
        it++;   // skipping the header
        while(iplist[it].name != checkBoxFieldName+"end_of_optiField") {    // and running until the footer
            if(iplist[it].fieldRow.length > 0) {    // skip the marker dummy input lines (they should always stay invisible)
                iplist[it].setVisible(newState);
                if(newState && (iplist[it].type == Blockly.NEXT_STATEMENT) ) {
                    var blockList = sourceBlock.getSlotContentsList(iplist[it].name);
                    for (var i = 0, childBlock; childBlock = blockList[i]; i++) {
                        childBlock.render();
                    }
                }
            }
            it++;
        }
    }
    sourceBlock.render();

    return newState;
}
<commit_msg>cosmetic: some renames<commit_after>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 * ***************************************************************************

    In this file we extend the standard Blockly library with application-specific functionality
    that seems to be core enough to become core extension.
 */

/**
 * Returns the list of all blocks currently inserted&chained into a slot specified by slotName.
 *
 * It is way easier to iterate this way (just one call, and you always get a list, even if empty).
 */
Blockly.Block.prototype.getSlotContentsList = function(slotName) {
    var slotContentsList = [];

    var next = this.getInputTargetBlock(slotName);

    while(next) {
        slotContentsList.push( next );
        next = next.getNextBlock();
    }

    return slotContentsList;
};

/**
 * Returns the list of all statement inputs (slots) available in a block.
 */
Blockly.Block.prototype.getStatementInputNames = function() {
    var statementInputNames = [];

    for (var i = 0, input; input = this.inputList[i]; i++) {
        if(input.type == Blockly.NEXT_STATEMENT) {
            statementInputNames.push(input.name);
        }
    }

    return statementInputNames;
}

//function to toggle hide/show optiFields
function optiField_setter(newState) {
	var checkBoxFieldName   = this.name;                                // name of the checkbox field
	var startMarker         = checkBoxFieldName.split("_checkbox")[0];  // name of the optiField's dummyInput
    var stopMarker          = startMarker +"end_of_optiField";          // name of the closing bracket

	var sourceBlock=this.sourceBlock_;
	var it = 0;
	var iplist=sourceBlock.inputList;

        //find out at which position of the inputList of sourceBlock the checkbox is present.
    while(iplist[it].name != startMarker ) {
        it++;
    }

    /*
     *  If the input field has fieldRow of length 4,
     *  then it means that it's a single level optiField with no special label
     *  (label of the attibute/element itself is used).
     *
     *  fieldRow indices:
     *      0 : The tree path made of unicode table-building characters
     *      1 : The checkbox
     *      2 : The text label for the field
     *      3 : The text/dropdown field
     */

    if(iplist[it].fieldRow.length == 4) {   // currently that's the way to detect a single-row optifield (bit risky)
        iplist[it].fieldRow[3].setVisible(newState);
    } else {
        it++;   // skipping the header
        while(iplist[it].name != stopMarker) {      // and running until the stopMarker
            if(iplist[it].fieldRow.length > 0) {    // skip the marker dummy input lines (they should always stay invisible)
                iplist[it].setVisible(newState);
                if(newState && (iplist[it].type == Blockly.NEXT_STATEMENT) ) {
                    var blockList = sourceBlock.getSlotContentsList(iplist[it].name);
                    for (var i = 0, childBlock; childBlock = blockList[i]; i++) {
                        childBlock.render();
                    }
                }
            }
            it++;
        }
    }
    sourceBlock.render();

    return newState;
}
<|endoftext|>