<commit_before>'use strict';

const Pooling = require('generic-pool');
const Promise = require('../../promise');
const _ = require('lodash');
const Utils = require('../../utils');
const debug = Utils.getLogger().debugContext('pool');
const semver = require('semver');

const defaultPoolingConfig = {
  max: 5,
  min: 0,
  idle: 10000,
  acquire: 10000,
  evict: 10000,
  handleDisconnects: true
};

/**
 * Abstract Connection Manager
 *
 * Connection manager which handles pool, replication and determining database version
 * Works with generic-pool to maintain connection pool
 *
 * @private
 */
class ConnectionManager {
  constructor(dialect, sequelize) {
    const config = _.cloneDeep(sequelize.config);

    this.sequelize = sequelize;
    this.config = config;
    this.dialect = dialect;
    this.versionPromise = null;
    this.dialectName = this.sequelize.options.dialect;

    if (config.pool === false) {
      throw new Error('Support for pool:false was removed in v4.0');
    }

    config.pool = _.defaults(config.pool || {}, defaultPoolingConfig, {
      validate: this._validate.bind(this),
      Promise
    });

    process.on('beforeExit', () => {
      this._onProcessExit.call(this);
    });

    this.initPools();
  }

  refreshTypeParser(dataTypes) {
    _.each(dataTypes, dataType => {
      if (dataType.hasOwnProperty('parse')) {
        if (dataType.types[this.dialectName]) {
          this._refreshTypeParser(dataType);
        } else {
          throw new Error('Parse function not supported for type ' + dataType.key + ' in dialect ' + this.dialectName);
        }
      }
    });
  }

  /**
   * Handler which executes on process exit or connection manager shutdown
   *
   * @private
   * @return {Promise}
   */
  _onProcessExit() {
    if (!this.pool) {
      return Promise.resolve();
    }

    return this.pool.drain().then(() => {
      debug('connection drain due to process exit');
      return this.pool.clear();
    });
  }

  /**
   * Drain the pool and close it permanently
   *
   * @return {Promise}
   */
  close() {
    // Mark close of pool
    this.getConnection = function getConnection() {
      return Promise.reject(new Error('ConnectionManager.getConnection was called after the connection manager was closed!'));
    };

    return this._onProcessExit();
  }

  /**
   * Initialize connection pool. By default pool autostart is set to false, so no connection will be
   * be created unless `pool.acquire` is called.
   */
  initPools() {
    const config = this.config;

    if (!config.replication) {
      this.pool = Pooling.createPool({
        create: () => this._connect(config).catch(err => err),
        destroy: mayBeConnection => {
          if (mayBeConnection instanceof Error) {
            return Promise.resolve();
          }

          return this._disconnect(mayBeConnection)
            .tap(() => { debug('connection destroy'); });
        },
        validate: config.pool.validate
      }, {
        Promise: config.pool.Promise,
        testOnBorrow: true,
        returnToHead: true,
        autostart: false,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        evictionRunIntervalMillis: config.pool.evict
      });

      debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, no replication`);

      return;
    }

    let reads = 0;

    if (!Array.isArray(config.replication.read)) {
      config.replication.read = [config.replication.read];
    }

    // Map main connection config
    config.replication.write = _.defaults(config.replication.write, _.omit(config, 'replication'));

    // Apply defaults to each read config
    config.replication.read = _.map(config.replication.read, readConfig =>
      _.defaults(readConfig, _.omit(this.config, 'replication'))
    );

    // custom pooling for replication (original author @janmeier)
    this.pool = {
      release: client => {
        if (client.queryType === 'read') {
          return this.pool.read.release(client);
        } else {
          return this.pool.write.release(client);
        }
      },
      acquire: (priority, queryType, useMaster) => {
        useMaster = _.isUndefined(useMaster) ? false : useMaster;
        if (queryType === 'SELECT' && !useMaster) {
          return this.pool.read.acquire(priority)
            .then(mayBeConnection => this._determineConnection(mayBeConnection));
        } else {
          return this.pool.write.acquire(priority)
            .then(mayBeConnection => this._determineConnection(mayBeConnection));
        }
      },
      destroy: mayBeConnection => {
        if (mayBeConnection instanceof Error) {
          return Promise.resolve();
        }

        return this.pool[mayBeConnection.queryType].destroy(mayBeConnection)
          .tap(() => { debug('connection destroy'); });
      },
      clear: () => {
        return Promise.join(
          this.pool.read.clear(),
          this.pool.write.clear()
        ).tap(() => { debug('all connection clear'); });
      },
      drain: () => {
        return Promise.join(
          this.pool.write.drain(),
          this.pool.read.drain()
        );
      },
      read: Pooling.createPool({
        create: () => {
          const nextRead = reads++ % config.replication.read.length; // round robin config
          return this
            ._connect(config.replication.read[nextRead])
            .tap(connection => {
              connection.queryType = 'read';
            })
            .catch(err => err);
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate
      }, {
        Promise: config.pool.Promise,
        testOnBorrow: true,
        returnToHead: true,
        autostart: false,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        evictionRunIntervalMillis: config.pool.evict
      }),
      write: Pooling.createPool({
        create: () => {
          return this
            ._connect(config.replication.write)
            .tap(connection => {
              connection.queryType = 'write';
            })
            .catch(err => err);
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate
      }, {
        Promise: config.pool.Promise,
        testOnBorrow: true,
        returnToHead: true,
        autostart: false,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        evictionRunIntervalMillis: config.pool.evict
      })
    };

    debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, with replication`);
  }

  /**
   * Get connection from pool. It sets database version if it's not already set.
   * Call pool.acquire to get a connection
   *
   * @param {Object}   [options]                 Pool options
   * @param {Integer}  [options.priority]        Set priority for this call. Read more at https://github.com/coopernurse/node-pool#priority-queueing
   * @param {String}   [options.type]            Set which replica to use. Available options are `read` and `write`
   * @param {Boolean}  [options.useMaster=false] Force master or write replica to get connection from
   *
   * @return {Promise<Connection>}
   */
  getConnection(options) {
    options = options || {};

    let promise;
    if (this.sequelize.options.databaseVersion === 0) {
      if (this.versionPromise) {
        promise = this.versionPromise;
      } else {
        promise = this.versionPromise = this._connect(this.config.replication.write || this.config)
          .then(connection => {
            const _options = {};

            _options.transaction = {connection}; // Cheat .query to use our private connection
            _options.logging = () => {};
            _options.logging.__testLoggingFn = true;

            return this.sequelize.databaseVersion(_options).then(version => {
              this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.defaultVersion;
              this.versionPromise = null;

              return this._disconnect(connection);
            });
          }).catch(err => {
            this.versionPromise = null;
            throw err;
          });
      }
    } else {
      promise = Promise.resolve();
    }

    return promise.then(() => {
      return this.pool.acquire(options.priority, options.type, options.useMaster)
        .then(mayBeConnection => this._determineConnection(mayBeConnection))
        .tap(() => { debug('connection acquired'); });
    });
  }

  /**
   * Release a pooled connection so it can be utilized by other connection requests
   *
   * @param {Connection} connection
   *
   * @return {Promise}
   */
  releaseConnection(connection) {
    return this.pool.release(connection)
      .tap(() => { debug('connection released'); })
      .catch(/Resource not currently part of this pool/, () => {});
  }

  /**
   * Check if something acquired by pool is indeed a connection but not an Error instance
   * Why we need to do this https://github.com/sequelize/sequelize/pull/8330
   *
   * @param {Object|Error} mayBeConnection Object which can be either connection or error
   *
   * @retun {Promise<Connection>}
   */
  _determineConnection(mayBeConnection) {
    if (mayBeConnection instanceof Error) {
      return Promise.resolve(this.pool.destroy(mayBeConnection))
        .catch(/Resource not currently part of this pool/, () => {})
        .then(() => { throw mayBeConnection; });
    }

    return Promise.resolve(mayBeConnection);
  }

  /**
   * Call dialect library to get connection
   *
   * @param {*} config Connection config
   * @private
   * @return {Promise<Connection>}
   */
  _connect(config) {
    return this.sequelize.runHooks('beforeConnect', config)
      .then(() => this.dialect.connectionManager.connect(config))
      .then(connection => this.sequelize.runHooks('afterConnect', connection, config).return(connection));
  }

  /**
   * Call dialect library to disconnect a connection
   *
   * @param {Connection} connection
   * @private
   * @return {Promise}
   */
  _disconnect(connection) {
    return this.dialect.connectionManager.disconnect(connection);
  }

  /**
   * Determine if a connection is still valid or not
   *
   * @param {Connection} connection
   *
   * @return {Boolean}
   */
  _validate(connection) {
    if (!this.dialect.connectionManager.validate) {
      return true;
    }

    return this.dialect.connectionManager.validate(connection);
  }
}

