<commit_before>var EOL = require('os').EOL
  , fs = require('fs')
  , assert = require('assert')
  , path = require('path')
  , touch = require('touch')
  , util = require('util')
  , events = require('events')
  , utils = require('cli-util')
  , uniq = utils.uniq;

var stores = {};

function noop(){};

var HistoryStore = function(parent, options, lines) {
  options = options || {};
  lines = this.readLines(lines);
  options.flush = options.flush !== undefined ? options.flush : true;
  options.duplicates = options.duplicates !== undefined
    ? options.duplicates : false;
  options.limit = options.limit === 'number' ? options.limit : 2048;
  this.file = options.file;
  this.options = options;
  this._parent = parent;
  this._history = lines;
  this._checkpoint = this._history.length;
  this._stream = fs.createWriteStream(this.file, {flags: 'a+'});
  this._stats = null;
}

/**
 *  Get the underlying history array.
 */
HistoryStore.prototype.history = function() {
  return this._history;
}

/**
 *  Get the underlying file stats.
 */
HistoryStore.prototype.stats = function(cb) {
  var scope = this;
  if(typeof cb === 'function') {
    fs.stat(this.file, function(err, stats) {
      if(err) return cb(err, scope);
      stats.file = scope.file;
      scope._stats = stats;
      scope._checkpoint = scope._history.length;
      return cb(err, scope);
    });
  }
  return this._stats;
}

/**
 *  Get the parent History instance.
 */
HistoryStore.prototype.parent = function() {
  return this._parent;
}

/**
 *  Read lines into an array.
 *
 *  @param lines A string or buffer.
 *
 *  @return An array of lines.
 */
HistoryStore.prototype.readLines = function(lines) {
  if(!lines) return [];
  if(lines instanceof Buffer) lines = '' + lines;
  lines = lines.split('\n');
  lines = lines.filter(function(line) {
    line = line.replace(/\r$/, '');
    line = line.trim();
    return line;
  })
  if(!this.options.duplicates) {
    lines = uniq(lines);
  }
  return lines;
}

/**
 *  Import into this history store.
 *
 *  If content is a callback function all data is read from disc,
 *  otherwise content should be a string or array to import.
 *
 *  When content is specified the and this instance is flushing
 *  the file is written to disc.
 *
 *  If content is specified but no callback then the internal representation
 *  is updated but content is not flushed to disc.
 *
 *  @param content String or array to import.
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.import = function(content, cb) {
  var scope = this;
  // no content so read the file and import the data
  if(typeof content === 'function') {
    cb = content;
    return fs.readFile(this.file, function(err, content) {
      if(err) return cb(err, null, scope);
      scope.stats(function(err) {
        if(err) return cb(err);
        scope._history = scope.readLines(content);
        scope._checkpoint = scope._history.length;
        cb(null, content, scope);
      })
    })
  }
  // got string content, convert to an array
  if(typeof content === 'string') content = this.readLines(content);
  assert(Array.isArray(content),
    'invalid history content type, must be array or string');

  // update internal representation
  this._history = content;
  this._checkpoint = 0;
  // write out if we have callback
  if(typeof cb === 'function') {
    this._write(this.getLines(), cb);
  }
}

/**
 *  Determine if the stored checkpoint is synchronized
 *  with the history array.
 *
 *  @return A boolean indicating if the internal checkpoint is at
 *  the end of the history array.
 */
HistoryStore.prototype.isFlushed = function() {
  return this._checkpoint === this._history.length;
}

/**
 *  Get a string of lines from the underlying arrat of lines.
 *
 *  Includes a trailing newline.
 *
 *  @param checkpoint The start index into the history array.
 *  @param length The end index into the history array.
 */
HistoryStore.prototype.getLines = function(checkpoint, length) {
  var lines = this._history.slice(
    checkpoint || this._checkpoint, length || this._history.length);
  // add trailing newline
  if(lines[lines.length - 1]) {
    lines.push('');
  }
  return lines.join(EOL);
}

/**
 *  Read the history file from disc and load it into
 *  this instance.
 *
 *  @param cb A callback function invoked when the history
 *  has been read from disc or on error.
 */
HistoryStore.prototype.read = function(cb) {
  var scope = this;
  cb = typeof cb === 'function' ? cb : noop;
  return this.import(function(err) {
    if(err && err.code === 'ENOENT' && create) {
      return touch(file, function(err) {
        if(err) return cb(err, scope);
        scope.read(options, cb);
      });
    }
    cb(err, scope);
  });
}

/**
 *  Add a line to this history store.
 *
 *  @param line The line to append.
 *  @param options The append options.
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.add = function(line, options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  cb = typeof cb === 'function' ? cb : noop;
  var scope = this
    , flush = options.flush || this.options.flush;
  if(!this.options.duplicates && ~this._history.indexOf(line)) {
    return cb(null, scope);
  }
  //console.log('flush %s', flush);
  assert(typeof line === 'string', 'history entry must be a string')
  line = '' + line;
  line = line.replace(/\r?\n$/, '');
  this._history.push(line);
  this._write(flush, cb);
}

/**
 *  Remove the last history item.
 *
 *  If this store is not set to flush to disc then this method
 *  acts like peek.
 *
 *  Truncates the history file when flushing to disc.
 *
 *  @param options The options.
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.pop = function(options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var scope = this
    , flush = options.flush || this.options.flush;
  var item = this._history.pop();
  var contents = this.getLines();
  var len = Buffer.byteLength(item + EOL);
  cb = typeof cb === 'function' ? cb : noop;
  if(!flush) {
    // not flushing to disc, so this acts more like peek()
    this._history.push(item);
    return cb(null, item, scope);
  }
  var length = this._stats.size - len;
  fs.ftruncate(this._stream.fd, length, function(err) {
    if(err) {
      // TODO: we need to re-initialize from the state on disc
    }else{
      scope._checkpoint = scope._history.length;
    }
    cb(err, item, scope);
  })
}

/**
 *  Remove all history items.
 *
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.clear = function(cb) {
  var scope = this;
  fs.writeFile(this.file, '', function(err) {
    if(err) return cb(err, scope);
    scope._history = [];
    scope._checkpoint = 0;
    cb(null, scope);
  })
}

/**
 *  Closes the underlying stream.
 *
 *  @param cb A callback function invoked when the
 *  stream has finished or on error.
 */
HistoryStore.prototype.close = function(cb) {
  if(this._stream) {
    this._stream.once('finish', cb);
    this._stream.end();
    this._stream = null;
  }
}

/**
 *  @private
 *
 *  Write to disc and update the internal stats upon successful write.
 */
HistoryStore.prototype._write = function(flush, cb) {
  var scope = this
    , contents = typeof flush === 'string' || flush instanceof Buffer
      ? flush : null;
  if(!flush || this._checkpoint === this._history.length) return cb(null, scope);
  //console.log('write to disc %s %s', this._checkpoint, this._history.length);
  var append = !contents;
  if(append) {
    contents = this.getLines();
  }
  function write(stream, cb) {
    stream.write(contents, function onwrite(err) {
      if(err) return cb(err, scope);
      scope.stats(cb);
    });
  }
  if(!append) {
    var st = fs.createWriteStream(this.file, {flags: 'w+'});
    write.call(scope, st, function(err) {
      st.end();
      if(err) return cb(err, scope);
      cb(null, scope);
    });
  }else{
    write.call(scope, this._stream, cb);
  }
}

var History = function(options) {
  options = options || {};
  options.create = options.create !== undefined ? options.create : true;
  this.options = options;
}

util.inherits(History, events.EventEmitter);

History.prototype.load = function(options, cb) {
  var scope = this;
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var file = options.file || this.options.file
    , create = options.create !== undefined
      ? options.create : this.options.create;
  assert(file, 'cannot load history with no file');
  file = path.normalize(file);
  if(stores[file] && !options.force) {
    return cb(null, stores[file]);
  }

  var store = new HistoryStore(scope, scope.options);
  stores[file] = store;

  store.read(function(err) {
    cb(err, store, scope);
  })
}

/**
 *  Get a history store by file path or all stores.
 */
History.prototype.getStore = function(file) {
  if(file) return stores[file];
  return stores;
}

function history(options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var h = new History(options);
  if(cb) {
    h.load(options, cb);
  }
  return h;
}

history.History = History;