module.exports = ConnectionManager;
module.exports.ConnectionManager = ConnectionManager;
module.exports.default = ConnectionManager;
<commit_msg>fix(connection-manager): only use close to shutdown (#8789)<commit_after>'use strict';

const Pooling = require('generic-pool');
const Promise = require('../../promise');
const _ = require('lodash');
const Utils = require('../../utils');
const debug = Utils.getLogger().debugContext('pool');
const semver = require('semver');

const defaultPoolingConfig = {
  max: 5,
  min: 0,
  idle: 10000,
  acquire: 10000,
  evict: 10000,
  handleDisconnects: true
};

/**
 * Abstract Connection Manager
 *
 * Connection manager which handles pool, replication and determining database version
 * Works with generic-pool to maintain connection pool
 *
 * @private
 */
class ConnectionManager {
  constructor(dialect, sequelize) {
    const config = _.cloneDeep(sequelize.config);

    this.sequelize = sequelize;
    this.config = config;
    this.dialect = dialect;
    this.versionPromise = null;
    this.dialectName = this.sequelize.options.dialect;

    if (config.pool === false) {
      throw new Error('Support for pool:false was removed in v4.0');
    }

    config.pool = _.defaults(config.pool || {}, defaultPoolingConfig, {
      validate: this._validate.bind(this),
      Promise
    });

    this.initPools();
  }

  refreshTypeParser(dataTypes) {
    _.each(dataTypes, dataType => {
      if (dataType.hasOwnProperty('parse')) {
        if (dataType.types[this.dialectName]) {
          this._refreshTypeParser(dataType);
        } else {
          throw new Error('Parse function not supported for type ' + dataType.key + ' in dialect ' + this.dialectName);
        }
      }
    });
  }

  /**
   * Handler which executes on process exit or connection manager shutdown
   *
   * @private
   * @return {Promise}
   */
  _onProcessExit() {
    if (!this.pool) {
      return Promise.resolve();
    }

    return this.pool.drain().then(() => {
      debug('connection drain due to process exit');
      return this.pool.clear();
    });
  }

  /**
   * Drain the pool and close it permanently
   *
   * @return {Promise}
   */
  close() {
    // Mark close of pool
    this.getConnection = function getConnection() {
      return Promise.reject(new Error('ConnectionManager.getConnection was called after the connection manager was closed!'));
    };

    return this._onProcessExit();
  }

  /**
   * Initialize connection pool. By default pool autostart is set to false, so no connection will be
   * be created unless `pool.acquire` is called.
   */
  initPools() {
    const config = this.config;

    if (!config.replication) {
      this.pool = Pooling.createPool({
        create: () => this._connect(config).catch(err => err),
        destroy: mayBeConnection => {
          if (mayBeConnection instanceof Error) {
            return Promise.resolve();
          }

          return this._disconnect(mayBeConnection)
            .tap(() => { debug('connection destroy'); });
        },
        validate: config.pool.validate
      }, {
        Promise: config.pool.Promise,
        testOnBorrow: true,
        returnToHead: true,
        autostart: false,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        evictionRunIntervalMillis: config.pool.evict
      });

      debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, no replication`);

      return;
    }

    let reads = 0;

    if (!Array.isArray(config.replication.read)) {
      config.replication.read = [config.replication.read];
    }

    // Map main connection config
    config.replication.write = _.defaults(config.replication.write, _.omit(config, 'replication'));

    // Apply defaults to each read config
    config.replication.read = _.map(config.replication.read, readConfig =>
      _.defaults(readConfig, _.omit(this.config, 'replication'))
    );

    // custom pooling for replication (original author @janmeier)
    this.pool = {
      release: client => {
        if (client.queryType === 'read') {
          return this.pool.read.release(client);
        } else {
          return this.pool.write.release(client);
        }
      },
      acquire: (priority, queryType, useMaster) => {
        useMaster = _.isUndefined(useMaster) ? false : useMaster;
        if (queryType === 'SELECT' && !useMaster) {
          return this.pool.read.acquire(priority)
            .then(mayBeConnection => this._determineConnection(mayBeConnection));
        } else {
          return this.pool.write.acquire(priority)
            .then(mayBeConnection => this._determineConnection(mayBeConnection));
        }
      },
      destroy: mayBeConnection => {
        if (mayBeConnection instanceof Error) {
          return Promise.resolve();
        }

        return this.pool[mayBeConnection.queryType].destroy(mayBeConnection)
          .tap(() => { debug('connection destroy'); });
      },
      clear: () => {
        return Promise.join(
          this.pool.read.clear(),
          this.pool.write.clear()
        ).tap(() => { debug('all connection clear'); });
      },
      drain: () => {
        return Promise.join(
          this.pool.write.drain(),
          this.pool.read.drain()
        );
      },
      read: Pooling.createPool({
        create: () => {
          const nextRead = reads++ % config.replication.read.length; // round robin config
          return this
            ._connect(config.replication.read[nextRead])
            .tap(connection => {
              connection.queryType = 'read';
            })
            .catch(err => err);
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate
      }, {
        Promise: config.pool.Promise,
        testOnBorrow: true,
        returnToHead: true,
        autostart: false,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        evictionRunIntervalMillis: config.pool.evict
      }),
      write: Pooling.createPool({
        create: () => {
          return this
            ._connect(config.replication.write)
            .tap(connection => {
              connection.queryType = 'write';
            })
            .catch(err => err);
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate
      }, {
        Promise: config.pool.Promise,
        testOnBorrow: true,
        returnToHead: true,
        autostart: false,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        evictionRunIntervalMillis: config.pool.evict
      })
    };

    debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, with replication`);
  }

  /**
   * Get connection from pool. It sets database version if it's not already set.
   * Call pool.acquire to get a connection
   *
   * @param {Object}   [options]                 Pool options
   * @param {Integer}  [options.priority]        Set priority for this call. Read more at https://github.com/coopernurse/node-pool#priority-queueing
   * @param {String}   [options.type]            Set which replica to use. Available options are `read` and `write`
   * @param {Boolean}  [options.useMaster=false] Force master or write replica to get connection from
   *
   * @return {Promise<Connection>}
   */
  getConnection(options) {
    options = options || {};

    let promise;
    if (this.sequelize.options.databaseVersion === 0) {
      if (this.versionPromise) {
        promise = this.versionPromise;
      } else {
        promise = this.versionPromise = this._connect(this.config.replication.write || this.config)
          .then(connection => {
            const _options = {};

            _options.transaction = {connection}; // Cheat .query to use our private connection
            _options.logging = () => {};
            _options.logging.__testLoggingFn = true;

            return this.sequelize.databaseVersion(_options).then(version => {
              this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.defaultVersion;
              this.versionPromise = null;

              return this._disconnect(connection);
            });
          }).catch(err => {
            this.versionPromise = null;
            throw err;
          });
      }
    } else {
      promise = Promise.resolve();
    }

    return promise.then(() => {
      return this.pool.acquire(options.priority, options.type, options.useMaster)
        .then(mayBeConnection => this._determineConnection(mayBeConnection))
        .tap(() => { debug('connection acquired'); });
    });
  }

  /**
   * Release a pooled connection so it can be utilized by other connection requests
   *
   * @param {Connection} connection
   *
   * @return {Promise}
   */
  releaseConnection(connection) {
    return this.pool.release(connection)
      .tap(() => { debug('connection released'); })
      .catch(/Resource not currently part of this pool/, () => {});
  }

  /**
   * Check if something acquired by pool is indeed a connection but not an Error instance
   * Why we need to do this https://github.com/sequelize/sequelize/pull/8330
   *
   * @param {Object|Error} mayBeConnection Object which can be either connection or error
   *
   * @retun {Promise<Connection>}
   */
  _determineConnection(mayBeConnection) {
    if (mayBeConnection instanceof Error) {
      return Promise.resolve(this.pool.destroy(mayBeConnection))
        .catch(/Resource not currently part of this pool/, () => {})
        .then(() => { throw mayBeConnection; });
    }

    return Promise.resolve(mayBeConnection);
  }

  /**
   * Call dialect library to get connection
   *
   * @param {*} config Connection config
   * @private
   * @return {Promise<Connection>}
   */
  _connect(config) {
    return this.sequelize.runHooks('beforeConnect', config)
      .then(() => this.dialect.connectionManager.connect(config))
      .then(connection => this.sequelize.runHooks('afterConnect', connection, config).return(connection));
  }

  /**
   * Call dialect library to disconnect a connection
   *
   * @param {Connection} connection
   * @private
   * @return {Promise}
   */
  _disconnect(connection) {
    return this.dialect.connectionManager.disconnect(connection);
  }

  /**
   * Determine if a connection is still valid or not
   *
   * @param {Connection} connection
   *
   * @return {Boolean}
   */
  _validate(connection) {
    if (!this.dialect.connectionManager.validate) {
      return true;
    }

    return this.dialect.connectionManager.validate(connection);
  }
}

module.exports = ConnectionManager;
module.exports.ConnectionManager = ConnectionManager;
module.exports.default = ConnectionManager;
<|endoftext|>


<commit_before>(function(window){

    function anything() {

        this.version = "0.0.1"

    }

    //Functions go here
    var doTheThing = function() {
        var test = 1+1;

        console.log(test);
        console.log('Thing is done');
    };

    var flipText = function(text)
    {
        var flipDict={'A':'∀','B':'𐐒','C':'Ɔ','E':'Ǝ','F':'Ⅎ','G':'פ','H':'H','I':'I','J':'ſ','L':'˥','M':'W','N':'N','P':'Ԁ','R':'ᴚ','T':'⊥','U':'∩','V':'Λ','Y':'⅄','a':'ɐ','b':'q','c':'ɔ','d':'p','e':'ǝ','f':'ɟ','g':'ƃ','h':'ɥ','i':'ᴉ','j':'ɾ','k':'ʞ','m':'ɯ','n':'u','p':'d','q':'b','r':'ɹ','t':'ʇ','u':'n','v':'ʌ','w':'ʍ','y':'ʎ','1':'Ɩ','2':'ᄅ','3':'Ɛ','4':'ㄣ','5':'ϛ','6':'9','7':'ㄥ','8':'8','9':'6','0':'0','.':'˙',',':'\'','\'':',','"':',,','`':',','<':'>','>':'<','∴':'∵','&':'⅋','_':'‾','?':'¿','!':'¡','[':']',']':'[','(':')',')':'(','{':'}','}':'{'};
        for (var i in flipDict) {
            flipDict[flipDict[i]] = i
        }
        var r = []
        for (var ix = 0; ix < text.length; ix++) {
            var c = text.charAt(ix)
            var f = flipDict[c]
            r.push(typeof f != 'undefined'? f : c);
        }
        return r.reverse().join('');
    }

    var getOffMyLawn = function(message)
    {
        alert(message);
    }

    var greetHannah = function()
    {
        alert("Hey. Uhh.. Hello.")
    }

    //prototypes go here
    anything.prototype.doTheThing = doTheThing;
    anything.prototype.flipText = flipText;
    anything.prototype.getOffMyLawn = getOffMyLawn;
    anything.prototype.greetHannah = greetHannah;

    //put that shit where everyone can see it.
    if(typeof(window.Δ) === 'undefined'){
        window.Δ = new anything();
    }
    else{
        console.log("Δ already defined.");
    }
})(window);
<commit_msg>Added a random function, returns a random integer<commit_after>(function(window){

    function anything() {

        this.version = "0.0.1"

    }

    //Functions go here
    var doTheThing = function() {
        var test = 1+1;

        console.log(test);
        console.log('Thing is done');
    };

    var flipText = function(text)
    {
        var flipDict={'A':'∀','B':'𐐒','C':'Ɔ','E':'Ǝ','F':'Ⅎ','G':'פ','H':'H','I':'I','J':'ſ','L':'˥','M':'W','N':'N','P':'Ԁ','R':'ᴚ','T':'⊥','U':'∩','V':'Λ','Y':'⅄','a':'ɐ','b':'q','c':'ɔ','d':'p','e':'ǝ','f':'ɟ','g':'ƃ','h':'ɥ','i':'ᴉ','j':'ɾ','k':'ʞ','m':'ɯ','n':'u','p':'d','q':'b','r':'ɹ','t':'ʇ','u':'n','v':'ʌ','w':'ʍ','y':'ʎ','1':'Ɩ','2':'ᄅ','3':'Ɛ','4':'ㄣ','5':'ϛ','6':'9','7':'ㄥ','8':'8','9':'6','0':'0','.':'˙',',':'\'','\'':',','"':',,','`':',','<':'>','>':'<','∴':'∵','&':'⅋','_':'‾','?':'¿','!':'¡','[':']',']':'[','(':')',')':'(','{':'}','}':'{'};
        for (var i in flipDict) {
            flipDict[flipDict[i]] = i
        }
        var r = []
        for (var ix = 0; ix < text.length; ix++) {
            var c = text.charAt(ix)
            var f = flipDict[c]
            r.push(typeof f != 'undefined'? f : c);
        }
        return r.reverse().join('');
    }

    var getOffMyLawn = function(message)
    {
        alert(message);
    }

    var greetHannah = function()
    {
        alert("Hey. Uhh.. Hello.")
    }

    var getRandomNumber = function ()
    {
        return 4; // chosen by fair dice roll
                  // guaranteed to be random
    }

    //prototypes go here
    anything.prototype.doTheThing = doTheThing;
    anything.prototype.flipText = flipText;
    anything.prototype.getOffMyLawn = getOffMyLawn;
    anything.prototype.greetHannah = greetHannah;
    anything.prototype.getRandomNumber = getRandomNumber;

    //put that shit where everyone can see it.
    if(typeof(window.Δ) === 'undefined'){
        window.Δ = new anything();
    }
    else{
        console.log("Δ already defined.");
    }
})(window);
<|endoftext|>


<commit_before>/**
 *                        WHITEBOPHIR
 *********************************************************
 * @licstart  The following is the entire license notice for the
 *  JavaScript code in this page.
 *
 * Copyright (C) 2013  Ophir LOJKINE
 *
 *
 * The JavaScript code in this page is free software: you can
 * redistribute it and/or modify it under the terms of the GNU
 * General Public License (GNU GPL) as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version.  The code is distributed WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 * As additional permission under GNU GPL version 3 section 7, you
 * may distribute non-source (e.g., minimized or compacted) forms of
 * that code without the copy of the GNU GPL normally required by
 * section 4, provided you include this license notice and a URL
 * through which recipients can access the Corresponding Source.
 *
 * @licend
 */

(function () { //Code isolation
    var ZOOM_FACTOR = .5;
    var origin = {
        scrollX: document.documentElement.scrollLeft,
        scrollY: document.documentElement.scrollTop,
        x: 0.0,
        y: 0.0,
        clientY: 0,
        scale: 1.0
    };
    var moved = false, pressed = false;

    function zoom(origin, scale) {
        var oldScale = origin.scale;
        var newScale = Tools.setScale(scale);
        window.scrollTo(
            origin.scrollX + origin.x * (newScale - oldScale),
            origin.scrollY + origin.y * (newScale - oldScale)
        );
    }

    var animation = null;
    function animate(scale) {
        cancelAnimationFrame(animation);
        animation = requestAnimationFrame(function () {
            zoom(origin, scale);
        });
    }

    function setOrigin(x, y, evt, isTouchEvent) {
        origin.scrollX = document.documentElement.scrollLeft;
        origin.scrollY = document.documentElement.scrollTop;
        origin.x = x;
        origin.y = y;
        origin.clientY = getClientY(evt, isTouchEvent);
        origin.scale = Tools.getScale();
    }

    function press(x, y, evt, isTouchEvent) {
        evt.preventDefault();
        setOrigin(x, y, evt, isTouchEvent);
        moved = false;
        pressed = true;
    }

    function move(x, y, evt, isTouchEvent) {
        if (pressed) {
            evt.preventDefault();
            var delta = getClientY(evt, isTouchEvent) - origin.clientY;
            var scale = origin.scale * (1 + delta * ZOOM_FACTOR / 100);
            if (Math.abs(delta) > 1) moved = true;
            animation = animate(scale);
        }
    }

    function onwheel(evt) {
        evt.preventDefault();
        if (evt.ctrlKey || Tools.curTool === zoomTool) {
            // zoom
            var scale = Tools.getScale();
            var x = evt.pageX / scale;
            var y = evt.pageY / scale;
            setOrigin(x, y, evt, false);
            animate((1 - ((evt.deltaY > 0) - (evt.deltaY < 0)) * 0.25) * Tools.getScale());
        } else if (evt.altKey) {
            // make finer changes if shift is being held
            var change = evt.shiftKey ? 1 : 5;
            // change tool size
            Tools.setSize(Tools.getSize() - ((evt.deltaY > 0) - (evt.deltaY < 0)) * change);
        } else if (evt.shiftKey) {
            // scroll horizontally
            window.scrollTo(document.documentElement.scrollLeft + evt.deltaY, document.documentElement.scrollTop + evt.deltaX);
        } else {
            // regular scrolling
            window.scrollTo(document.documentElement.scrollLeft + evt.deltaX, document.documentElement.scrollTop + evt.deltaY);
        }
    }
    Tools.board.addEventListener("wheel", onwheel, { passive: false });

    Tools.board.addEventListener("touchmove", function ontouchmove(evt) {
        // 2-finger pan to zoom
        var touches = evt.touches;
        if (touches.length === 2) {
            var x0 = touches[0].clientX, x1 = touches[1].clientX,
                y0 = touches[0].clientY, y1 = touches[1].clientY,
                dx = x0 - x1,
                dy = y0 - y1;
            var x = (touches[0].pageX + touches[1].pageX) / 2 / Tools.getScale(),
                y = (touches[0].pageY + touches[1].pageY) / 2 / Tools.getScale();
            var distance = Math.sqrt(dx * dx + dy * dy);
            if (!pressed) {
                pressed = true;
                setOrigin(x, y, evt, true);
                origin.distance = distance;
            } else {
                var delta = distance - origin.distance;
                var scale = origin.scale * (1 + delta * ZOOM_FACTOR / 100);
                animate(scale);
            }
        }
    }, { passive: true });
    function touchend() {
        pressed = false;
    }
    Tools.board.addEventListener("touchend", touchend);
    Tools.board.addEventListener("touchcancel", touchend);

    function release(x, y, evt, isTouchEvent) {
        if (pressed && !moved) {
            var delta = (evt.shiftKey === true) ? -1 : 1;
            var scale = Tools.getScale() * (1 + delta * ZOOM_FACTOR);
            zoom(origin, scale);
        }
        pressed = false;
    }

    function key(down) {
        return function (evt) {
            if (evt.key === "Shift") {
                Tools.svg.style.cursor = "zoom-" + (down ? "out" : "in");
            }
        }
    }

    function getClientY(evt, isTouchEvent) {
        return isTouchEvent ? evt.changedTouches[0].clientY : evt.clientY;
    }

    var keydown = key(true);
    var keyup = key(false);

    function onstart() {
        window.addEventListener("keydown", keydown);
        window.addEventListener("keyup", keyup);
    }
    function onquit() {
        window.removeEventListener("keydown", keydown);
        window.removeEventListener("keyup", keyup);
    }

    var zoomTool = {
        "name": "Zoom",
		"shortcut": "z",
        "listeners": {
            "press": press,
            "move": move,
            "release": release,
        },
        "onstart": onstart,
        "onquit": onquit,
        "mouseCursor": "zoom-in",
        "icon": "tools/zoom/icon.svg",
        "helpText": "click_to_zoom",
        "showMarker": true,
    };
    Tools.add(zoomTool);
})(); //End of code isolation
<commit_msg>Use mouse wheel to zoom by default<commit_after>/**
 *                        WHITEBOPHIR
 *********************************************************
 * @licstart  The following is the entire license notice for the
 *  JavaScript code in this page.
 *
 * Copyright (C) 2013  Ophir LOJKINE
 *
 *
 * The JavaScript code in this page is free software: you can
 * redistribute it and/or modify it under the terms of the GNU
 * General Public License (GNU GPL) as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version.  The code is distributed WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 * As additional permission under GNU GPL version 3 section 7, you
 * may distribute non-source (e.g., minimized or compacted) forms of
 * that code without the copy of the GNU GPL normally required by
 * section 4, provided you include this license notice and a URL
 * through which recipients can access the Corresponding Source.
 *
 * @licend
 */

(function () { //Code isolation
    var ZOOM_FACTOR = .5;
    var origin = {
        scrollX: document.documentElement.scrollLeft,
        scrollY: document.documentElement.scrollTop,
        x: 0.0,
        y: 0.0,
        clientY: 0,
        scale: 1.0
    };
    var moved = false, pressed = false;

    function zoom(origin, scale) {
        var oldScale = origin.scale;
        var newScale = Tools.setScale(scale);
        window.scrollTo(
            origin.scrollX + origin.x * (newScale - oldScale),
            origin.scrollY + origin.y * (newScale - oldScale)
        );
    }

    var animation = null;
    function animate(scale) {
        cancelAnimationFrame(animation);
        animation = requestAnimationFrame(function () {
            zoom(origin, scale);
        });
    }

    function setOrigin(x, y, evt, isTouchEvent) {
        origin.scrollX = document.documentElement.scrollLeft;
        origin.scrollY = document.documentElement.scrollTop;
        origin.x = x;
        origin.y = y;
        origin.clientY = getClientY(evt, isTouchEvent);
        origin.scale = Tools.getScale();
    }

    function press(x, y, evt, isTouchEvent) {
        evt.preventDefault();
        setOrigin(x, y, evt, isTouchEvent);
        moved = false;
        pressed = true;
    }

    function move(x, y, evt, isTouchEvent) {
        if (pressed) {
            evt.preventDefault();
            var delta = getClientY(evt, isTouchEvent) - origin.clientY;
            var scale = origin.scale * (1 + delta * ZOOM_FACTOR / 100);
            if (Math.abs(delta) > 1) moved = true;
            animation = animate(scale);
        }
    }

    function onwheel(evt) {
        evt.preventDefault();
        if (!evt.ctrlKey) {
            // zoom
            var scale = Tools.getScale();
            var x = evt.pageX / scale;
            var y = evt.pageY / scale;
            setOrigin(x, y, evt, false);
            animate((1 - ((evt.deltaY > 0) - (evt.deltaY < 0)) * 0.25) * Tools.getScale());
        } else if (evt.altKey) {
            // make finer changes if shift is being held
            var change = evt.shiftKey ? 1 : 5;
            // change tool size
            Tools.setSize(Tools.getSize() - ((evt.deltaY > 0) - (evt.deltaY < 0)) * change);
        } else if (evt.shiftKey) {
            // scroll horizontally
            window.scrollTo(document.documentElement.scrollLeft + evt.deltaY, document.documentElement.scrollTop + evt.deltaX);
        } else {
            // regular scrolling
            window.scrollTo(document.documentElement.scrollLeft + evt.deltaX, document.documentElement.scrollTop + evt.deltaY);
        }
    }
    Tools.board.addEventListener("wheel", onwheel, { passive: false });

    Tools.board.addEventListener("touchmove", function ontouchmove(evt) {
        // 2-finger pan to zoom
        var touches = evt.touches;
        if (touches.length === 2) {
            var x0 = touches[0].clientX, x1 = touches[1].clientX,
                y0 = touches[0].clientY, y1 = touches[1].clientY,
                dx = x0 - x1,
                dy = y0 - y1;
            var x = (touches[0].pageX + touches[1].pageX) / 2 / Tools.getScale(),
                y = (touches[0].pageY + touches[1].pageY) / 2 / Tools.getScale();
            var distance = Math.sqrt(dx * dx + dy * dy);
            if (!pressed) {
                pressed = true;
                setOrigin(x, y, evt, true);
                origin.distance = distance;
            } else {
                var delta = distance - origin.distance;
                var scale = origin.scale * (1 + delta * ZOOM_FACTOR / 100);
                animate(scale);
            }
        }
    }, { passive: true });
    function touchend() {
        pressed = false;
    }
    Tools.board.addEventListener("touchend", touchend);
    Tools.board.addEventListener("touchcancel", touchend);

    function release(x, y, evt, isTouchEvent) {
        if (pressed && !moved) {
            var delta = (evt.shiftKey === true) ? -1 : 1;
            var scale = Tools.getScale() * (1 + delta * ZOOM_FACTOR);
            zoom(origin, scale);
        }
        pressed = false;
    }

    function key(down) {
        return function (evt) {
            if (evt.key === "Shift") {
                Tools.svg.style.cursor = "zoom-" + (down ? "out" : "in");
            }
        }
    }

    function getClientY(evt, isTouchEvent) {
        return isTouchEvent ? evt.changedTouches[0].clientY : evt.clientY;
    }

    var keydown = key(true);
    var keyup = key(false);

    function onstart() {
        window.addEventListener("keydown", keydown);
        window.addEventListener("keyup", keyup);
    }
    function onquit() {
        window.removeEventListener("keydown", keydown);
        window.removeEventListener("keyup", keyup);
    }

    var zoomTool = {
        "name": "Zoom",
		"shortcut": "z",
        "listeners": {
            "press": press,
            "move": move,
            "release": release,
        },
        "onstart": onstart,
        "onquit": onquit,
        "mouseCursor": "zoom-in",
        "icon": "tools/zoom/icon.svg",
        "helpText": "click_to_zoom",
        "showMarker": true,
    };
    Tools.add(zoomTool);
})(); //End of code isolation
<|endoftext|>


<commit_before>var _ = require("underscore");
var Backbone = require("backbone");

var StreamSaveModel = require("models").StreamSaveModel;
var utils = require("utils");

var DAG = require("./../../conceptviz/js/DAG").DAG;

/********************************************************************************
*  Creator Models:
*
*
*********************************************************************************/

var CourseModel = StreamSaveModel.extend({

    defaults: {
        name: "",
        isPublished: false
    },

    BASE_URL: "/api/v1/courses/",

    url: function() {
        if(this.isNew()) {
            return this.BASE_URL;
        }
        return "{0}{1}/".format(this.BASE_URL, this.id);
    },

    studentURL: function() {
        utils.assert(this.attributes.slug, "Slug not found");
        return "#/{0}/".format(this.attributes.slug);
    },

    creatorURL: function() {
        var base = "/creator/course/";
        var url;
        if(this.attributes.isPublished) {
            url = "{0}{1}/".format(base, this.attributes.slug);
        }
        else {
            url = "{0}{1}/".format(base, this.attributes.id);
        }
        return url;
    }
});

var ConceptModel = Backbone.Model.extend({

    parse: function(attrs) {
        attrs.url = "/#creator/concept/{0}/".format(attrs.id);
        return attrs;
    }
});

var ConceptCollection = Backbone.Collection.extend({

    initialize: function(options) {
        this.course = options.course;
        this.dag = options.dag;
    },

    model: ConceptModel,

    url: function() {
        return "{0}concepts/".format(this.course.url())
    },

    parse: function(concepts) {
        _.each(concepts, function(c) {
            this.dag.addNode(c);
        }, this);

        return concepts;
    }
});

var DependencyModel = Backbone.Model.extend({

});

var DependencyCollection = Backbone.Collection.extend({

    model: DependencyModel,

    initialize: function(options) {
        this.course = options.course;
        this.dag = options.dag;
    },

    url: function() {
        return "{0}dependencies/".format(this.course.url());
    },

    //from is a keyword in Python, so I'm using start and end on the server
    //todo -> change client code to start and end as well.
    parse: function(response) {

        var deps = [];
        _.each(response, function(d) {
            deps.push({
                from: d.start,
                to: d.end
            });
        });
        return deps;
    },

    initializeDAG: function() {
        _.each(this.toJSON(), function(dep) {
            this.dag.addEdge(dep.from, dep.to);
        }, this);
    }
});

var PretestModel = Backbone.Model.extend({

    url: function() {
        return "/api/v1/courses/{0}/pretest/".format(this.attributes.id);
    },

    getConceptQuiz: function(conceptId) {
        return this.attributes[conceptId];
    },

});

/********************************************************************************
*  Creator Store:
*
*
*********************************************************************************/

var CreatorStore = function(options) {

    if(!options.hasOwnProperty("setRoute")) {
        options.setRoute = true;
    }
    this.options = options;

    this.dag = new DAG({});

    this._course = new CourseModel(options);
    this._concepts = new ConceptCollection({course: this._course, dag: this.dag});
    this._dependencies = new DependencyCollection({course: this._course, dag: this.dag});

    if(this._course.isNew()) {
        this._course.once("sync", this.setRoute, this);
    }
    this.listenToEvents();
    window.course = this._course;
};

CreatorStore.prototype = {

    listenToEvents: function() {
        this._course.on("sync", this.onCourseSynced, this);
    },

    cleanup: function() {
        this._course.off("sync", this.onCourseSynced);
    },

    getName: function() {
        return this._course.get("name");
    },

    setName: function(name) {
        this._course.set("name", name);
        this._course.save();
    },

    isPublished: function() {
        return this._course.attributes.isPublished;
    },

    getStudentURL: function() {
        return this._course.studentURL();
    },

    togglePublish: function() {
        var isPublished = !this.isPublished();
        this._course.set({
            isPublished: isPublished
        });

        var self = this;
        this._isPublishedChanged = true;
        this._course.save();
    },

    onCourseSynced: function() {
        if(!this._isPublishedChanged) {
            return;
        }
        this.setRoute(true);
        this._isPublishedChanged = false;
        this.trigger("change:isPublished", this.isPublished(), this);
    },

    getConcepts: function() {
        return this._concepts.toJSON();
    },

    addConcept: function(concept) {

        var model = this._concepts.add(concept);
        var self = this;

        var onSaved = function() {
            self.trigger("add:concept", concept, self);
        }
        if(model.isNew()) {
            model.save().then(onSaved);
        }
        else {
            onSaved();
        }
    },

    addDependency: function(from, to) {

        var edge = {
            from: from,
            to: to
        };

        var nodesByLevel;
        try {
            this.dag.addEdge(from, to);
            nodesByLevel = this.dag.sort();
        } catch (e) {
            this.dag.removeEdge(from, to);
            return false;
        }

        var model = this._dependencies.add(edge);
        var self = this;
        var onSaved = function() {
            var edges = self.dag.getEdges();
            var graph = {
                levels: nodesByLevel,
                edges: edges
            }
            self.trigger("add:dependency", graph, edge);
        };

        if(model.isNew()) {
            model.save().then(onSaved);
        }
        else {
            onSaved();
        }

        return true;
    },

    getRootConcept: function() {

        var graph = this.getGraph();
        var levels = graph.levels;
        if(!levels.length) {
            return null;
        }
        return levels[0][0];
    },

    getConceptURL: function(conceptSlug) {
        return "{0}{1}/".format(this._course.studentURL(), conceptSlug);
    },

    getGraph: function() {
        return {
            levels: this.dag.sort(),
            edges: this.dag.getEdges()
        };
    },

    fetch: function() {

        if(this._course.isNew()) {
            return $.Deferred().resolve().promise()
        }

        var one = this._course.fetch();
        var two = this._concepts.fetch();
        var three = this._dependencies.fetch();

        var promises = [one, two, three];

        var self = this;
        var fetchedPromise = $.when.apply($, promises);
        fetchedPromise.then(function() {
            self._dependencies.initializeDAG();
            self.setRoute(true);
        });

        return fetchedPromise;

    },

    setRoute: function(replace) {

        if(!this.options.setRoute) {
            return;
        }
        replace = replace || false;
        var url = this._course.creatorURL();
        Backbone.history.navigate(url, {trigger: false, replace: replace});
    }

};

_.extend(CreatorStore.prototype, Backbone.Events);
CreatorStore.prototype.constructor = CreatorStore;

/********************************************************************************
*  Student Models and Stores
*
*
*********************************************************************************/

var ProgressModel = Backbone.Model.extend({

    url: function() {
        return "/api/v1/courses/{0}/student-progress/".format(this.attributes.id);
    },

    isNew: function() {

        var keys = Object.keys(this.attributes);
        var length = keys.length;
        for(var i = 0; i < length; i++) {
            var progress = this.attributes[keys[i]];
            if(progress.answered > 0) {
                return false;
            }
        }
        return true;
    },

    parse: function(response) {
        _.each(response, function(attrs, id) {
            attrs.progress = this.calculateProgress(attrs.answered, attrs.total);
        }, this);
        return response;
    },

    calculateProgress: function(answered, total) {
        if(total === 0) {
            return 1;
        }
        return answered / total;
    }

});

var StudentStates = {

    NEW_VISITOR: 0,

    COMPLETELY_NEW: 1,

    PRETEST: 2,

    DASHBOARD: 3

};

var StudentStore = function(options) {

    this._channel = options.channel || this;

    this._progress = new ProgressModel({
        id: options.id
    });

    if(this.getState() === null) {
        this.setState(StudentStates.NEW_VISITOR);
    }

};

StudentStore.prototype = {

    STATE_KEY: "student:course:state",

    SKILL_ESTIMATION_KEY: "student:course:skill-estimation",

    /**
     * set student state. Use the number code, not the name
     * @param {int} state
     */
    setState: function(state) {
        this._storeInteger(this.STATE_KEY, state);
        this._channel.trigger("change:state", state, this);
    },

    /**
     * @return {Number}
     */
    getState: function() {
        return this._loadInteger(this.STATE_KEY);
    },

    /**
     * Use the number code, not the name
     * @param {int} level
     */
    setSkillEstimationLevel: function(level) {
        this._storeInteger(this.SKILL_ESTIMATION_KEY, level);
    },

    /**
     * @return {Number}
     */
    getSkillEstimationLevel: function() {
        return this._loadInteger(this.SKILL_ESTIMATION_KEY);
    },

    _storeInteger: function(key, value) {
        localStorage.setItem(key, value);
    },

    _loadInteger: function(key) {
        var value = localStorage.getItem(key);
        if(value === null) {
            return value;
        };
        return parseInt(value);
    },

    /**
    * Get number of questions attempted, total number of questions and progress
    * in each concept.
    * Example:
    *   {
    *        "id": "awesome",
    *        "d597a0f8-ba60-45fe-819c-6a7aa0210d6a": {
    *            "total": 4,
    *            "answered": 2,
    *            "progress": 0.5
    *        },
    *        "906be0d8-aaa0-458b-ab04-6330f956975f": {
    *            "total": 5,
    *            "answered": 2,
    *            "progress": 0.4
    *        },
    *        "92416f00-2228-4799-8caa-d7cb27286eef": {
    *            "total": 1,
    *            "answered": 1,
    *            "progress": 1
    *        }
    *    }
    * @return {object}
    */
    getProgress: function() {
        return this._progress.toJSON();
    },

    /**
    *  1. Fetch student progress
    *  2. Return a promise that is resolved after step 3
    *  3. If the student has answered at least one quiz correctly, show dashboard
    *  @return {Promise}
    */
    fetch: function() {

        var self = this;
        return this._progress.fetch().then(function() {
            if(!self._progress.isNew()) {
                self.setState(StudentStates.DASHBOARD);
            }
        });
    }
};

StudentStore.prototype.constructor = StudentStore;
_.extend(StudentStore.prototype, Backbone.Events);

module.exports = {
    CreatorStore, CreatorStore,
    StudentStore: StudentStore,
    PretestModel: PretestModel,
    StudentStates: StudentStates
};
<commit_msg>Course Creator: Fixed bug where new concepts were not added to the DAG.<commit_after>var _ = require("underscore");
var Backbone = require("backbone");

var StreamSaveModel = require("models").StreamSaveModel;
var utils = require("utils");

var DAG = require("./../../conceptviz/js/DAG").DAG;

/********************************************************************************
*  Creator Models:
*
*
*********************************************************************************/

var CourseModel = StreamSaveModel.extend({

    defaults: {
        name: "",
        isPublished: false
    },

    BASE_URL: "/api/v1/courses/",

    url: function() {
        if(this.isNew()) {
            return this.BASE_URL;
        }
        return "{0}{1}/".format(this.BASE_URL, this.id);
    },

    studentURL: function() {
        utils.assert(this.attributes.slug, "Slug not found");
        return "#/{0}/".format(this.attributes.slug);
    },

    creatorURL: function() {
        var base = "/creator/course/";
        var url;
        if(this.attributes.isPublished) {
            url = "{0}{1}/".format(base, this.attributes.slug);
        }
        else {
            url = "{0}{1}/".format(base, this.attributes.id);
        }
        return url;
    }
});

var ConceptModel = Backbone.Model.extend({

    parse: function(attrs) {
        attrs.url = "/#creator/concept/{0}/".format(attrs.id);
        return attrs;
    }
});

var ConceptCollection = Backbone.Collection.extend({

    initialize: function(options) {
        this.course = options.course;
        this.dag = options.dag;
    },

    model: ConceptModel,

    url: function() {
        return "{0}concepts/".format(this.course.url())
    },

    parse: function(concepts) {
        _.each(concepts, function(c) {
            this.dag.addNode(c);
        }, this);

        return concepts;
    }
});

var DependencyModel = Backbone.Model.extend({

});

var DependencyCollection = Backbone.Collection.extend({

    model: DependencyModel,

    initialize: function(options) {
        this.course = options.course;
        this.dag = options.dag;
    },

    url: function() {
        return "{0}dependencies/".format(this.course.url());
    },

    //from is a keyword in Python, so I'm using start and end on the server
    //todo -> change client code to start and end as well.
    parse: function(response) {

        var deps = [];
        _.each(response, function(d) {
            deps.push({
                from: d.start,
                to: d.end
            });
        });
        return deps;
    },

    initializeDAG: function() {
        _.each(this.toJSON(), function(dep) {
            this.dag.addEdge(dep.from, dep.to);
        }, this);
    }
});

var PretestModel = Backbone.Model.extend({

    url: function() {
        return "/api/v1/courses/{0}/pretest/".format(this.attributes.id);
    },

    getConceptQuiz: function(conceptId) {
        return this.attributes[conceptId];
    },

});

/********************************************************************************
*  Creator Store:
*
*
*********************************************************************************/

var CreatorStore = function(options) {

    if(!options.hasOwnProperty("setRoute")) {
        options.setRoute = true;
    }
    this.options = options;

    this.dag = new DAG({});

    this._course = new CourseModel(options);
    this._concepts = new ConceptCollection({course: this._course, dag: this.dag});
    this._dependencies = new DependencyCollection({course: this._course, dag: this.dag});

    if(this._course.isNew()) {
        this._course.once("sync", this.setRoute, this);
    }
    this.listenToEvents();
    window.course = this._course;
};

CreatorStore.prototype = {

    listenToEvents: function() {
        this._course.on("sync", this.onCourseSynced, this);
    },

    cleanup: function() {
        this._course.off("sync", this.onCourseSynced);
    },

    getName: function() {
        return this._course.get("name");
    },

    setName: function(name) {
        this._course.set("name", name);
        this._course.save();
    },

    isPublished: function() {
        return this._course.attributes.isPublished;
    },

    getStudentURL: function() {
        return this._course.studentURL();
    },

    togglePublish: function() {
        var isPublished = !this.isPublished();
        this._course.set({
            isPublished: isPublished
        });

        var self = this;
        this._isPublishedChanged = true;
        this._course.save();
    },

    onCourseSynced: function() {
        if(!this._isPublishedChanged) {
            return;
        }
        this.setRoute(true);
        this._isPublishedChanged = false;
        this.trigger("change:isPublished", this.isPublished(), this);
    },

    getConcepts: function() {
        return this._concepts.toJSON();
    },

    addConcept: function(concept) {

        var model = this._concepts.add(concept);
        var self = this;

        var onSaved = function() {
            self.dag.addNode(model.toJSON());
            self.trigger("add:concept", concept, self);
        }
        if(model.isNew()) {
            model.save().then(onSaved);
        }
        else {
            onSaved();
        }
    },

    addDependency: function(from, to) {

        var edge = {
            from: from,
            to: to
        };

        var nodesByLevel;
        try {
            this.dag.addEdge(from, to);
            nodesByLevel = this.dag.sort();
        } catch (e) {
            this.dag.removeEdge(from, to);
            return false;
        }

        var model = this._dependencies.add(edge);
        var self = this;
        var onSaved = function() {
            var edges = self.dag.getEdges();
            var graph = {
                levels: nodesByLevel,
                edges: edges
            }
            self.trigger("add:dependency", graph, edge);
        };

        if(model.isNew()) {
            model.save().then(onSaved);
        }
        else {
            onSaved();
        }

        return true;
    },

    getRootConcept: function() {

        var graph = this.getGraph();
        var levels = graph.levels;
        if(!levels.length) {
            return null;
        }
        return levels[0][0];
    },

    getConceptURL: function(conceptSlug) {
        return "{0}{1}/".format(this._course.studentURL(), conceptSlug);
    },

    getGraph: function() {
        return {
            levels: this.dag.sort(),
            edges: this.dag.getEdges()
        };
    },

    fetch: function() {

        if(this._course.isNew()) {
            return $.Deferred().resolve().promise()
        }

        var one = this._course.fetch();
        var two = this._concepts.fetch();
        var three = this._dependencies.fetch();

        var promises = [one, two, three];

        var self = this;
        var fetchedPromise = $.when.apply($, promises);
        fetchedPromise.then(function() {
            self._dependencies.initializeDAG();
            self.setRoute(true);
        });

        return fetchedPromise;

    },

    setRoute: function(replace) {

        if(!this.options.setRoute) {
            return;
        }
        replace = replace || false;
        var url = this._course.creatorURL();
        Backbone.history.navigate(url, {trigger: false, replace: replace});
    }

};

_.extend(CreatorStore.prototype, Backbone.Events);
CreatorStore.prototype.constructor = CreatorStore;

/********************************************************************************
*  Student Models and Stores
*
*
*********************************************************************************/

var ProgressModel = Backbone.Model.extend({

    url: function() {
        return "/api/v1/courses/{0}/student-progress/".format(this.attributes.id);
    },

    isNew: function() {

        var keys = Object.keys(this.attributes);
        var length = keys.length;
        for(var i = 0; i < length; i++) {
            var progress = this.attributes[keys[i]];
            if(progress.answered > 0) {
                return false;
            }
        }
        return true;
    },

    parse: function(response) {
        _.each(response, function(attrs, id) {
            attrs.progress = this.calculateProgress(attrs.answered, attrs.total);
        }, this);
        return response;
    },

    calculateProgress: function(answered, total) {
        if(total === 0) {
            return 1;
        }
        return answered / total;
    }

});

var StudentStates = {

    NEW_VISITOR: 0,

    COMPLETELY_NEW: 1,

    PRETEST: 2,

    DASHBOARD: 3

};

var StudentStore = function(options) {

    this._channel = options.channel || this;

    this._progress = new ProgressModel({
        id: options.id
    });

    if(this.getState() === null) {
        this.setState(StudentStates.NEW_VISITOR);
    }

};

StudentStore.prototype = {

    STATE_KEY: "student:course:state",

    SKILL_ESTIMATION_KEY: "student:course:skill-estimation",

    /**
     * set student state. Use the number code, not the name
     * @param {int} state
     */
    setState: function(state) {
        this._storeInteger(this.STATE_KEY, state);
        this._channel.trigger("change:state", state, this);
    },

    /**
     * @return {Number}
     */
    getState: function() {
        return this._loadInteger(this.STATE_KEY);
    },

    /**
     * Use the number code, not the name
     * @param {int} level
     */
    setSkillEstimationLevel: function(level) {
        this._storeInteger(this.SKILL_ESTIMATION_KEY, level);
    },

    /**
     * @return {Number}
     */
    getSkillEstimationLevel: function() {
        return this._loadInteger(this.SKILL_ESTIMATION_KEY);
    },

    _storeInteger: function(key, value) {
        localStorage.setItem(key, value);
    },

    _loadInteger: function(key) {
        var value = localStorage.getItem(key);
        if(value === null) {
            return value;
        };
        return parseInt(value);
    },

    /**
    * Get number of questions attempted, total number of questions and progress
    * in each concept.
    * Example:
    *   {
    *        "id": "awesome",
    *        "d597a0f8-ba60-45fe-819c-6a7aa0210d6a": {
    *            "total": 4,
    *            "answered": 2,
    *            "progress": 0.5
    *        },
    *        "906be0d8-aaa0-458b-ab04-6330f956975f": {
    *            "total": 5,
    *            "answered": 2,
    *            "progress": 0.4
    *        },
    *        "92416f00-2228-4799-8caa-d7cb27286eef": {
    *            "total": 1,
    *            "answered": 1,
    *            "progress": 1
    *        }
    *    }
    * @return {object}
    */
    getProgress: function() {
        return this._progress.toJSON();
    },

    /**
    *  1. Fetch student progress
    *  2. Return a promise that is resolved after step 3
    *  3. If the student has answered at least one quiz correctly, show dashboard
    *  @return {Promise}
    */
    fetch: function() {

        var self = this;
        return this._progress.fetch().then(function() {
            if(!self._progress.isNew()) {
                self.setState(StudentStates.DASHBOARD);
            }
        });
    }
};

StudentStore.prototype.constructor = StudentStore;
_.extend(StudentStore.prototype, Backbone.Events);

module.exports = {
    CreatorStore, CreatorStore,
    StudentStore: StudentStore,
    PretestModel: PretestModel,
    StudentStates: StudentStates
};
<|endoftext|>


<commit_before>'use strict'

app.controller('ProfileCtrl', function($scope, $http, $location, $routeParams) {

  let userId = $routeParams.id

  // gets existing boards
  $http
  .get('/api/profile/' + userId)
  .then(res => {
    console.log(res)
    $scope.boards = res.data
  })

  $scope.createBoard = () => {

    let boardBody = {
      boardName: $scope.boardName,
      boardOwnerId: userId,
      members: [
        userId
      ],
      tasks: []
    }
    // in 'tasks' array, add objects as { name: '', tasks: ['stuff', 'other stuff']}

    $http
    .post('/api/profile/' + userId, boardBody)
    .then(res => {
      console.log(res)
    })
  }

  $scope.showEdit = []

  $scope.showEditBox = (index) => {
    $scope.showEdit[index] = true
    console.log($scope.showEdit)
  }

  $scope.boardNameUpdate = []

  $scope.editBoard = (index, boardId) => {
    let newName = {
      boardName: $scope.boardNameUpdate[index]
    }

    console.log(newName)

    $http
    .put('/api/profile/' + boardId, newName)
    .then(updatedBoard => {
      console.log(updatedBoard)
    })
  }

  $scope.deleteBoard = (boardId) => {
    console.log(boardId)
    $http
    .delete('/api/profile/' + boardId)
    .then(res => {
      console.log(res)
    })
  }

})
<commit_msg>profile gets board whenevr you create and delete or edit one<commit_after>'use strict'

app.controller('ProfileCtrl', function($scope, $http, $location, $routeParams) {

  let userId = $routeParams.id

  // gets existing boards
  const getBoards = () => {
    $http
    .get('/api/profile/' + userId)
    .then(res => {
      console.log(res)
      $scope.boards = res.data
    })
  }

  getBoards()

  $scope.createBoard = () => {

    let boardBody = {
      boardName: $scope.boardName,
      boardOwnerId: userId,
      members: [
        userId
      ],
      tasks: []
    }
    // in 'tasks' array, add objects as { name: '', tasks: ['stuff', 'other stuff']}

    $http
    .post('/api/profile/' + userId, boardBody)
    .then(res => {
      console.log(res)
    })

    $scope.boardName = ''

    getBoards()
  }

  $scope.showEdit = []

  $scope.showEditBox = (index) => {
    $scope.showEdit[index] = true
    console.log($scope.showEdit)
  }

  $scope.boardNameUpdate = []

  $scope.editBoard = (index, boardId) => {
    let newName = {
      boardName: $scope.boardNameUpdate[index]
    }

    console.log(newName)

    $http
    .put('/api/profile/' + boardId, newName)
    .then(updatedBoard => {
      console.log(updatedBoard)
    })
    getBoards()
  }

  $scope.deleteBoard = (boardId) => {
    console.log(boardId)
    $http
    .delete('/api/profile/' + boardId)
    .then(res => {
      console.log(res)
    })
    getBoards()
  }

})
<|endoftext|>


<commit_before>/**
 *
 */

function logAutoconnectProxy(acp){
	console.log('adding logger');
	acp.on('source.connect',function(source){

		source.on('open',function(){
			console.log('autoconnect created proxy: there are '+acp.connectionPoolCount()+' ready sockets');
		}).on('message', function message(data, flags) {
			console.log('autoconnect proxy source sends: '+(typeof data));
		}).on('close',function(code, message){
			console.log('autoconnect proxy source close: '+code+' '+message);
		}).on('error',function(error){
			console.log('autoconnect proxy source error: '+error);
		});

	}).on('destination.connect',function(destination){

		destination.on('message', function message(data, flags) {
			console.log('autoconnect proxy destination sends: '+(typeof data));
		}).on('error',function(error){
			console.error('autoconnect proxy destination error: '+error+' | '+(typeof error));
		}).on('close',function(code, message){
			console.log('autoconnect proxy destination close: '+code+' '+message);
		});

	});
}

function logBridgeProxy(brdg){

	brdg.server.on('close',function(code, mesage){
		console.log('bridge closed: '+code+' - '+message);
	});

	brdg.on('server.connect',function(server){

		console.log('bridge recieved server socket');

		server.on('message', function message(data, flags) {
			console.log('bridge server sends: '+(typeof data));
		}).on('close',function(code, message){
			console.log('bridge server close: '+code+' '+message);
		}).on('error',function(error){
			console.log('bridge server error: '+error)
		})

	}).on('client.connect',function(client){
		console.log('bridge recieved client socket');

		client.on('message', function message(data, flags) {
			log('bridge client sends: '+(typeof data));
		}).on('close',function(code, message){
			console.log('bridge client  close: '+code+' '+message);
		}).on('error',function(error){
			console.log('bridge client error: '+error)
		});

	}).on('pair',function(server, client){

		console.log('bridge paired server client sockets');
	});

}

module.exports={
		logAutoconnectProxy:logAutoconnectProxy,
		logBridgeProxy:logBridgeProxy

}
<commit_msg>fix log => console.log<commit_after>/**
 *
 */

function logAutoconnectProxy(acp){
	console.log('adding logger');
	acp.on('source.connect',function(source){

		source.on('open',function(){
			console.log('autoconnect created proxy: there are '+acp.connectionPoolCount()+' ready sockets');
		}).on('message', function message(data, flags) {
			console.log('autoconnect proxy source sends: '+(typeof data));
		}).on('close',function(code, message){
			console.log('autoconnect proxy source close: '+code+' '+message);
		}).on('error',function(error){
			console.log('autoconnect proxy source error: '+error);
		});

	}).on('destination.connect',function(destination){

		destination.on('message', function message(data, flags) {
			console.log('autoconnect proxy destination sends: '+(typeof data));
		}).on('error',function(error){
			console.error('autoconnect proxy destination error: '+error+' | '+(typeof error));
		}).on('close',function(code, message){
			console.log('autoconnect proxy destination close: '+code+' '+message);
		});

	});
}

function logBridgeProxy(brdg){

	brdg.server.on('close',function(code, mesage){
		console.log('bridge closed: '+code+' - '+message);
	});

	brdg.on('server.connect',function(server){

		console.log('bridge recieved server socket');

		server.on('message', function message(data, flags) {
			console.log('bridge server sends: '+(typeof data));
		}).on('close',function(code, message){
			console.log('bridge server close: '+code+' '+message);
		}).on('error',function(error){
			console.log('bridge server error: '+error)
		})

	}).on('client.connect',function(client){
		console.log('bridge recieved client socket');

		client.on('message', function message(data, flags) {
		console.log('bridge client sends: '+(typeof data));
		}).on('close',function(code, message){
			console.log('bridge client  close: '+code+' '+message);
		}).on('error',function(error){
			console.log('bridge client error: '+error)
		});

	}).on('pair',function(server, client){

		console.log('bridge paired server client sockets');
	});

}

module.exports={
		logAutoconnectProxy:logAutoconnectProxy,
		logBridgeProxy:logBridgeProxy

}
<|endoftext|>


<commit_before>import test from 'ava'

import '../../helpers/screeps-globals'

import { createBoundingBoxForRange } from '../../../src/extends/roomposition'

const BOUND_MIN = 0
const BOUND_MAX = 49

function testMacro (t, x, y, range) {
  const { left, right, top, bottom } = createBoundingBoxForRange(x, y, range)

  t.true(left <= right, 'Left value is less than or equal to right value')
  t.true(top <= bottom, 'Bottom value is less than or equal to top value')

  t.true(BOUND_MIN <= left && left <= BOUND_MAX, 'Left value is out of bound')
  t.true(BOUND_MIN <= right && right <= BOUND_MAX, 'Right value is out of bound')
  t.true(BOUND_MIN <= top && top <= BOUND_MAX, 'Top value is out of bound')
  t.true(BOUND_MIN <= bottom && bottom <= BOUND_MAX, 'Bottom value is out of bound')

  // @todo add some assertions based on range
}

test('Works for x great than y', testMacro, 20, 10, 10)

test('Works for x less than y', testMacro, 10, 20, 10)

test('Works for x equal to y', testMacro, 10, 10, 10)

test('Works for negative range', testMacro, 10, 10, -10)

test('Works for negative x value', testMacro, -10, 10, 10)

test('Works for negative y value', testMacro, 10, -10, 10)

test('Works for small out of bound x value', testMacro, -100, 10, 10)

test('Works for large out of bound x value', testMacro, 100, 10, 10)

test('Works for small out of bound y value', testMacro, 10, -100, 10)

test('Works for large out of bound y value', testMacro, 10, 100, 10)

test('Works for large range value', testMacro, 10, 10, 100)
<commit_msg>Fixed a type-o<commit_after>import test from 'ava'

import '../../helpers/screeps-globals'

import { createBoundingBoxForRange } from '../../../src/extends/roomposition'

const BOUND_MIN = 0
const BOUND_MAX = 49

function testMacro (t, x, y, range) {
  const { left, right, top, bottom } = createBoundingBoxForRange(x, y, range)

  t.true(left <= right, 'Left value is less than or equal to right value')
  t.true(top <= bottom, 'Bottom value is less than or equal to top value')

  t.true(BOUND_MIN <= left && left <= BOUND_MAX, 'Left value is out of bound')
  t.true(BOUND_MIN <= right && right <= BOUND_MAX, 'Right value is out of bound')
  t.true(BOUND_MIN <= top && top <= BOUND_MAX, 'Top value is out of bound')
  t.true(BOUND_MIN <= bottom && bottom <= BOUND_MAX, 'Bottom value is out of bound')

  // @todo add some assertions based on range
}

test('Works for x greater than y', testMacro, 20, 10, 10)

test('Works for x less than y', testMacro, 10, 20, 10)

test('Works for x equal to y', testMacro, 10, 10, 10)

test('Works for negative range', testMacro, 10, 10, -10)

test('Works for negative x value', testMacro, -10, 10, 10)

test('Works for negative y value', testMacro, 10, -10, 10)

test('Works for small out of bound x value', testMacro, -100, 10, 10)

test('Works for large out of bound x value', testMacro, 100, 10, 10)

test('Works for small out of bound y value', testMacro, 10, -100, 10)

test('Works for large out of bound y value', testMacro, 10, 100, 10)

test('Works for large range value', testMacro, 10, 10, 100)
<|endoftext|>


<commit_before>function __setGetElementValue__(view,getter){
    function set(val){
        if (!this.dataset["attrType"]){
            if (this.tagName == "INPUT" || this.tagName == "SELECT" || this.tagName == "TEXTAREA") $(this).val(val);
            else this.innerText = val;
        }
        else if (this.dataset["attrType"] == "text") this.innerText = val;
        else if (this.dataset["attrType"] == "html") this.innerHTML = val;
        else $(this).attr(this.dataset["attrType"],val);
    }
    if (typeof view["get_"+getter] == "function"){
        var val = view["get_"+getter]();
        if (typeof val == "object" && "then" in val) val.then(set.bind(this));
        else set.call(this,val);
    }
    else set.call(this,view.model.get(getter));
}

function __updateModelView__(attrs){
    var _this = this;
    if (this.$el.find("[data-model-attr]").length != 0){
        for(var i in attrs){
            var $subElement = this.$el.find("[data-model-attr^='"+i+"']");
            if (!$subElement.length) continue;
            $subElement.each(function(){
                var attrsList = this.dataset["modelAttr"].split(".");
                var attrValue = attrs[attrsList.shift()];
                try {
                    while(attrsList.length != 0){
                        attrValue = attrValue[attrsList.shift()];
                    }
                }
                catch(e){
                    attrValue = attrValue.toString();
                }
                if (!this.dataset["attrType"]) this.innerText = attrValue;
                else if (this.dataset["attrType"] == "text") this.innerText = attrValue;
                else if (this.dataset["attrType"] == "html") this.innerHTML = attrValue;
                else $(this).attr(this.dataset["attrType"],attrValue);
            });
        }
    }
    this.$el.find("[data-model-get],[data-model-set]").each(function(){
        __setGetElementValue__.call(this,_this,this.dataset.modelGet || this.dataset.modelSet);
    });
    __renderDataRoutes__.call(this);
}

m.ModelView = m.View.extend({
    viewType: "model",
    initialize: function(model){
        var _this = this;
        this.model = model;
        this.listenTo(model,"change",this.__update__);
        this.listenTo(model,"destroy",_this.remove);
        m.View.prototype.initialize.apply(this,arguments);
    },
    __set__: function(){
        __updateModelView__.call(this,this.model.attributes);
        var view = this;
        this.$el.find("[data-model-set]").each(function(){
            var setter = this.dataset.modelSet;
            var _this = this;
            var interval = null;
            view.listenTo(view.model,"sync",function(){
                __setGetElementValue__.call(_this,view,setter);
            });
            if (!(this.dataset.silent || view.silent)){
                $(this).keyup(function(){
                    clearTimeout(interval);
                    interval = setTimeout(function(){$(_this).trigger("change");},150);
                });
                $(this).change(function(){
                    if (typeof view["set_"+setter] == "function") view["set_"+setter]($(this).val(),this);
                    else view.model.set(setter,$(this).val());
                });
            }
        });
        this.$el.attr("id",this.model.id);
    },
    __update__:function(a,b,c){
        __updateModelView__.call(this,this.model.changedAttributes());
    },
    remove: function(){
        if (!this.model.collection){
            delete __syncNames__[this.__syncName__];
        }
        m.View.prototype.remove.call(this);
    },
    destroy: function(){
        return this.model.destroy();
    },
    save: function(){
        var view = this;
        this.$el.find("[data-model-set]").each(function(){
            var setter = this.dataset.modelSet;
            if (typeof view["set_"+setter] == "function") view["set_"+setter]($(this).val(),this);
            else view.model.set(setter,$(this).val(),{silent: true});
        });
        return view.model.save();
    },
    fetch: function(){
        return this.model.fetch();
    }
});<commit_msg>add this to get/set attribute function<commit_after>function __setGetElementValue__(view,getter){
    function set(val){
        if (!this.dataset["attrType"]){
            if (this.tagName == "INPUT" || this.tagName == "SELECT" || this.tagName == "TEXTAREA") $(this).val(val);
            else this.innerText = val;
        }
        else if (this.dataset["attrType"] == "text") this.innerText = val;
        else if (this.dataset["attrType"] == "html") this.innerHTML = val;
        else $(this).attr(this.dataset["attrType"],val);
    }
    if (typeof view["get_"+getter] == "function"){
        var val = view["get_"+getter](this);
        // Для деферед ответов
        if (typeof val == "object" && "then" in val) val.then(set.bind(this));
        else set.call(this,val);
    }
    else set.call(this,view.model.get(getter));
}

function __updateModelView__(attrs){
    var _this = this;
    if (this.$el.find("[data-model-attr]").length != 0){
        for(var i in attrs){
            var $subElement = this.$el.find("[data-model-attr^='"+i+"']");
            if (!$subElement.length) continue;
            $subElement.each(function(){
                var attrsList = this.dataset["modelAttr"].split(".");
                var attrValue = attrs[attrsList.shift()];
                try {
                    while(attrsList.length != 0){
                        attrValue = attrValue[attrsList.shift()];
                    }
                }
                catch(e){
                    attrValue = attrValue.toString();
                }
                if (!this.dataset["attrType"]) this.innerText = attrValue;
                else if (this.dataset["attrType"] == "text") this.innerText = attrValue;
                else if (this.dataset["attrType"] == "html") this.innerHTML = attrValue;
                else $(this).attr(this.dataset["attrType"],attrValue);
            });
        }
    }
    this.$el.find("[data-model-get],[data-model-set]").each(function(){
        __setGetElementValue__.call(this,_this,this.dataset.modelGet || this.dataset.modelSet);
    });
    __renderDataRoutes__.call(this);
}

m.ModelView = m.View.extend({
    viewType: "model",
    initialize: function(model){
        var _this = this;
        this.model = model;
        this.listenTo(model,"change",this.__update__);
        this.listenTo(model,"destroy",_this.remove);
        m.View.prototype.initialize.apply(this,arguments);
    },
    __set__: function(){
        __updateModelView__.call(this,this.model.attributes);
        var view = this;
        this.$el.find("[data-model-set]").each(function(){
            var setter = this.dataset.modelSet;
            var _this = this;
            var interval = null;
            view.listenTo(view.model,"sync",function(){
                __setGetElementValue__.call(_this,view,setter);
            });
            if (!(this.dataset.silent || view.silent)){
                $(this).keyup(function(){
                    clearTimeout(interval);
                    interval = setTimeout(function(){$(_this).trigger("change");},150);
                });
                $(this).change(function(){
                    if (typeof view["set_"+setter] == "function") view["set_"+setter]($(this).val(),this);
                    else view.model.set(setter,$(this).val());
                });
            }
        });
        this.$el.attr("id",this.model.id);
    },
    __update__:function(a,b,c){
        __updateModelView__.call(this,this.model.changedAttributes());
    },
    remove: function(){
        if (!this.model.collection){
            delete __syncNames__[this.__syncName__];
        }
        m.View.prototype.remove.call(this);
    },
    destroy: function(){
        return this.model.destroy();
    },
    save: function(){
        var view = this;
        this.$el.find("[data-model-set]").each(function(){
            var setter = this.dataset.modelSet;
            if (typeof view["set_"+setter] == "function") view["set_"+setter]($(this).val(),this);
            else view.model.set(setter,$(this).val(),{silent: true});
        });
        return view.model.save();
    },
    fetch: function(){
        return this.model.fetch();
    }
});<|endoftext|>


<commit_before>'use strict';
import moment from 'moment';
const statIndex = {'Hp': 0, 'Atk': 1, 'Def': 2, 'SpAtk': 3, 'SpDef': 4, 'Spe': 5};
const genderDifferences = new Set([
  3, 12, 19, 20, 25, 26, 41, 42, 44, 45, 64, 65, 85, 97, 111, 112, 118, 119, 123, 129, 130, 154,
  165, 166, 185, 186, 190, 194, 198, 202, 203, 207, 208, 212, 214, 215, 221, 224, 229, 232, 255,
  256, 257, 267, 269, 272, 274, 275, 307, 308, 315, 316, 317, 322, 323, 332, 350, 369, 396, 397,
  398, 399, 400, 401, 402, 405, 407, 415, 417, 419, 424, 443, 444, 445, 449, 450, 453, 454, 456,
  457, 459, 460, 461, 464, 465, 473, 521, 592, 593, 668, 678
]);

module.exports = function($routeParams, $scope, io) {
  this.data = this.data || {};
  this.id = $routeParams.pokemonid || this.data.id;
  this.parseProps = () => {
    this.paddedTid = this.data.tid.toString().padStart(5, '0');
    this.paddedSid = this.data.sid.toString().padStart(5, '0');
    this.paddedEsv = this.data.esv.toString().padStart(4, '0');
    this.paddedTsv = this.data.tsv.toString().padStart(4, '0');

    this.speciesWithForme = this.data.speciesName + `${this.data.formName ? '-' + this.data.formName : ''}`;

    this.ivs = [
      this.data.ivHp,
      this.data.ivAtk,
      this.data.ivDef,
      this.data.ivSpAtk,
      this.data.ivSpDef,
      this.data.ivSpe
    ];

    this.totalExpToNextLevel = this.data.expFromPreviousLevel + this.data.expToNextLevel;

    this.stats = {
      HP: {
        base: this.data.baseStatHp,
        fullName: 'Hit Points',
        iv: this.data.ivHp,
        ev: this.data.evHp,
        total: this.data.statHp
      },
      Atk: {
        base: this.data.baseStatAtk,
        fullName: 'Attack',
        iv: this.data.ivAtk,
        ev: this.data.evAtk,
        total: this.data.statAtk
      },
      Def: {
        base: this.data.baseStatDef,
        fullName: 'Defense',
        iv: this.data.ivDef,
        ev: this.data.evDef,
        total: this.data.statDef
      },
      SpAtk: {
        base: this.data.baseStatSpAtk,
        fullName: 'Special Attack',
        iv: this.data.ivSpAtk,
        ev: this.data.evSpAtk,
        total: this.data.statSpAtk
      },
      SpDef: {
        base: this.data.baseStatSpDef,
        fullName: 'Special Defense',
        iv: this.data.ivSpDef,
        ev: this.data.evSpDef,
        total: this.data.statSpDef
      },
      Spe: {
        base: this.data.baseStatSpe,
        fullName: 'Speed',
        iv: this.data.ivSpe,
        ev: this.data.evSpe,
        total: this.data.statSpe
      }
    };

    this.contestStats = {
      cool: this.data.contestStatCool,
      beauty: this.data.contestStatBeauty,
      cute: this.data.contestStatCute,
      clever: this.data.contestStatSmart,
      tough: this.data.contestStatTough,
      sheen: this.data.contestStatSheen
    };

    this.moves = [
      {
        moveName: this.data.move1Name,
        moveType: this.data.move1Type,
        Pp: this.data.move1Pp,
        Ppu: this.data.move1Ppu
      },
      {
        moveName: this.data.move2Name,
        moveType: this.data.move2Type,
        Pp: this.data.move2Pp,
        Ppu: this.data.move2Ppu
      },
      {
        moveName: this.data.move3Name,
        moveType: this.data.move3Type,
        Pp: this.data.move3Pp,
        Ppu: this.data.move3Ppu
      },
      {
        moveName: this.data.move4Name,
        moveType: this.data.move4Type,
        Pp: this.data.move4Pp,
        Ppu: this.data.move4Ppu
      }
    ];

    this.eggMoves = [
      this.data.eggMove1Name,
      this.data.eggMove2Name,
      this.data.eggMove3Name,
      this.data.eggMove4Name
    ];

    this.gameLabel = 'game-' + (this.data.otGameName || '').replace(' ', '-').toLowerCase();

    this.isKB = this.data.otGameId >= 24 && this.data.otGameId <= 29;
    this.hasHA = this.data.abilityNum === 4;
    this.isFromGen4 = [7, 8, 10, 11, 12].indexOf(this.data.otGameId) > -1;

    this.iconUrl = `pokemon/${this.data.isShiny ? 'shiny' : 'regular'}/${
      this.data.speciesName && this.data.speciesName.toLowerCase()}`;
    this.spriteUrl = `pokemon/${this.data.isShiny ? 'shiny' : 'regular'}/${this.data.gender === 'F'
      && genderDifferences.has(this.data.dexNo) ? 'female/' : ''}${this.data.dexNo}${this.data.formId > 0 &&
      this.data.dexNo !== 664 && this.data.dexNo !== 665 ? '-' + this.data.formId : ''}`;
    this.ballNameUrl = this.data.ballName
      ? this.data.ballName.replace(' ', '-').replace('é', 'e').toLowerCase()
      : null;

    this.heldItemUrl = this.data.heldItemName
      ? this.data.heldItemName.replace(' ', '-').replace('é', 'e').toLowerCase()
      : null;

    this.natureStats = [statIndex[this.data.increasedStat], statIndex[this.data.decreasedStat]];

    this.displayMetDate = parseDate(this.data.metDate);
    this.displayEggDate = parseDate(this.data.eggDate);

    this.places = [
      {country: this.data.geoLocation1CountryId, region: this.data.geoLocation1RegionId},
      {country: this.data.geoLocation2CountryId, region: this.data.geoLocation2RegionId},
      {country: this.data.geoLocation3CountryId, region: this.data.geoLocation3RegionId},
      {country: this.data.geoLocation4CountryId, region: this.data.geoLocation4RegionId},
      {country: this.data.geoLocation5CountryId, region: this.data.geoLocation5RegionId}
    ];

    this.hasFullData = true;
    return this;
  };

  this.fetch = () => {
    return io.socket.getAsync(`/p/${this.id}`).then(data => {
      Object.assign(this.data, data);
    }).then(this.parseProps).then(() => $scope.$apply());
  };
};

function parseDate(timestamp) {
  return timestamp && moment.utc(timestamp).format('MMMM Do, YYYY');
}
<commit_msg>Fix Cosplay Pikachu sprite<commit_after>'use strict';
import moment from 'moment';
const statIndex = {'Hp': 0, 'Atk': 1, 'Def': 2, 'SpAtk': 3, 'SpDef': 4, 'Spe': 5};
const genderDifferences = new Set([
  3, 12, 19, 20, 25, 26, 41, 42, 44, 45, 64, 65, 85, 97, 111, 112, 118, 119, 123, 129, 130, 154,
  165, 166, 185, 186, 190, 194, 198, 202, 203, 207, 208, 212, 214, 215, 221, 224, 229, 232, 255,
  256, 257, 267, 269, 272, 274, 275, 307, 308, 315, 316, 317, 322, 323, 332, 350, 369, 396, 397,
  398, 399, 400, 401, 402, 405, 407, 415, 417, 419, 424, 443, 444, 445, 449, 450, 453, 454, 456,
  457, 459, 460, 461, 464, 465, 473, 521, 592, 593, 668, 678
]);

module.exports = function($routeParams, $scope, io) {
  this.data = this.data || {};
  this.id = $routeParams.pokemonid || this.data.id;
  this.parseProps = () => {
    this.paddedTid = this.data.tid.toString().padStart(5, '0');
    this.paddedSid = this.data.sid.toString().padStart(5, '0');
    this.paddedEsv = this.data.esv.toString().padStart(4, '0');
    this.paddedTsv = this.data.tsv.toString().padStart(4, '0');

    this.speciesWithForme = this.data.speciesName + `${this.data.formName ? '-' + this.data.formName : ''}`;

    this.ivs = [
      this.data.ivHp,
      this.data.ivAtk,
      this.data.ivDef,
      this.data.ivSpAtk,
      this.data.ivSpDef,
      this.data.ivSpe
    ];

    this.totalExpToNextLevel = this.data.expFromPreviousLevel + this.data.expToNextLevel;

    this.stats = {
      HP: {
        base: this.data.baseStatHp,
        fullName: 'Hit Points',
        iv: this.data.ivHp,
        ev: this.data.evHp,
        total: this.data.statHp
      },
      Atk: {
        base: this.data.baseStatAtk,
        fullName: 'Attack',
        iv: this.data.ivAtk,
        ev: this.data.evAtk,
        total: this.data.statAtk
      },
      Def: {
        base: this.data.baseStatDef,
        fullName: 'Defense',
        iv: this.data.ivDef,
        ev: this.data.evDef,
        total: this.data.statDef
      },
      SpAtk: {
        base: this.data.baseStatSpAtk,
        fullName: 'Special Attack',
        iv: this.data.ivSpAtk,
        ev: this.data.evSpAtk,
        total: this.data.statSpAtk
      },
      SpDef: {
        base: this.data.baseStatSpDef,
        fullName: 'Special Defense',
        iv: this.data.ivSpDef,
        ev: this.data.evSpDef,
        total: this.data.statSpDef
      },
      Spe: {
        base: this.data.baseStatSpe,
        fullName: 'Speed',
        iv: this.data.ivSpe,
        ev: this.data.evSpe,
        total: this.data.statSpe
      }
    };

    this.contestStats = {
      cool: this.data.contestStatCool,
      beauty: this.data.contestStatBeauty,
      cute: this.data.contestStatCute,
      clever: this.data.contestStatSmart,
      tough: this.data.contestStatTough,
      sheen: this.data.contestStatSheen
    };

    this.moves = [
      {
        moveName: this.data.move1Name,
        moveType: this.data.move1Type,
        Pp: this.data.move1Pp,
        Ppu: this.data.move1Ppu
      },
      {
        moveName: this.data.move2Name,
        moveType: this.data.move2Type,
        Pp: this.data.move2Pp,
        Ppu: this.data.move2Ppu
      },
      {
        moveName: this.data.move3Name,
        moveType: this.data.move3Type,
        Pp: this.data.move3Pp,
        Ppu: this.data.move3Ppu
      },
      {
        moveName: this.data.move4Name,
        moveType: this.data.move4Type,
        Pp: this.data.move4Pp,
        Ppu: this.data.move4Ppu
      }
    ];

    this.eggMoves = [
      this.data.eggMove1Name,
      this.data.eggMove2Name,
      this.data.eggMove3Name,
      this.data.eggMove4Name
    ];

    this.gameLabel = 'game-' + (this.data.otGameName || '').replace(' ', '-').toLowerCase();

    this.isKB = this.data.otGameId >= 24 && this.data.otGameId <= 29;
    this.hasHA = this.data.abilityNum === 4;
    this.isFromGen4 = [7, 8, 10, 11, 12].indexOf(this.data.otGameId) > -1;

    this.iconUrl = `pokemon/${this.data.isShiny ? 'shiny' : 'regular'}/${
      this.data.speciesName && this.data.speciesName.toLowerCase()}`;
    this.spriteUrl = `pokemon/${this.data.isShiny ? 'shiny' : 'regular'}/${this.data.gender === 'F'
      && genderDifferences.has(this.data.dexNo) ? 'female/' : ''}${this.data.dexNo}${this.data.formId > 0 &&
      [25, 664, 665].indexOf(this.data.dexNo) === -1 ? '-' + this.data.formId : ''}`;
    this.ballNameUrl = this.data.ballName
      ? this.data.ballName.replace(' ', '-').replace('é', 'e').toLowerCase()
      : null;

    this.heldItemUrl = this.data.heldItemName
      ? this.data.heldItemName.replace(' ', '-').replace('é', 'e').toLowerCase()
      : null;

    this.natureStats = [statIndex[this.data.increasedStat], statIndex[this.data.decreasedStat]];

    this.displayMetDate = parseDate(this.data.metDate);
    this.displayEggDate = parseDate(this.data.eggDate);

    this.places = [
      {country: this.data.geoLocation1CountryId, region: this.data.geoLocation1RegionId},
      {country: this.data.geoLocation2CountryId, region: this.data.geoLocation2RegionId},
      {country: this.data.geoLocation3CountryId, region: this.data.geoLocation3RegionId},
      {country: this.data.geoLocation4CountryId, region: this.data.geoLocation4RegionId},
      {country: this.data.geoLocation5CountryId, region: this.data.geoLocation5RegionId}
    ];

    this.hasFullData = true;
    return this;
  };

  this.fetch = () => {
    return io.socket.getAsync(`/p/${this.id}`).then(data => {
      Object.assign(this.data, data);
    }).then(this.parseProps).then(() => $scope.$apply());
  };
};

function parseDate(timestamp) {
  return timestamp && moment.utc(timestamp).format('MMMM Do, YYYY');
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------------------------------------------------
/// GeolocationService
///
/// @module
//----------------------------------------------------------------------------------------------------------------------

import Promise from 'bluebird';
import ol from 'openlayers';
import { toastService as toastSvc } from 'vueboot';

import mapSvc from './map';
import CurrentPosLayer from '../layers/currentPos';

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

class GeolocationService {
    constructor()
    {
        this.autoUpdateView = false;
        this.currentPos = new ol.Feature(new ol.geom.Point([0, 0]));

        // Setup currentPosLayer
        CurrentPosLayer.addFeature(this.currentPos);

        // Setup GeoLocation
        if("geolocation" in navigator)
        {
            // Watch the current position, and keep it updated
            this.watchHandle = navigator.geolocation.watchPosition(this._updatePos.bind(this), this._errorGettingPos.bind(this), {
                    enableHighAccuracy: true,
                    maximumAge        : 30000,
                    timeout           : 27000
                });
        }
        else
        {
            toastSvc.create({
                type: 'danger',
                dismissible: true,
                content: 'Geolocation Disabled.',
                timeout: false
            });
        } // end if
    } // end constructor

    _updatePos(position)
    {
        var coords = ol.proj.fromLonLat([
            position.coords.longitude,
            position.coords.latitude
        ]);

        console.log('updating pos...');

        // Store the current position
        this.currentPos.getGeometry().setCoordinates(coords);

        if(this.autoUpdateView)
        {
            this._updateView();
        } // end if
    } // end _updatePos

    _updateView()
    {
        var view = mapSvc.map.getView();
        view.setCenter(this.currentPos.getGeometry().getCoordinates());

        return Promise.resolve();
    } // end updateView

    _errorGettingPos(error)
    {
        console.error('Unable to retrieve your location.', error);

        toastSvc.create({
            type: 'danger',
            dismissible: true,
            content: 'Unable to retrieve your location.',
            timeout: false
        });
    } // end _errorGettingPos

    updateLocation()
    {
        return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject); })
            .then((position) =>
            {
                this._updatePos(position);
                this._updateView();
            })
            .catch(this._errorGettingPos.bind(this));
    } // end updateLocation

    zoomToLocation()
    {
        var map = mapSvc.map;
        var view = mapSvc.map.getView();

        console.log('zoom!!!');

        // Fit the view to the point
        view.fit(this.currentPos.getGeometry(), map.getSize(), {
            padding: [5, 5, 5, 5],
            maxZoom: 17
        });
    } // end zoomToLocation
} // end GeolocationService

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

export default new GeolocationService();

//----------------------------------------------------------------------------------------------------------------------
<commit_msg>more whoops.<commit_after>//----------------------------------------------------------------------------------------------------------------------
/// GeolocationService
///
/// @module
//----------------------------------------------------------------------------------------------------------------------

import Promise from 'bluebird';
import ol from 'openlayers';
import { toastService as toastSvc } from 'vueboot';

import mapSvc from './map';
import CurrentPosLayer from '../layers/currentPos';

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

class GeolocationService {
    constructor()
    {
        this.autoUpdateView = false;
        this.currentPos = new ol.Feature(new ol.geom.Point([0, 0]));

        // Setup currentPosLayer
        CurrentPosLayer.addFeature(this.currentPos);

        // Setup GeoLocation
        if("geolocation" in navigator)
        {
            // Watch the current position, and keep it updated
            this.watchHandle = navigator.geolocation.watchPosition(this._updatePos.bind(this), this._errorGettingPos.bind(this), {
                    enableHighAccuracy: true,
                    maximumAge        : 30000,
                    timeout           : 27000
                });
        }
        else
        {
            toastSvc.create({
                type: 'danger',
                dismissible: true,
                content: 'Geolocation Disabled.',
                timeout: false
            });
        } // end if
    } // end constructor