module.exports = history;
<commit_msg>Set checkpoint in _write() not stats().<commit_after>var EOL = require('os').EOL
  , fs = require('fs')
  , assert = require('assert')
  , path = require('path')
  , touch = require('touch')
  , util = require('util')
  , events = require('events')
  , utils = require('cli-util')
  , uniq = utils.uniq;

var stores = {};

function noop(){};

var HistoryStore = function(parent, options, lines) {
  options = options || {};
  lines = this.readLines(lines);
  options.flush = options.flush !== undefined ? options.flush : true;
  options.duplicates = options.duplicates !== undefined
    ? options.duplicates : false;
  options.limit = options.limit === 'number' ? options.limit : 2048;
  this.file = options.file;
  this.options = options;
  this._parent = parent;
  this._history = lines;
  this._checkpoint = this._history.length;
  this._stream = fs.createWriteStream(this.file, {flags: 'a+'});
  this._stats = null;
}

/**
 *  Get the underlying history array.
 */
HistoryStore.prototype.history = function() {
  return this._history;
}

/**
 *  Get the underlying file stats.
 */
HistoryStore.prototype.stats = function(cb) {
  var scope = this;
  if(typeof cb === 'function') {
    fs.stat(this.file, function(err, stats) {
      if(err) return cb(err, scope);
      stats.file = scope.file;
      scope._stats = stats;
      return cb(err, scope);
    });
  }
  return this._stats;
}

/**
 *  Get the parent History instance.
 */
HistoryStore.prototype.parent = function() {
  return this._parent;
}

/**
 *  Read lines into an array.
 *
 *  @param lines A string or buffer.
 *
 *  @return An array of lines.
 */
HistoryStore.prototype.readLines = function(lines) {
  if(!lines) return [];
  if(lines instanceof Buffer) lines = '' + lines;
  lines = lines.split('\n');
  lines = lines.filter(function(line) {
    line = line.replace(/\r$/, '');
    line = line.trim();
    return line;
  })
  if(!this.options.duplicates) {
    lines = uniq(lines);
  }
  return lines;
}

/**
 *  Import into this history store.
 *
 *  If content is a callback function all data is read from disc,
 *  otherwise content should be a string or array to import.
 *
 *  When content is specified the and this instance is flushing
 *  the file is written to disc.
 *
 *  If content is specified but no callback then the internal representation
 *  is updated but content is not flushed to disc.
 *
 *  @param content String or array to import.
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.import = function(content, cb) {
  var scope = this;
  // no content so read the file and import the data
  if(typeof content === 'function') {
    cb = content;
    return fs.readFile(this.file, function(err, content) {
      if(err) return cb(err, null, scope);
      scope.stats(function(err) {
        if(err) return cb(err);
        scope._history = scope.readLines(content);
        scope._checkpoint = scope._history.length;
        cb(null, content, scope);
      })
    })
  }
  // got string content, convert to an array
  if(typeof content === 'string') content = this.readLines(content);
  assert(Array.isArray(content),
    'invalid history content type, must be array or string');

  // update internal representation
  this._history = content;
  this._checkpoint = 0;
  // write out if we have callback
  if(typeof cb === 'function') {
    this._write(this.getLines(), cb);
  }
}

/**
 *  Determine if the stored checkpoint is synchronized
 *  with the history array.
 *
 *  @return A boolean indicating if the internal checkpoint is at
 *  the end of the history array.
 */
HistoryStore.prototype.isFlushed = function() {
  return this._checkpoint === this._history.length;
}

/**
 *  Get a string of lines from the underlying arrat of lines.
 *
 *  Includes a trailing newline.
 *
 *  @param checkpoint The start index into the history array.
 *  @param length The end index into the history array.
 */
HistoryStore.prototype.getLines = function(checkpoint, length) {
  var lines = this._history.slice(
    checkpoint || this._checkpoint, length || this._history.length);
  // add trailing newline
  if(lines[lines.length - 1]) {
    lines.push('');
  }
  return lines.join(EOL);
}

/**
 *  Read the history file from disc and load it into
 *  this instance.
 *
 *  @param cb A callback function invoked when the history
 *  has been read from disc or on error.
 */
HistoryStore.prototype.read = function(cb) {
  var scope = this;
  cb = typeof cb === 'function' ? cb : noop;
  return this.import(function(err) {
    if(err && err.code === 'ENOENT' && create) {
      return touch(file, function(err) {
        if(err) return cb(err, scope);
        scope.read(options, cb);
      });
    }
    cb(err, scope);
  });
}

/**
 *  Add a line to this history store.
 *
 *  @param line The line to append.
 *  @param options The append options.
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.add = function(line, options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  cb = typeof cb === 'function' ? cb : noop;
  var scope = this
    , flush = options.flush || this.options.flush;
  if(!this.options.duplicates && ~this._history.indexOf(line)) {
    return cb(null, scope);
  }
  //console.log('flush %s', flush);
  assert(typeof line === 'string', 'history entry must be a string')
  line = '' + line;
  line = line.replace(/\r?\n$/, '');
  this._history.push(line);
  this._write(flush, cb);
}

/**
 *  Remove the last history item.
 *
 *  If this store is not set to flush to disc then this method
 *  acts like peek.
 *
 *  Truncates the history file when flushing to disc.
 *
 *  @param options The options.
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.pop = function(options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var scope = this
    , flush = options.flush || this.options.flush;
  var item = this._history.pop();
  var contents = this.getLines();
  var len = Buffer.byteLength(item + EOL);
  cb = typeof cb === 'function' ? cb : noop;
  if(!flush) {
    // not flushing to disc, so this acts more like peek()
    this._history.push(item);
    return cb(null, item, scope);
  }
  var length = this._stats.size - len;
  fs.ftruncate(this._stream.fd, length, function(err) {
    if(err) {
      // TODO: we need to re-initialize from the state on disc
    }else{
      scope._checkpoint = scope._history.length;
    }
    cb(err, item, scope);
  })
}

/**
 *  Remove all history items.
 *
 *  @param cb A callback function invoked when the history
 *  has been synced to disc or on error.
 */
HistoryStore.prototype.clear = function(cb) {
  var scope = this;
  fs.writeFile(this.file, '', function(err) {
    if(err) return cb(err, scope);
    scope._history = [];
    scope._checkpoint = 0;
    cb(null, scope);
  })
}

/**
 *  Closes the underlying stream.
 *
 *  @param cb A callback function invoked when the
 *  stream has finished or on error.
 */
HistoryStore.prototype.close = function(cb) {
  if(this._stream) {
    this._stream.once('finish', cb);
    this._stream.end();
    this._stream = null;
  }
}

/**
 *  @private
 *
 *  Write to disc and update the internal stats upon successful write.
 */
HistoryStore.prototype._write = function(flush, cb) {
  var scope = this
    , contents = typeof flush === 'string' || flush instanceof Buffer
      ? flush : null;
  if(!flush || this._checkpoint === this._history.length) return cb(null, scope);
  //console.log('write to disc %s %s', this._checkpoint, this._history.length);
  var append = !contents;
  if(append) {
    contents = this.getLines();
  }
  function write(stream, cb) {
    stream.write(contents, function onwrite(err) {
      if(err) return cb(err, scope);
      scope.stats(function(err) {
        if(err) return cb(err, scope);
        scope._checkpoint = scope._history.length;
        cb(null, scope);
      });
    });
  }
  if(!append) {
    var st = fs.createWriteStream(this.file, {flags: 'w+'});
    write.call(scope, st, function(err) {
      st.end();
      if(err) return cb(err, scope);
      cb(null, scope);
    });
  }else{
    write.call(scope, this._stream, cb);
  }
}

var History = function(options) {
  options = options || {};
  options.create = options.create !== undefined ? options.create : true;
  this.options = options;
}

util.inherits(History, events.EventEmitter);

History.prototype.load = function(options, cb) {
  var scope = this;
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var file = options.file || this.options.file
    , create = options.create !== undefined
      ? options.create : this.options.create;
  assert(file, 'cannot load history with no file');
  file = path.normalize(file);
  if(stores[file] && !options.force) {
    return cb(null, stores[file]);
  }

  var store = new HistoryStore(scope, scope.options);
  stores[file] = store;

  store.read(function(err) {
    cb(err, store, scope);
  })
}