    _updatePos(position)
    {
        var coords = ol.proj.fromLonLat([
            position.coords.longitude,
            position.coords.latitude
        ]);

        console.log('updating pos...');

        // Store the current position
        this.currentPos.getGeometry().setCoordinates(coords);

        if(this.autoUpdateView)
        {
            this._updateView();
        } // end if
    } // end _updatePos

    _updateView()
    {
        var view = mapSvc.map.getView();
        view.setCenter(this.currentPos.getGeometry().getCoordinates());
    } // end updateView

    _errorGettingPos(error)
    {
        console.error('Unable to retrieve your location.', error);

        toastSvc.create({
            type: 'danger',
            dismissible: true,
            content: 'Unable to retrieve your location.',
            timeout: false
        });
    } // end _errorGettingPos

    updateLocation()
    {
        return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject); })
            .then((position) =>
            {
                this._updatePos(position);
                this._updateView();
            })
            .catch(this._errorGettingPos.bind(this));
    } // end updateLocation

    zoomToLocation()
    {
        var map = mapSvc.map;
        var view = mapSvc.map.getView();

        console.log('zoom!!!');

        // Fit the view to the point
        view.fit(this.currentPos.getGeometry(), map.getSize(), {
            padding: [5, 5, 5, 5],
            maxZoom: 17
        });
    } // end zoomToLocation
} // end GeolocationService

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

export default new GeolocationService();

//----------------------------------------------------------------------------------------------------------------------
<|endoftext|>