/**
 *  Get a history store by file path or all stores.
 */
History.prototype.getStore = function(file) {
  if(file) return stores[file];
  return stores;
}

function history(options, cb) {
  if(typeof options === 'function') {
    cb = options;
    options = null;
  }
  options = options || {};
  var h = new History(options);
  if(cb) {
    h.load(options, cb);
  }
  return h;
}

history.History = History;

module.exports = history;
<|endoftext|>


<commit_before>function Load () {
    this.loadBar = null;
    this.playButton = null;
    this.background = null;
}

Load.prototype.preload = function () {
    this.loadBar = this.add.text(this.game.width / 2, this.game.height / 2, 'Loading assets...');
    this.loadBar.x -= this.loadBar.width / 2;
    this.loadBar.y -= this.loadBar.height / 2;
    this.testRenderer();

    // some game settings
    game.scale.scaleMode = Phaser.ScaleManager.USER_SCALE;
    game.scale.onResize = function () {
        game.scale.setGameSize(document.body.clientWidth, document.body.clientHeight);
    };
    game.time.advancedTiming = true;
    game.stage.backgroundColor = '#0080ff';

    // load assets
    game.load.image('ball', 'assets/ball.png');
    game.load.atlasJSONArray('shapes', 'img/shapes_small.png', 'img/shapes_small.json');
    game.load.image('background', 'assets/background.png');
};

Load.prototype.preloadUpdate = function () {
    this.loadBar.x = this.game.width / 2 - this.loadBar.width / 2;
    this.loadBar.y = this.game.height / 2 - this.loadBar.height / 2;
};

Load.prototype.create = function() {
    this.background = this.add.sprite(0, 0, 'background');
    this.background.width = this.game.width;
    this.background.height = this.game.height;
    this.background.moveDown();
    this.loadBar.text = 'Start!';
    this.playButton = this.add.button(this.game.width / 2 - 100, this.game.height / 2 - 35,
      'ball', this.playGame, this);
    this.loadBar.moveUp();
    this.playButton.width = 200;
    this.playButton.height = 70;
};

Load.prototype.update = function () {
    var w = this.game.width;
    var h = this.game.height;
    this.loadBar.x = w / 2 - this.loadBar.width / 2;
    this.loadBar.y = h / 2 - this.loadBar.height / 2;
    this.playButton.x = w / 2 - this.playButton.width / 2;
    this.playButton.y = h / 2 - this.playButton.height / 2;
    this.background.width = w;
    this.background.height = h;
};

Load.prototype.playGame = function () {
    this.state.start('GameScreen');
};

Load.prototype.testRenderer = function () {
    // Test the renderer
    var renderer = 'unknown';
    switch (this.game.renderType) {
      case Phaser.CANVAS:
        renderer = 'CANVAS';
        break;
      case Phaser.WEBGL:
        renderer = 'WEBGL';
        break;
      case Phaser.HEADLESS:
        renderer = 'HEADLESS';
        break;
    }
    try {
        localStorage.setItem('ShapeClear.renderer', renderer);
    }
    catch (e) {
        ;
    }
};
<commit_msg>HACK workaround for Firefox running under file://<commit_after>function Load () {
    this.loadBar = null;
    this.playButton = null;
    this.background = null;
    // HACK
    this.loadTicks = 0;
}

Load.prototype.preload = function () {
    this.loadBar = this.add.text(this.game.width / 2, this.game.height / 2, 'Loading assets...');
    this.loadBar.x -= this.loadBar.width / 2;
    this.loadBar.y -= this.loadBar.height / 2;
    this.testRenderer();

    // some game settings
    game.scale.scaleMode = Phaser.ScaleManager.USER_SCALE;
    game.scale.onResize = function () {
        game.scale.setGameSize(document.body.clientWidth, document.body.clientHeight);
    };
    game.time.advancedTiming = true;
    game.stage.backgroundColor = '#0080ff';

    // load assets
    game.load.image('ball', 'assets/ball.png');
    game.load.atlasJSONArray('shapes', 'img/shapes_small.png', 'img/shapes_small.json');
    game.load.image('background', 'assets/background.png');
};

Load.prototype.preloadUpdate = function () {
    this.loadBar.x = this.game.width / 2 - this.loadBar.width / 2;
    this.loadBar.y = this.game.height / 2 - this.loadBar.height / 2;
};

Load.prototype.create = function() {
    this.background = this.add.sprite(0, 0, 'background');
    this.background.width = this.game.width;
    this.background.height = this.game.height;
    this.background.moveDown();
    this.loadBar.text = 'Start!';
    this.playButton = this.add.button(this.game.width / 2 - 100, this.game.height / 2 - 35,
      'ball', this.playGame, this);
    this.loadBar.moveUp();
    this.playButton.width = 200;
    this.playButton.height = 70;
};

Load.prototype.update = function () {
    var w = this.game.width;
    var h = this.game.height;
    this.loadBar.x = w / 2 - this.loadBar.width / 2;
    this.loadBar.y = h / 2 - this.loadBar.height / 2;
    this.playButton.x = w / 2 - this.playButton.width / 2;
    this.playButton.y = h / 2 - this.playButton.height / 2;
    this.background.width = w;
    this.background.height = h;

    // HACK workaround for Firefox running under file://
    this.loadTicks++;
    if (this.loadTicks == 10 && location.protocol === 'file:') {
        this.game.cache.destroy();
        this.state.start('Load');
    }
};

Load.prototype.playGame = function () {
    this.state.start('GameScreen');
};

Load.prototype.testRenderer = function () {
    // Test the renderer
    var renderer = 'unknown';
    switch (this.game.renderType) {
      case Phaser.CANVAS:
        renderer = 'CANVAS';
        break;
      case Phaser.WEBGL:
        renderer = 'WEBGL';
        break;
      case Phaser.HEADLESS:
        renderer = 'HEADLESS';
        break;
    }
    try {
        localStorage.setItem('ShapeClear.renderer', renderer);
    }
    catch (e) {
        ;
    }
};
<|endoftext|>


<commit_before>/*
  Youtube Player with Playlist (v2.1)
  https://github.com/carloscabo/responsive-youtube-player-with-playlist
  by Carlos Cabo (@putuko)
*/

var RYPP = (function($, undefined) {

  function Rypp(el, api_key, options) {

    if (typeof api_key === 'undefined') {
      console.log("Youtube API V3 requires a valid API KEY.\nFollow the instructions at: https://developers.google.com/youtube/v3/getting-started");
      return false;
    }

    // DOM Elements container
    this.DOM = {};

    // Default settings container
    this.options = {};

    // Data / urls
    this.data = {
      // Playlist url
      ytapi: {
        playlist: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
        videolist: 'https://www.googleapis.com/youtube/v3/videos?part=snippet&maxResults=50&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}'
      },
      firsttime: true
    };

    // Initialize
    this.init(el, api_key, options);
  }

  // Prototype for the instance
  Rypp.prototype = {

    init: function(el, api_key, options) {

      // Api key
      this.api_key = api_key;

      // Default options
      this.options = {
        autoplay: true,
        autonext: true,
        loop: true,
        mute: false
      };

      // Merge initial options
      if (typeof options !== 'undefined') {
        $.extend(this.options, options);
      }

      // YT Player object
      this.ytplayer = null;

      // DOM elements
      this.DOM = {};
      this.DOM.$el = $(el);
      this.DOM.$playlc = this.DOM.$el.find('.RYPP-playlist');
      this.DOM.$items =  this.DOM.$el.find('.RYPP-items');
      this.DOM.$videoc = this.DOM.$el.find('.RYPP-video');

      // Unique player ID
      this.data.player_uid = (Math.random().toString(16).substr(2,8));
      this.DOM.$el.attr('data-rypp',this.data.player_uid).find('.RYPP-video-player').attr('id','RYPP-vp-'+this.data.player_uid);

      // Link JS only once
      if (typeof YT === 'undefined') {
        var
          tag = document.createElement('script'),
          hID = document.getElementsByTagName('head')[0];
        // Add youtube API in HEAD
        // tag.src = "https://www.youtube.com/iframe_api";
        tag.src = 'http://www.youtube.com/player_api';
        hID.appendChild(tag);
      }
    },

    onYouTubeIframeAPIReady: function() {
      this.populatePlaylist();
    },

    populatePlaylist: function() {
      // Empty playlist
      this.DOM.$items.html('').append($('
'));

      // Now we read the video list from playlist data or from IDs...
      if (this.DOM.$el.attr('data-playlist')) {
        this.getVideosFrom(
          'playlist',
          this.DOM.$el.attr('data-playlist')
        );
      } else if (this.DOM.$el.attr('data-ids')) {
        var vl = this.DOM.$el.attr('data-ids');
        // Clean spaces
        vl = ($.map(vl.split(','),$.trim)).join(',');
        this.getVideosFrom(
          'videolist',
          vl
        );
      }
    },

    addAPIPlayer: function() {
      var that = this;

      this.ytplayer = new YT.Player('RYPP-vp-'+this.data.player_uid, {
        // height: '390',
        // width: '640',
        playerVars: {
          // controls: 0,
          // showinfo: 0 ,
          // autoplay: 0,
          enablejsapi: 1,
          rel: 0,
          modestbranding: 1,
          wmode: 'transparent'
        },
        events: {
          'onReady': function(){
            that.onPlayerReady();
          },
          'onStateChange': function(e){
            that.onPlayerStateChange(e);
          },
          'onError': function(e) {
            console.log(e);
          }
        }
      });
    },

    // Ready to play
    onPlayerReady: function() {
      this.startPlayList();
    },

    // When video finish
    onPlayerStateChange: function(e){

      if (typeof e !== 'undefined') {

        // On video loaded?
        if(e.data === -1 && this.data.firsttime) {
          if(!this.options.autoplay) {
            this.ytplayer.pauseVideo();
          }
          if(this.options.mute) {
            this.ytplayer.mute();
          }
        }

        // Play next
        var next = null;
        if(e.data === 0 && this.options.autonext) {
          next = this.DOM.$items.find('li.selected').next();
          if (next.length === 0 && this.options.loop) {
            next = this.DOM.$items.find('li').first();
          }
          next.click();
        }

        // First video
        this.data.firsttime = false;

      }

    },

    // Get video from data-ids or playlist
    getVideosFrom: function(kind, resources_id) {
      var
        that = this,
        url  = this.data.ytapi[kind].replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);

      $.ajaxSetup ({cache: false});
      $.ajax(url, {
        context: this,
        dataType: 'json',
        crossDomain: true,
        error: function(){
          // Not successful
        },
        success: function(data){

          for (i = 0, len = data.items.length; i < len; i++) {
            var item = data.items[i];
            // Videos without thumbnail were deleted!
            if (typeof item.snippet.thumbnails !== 'undefined') {
              var
                vid  = null,
                tit  = item.snippet.title,
                aut  = item.snippet.channelTitle,
                thu  = item.snippet.thumbnails.default.url;
              if (typeof item.snippet.resourceId === 'undefined') {
                // ID de un vídeo
                vid = item.id;
              } else {
                // Elemento de playlist
                vid =  item.snippet.resourceId.videoId;
              }
              that.addVideo2Playlist(vid, tit, aut, thu);
            }
          }
          that.addAPIPlayer();
        }
      });
    },

    // All videos are supossed to be loaded
    // lets start the playlist
    startPlayList: function() {

      var
        D = this.DOM,
        vid = null,
        that = this;

      // Click on playlist elemnts
      D.$items.on('click', 'li', function(e) {
        e.preventDefault();
        D.$items.find('li').removeClass('selected');
        $(this).addClass('selected');
        vid = $(this).data('video-id');
        // Call YT API function
        that.ytplayer.loadVideoById(vid);
      });

      // Select first if none
      if (D.$items.find('li.selected').length === 0) {
        D.$items.find('li').first().click();
      }
    },

    // Add video block to playlist
    addVideo2Playlist: function(vid, tit, aut, thu) {
      var
        D  = this.DOM;
      $('

'+tit+'
'+aut+'

').appendTo(D.$items.find('ol'));
    },

  }; // prototypes

  return Rypp;

}(jQuery));

// Here will be stored all the instances of RYPP in the page
var RYPP_instances = [];

// YOUTUBE API CALLBACK
function onYouTubeIframeAPIReady() {
  for (var i = RYPP_instances.length - 1; i >= 0; i--) {
    RYPP_instances[i].onYouTubeIframeAPIReady();
  }
}

// JQuery hook
$.fn.rypp = function(api_key, options) {
  return this.each(function() {
    RYPP_instances.push(new RYPP(this, api_key, options));
  });
};
<commit_msg>Changed the way that onYouTubeIframeAPIReady is called<commit_after>/*
  Youtube Player with Playlist (v2.1)
  https://github.com/carloscabo/responsive-youtube-player-with-playlist
  by Carlos Cabo (@putuko)
*/

var RYPP = (function($, undefined) {
  'use strict';

  function Rypp(el, api_key, options) {

    if (typeof api_key === 'undefined') {
      console.log("Youtube API V3 requires a valid API KEY.\nFollow the instructions at: https://developers.google.com/youtube/v3/getting-started");
      return false;
    }

    // DOM Elements container
    this.DOM = {};

    // Default settings container
    this.options = {};

    // Data / urls
    this.data = {
      // Playlist url
      ytapi: {
        playlist: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
        videolist: 'https://www.googleapis.com/youtube/v3/videos?part=snippet&maxResults=50&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}'
      },
      firsttime: true
    };

    // Initialize
    this.init(el, api_key, options);
  }

  // Prototype for the instance
  Rypp.prototype = {

    init: function(el, api_key, options) {

      // Api key
      this.api_key = api_key;

      // Default options
      this.options = {
        autoplay: true,
        autonext: true,
        loop: true,
        mute: false
      };

      // Merge initial options
      if (typeof options !== 'undefined') {
        $.extend(this.options, options);
      }

      // YT Player object
      this.ytplayer = null;

      // DOM elements
      this.DOM = {};
      this.DOM.$el = $(el);
      this.DOM.$playlc = this.DOM.$el.find('.RYPP-playlist');
      this.DOM.$items =  this.DOM.$el.find('.RYPP-items');
      this.DOM.$videoc = this.DOM.$el.find('.RYPP-video');

      // Unique player ID
      this.data.player_uid = (Math.random().toString(16).substr(2,8));
      this.DOM.$el.attr('data-rypp',this.data.player_uid).find('.RYPP-video-player').attr('id','RYPP-vp-'+this.data.player_uid);

      // Link JS only once
      if (typeof YT === 'undefined') {
        var
          tag = document.createElement('script'),
          hID = document.getElementsByTagName('head')[0];
        // Add youtube API in HEAD
        // tag.src = "https://www.youtube.com/iframe_api";
        tag.src = 'http://www.youtube.com/player_api';
        hID.appendChild(tag);
      }

    },

    onYouTubeIframeAPIReady: function() {
      this.populatePlaylist();
    },

    populatePlaylist: function() {
      // Empty playlist
      this.DOM.$items.html('').append($('
'));

      // Now we read the video list from playlist data or from IDs...
      if (this.DOM.$el.attr('data-playlist')) {
        this.getVideosFrom(
          'playlist',
          this.DOM.$el.attr('data-playlist')
        );
      } else if (this.DOM.$el.attr('data-ids')) {
        var vl = this.DOM.$el.attr('data-ids');
        // Clean spaces
        vl = ($.map(vl.split(','),$.trim)).join(',');
        this.getVideosFrom(
          'videolist',
          vl
        );
      }
    },

    addAPIPlayer: function() {
      var that = this;

      this.ytplayer = new YT.Player('RYPP-vp-'+this.data.player_uid, {
        // height: '390',
        // width: '640',
        playerVars: {
          // controls: 0,
          // showinfo: 0 ,
          // autoplay: 0,
          enablejsapi: 1,
          rel: 0,
          modestbranding: 1,
          wmode: 'transparent'
        },
        events: {
          'onReady': function(){
            that.onPlayerReady();
          },
          'onStateChange': function(e){
            that.onPlayerStateChange(e);
          },
          'onError': function(e) {
            console.log(e);
          }
        }
      });
    },

    // Ready to play
    onPlayerReady: function() {
      this.startPlayList();
    },

    // When video finish
    onPlayerStateChange: function(e){

      if (typeof e !== 'undefined') {

        // On video loaded?
        if(e.data === -1 && this.data.firsttime) {
          if(!this.options.autoplay) {
            this.ytplayer.pauseVideo();
          }
          if(this.options.mute) {
            this.ytplayer.mute();
          }
        }

        // Play next
        var next = null;
        if(e.data === 0 && this.options.autonext) {
          next = this.DOM.$items.find('li.selected').next();
          if (next.length === 0 && this.options.loop) {
            next = this.DOM.$items.find('li').first();
          }
          next.click();
        }

        // First video
        this.data.firsttime = false;

      }

    },

    // Get video from data-ids or playlist
    getVideosFrom: function(kind, resources_id) {
      var
        that = this,
        url  = this.data.ytapi[kind].replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);

      $.ajaxSetup ({cache: false});
      $.ajax(url, {
        context: this,
        dataType: 'json',
        crossDomain: true,
        error: function(){
          // Not successful
        },
        success: function(data){

          // console.log(data.items);

          for (var i = 0, len = data.items.length; i < len; i++) {
            var item = data.items[i];

            // Videos without thumbnail were deleted!
            if (typeof item.snippet.thumbnails !== 'undefined') {

              var
                vid  = null,
                tit  = item.snippet.title,
                aut  = item.snippet.channelTitle,
                thu  = item.snippet.thumbnails.default.url;
              if (typeof item.snippet.resourceId === 'undefined') {
                // ID de un vídeo
                vid = item.id;
              } else {
                // Elemento de playlist
                vid =  item.snippet.resourceId.videoId;
              }
              that.addVideo2Playlist(vid, tit, aut, thu);
            }
          }
          that.addAPIPlayer();
        }
      });
    },

    // All videos are supossed to be loaded
    // lets start the playlist
    startPlayList: function() {

      var
        D = this.DOM,
        vid = null,
        that = this;

      // Click on playlist elemnts
      D.$items.on('click', 'li', function(e) {
        e.preventDefault();
        D.$items.find('li').removeClass('selected');
        $(this).addClass('selected');
        vid = $(this).data('video-id');
        // Call YT API function
        that.ytplayer.loadVideoById(vid);
      });

      // Select first if none
      if (D.$items.find('li.selected').length === 0) {
        D.$items.find('li').first().click();
      }
    },

    // Add video block to playlist
    addVideo2Playlist: function(vid, tit, aut, thu) {
      var
        D  = this.DOM;
      $('

'+tit+'
'+aut+'

').appendTo(D.$items.find('ol'));
    },

  }; // prototypes

  return Rypp;

}(jQuery));

// YOUTUBE API CALLBACK
function onYouTubeIframeAPIReady() {
  $('[data-rypp]').each(function(idx, el) {
    $(el)[0].rypp_data_obj.onYouTubeIframeAPIReady();
  });
}

// JQuery hook
$.fn.rypp = function(api_key, options) {
  return this.each(function() {
    // Store object in DOM element
    this.rypp_data_obj = new RYPP(this, api_key, options);
  });
};
<|endoftext|>


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

/**
 * Utility functions for Dot, placed into the dot.X namespace.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

define( function( require ) {
  'use strict';

  var dot = require( 'DOT/dot' );
  // require( 'DOT/Vector2' ); // Require.js doesn't like the circular reference

  // constants
  var EPSILON = Number.MIN_VALUE;
  var TWO_PI = 2 * Math.PI;

  // "static" variables used in boxMullerTransform
  var generate;
  var z0;
  var z1;

  dot.Util = {
    testAssert: function() {
      return 'assert.dot: ' + ( assert ? 'true' : 'false' );
    },

    clamp: function( value, min, max ) {
      if ( value < min ) {
        return min;
      }
      else if ( value > max ) {
        return max;
      }
      else {
        return value;
      }
    },

    // returns a number between [min,max) with the same equivalence class as value mod (max-min)
    moduloBetweenDown: function( value, min, max ) {
      assert && assert( max > min, 'max > min required for moduloBetween' );

      var divisor = max - min;

      // get a partial result of value-min between [0,divisor)
      var partial = ( value - min ) % divisor;
      if ( partial < 0 ) {
        // since if value-min < 0, the remainder will give us a negative number
        partial += divisor;
      }

      return partial + min; // add back in the minimum value
    },

    // returns a number between (min,max] with the same equivalence class as value mod (max-min)
    moduloBetweenUp: function( value, min, max ) {
      return -Util.moduloBetweenDown( -value, -max, -min );
    },

    // Returns an array of integers from A to B (including both A to B)
    rangeInclusive: function( a, b ) {
      if ( b < a ) {
        return [];
      }
      var result = new Array( b - a + 1 );
      for ( var i = a; i <= b; i++ ) {
        result[ i - a ] = i;
      }
      return result;
    },

    // Returns an array of integers between A and B (excluding both A to B)
    rangeExclusive: function( a, b ) {
      return Util.rangeInclusive( a + 1, b - 1 );
    },

    toRadians: function( degrees ) {
      return Math.PI * degrees / 180;
    },

    toDegrees: function( radians ) {
      return 180 * radians / Math.PI;
    },

    // find the greatest common denominator using the classic algorithm
    gcd: function( a, b ) {
      return b === 0 ? a : this.gcd( b, a % b );
    },

    // intersection between the line from p1-p2 and the line from p3-p4
    // Taken from an answer in http://stackoverflow.com/questions/385305/efficient-maths-algorithm-to-calculate-intersections
    // Does not handle parallel lines
    lineLineIntersection: function( p1, p2, p3, p4 ) {
      var x12 = p1.x - p2.x;
      var x34 = p3.x - p4.x;
      var y12 = p1.y - p2.y;
      var y34 = p3.y - p4.y;

      var denom = x12 * y34 - y12 * x34;

      var a = p1.x * p2.y - p1.y * p2.x;
      var b = p3.x * p4.y - p3.y * p4.x;

      return new dot.Vector2(
        ( a * x34 - x12 * b ) / denom,
        ( a * y34 - y12 * b ) / denom
      );
    },

    // assumes a sphere with the specified radius, centered at the origin
    sphereRayIntersection: function( radius, ray, epsilon ) {
      epsilon = epsilon === undefined ? 1e-5 : epsilon;

      // center is the origin for now, but leaving in computations so that we can change that in the future. optimize away if needed
      var center = new dot.Vector3();

      var rayDir = ray.dir;
      var pos = ray.pos;
      var centerToRay = pos.minus( center );

      // basically, we can use the quadratic equation to solve for both possible hit points (both +- roots are the hit points)
      var tmp = rayDir.dot( centerToRay );
      var centerToRayDistSq = centerToRay.magnitudeSquared();
      var det = 4 * tmp * tmp - 4 * ( centerToRayDistSq - radius * radius );
      if ( det < epsilon ) {
        // ray misses sphere entirely
        return null;
      }

      var base = rayDir.dot( center ) - rayDir.dot( pos );
      var sqt = Math.sqrt( det ) / 2;

      // the "first" entry point distance into the sphere. if we are inside the sphere, it is behind us
      var ta = base - sqt;

      // the "second" entry point distance
      var tb = base + sqt;

      if ( tb < epsilon ) {
        // sphere is behind ray, so don't return an intersection
        return null;
      }

      var hitPositionB = ray.pointAtDistance( tb );
      var normalB = hitPositionB.minus( center ).normalized();

      if ( ta < epsilon ) {
        // we are inside the sphere
        // in => out
        return {
          distance: tb,
          hitPoint: hitPositionB,
          normal: normalB.negated(),
          fromOutside: false
        };
      }
      else {
        // two possible hits
        var hitPositionA = ray.pointAtDistance( ta );
        var normalA = hitPositionA.minus( center ).normalized();

        // close hit, we have out => in
        return {
          distance: ta,
          hitPoint: hitPositionA,
          normal: normalA,
          fromOutside: true
        };
      }
    },

    // return an array of real roots of ax^2 + bx + c = 0
    solveQuadraticRootsReal: function( a, b, c ) {
      var epsilon = 1E7;

      //We need to test whether a is several orders of magnitude less than b or c. If so, return the result as a solution to the linear (easy) equation
      if ( a === 0 || Math.abs( b / a ) > epsilon || Math.abs( c / a ) > epsilon ) {
        return [ -c / b ];
      }

      var discriminant = b * b - 4 * a * c;
      if ( discriminant < 0 ) {
        return [];
      }
      var sqrt = Math.sqrt( discriminant );
      // TODO: how to handle if discriminant is 0? give unique root or double it?
      // TODO: probably just use Complex for the future
      return [
        ( -b - sqrt ) / ( 2 * a ),
        ( -b + sqrt ) / ( 2 * a )
      ];
    },

    // return an array of real roots of ax^3 + bx^2 + cx + d = 0
    solveCubicRootsReal: function( a, b, c, d ) {
      // TODO: a Complex type!

      //We need to test whether a is several orders of magnitude less than b, c, d
      var epsilon = 1E7;

      if ( a === 0 || Math.abs( b / a ) > epsilon || Math.abs( c / a ) > epsilon || Math.abs( d / a ) > epsilon ) {
        return Util.solveQuadraticRootsReal( b, c, d );
      }
      if ( d === 0 || Math.abs( a / d ) > epsilon || Math.abs( b / d ) > epsilon || Math.abs( c / d ) > epsilon ) {
        return Util.solveQuadraticRootsReal( a, b, c );
      }

      b /= a;
      c /= a;
      d /= a;

      var q = ( 3.0 * c - ( b * b ) ) / 9;
      var r = ( -(27 * d) + b * (9 * c - 2 * (b * b)) ) / 54;
      var discriminant = q * q * q + r * r;
      var b3 = b / 3;

      if ( discriminant > 0 ) {
        // a single real root
        var dsqrt = Math.sqrt( discriminant );
        return [ Util.cubeRoot( r + dsqrt ) + Util.cubeRoot( r - dsqrt ) - b3 ];
      }

      // three real roots
      if ( discriminant === 0 ) {
        // contains a double root
        var rsqrt = Util.cubeRoot( r );
        var doubleRoot = b3 - rsqrt;
        return [ -b3 + 2 * rsqrt, doubleRoot, doubleRoot ];
      }
      else {
        // all unique
        var qX = -q * q * q;
        qX = Math.acos( r / Math.sqrt( qX ) );
        var rr = 2 * Math.sqrt( -q );
        return [
          -b3 + rr * Math.cos( qX / 3 ),
          -b3 + rr * Math.cos( ( qX + 2 * Math.PI ) / 3 ),
          -b3 + rr * Math.cos( ( qX + 4 * Math.PI ) / 3 )
        ];
      }
    },

    cubeRoot: function( x ) {
      return x >= 0 ? Math.pow( x, 1 / 3 ) : -Math.pow( -x, 1 / 3 );
    },

    // Linearly interpolate two points and evaluate the line equation for a third point
    // f( a1 ) = b1, f( a2 ) = b2, f( a3 ) = <linear mapped value>
    linear: function( a1, a2, b1, b2, a3 ) {
      return ( b2 - b1 ) / ( a2 - a1 ) * ( a3 - a1 ) + b1;
    },

    /**
     * A predictable implementation of toFixed.
     * JavaScript's toFixed is notoriously buggy, behavior differs depending on browser,
     * because the spec doesn't specify whether to round or floor.
     * @param {number} number
     * @param {number} decimalPlaces
     * @returns {string}
     */
    toFixed: function( number, decimalPlaces ) {
      var multiplier = Math.pow( 10, decimalPlaces );
      var value = Math.round( number * multiplier ) / multiplier;
      return value.toFixed( decimalPlaces );
    },

    // Convenience for returning a number instead of a string.
    toFixedNumber: function( number, decimalPlaces ) {
      return parseFloat( Util.toFixed( number, decimalPlaces ) );
    },

    isInteger: function( n ) {
      return ( typeof n === 'number' ) && ( n % 1 === 0 );
    },

    /*
     * Computes the intersection of two line segments. Algorithm taken from Paul Bourke, 1989:
     * http://paulbourke.net/geometry/pointlineplane/
     * http://paulbourke.net/geometry/pointlineplane/pdb.c
     * Ported from MathUtil.java on 9/20/2013 by @samreid
     * line a goes from point 1->2 and line b goes from 3->4
     * @returns a Vector2 of the intersection point, or null if no intersection
     */
    lineSegmentIntersection: function( x1, y1, x2, y2, x3, y3, x4, y4 ) {
      var numA = ( x4 - x3 ) * ( y1 - y3 ) - ( y4 - y3 ) * ( x1 - x3 );
      var numB = ( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 );
      var denom = ( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 );

      // If denominator is 0, the lines are parallel or coincident
      if ( denom === 0 ) {
        return null;
      }
      else {
        var ua = numA / denom;
        var ub = numB / denom;

        // ua and ub must both be in the range 0 to 1 for the segments to have an intersection pt.
        if ( !( ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) ) {
          return null;
        }
        else {
          var x = x1 + ua * ( x2 - x1 );
          var y = y1 + ua * ( y2 - y1 );
          return new dot.Vector2( x, y );
        }
      }
    },

    /**
     * Squared distance from a point to a line segment squared.
     * See http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
     *
     * @param point the point
     * @param a start point of a line segment
     * @param b end point of a line segment
     * @returns {Number}
     */
    distToSegmentSquared: function( point, a, b ) {
      var segmentLength = a.distanceSquared( b );
      if ( segmentLength === 0 ) { return point.distanceSquared( a ); }
      var t = ((point.x - a.x) * (b.x - a.x) + (point.y - a.y) * (b.y - a.y)) / segmentLength;
      return t < 0 ? point.distanceSquared( a ) :
             t > 1 ? point.distanceSquared( b ) :
             point.distanceSquared( new dot.Vector2( a.x + t * (b.x - a.x), a.y + t * (b.y - a.y) ) );
    },

    /**
     * Squared distance from a point to a line segment squared.
     * @param point the point
     * @param a start point of a line segment
     * @param b end point of a line segment
     * @returns {Number}
     */
    distToSegment: function( point, a, b ) { return Math.sqrt( this.distToSegmentSquared( point, a, b ) ); },

    arePointsCollinear: function( a, b, c, epsilon ) {
      if ( epsilon === undefined ) {
        epsilon = 0;
      }
      return Util.triangleArea( a, b, c ) <= epsilon;
    },

    triangleArea: function( a, b, c ) {
      return Math.abs( Util.triangleAreaSigned( a, b, c ) );
    },

    // TODO: investigate which way we want the sign (Canvas or WebGL style)
    triangleAreaSigned: function( a, b, c ) {
      return a.x * ( b.y - c.y ) + b.x * ( c.y - a.y ) + c.x * ( a.y - b.y );
    },

    log10: function( val ) {
      return Math.log( val ) / Math.LN10;
    },

    /**
     * Generates a random Gaussian sample with the given mean and standard deviation.
     * This method relies on the "static" variables generate, z0, and z1 defined above.
     * Random.js is the primary client of this function, but it is defined here so it can be
     * used other places more easily if need be.
     * Code inspired by example here: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform.
     *
     * @param mu the mean of the Gaussian
     * @param sigma the standard deviation of the Gaussian
     * @returns {number}
     */
    boxMullerTransform: function( mu, sigma ) {
      generate = !generate;

      if ( !generate ) {
        return z1 * sigma + mu;
      }

      var u1;
      var u2;
      do {
        u1 = Math.random();
        u2 = Math.random();
      }
      while ( u1 <= EPSILON );

      z0 = Math.sqrt( -2.0 * Math.log( u1 ) ) * Math.cos( TWO_PI * u2 );
      z1 = Math.sqrt( -2.0 * Math.log( u1 ) ) * Math.sin( TWO_PI * u2 );
      return z0 * sigma + mu;
    }
  };

  var Util = dot.Util;

  // make these available in the main namespace directly (for now)
  dot.testAssert = Util.testAssert;
  dot.clamp = Util.clamp;
  dot.moduloBetweenDown = Util.moduloBetweenDown;
  dot.moduloBetweenUp = Util.moduloBetweenUp;
  dot.rangeInclusive = Util.rangeInclusive;
  dot.rangeExclusive = Util.rangeExclusive;
  dot.toRadians = Util.toRadians;
  dot.toDegrees = Util.toDegrees;
  dot.lineLineIntersection = Util.lineLineIntersection;
  dot.sphereRayIntersection = Util.sphereRayIntersection;
  dot.solveQuadraticRootsReal = Util.solveQuadraticRootsReal;
  dot.solveCubicRootsReal = Util.solveCubicRootsReal;
  dot.cubeRoot = Util.cubeRoot;
  dot.linear = Util.linear;
  dot.boxMullerTransform = Util.boxMullerTransform;

  return Util;
} );
<commit_msg>#35 change Util.toFixed to use IEEE 754 "Round half away from zero" algorithm<commit_after>// Copyright 2002-2015, University of Colorado Boulder

/**
 * Utility functions for Dot, placed into the dot.X namespace.
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

define( function( require ) {
  'use strict';

  var dot = require( 'DOT/dot' );
  // require( 'DOT/Vector2' ); // Require.js doesn't like the circular reference

  // constants
  var EPSILON = Number.MIN_VALUE;
  var TWO_PI = 2 * Math.PI;

  // "static" variables used in boxMullerTransform
  var generate;
  var z0;
  var z1;

  dot.Util = {
    testAssert: function() {
      return 'assert.dot: ' + ( assert ? 'true' : 'false' );
    },

    clamp: function( value, min, max ) {
      if ( value < min ) {
        return min;
      }
      else if ( value > max ) {
        return max;
      }
      else {
        return value;
      }
    },

    // returns a number between [min,max) with the same equivalence class as value mod (max-min)
    moduloBetweenDown: function( value, min, max ) {
      assert && assert( max > min, 'max > min required for moduloBetween' );

      var divisor = max - min;

      // get a partial result of value-min between [0,divisor)
      var partial = ( value - min ) % divisor;
      if ( partial < 0 ) {
        // since if value-min < 0, the remainder will give us a negative number
        partial += divisor;
      }

      return partial + min; // add back in the minimum value
    },

    // returns a number between (min,max] with the same equivalence class as value mod (max-min)
    moduloBetweenUp: function( value, min, max ) {
      return -Util.moduloBetweenDown( -value, -max, -min );
    },

    // Returns an array of integers from A to B (including both A to B)
    rangeInclusive: function( a, b ) {
      if ( b < a ) {
        return [];
      }
      var result = new Array( b - a + 1 );
      for ( var i = a; i <= b; i++ ) {
        result[ i - a ] = i;
      }
      return result;
    },

    // Returns an array of integers between A and B (excluding both A to B)
    rangeExclusive: function( a, b ) {
      return Util.rangeInclusive( a + 1, b - 1 );
    },

    toRadians: function( degrees ) {
      return Math.PI * degrees / 180;
    },

    toDegrees: function( radians ) {
      return 180 * radians / Math.PI;
    },

    // find the greatest common denominator using the classic algorithm
    gcd: function( a, b ) {
      return b === 0 ? a : this.gcd( b, a % b );
    },

    // intersection between the line from p1-p2 and the line from p3-p4
    // Taken from an answer in http://stackoverflow.com/questions/385305/efficient-maths-algorithm-to-calculate-intersections
    // Does not handle parallel lines
    lineLineIntersection: function( p1, p2, p3, p4 ) {
      var x12 = p1.x - p2.x;
      var x34 = p3.x - p4.x;
      var y12 = p1.y - p2.y;
      var y34 = p3.y - p4.y;

      var denom = x12 * y34 - y12 * x34;

      var a = p1.x * p2.y - p1.y * p2.x;
      var b = p3.x * p4.y - p3.y * p4.x;

      return new dot.Vector2(
        ( a * x34 - x12 * b ) / denom,
        ( a * y34 - y12 * b ) / denom
      );
    },

    // assumes a sphere with the specified radius, centered at the origin
    sphereRayIntersection: function( radius, ray, epsilon ) {
      epsilon = epsilon === undefined ? 1e-5 : epsilon;

      // center is the origin for now, but leaving in computations so that we can change that in the future. optimize away if needed
      var center = new dot.Vector3();

      var rayDir = ray.dir;
      var pos = ray.pos;
      var centerToRay = pos.minus( center );

      // basically, we can use the quadratic equation to solve for both possible hit points (both +- roots are the hit points)
      var tmp = rayDir.dot( centerToRay );
      var centerToRayDistSq = centerToRay.magnitudeSquared();
      var det = 4 * tmp * tmp - 4 * ( centerToRayDistSq - radius * radius );
      if ( det < epsilon ) {
        // ray misses sphere entirely
        return null;
      }

      var base = rayDir.dot( center ) - rayDir.dot( pos );
      var sqt = Math.sqrt( det ) / 2;

      // the "first" entry point distance into the sphere. if we are inside the sphere, it is behind us
      var ta = base - sqt;

      // the "second" entry point distance
      var tb = base + sqt;

      if ( tb < epsilon ) {
        // sphere is behind ray, so don't return an intersection
        return null;
      }

      var hitPositionB = ray.pointAtDistance( tb );
      var normalB = hitPositionB.minus( center ).normalized();

      if ( ta < epsilon ) {
        // we are inside the sphere
        // in => out
        return {
          distance: tb,
          hitPoint: hitPositionB,
          normal: normalB.negated(),
          fromOutside: false
        };
      }
      else {
        // two possible hits
        var hitPositionA = ray.pointAtDistance( ta );
        var normalA = hitPositionA.minus( center ).normalized();

        // close hit, we have out => in
        return {
          distance: ta,
          hitPoint: hitPositionA,
          normal: normalA,
          fromOutside: true
        };
      }
    },

    // return an array of real roots of ax^2 + bx + c = 0
    solveQuadraticRootsReal: function( a, b, c ) {
      var epsilon = 1E7;

      //We need to test whether a is several orders of magnitude less than b or c. If so, return the result as a solution to the linear (easy) equation
      if ( a === 0 || Math.abs( b / a ) > epsilon || Math.abs( c / a ) > epsilon ) {
        return [ -c / b ];
      }

      var discriminant = b * b - 4 * a * c;
      if ( discriminant < 0 ) {
        return [];
      }
      var sqrt = Math.sqrt( discriminant );
      // TODO: how to handle if discriminant is 0? give unique root or double it?
      // TODO: probably just use Complex for the future
      return [
        ( -b - sqrt ) / ( 2 * a ),
        ( -b + sqrt ) / ( 2 * a )
      ];
    },

    // return an array of real roots of ax^3 + bx^2 + cx + d = 0
    solveCubicRootsReal: function( a, b, c, d ) {
      // TODO: a Complex type!

      //We need to test whether a is several orders of magnitude less than b, c, d
      var epsilon = 1E7;

      if ( a === 0 || Math.abs( b / a ) > epsilon || Math.abs( c / a ) > epsilon || Math.abs( d / a ) > epsilon ) {
        return Util.solveQuadraticRootsReal( b, c, d );
      }
      if ( d === 0 || Math.abs( a / d ) > epsilon || Math.abs( b / d ) > epsilon || Math.abs( c / d ) > epsilon ) {
        return Util.solveQuadraticRootsReal( a, b, c );
      }

      b /= a;
      c /= a;
      d /= a;

      var q = ( 3.0 * c - ( b * b ) ) / 9;
      var r = ( -(27 * d) + b * (9 * c - 2 * (b * b)) ) / 54;
      var discriminant = q * q * q + r * r;
      var b3 = b / 3;

      if ( discriminant > 0 ) {
        // a single real root
        var dsqrt = Math.sqrt( discriminant );
        return [ Util.cubeRoot( r + dsqrt ) + Util.cubeRoot( r - dsqrt ) - b3 ];
      }

      // three real roots
      if ( discriminant === 0 ) {
        // contains a double root
        var rsqrt = Util.cubeRoot( r );
        var doubleRoot = b3 - rsqrt;
        return [ -b3 + 2 * rsqrt, doubleRoot, doubleRoot ];
      }
      else {
        // all unique
        var qX = -q * q * q;
        qX = Math.acos( r / Math.sqrt( qX ) );
        var rr = 2 * Math.sqrt( -q );
        return [
          -b3 + rr * Math.cos( qX / 3 ),
          -b3 + rr * Math.cos( ( qX + 2 * Math.PI ) / 3 ),
          -b3 + rr * Math.cos( ( qX + 4 * Math.PI ) / 3 )
        ];
      }
    },

    cubeRoot: function( x ) {
      return x >= 0 ? Math.pow( x, 1 / 3 ) : -Math.pow( -x, 1 / 3 );
    },

    // Linearly interpolate two points and evaluate the line equation for a third point
    // f( a1 ) = b1, f( a2 ) = b2, f( a3 ) = <linear mapped value>
    linear: function( a1, a2, b1, b2, a3 ) {
      return ( b2 - b1 ) / ( a2 - a1 ) * ( a3 - a1 ) + b1;
    },

    /**
     * A predictable implementation of toFixed.
     * JavaScript's toFixed is notoriously buggy, behavior differs depending on browser,
     * because the spec doesn't specify whether to round or floor.
     *
     * This is the IEEE 754 "Round half away from zero" algorithm, see
     * https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero
     * It treats positive and negative values symmetrically, which is desirable for sims (see dot#35).
     *
     * @param {number} number
     * @param {number} decimalPlaces
     * @returns {string}
     */
    toFixed: function( number, decimalPlaces ) {
      var multiplier = Math.pow( 10, decimalPlaces );
      var value = Math.round( Math.abs( number ) * multiplier ) / multiplier;
      if ( number < 0 ) { value *= -1; }
      return value.toFixed( decimalPlaces );
    },

    // Convenience for returning a number instead of a string.
    toFixedNumber: function( number, decimalPlaces ) {
      return parseFloat( Util.toFixed( number, decimalPlaces ) );
    },

    isInteger: function( n ) {
      return ( typeof n === 'number' ) && ( n % 1 === 0 );
    },

    /*
     * Computes the intersection of two line segments. Algorithm taken from Paul Bourke, 1989:
     * http://paulbourke.net/geometry/pointlineplane/
     * http://paulbourke.net/geometry/pointlineplane/pdb.c
     * Ported from MathUtil.java on 9/20/2013 by @samreid
     * line a goes from point 1->2 and line b goes from 3->4
     * @returns a Vector2 of the intersection point, or null if no intersection
     */
    lineSegmentIntersection: function( x1, y1, x2, y2, x3, y3, x4, y4 ) {
      var numA = ( x4 - x3 ) * ( y1 - y3 ) - ( y4 - y3 ) * ( x1 - x3 );
      var numB = ( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 );
      var denom = ( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 );

      // If denominator is 0, the lines are parallel or coincident
      if ( denom === 0 ) {
        return null;
      }
      else {
        var ua = numA / denom;
        var ub = numB / denom;

        // ua and ub must both be in the range 0 to 1 for the segments to have an intersection pt.
        if ( !( ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) ) {
          return null;
        }
        else {
          var x = x1 + ua * ( x2 - x1 );
          var y = y1 + ua * ( y2 - y1 );
          return new dot.Vector2( x, y );
        }
      }
    },

    /**
     * Squared distance from a point to a line segment squared.
     * See http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
     *
     * @param point the point
     * @param a start point of a line segment
     * @param b end point of a line segment
     * @returns {Number}
     */
    distToSegmentSquared: function( point, a, b ) {
      var segmentLength = a.distanceSquared( b );
      if ( segmentLength === 0 ) { return point.distanceSquared( a ); }
      var t = ((point.x - a.x) * (b.x - a.x) + (point.y - a.y) * (b.y - a.y)) / segmentLength;
      return t < 0 ? point.distanceSquared( a ) :
             t > 1 ? point.distanceSquared( b ) :
             point.distanceSquared( new dot.Vector2( a.x + t * (b.x - a.x), a.y + t * (b.y - a.y) ) );
    },

    /**
     * Squared distance from a point to a line segment squared.
     * @param point the point
     * @param a start point of a line segment
     * @param b end point of a line segment
     * @returns {Number}
     */
    distToSegment: function( point, a, b ) { return Math.sqrt( this.distToSegmentSquared( point, a, b ) ); },

    arePointsCollinear: function( a, b, c, epsilon ) {
      if ( epsilon === undefined ) {
        epsilon = 0;
      }
      return Util.triangleArea( a, b, c ) <= epsilon;
    },

    triangleArea: function( a, b, c ) {
      return Math.abs( Util.triangleAreaSigned( a, b, c ) );
    },

    // TODO: investigate which way we want the sign (Canvas or WebGL style)
    triangleAreaSigned: function( a, b, c ) {
      return a.x * ( b.y - c.y ) + b.x * ( c.y - a.y ) + c.x * ( a.y - b.y );
    },

    log10: function( val ) {
      return Math.log( val ) / Math.LN10;
    },

    /**
     * Generates a random Gaussian sample with the given mean and standard deviation.
     * This method relies on the "static" variables generate, z0, and z1 defined above.
     * Random.js is the primary client of this function, but it is defined here so it can be
     * used other places more easily if need be.
     * Code inspired by example here: https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform.
     *
     * @param mu the mean of the Gaussian
     * @param sigma the standard deviation of the Gaussian
     * @returns {number}
     */
    boxMullerTransform: function( mu, sigma ) {
      generate = !generate;

      if ( !generate ) {
        return z1 * sigma + mu;
      }

      var u1;
      var u2;
      do {
        u1 = Math.random();
        u2 = Math.random();
      }
      while ( u1 <= EPSILON );

      z0 = Math.sqrt( -2.0 * Math.log( u1 ) ) * Math.cos( TWO_PI * u2 );
      z1 = Math.sqrt( -2.0 * Math.log( u1 ) ) * Math.sin( TWO_PI * u2 );
      return z0 * sigma + mu;
    }
  };

  var Util = dot.Util;

  // make these available in the main namespace directly (for now)
  dot.testAssert = Util.testAssert;
  dot.clamp = Util.clamp;
  dot.moduloBetweenDown = Util.moduloBetweenDown;
  dot.moduloBetweenUp = Util.moduloBetweenUp;
  dot.rangeInclusive = Util.rangeInclusive;
  dot.rangeExclusive = Util.rangeExclusive;
  dot.toRadians = Util.toRadians;
  dot.toDegrees = Util.toDegrees;
  dot.lineLineIntersection = Util.lineLineIntersection;
  dot.sphereRayIntersection = Util.sphereRayIntersection;
  dot.solveQuadraticRootsReal = Util.solveQuadraticRootsReal;
  dot.solveCubicRootsReal = Util.solveCubicRootsReal;
  dot.cubeRoot = Util.cubeRoot;
  dot.linear = Util.linear;
  dot.boxMullerTransform = Util.boxMullerTransform;

  return Util;
} );
<|endoftext|>


<commit_before>
var spwan = require('child_process').spawn;
var argv = require('minimist')(process.argv.slice(2));

if(argv._.some(function(val){return val === 'watch'})){
  console.log(__dirname);
}<commit_msg>bugfix?<commit_after>
var argv = require('minimist')(process.argv.slice(2));

if(argv._.some(function(val){return val === 'watch'})){
  console.log(__dirname);
}<|endoftext|>


<commit_before>var script = document.createElement('script');
var url = 'http://jasonnor.github.io/js/src/coopraid.js';
var inner = "function createScript() {" +
			"	var script = document.createElement('script');" +
			"	script.onerror = function(){location.reload()};" +
			"	script.src = '" + url + "';" +
			"	document.body.appendChild(script);" +
			"}" +
			"function init(){" +
			"	if(window.$ && !$('#ready').is(':visible')) {" +
			"		setTimeout(createScript, 1000);" +
			"		console.log('Creating script ...');" +
			"	}" +
			"	else" +
			"		setTimeout(function(){init()}, 1000);" +
			"}" +
			"init();";
script.innerHTML = inner;
document.body.appendChild(script);
<commit_msg>Update link<commit_after>var script = document.createElement('script');
var url = 'https://cdn.rawgit.com/Jasonnor/Granblue-Autotasy/master/js/coopraid.js';
var inner = "function createScript() {" +
			"	var script = document.createElement('script');" +
			"	script.onerror = function(){location.reload()};" +
			"	script.src = '" + url + "';" +
			"	document.body.appendChild(script);" +
			"}" +
			"function init(){" +
			"	if(window.$ && !$('#ready').is(':visible')) {" +
			"		setTimeout(createScript, 1000);" +
			"		console.log('Creating script ...');" +
			"	}" +
			"	else" +
			"		setTimeout(function(){init()}, 1000);" +
			"}" +
			"init();";
script.innerHTML = inner;
document.body.appendChild(script);
<|endoftext|>