<commit_before>import { canvas, gl } from './context.js';

const default_options = {
  width: 800,
  height: 600,
  dom: document.body,
  fps: 60,
  autostart: true
};

class Game {

  constructor(options) {
    this.options = default_options;

    options = options || {};
    Object.keys(options).forEach(key => {
      this.options[key] = options[key];
    });

    canvas.width = this.options.width;
    canvas.height = this.options.height;

    this.options.dom.appendChild(canvas);

    this.running = this.options.autostart;

    this.last_tick = performance.now();
    this.last_render = this.last_tick;
    this.tick_length = 1000/this.options.fps;

    this.actions = {};

    this.tick((typeof performance !== 'undefined' && performance.now()) || 0);
  }

  stop() {
    this.running = false;
  }

  start() {
    this.running = true;
  }

  tick(tick_time) {
    window.requestAnimationFrame((tick_time) => this.tick(tick_time));
    const next_tick = this.last_tick + this.tick_length;

    if (tick_time > next_tick) {
      const ticks_qty = Math.floor((tick_time - this.last_tick) / this.tick_length);
      this.perform_ticks(ticks_qty);
      this.draw();
    }

  }

  add_frame_listener(name, action) {
    this.actions[name] = action;
  }

  remove_frame_listener(name) {
    delete this.actions[name];
  }

  perform_ticks(ticks_qty) {
    for(var i=0; i < ticks_qty; i++) {
      this.last_tick = this.last_tick + this.tick_length;
      this.update( this.last_tick );
    }
  }

  update(tick_time) {
    Object.keys(this.actions).forEach(action => {
      if (this.actions[action]) {
        this.actions[action](tick_time);
      }
    });

    // console.log('update');
  }

  draw() {
    // console.log('draw');
  }
}

export { Game };
<commit_msg>remove unneeded deps<commit_after>import { canvas } from './context.js';

const default_options = {
  width: 800,
  height: 600,
  dom: document.body,
  fps: 60,
  autostart: true
};

class Game {

  constructor(options) {
    this.options = default_options;

    options = options || {};
    Object.keys(options).forEach(key => {
      this.options[key] = options[key];
    });

    canvas.width = this.options.width;
    canvas.height = this.options.height;

    this.options.dom.appendChild(canvas);

    this.running = this.options.autostart;

    this.last_tick = performance.now();
    this.last_render = this.last_tick;
    this.tick_length = 1000/this.options.fps;

    this.actions = {};

    this.tick((typeof performance !== 'undefined' && performance.now()) || 0);
  }

  stop() {
    this.running = false;
  }

  start() {
    this.running = true;
  }

  tick(tick_time) {
    window.requestAnimationFrame((tick_time) => this.tick(tick_time));
    const next_tick = this.last_tick + this.tick_length;

    if (tick_time > next_tick) {
      const ticks_qty = Math.floor((tick_time - this.last_tick) / this.tick_length);
      this.perform_ticks(ticks_qty);
      this.draw();
    }

  }

  add_frame_listener(name, action) {
    this.actions[name] = action;
  }

  remove_frame_listener(name) {
    delete this.actions[name];
  }

  perform_ticks(ticks_qty) {
    for(var i=0; i < ticks_qty; i++) {
      this.last_tick = this.last_tick + this.tick_length;
      this.update( this.last_tick );
    }
  }

  update(tick_time) {
    Object.keys(this.actions).forEach(action => {
      if (this.actions[action]) {
        this.actions[action](tick_time);
      }
    });

    // console.log('update');
  }

  draw() {
    // console.log('draw');
  }
}

export { Game };
<|endoftext|>


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

var EventEmitter = require('events').EventEmitter;
// And so it begins
global.jake = new EventEmitter();

var fs = require('fs')
  , path = require('path')
  , taskNs = require('./task')
  , Task = taskNs.Task
  , FileTask = taskNs.FileTask
  , DirectoryTask = taskNs.DirectoryTask
  , Rule = require('./rule').Rule
  , Namespace = require('./namespace').Namespace
  , api = require('./api')
  , utils = require('./utils')
  , Program = require('./program').Program
  , Loader = require('./loader').Loader
  , pkg = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString());

var MAX_RULE_RECURSION_LEVEL = 16;

var Invocation = function (taskName, args) {
  this.taskName = taskName;
  this.args = args;
};

// Globalize jake and top-level API methods (e.g., `task`, `desc`)
utils.mixin(global, api);

// Copy utils onto base jake
utils.mixin(jake, utils);
// File utils should be aliased directly on base jake as well
utils.mixin(jake, utils.file);

utils.mixin(jake, new (function () {

  this._invocationChain = [];

  // Private variables
  // =================
  // Local reference for scopage
  var self = this;

  // Public properties
  // =================
  this.version = pkg.version;
  // Used when Jake exits with a specific error-code
  this.errorCode = undefined;
  // Loads Jakefiles/jakelibdirs
  this.loader = new Loader();
  // Name/value map of all the various tasks defined in a Jakefile.
  // Non-namespaced tasks are placed into 'default.'
  this.defaultNamespace = new Namespace('default', null);
  // For namespaced tasks -- tasks with no namespace are put into the
  // 'default' namespace so lookup code can work the same for both
  // namespaced and non-namespaced.
  this.currentNamespace = this.defaultNamespace;
  // Saves the description created by a 'desc' call that prefaces a
  // 'task' call that defines a task.
  this.currentTaskDescription = null;
  this.program = new Program();
  this.FileList = require('./file_list').FileList;
  this.PackageTask = require('./package_task').PackageTask;
  this.NpmPublishTask = require('./npm_publish_task').NpmPublishTask;
  this.WatchTask = require('./watch_task').WatchTask;
  this.TestTask = require('./test_task').TestTask;
  this.Task = Task;
  this.FileTask = FileTask;
  this.DirectoryTask = DirectoryTask;
  this.Namespace = Namespace;
  this.Rule = Rule;

  this.parseAllTasks = function () {
    var _parseNs = function (name, ns) {
      var nsTasks = ns.tasks
        , task
        , nsNamespaces = ns.childNamespaces
        , fullName;
      // Iterate through the tasks in each namespace
      for (var q in nsTasks) {
        task = nsTasks[q];
        // Prefix namespaced tasks
        fullName = name == 'default' ? q : name + ':' + q;
        // Save with 'taskname' or 'namespace:taskname' key
        task.fullName = fullName;
        jake.Task[fullName] = task;
      }
      for (var p in nsNamespaces) {
        fullName = (name == 'default') ? p : name + ':' + p;
        _parseNs(fullName, nsNamespaces[p]);
      }
    };

    _parseNs('default', jake.defaultNamespace);
  };

  /**
   * Displays the list of descriptions avaliable for tasks defined in
   * a Jakefile
   */
  this.showAllTaskDescriptions = function (f) {
    var p
      , maxTaskNameLength = 0
      , task
      , str = ''
      , padding
      , name
      , descr
      , filter = typeof f == 'string' ? f : null;

    for (p in jake.Task) {
      task = jake.Task[p];
      // Record the length of the longest task name -- used for
      // pretty alignment of the task descriptions
      maxTaskNameLength = p.length > maxTaskNameLength ?
        p.length : maxTaskNameLength;
    }
    // Print out each entry with descriptions neatly aligned
    for (p in jake.Task) {
      if (filter && p.indexOf(filter) == -1) {
        continue;
      }
      task = jake.Task[p];

      name = '\033[32m' + p + '\033[39m ';

      // Create padding-string with calculated length
      padding = (new Array(maxTaskNameLength - p.length + 2)).join(' ');

      descr = task.description;
      if (descr) {
        descr = '\033[90m # ' + descr + '\033[39m \033[37m \033[39m';
        console.log('jake ' + name + padding + descr);
      }
    }
  };

  this.createTask = function () {
    var args = Array.prototype.slice.call(arguments)
      , arg
      , obj
      , task
      , type
      , name
      , action
      , opts = {}
      , prereqs = [];

      type = args.shift();

    // name, [deps], [action]
    // Name (string) + deps (array) format
    if (typeof args[0] == 'string') {
      name = args.shift();
      if (Array.isArray(args[0])) {
        prereqs = args.shift();
      }
    }
    // name:deps, [action]
    // Legacy object-literal syntax, e.g.: {'name': ['depA', 'depB']}
    else {
      obj = args.shift();
      for (var p in obj) {
        prereqs = prereqs.concat(obj[p]);
        name = p;
      }
    }

    // Optional opts/callback or callback/opts
    while ((arg = args.shift())) {
      if (typeof arg == 'function') {
        action = arg;
      }
      else {
        opts = arg;
      }
    }

    task = jake.currentNamespace.resolveTask(name);
    if (task && !action) {
      // Task already exists and no action, just update prereqs, and return it.
      task.prereqs = task.prereqs.concat(prereqs);
      return task;
    }

    switch (type) {
      case 'directory':
        action = function () {
          jake.mkdirP(name);
        };
        task = new DirectoryTask(name, prereqs, action, opts);
        break;
      case 'file':
        task = new FileTask(name, prereqs, action, opts);
        break;
      default:
        task = new Task(name, prereqs, action, opts);
    }

    if (jake.currentTaskDescription) {
      task.description = jake.currentTaskDescription;
      jake.currentTaskDescription = null;
    }
    jake.currentNamespace.tasks[name] = task;
    task.namespace = jake.currentNamespace;

    // FIXME: Should only need to add a new entry for the current
    // task-definition, not reparse the entire structure
    jake.parseAllTasks();

    return task;
  };

  this.attemptRule = function (name, ns, level) {
    var prereqRule
      , prereq;
    if (level > MAX_RULE_RECURSION_LEVEL) {
      return null;
    }
    // Check Rule
    prereqRule = ns.matchRule(name);
    if (prereqRule) {
      prereq = prereqRule.createTask(name, level);
    }
    return prereq || null;
  };

  this.createPlaceholderFileTask = function (name, namespace) {
    var nsPath = ''
      , filePath = name.split(':').pop() // Strip any namespace
      , parts
      , fileTaskName
      , task
      , stats;

    if (namespace) {
      if (typeof namespace == 'string') {
        nsPath = namespace;
      }
      else {
        nsPath = namespace.path;
      }
    }

    parts = nsPath.split(':');
    parts.push(filePath);
    fileTaskName = parts.join(':');

    task = jake.Task[fileTaskName];

    // If there's not already an existing dummy FileTask for it,
    // create one
    if (!task) {
      // Create a dummy FileTask only if file actually exists
      if (fs.existsSync(filePath)) {
        stats = fs.statSync(filePath);
        task = new jake.FileTask(filePath);
        task.modTime = stats.mtime;
        task.dummy = true;
        // Put this dummy Task in the global Tasks list so
        // modTime will be eval'd correctly
        jake.Task[fileTaskName] = task;
      }
    }

    return task || null;
  };

  this.init = function () {
    var self = this;
    process.addListener('uncaughtException', function (err) {
      self.program.handleErr(err);
    });

  };

  this.run = function () {
    var args = Array.prototype.slice.call(arguments)
      , program = this.program
      , loader = this.loader
      , preempt
      , opts;

    program.parseArgs(args);
    program.init();

    preempt = program.firstPreemptiveOption();
    if (preempt) {
      preempt();
    }
    else {
      opts = program.opts;
      // Load Jakefile and jakelibdir files
      loader.loadFile(opts.jakefile);
      loader.loadDirectory(opts.jakelibdir);

      program.run();
    }
  };

})());

module.exports = jake;
<commit_msg>fullname property not getting set correctly on placeholder FileTask for on-disk files<commit_after>/*
 * Jake JavaScript build tool
 * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

var EventEmitter = require('events').EventEmitter;
// And so it begins
global.jake = new EventEmitter();

var fs = require('fs')
  , path = require('path')
  , taskNs = require('./task')
  , Task = taskNs.Task
  , FileTask = taskNs.FileTask
  , DirectoryTask = taskNs.DirectoryTask
  , Rule = require('./rule').Rule
  , Namespace = require('./namespace').Namespace
  , api = require('./api')
  , utils = require('./utils')
  , Program = require('./program').Program
  , Loader = require('./loader').Loader
  , pkg = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString());

var MAX_RULE_RECURSION_LEVEL = 16;

var Invocation = function (taskName, args) {
  this.taskName = taskName;
  this.args = args;
};

// Globalize jake and top-level API methods (e.g., `task`, `desc`)
utils.mixin(global, api);

// Copy utils onto base jake
utils.mixin(jake, utils);
// File utils should be aliased directly on base jake as well
utils.mixin(jake, utils.file);

utils.mixin(jake, new (function () {

  this._invocationChain = [];

  // Private variables
  // =================
  // Local reference for scopage
  var self = this;

  // Public properties
  // =================
  this.version = pkg.version;
  // Used when Jake exits with a specific error-code
  this.errorCode = undefined;
  // Loads Jakefiles/jakelibdirs
  this.loader = new Loader();
  // Name/value map of all the various tasks defined in a Jakefile.
  // Non-namespaced tasks are placed into 'default.'
  this.defaultNamespace = new Namespace('default', null);
  // For namespaced tasks -- tasks with no namespace are put into the
  // 'default' namespace so lookup code can work the same for both
  // namespaced and non-namespaced.
  this.currentNamespace = this.defaultNamespace;
  // Saves the description created by a 'desc' call that prefaces a
  // 'task' call that defines a task.
  this.currentTaskDescription = null;
  this.program = new Program();
  this.FileList = require('./file_list').FileList;
  this.PackageTask = require('./package_task').PackageTask;
  this.NpmPublishTask = require('./npm_publish_task').NpmPublishTask;
  this.WatchTask = require('./watch_task').WatchTask;
  this.TestTask = require('./test_task').TestTask;
  this.Task = Task;
  this.FileTask = FileTask;
  this.DirectoryTask = DirectoryTask;
  this.Namespace = Namespace;
  this.Rule = Rule;

  this.parseAllTasks = function () {
    var _parseNs = function (name, ns) {
      var nsTasks = ns.tasks
        , task
        , nsNamespaces = ns.childNamespaces
        , fullName;
      // Iterate through the tasks in each namespace
      for (var q in nsTasks) {
        task = nsTasks[q];
        // Prefix namespaced tasks
        fullName = name == 'default' ? q : name + ':' + q;
        // Save with 'taskname' or 'namespace:taskname' key
        task.fullName = fullName;
        jake.Task[fullName] = task;
      }
      for (var p in nsNamespaces) {
        fullName = (name == 'default') ? p : name + ':' + p;
        _parseNs(fullName, nsNamespaces[p]);
      }
    };

    _parseNs('default', jake.defaultNamespace);
  };

  /**
   * Displays the list of descriptions avaliable for tasks defined in
   * a Jakefile
   */
  this.showAllTaskDescriptions = function (f) {
    var p
      , maxTaskNameLength = 0
      , task
      , str = ''
      , padding
      , name
      , descr
      , filter = typeof f == 'string' ? f : null;

    for (p in jake.Task) {
      task = jake.Task[p];
      // Record the length of the longest task name -- used for
      // pretty alignment of the task descriptions
      maxTaskNameLength = p.length > maxTaskNameLength ?
        p.length : maxTaskNameLength;
    }
    // Print out each entry with descriptions neatly aligned
    for (p in jake.Task) {
      if (filter && p.indexOf(filter) == -1) {
        continue;
      }
      task = jake.Task[p];

      name = '\033[32m' + p + '\033[39m ';

      // Create padding-string with calculated length
      padding = (new Array(maxTaskNameLength - p.length + 2)).join(' ');

      descr = task.description;
      if (descr) {
        descr = '\033[90m # ' + descr + '\033[39m \033[37m \033[39m';
        console.log('jake ' + name + padding + descr);
      }
    }
  };

  this.createTask = function () {
    var args = Array.prototype.slice.call(arguments)
      , arg
      , obj
      , task
      , type
      , name
      , action
      , opts = {}
      , prereqs = [];

      type = args.shift();

    // name, [deps], [action]
    // Name (string) + deps (array) format
    if (typeof args[0] == 'string') {
      name = args.shift();
      if (Array.isArray(args[0])) {
        prereqs = args.shift();
      }
    }
    // name:deps, [action]
    // Legacy object-literal syntax, e.g.: {'name': ['depA', 'depB']}
    else {
      obj = args.shift();
      for (var p in obj) {
        prereqs = prereqs.concat(obj[p]);
        name = p;
      }
    }

    // Optional opts/callback or callback/opts
    while ((arg = args.shift())) {
      if (typeof arg == 'function') {
        action = arg;
      }
      else {
        opts = arg;
      }
    }

    task = jake.currentNamespace.resolveTask(name);
    if (task && !action) {
      // Task already exists and no action, just update prereqs, and return it.
      task.prereqs = task.prereqs.concat(prereqs);
      return task;
    }

    switch (type) {
      case 'directory':
        action = function () {
          jake.mkdirP(name);
        };
        task = new DirectoryTask(name, prereqs, action, opts);
        break;
      case 'file':
        task = new FileTask(name, prereqs, action, opts);
        break;
      default:
        task = new Task(name, prereqs, action, opts);
    }

    if (jake.currentTaskDescription) {
      task.description = jake.currentTaskDescription;
      jake.currentTaskDescription = null;
    }
    jake.currentNamespace.tasks[name] = task;
    task.namespace = jake.currentNamespace;

    // FIXME: Should only need to add a new entry for the current
    // task-definition, not reparse the entire structure
    jake.parseAllTasks();

    return task;
  };

  this.attemptRule = function (name, ns, level) {
    var prereqRule
      , prereq;
    if (level > MAX_RULE_RECURSION_LEVEL) {
      return null;
    }
    // Check Rule
    prereqRule = ns.matchRule(name);
    if (prereqRule) {
      prereq = prereqRule.createTask(name, level);
    }
    return prereq || null;
  };

  this.createPlaceholderFileTask = function (name, namespace) {
    var nsPath = ''
      , filePath = name.split(':').pop() // Strip any namespace
      , parts
      , fileTaskName
      , task
      , stats;

    if (namespace) {
      if (typeof namespace == 'string') {
        nsPath = namespace;
      }
      else {
        nsPath = namespace.path;
      }
    }

    parts = nsPath.length ? nsPath.split(':') : [];
    parts.push(filePath);
    fileTaskName = parts.join(':');

    task = jake.Task[fileTaskName];

    // If there's not already an existing dummy FileTask for it,
    // create one
    if (!task) {
      // Create a dummy FileTask only if file actually exists
      if (fs.existsSync(filePath)) {
        stats = fs.statSync(filePath);
        task = new jake.FileTask(filePath);
        task.fullName = fileTaskName;
        task.modTime = stats.mtime;
        task.dummy = true;
        // Put this dummy Task in the global Tasks list so
        // modTime will be eval'd correctly
        jake.Task[fileTaskName] = task;
      }
    }

    return task || null;
  };

  this.init = function () {
    var self = this;
    process.addListener('uncaughtException', function (err) {
      self.program.handleErr(err);
    });

  };

  this.run = function () {
    var args = Array.prototype.slice.call(arguments)
      , program = this.program
      , loader = this.loader
      , preempt
      , opts;

    program.parseArgs(args);
    program.init();

    preempt = program.firstPreemptiveOption();
    if (preempt) {
      preempt();
    }
    else {
      opts = program.opts;
      // Load Jakefile and jakelibdir files
      loader.loadFile(opts.jakefile);
      loader.loadDirectory(opts.jakelibdir);

      program.run();
    }
  };

})());

module.exports = jake;
<|endoftext|>


<commit_before>import * as Loop from 'gameboard/loop';

import Base from 'flockn/base';
import Graphics from 'flockn/graphics';
import Scene from 'flockn/scene';
import Color from 'flockn/types/color';
import Viewport from 'flockn/viewport';

import {addable, renderable, updateable} from 'flockn/mixins';

var root = window;

// Game is the entry point for all games made with flockn.
// Any number of `Scene` instances can be attached to a `Game` instance
class Game extends Base {
  constructor(descriptor) {
    // The new operator does not need to be set explicitly.
    // If it isn't we return an instance of `Game`
    if (!this || !this instanceof Game) {
      return new Game(descriptor);
    }

    // Extend the `Base` class
    super('Game', descriptor);

    // `this.container` is a string, which is the id of the element.
    // If it's not given, it should create a new element. This should be handled by the renderer.
    this.container = null;

    // By default, the width and height of a `Game` instance will be as large as the inside of the browser window.
    this.width = root.innerWidth;
    this.height = root.innerHeight;
    this.color = new Color(255, 255, 255);

    // Set the viewport object
    this.viewport = Viewport;

    // `this.activeScene` is set to `null` by default, but will change to the instance of the scene
    // once a scene will be shown
    this.activeScene = null;

    // A `Game` instance is the root element so the descriptor needs to be called directly,
    // because it won't be added to anywhere else
    this.call();

    Graphics.trigger('initialize', this);

    // Mix in `renderable` and `updateable`
    renderable.call(this);
    updateable.call(this);

    // Bind the game loop to the `update` event
    Loop.on('update', (dt) => {
      // Deltatime should not be a millisecond value, but a second one.
      // It should be a value between 0 - 1
      this.trigger('update', dt / 1000);
    });

    // Bind the game loop to the `render` event
    Loop.on('render', () => {
      this.trigger('render');
    });

    // Add a `resize` event to each `Game` instance
    root.addEventListener('resize', () => {
      var newWidth = root.innerWidth;
      var newHeight = root.innerHeight;

      this.trigger('resize', newWidth, newHeight);

      // Trigger resize event for the current scene
      var currentScene = this.children.byName(this.activeScene);

      if (currentScene) {
        currentScene.trigger('resize', root.innerWidth, root.innerHeight);
      }
    }, false);

    // Add an `orientationchange` event to each `Game` instance
    root.addEventListener('orientationchange', () => {
      this.trigger('orientationchange');
    }, false);
  }

  addScene() {
    // When adding a scene, the dimension of scenes should be
    // exactly as large as the `Game` instance itself
    this.queue.push(addable(Scene, this.children, function (child) {
      child.width = this.width;
      child.height = this.height;
    }).apply(this, arguments));
  }

  showScene(name) {
    // TODO: Add transitions
    this.children.forEach(scene => scene.visible = false);

    // Set the `activeScene` property
    this.activeScene = this.children.byName(name);
    this.activeScene.visible = true;

    if (this.activeScene) {
      this.activeScene.trigger('resize', root.innerWidth, root.innerHeight);

      // Trigger the `show` event
      this.trigger('show', name, this.children[this.activeScene]);
    }
  }

  preload(assets) {

  }

  run(name) {
    this.on('executed', () => {
      // Start the game loop
      Loop.run();

      if (!name) {
        // If there's only no name, take the first scene
        if (this.children.length >= 1) {
          name = this.children.first().name;
        }
      }

      // Show the scene if a parameter has been specified
      this.showScene(name);
    });
  }
}

export default Game;
<commit_msg>Game is serializable<commit_after>import * as Loop from 'gameboard/loop';

import Base from 'flockn/base';
import Graphics from 'flockn/graphics';
import Scene from 'flockn/scene';
import Color from 'flockn/types/color';
import Viewport from 'flockn/viewport';

import {addable, renderable, updateable, serializable} from 'flockn/mixins';

var root = window;

// Game is the entry point for all games made with flockn.
// Any number of `Scene` instances can be attached to a `Game` instance
class Game extends Base {
  constructor(descriptor) {
    // The new operator does not need to be set explicitly.
    // If it isn't we return an instance of `Game`
    if (!this || !this instanceof Game) {
      return new Game(descriptor);
    }

    // Extend the `Base` class
    super('Game', descriptor);

    // `this.container` is a string, which is the id of the element.
    // If it's not given, it should create a new element. This should be handled by the renderer.
    this.container = null;

    // By default, the width and height of a `Game` instance will be as large as the inside of the browser window.
    this.width = root.innerWidth;
    this.height = root.innerHeight;
    this.color = new Color(255, 255, 255);

    // Set the viewport object
    this.viewport = Viewport;

    // `this.activeScene` is set to `null` by default, but will change to the instance of the scene
    // once a scene will be shown
    this.activeScene = null;

    // A `Game` instance is the root element so the descriptor needs to be called directly,
    // because it won't be added to anywhere else
    this.call();

    Graphics.trigger('initialize', this);

    // Mix in `renderable` and `updateable`
    renderable.call(this);
    updateable.call(this);

    // Bind the game loop to the `update` event
    Loop.on('update', (dt) => {
      // Deltatime should not be a millisecond value, but a second one.
      // It should be a value between 0 - 1
      this.trigger('update', dt / 1000);
    });

    // Bind the game loop to the `render` event
    Loop.on('render', () => {
      this.trigger('render');
    });

    // Add a `resize` event to each `Game` instance
    root.addEventListener('resize', () => {
      var newWidth = root.innerWidth;
      var newHeight = root.innerHeight;

      this.trigger('resize', newWidth, newHeight);

      // Trigger resize event for the current scene
      var currentScene = this.children.byName(this.activeScene);

      if (currentScene) {
        currentScene.trigger('resize', root.innerWidth, root.innerHeight);
      }
    }, false);

    // Add an `orientationchange` event to each `Game` instance
    root.addEventListener('orientationchange', () => {
      this.trigger('orientationchange');
    }, false);
  }

  addScene() {
    // When adding a scene, the dimension of scenes should be
    // exactly as large as the `Game` instance itself
    this.queue.push(addable(Scene, this.children, function (child) {
      child.width = this.width;
      child.height = this.height;
    }).apply(this, arguments));
  }

  showScene(name) {
    // TODO: Add transitions
    this.children.forEach(scene => scene.visible = false);

    // Set the `activeScene` property
    this.activeScene = this.children.byName(name);
    this.activeScene.visible = true;

    if (this.activeScene) {
      this.activeScene.trigger('resize', root.innerWidth, root.innerHeight);

      // Trigger the `show` event
      this.trigger('show', name, this.children[this.activeScene]);
    }
  }

  preload(assets) {

  }

  run(name) {
    this.on('executed', () => {
      // Start the game loop
      Loop.run();

      if (!name) {
        // If there's only no name, take the first scene
        if (this.children.length >= 1) {
          name = this.children.first().name;
        }
      }

      // Show the scene if a parameter has been specified
      this.showScene(name);
    });
  }
}

serializable(Game);

export default Game;
<|endoftext|>


<commit_before>Jbob = function(providedArgs) {
  var defaults = {tags:[], nonSelfClosingTags:[]}
  var args = {}
  for (key in defaults) {
    if (providedArgs[key]) {
      args[key] = providedArgs[key]
    } else {
      args[key] = defaults[key]
    }
  }

  function include(arr, thing) {
    for (var i=0; i<arr.length; i++) {
      if (arr[i] == thing) {
        return true
      }
    }
    return false
  }

  function openTag(tagName, attributesStr) {
    return "<" + tagName + attributesStr + ">"
  }

  function closeTag(tagName) {
    return "</" + tagName + ">"
  }

  function selfCloseTag(tagName, attributesStr) {
    return "<" + tagName + attributesStr + "/>"
  }

  function isTag(str) {
    return str.replace(/\n/g, "").match(/^\s*<.*\/\w*>\s*$/)
  }

  function firstArgIsAttributes(args) {
    return typeof args[0] == "object" && !(args[0] instanceof Array)
  }

  function makeAttributesStr(attributes) {
    var attrs = []
    for (var key in attributes) {
      attrs.push(key + "=\"" + attributes[key] + "\"");
    }
    attrs.sort()

    return (attrs.length>0 ? " " : "") + attrs.join(" ")
  }

  function argumentsAsArray(arguments, startPos) {
    var arr = []
    for(var i=startPos; i<arguments.length; i++) {
      arr.push(arguments[i])
    }

    return arr
  }

  function flattenArray(arr) {
    var newArr = []
    for(var i=0; i<arr.length; i++) {
      var value = arr[i]
      if (value instanceof Array) {
        var innerArr = flattenArray(value)
        for(var j=0; j<innerArr.length; j++) {
          newArr.push(innerArr[j])
        }
      } else {
        newArr.push(arr[i])
      }
    }
    return newArr
  }

  function tagFunction(tagName) {
    return function() {
      var theFirstArgIsAttributes = firstArgIsAttributes(arguments)
      var attributesStr = theFirstArgIsAttributes ? makeAttributesStr(arguments[0]) : ""
      var inners = flattenArray(argumentsAsArray(arguments, theFirstArgIsAttributes ? 1 : 0))

      var parts = []

      if (inners.length >= 1) {
        parts.push(openTag(tagName, attributesStr))

        //todo: make this optional
        if (isTag(inners[0])) parts.push("\n")

        for(var i=0; i<inners.length; i++) {
          var inner = inners[i]
          parts.push(inner)
        }

        parts.push(closeTag(tagName))

        //todo: cache nonclosing answers? (perf)
      } else if (include(args.nonSelfClosingTags, tagName)) {
        parts.push(openTag(tagName, attributesStr))
        parts.push(closeTag(tagName))

      } else {
        parts.push(selfCloseTag(tagName, attributesStr))
      }

      //todo: make this optional
      parts.push("\n")

      return parts.join("")
    }
  }

  for (var i=0; i<args.tags.length; i++) {
    var tagName = args.tags[i]
    this[tagName] = tagFunction(tagName)
  }

  return null
}

Jbob.htmlTags = function(target) {
  Jbob.apply(target, [{
    tags: [
      "html", "head", "body", "script", "meta", "title", "link",
      "div", "p", "span", "a", "img", "br", "hr",
      "table", "tr", "th", "td", "thead", "tbody",
      "ul", "ol", "li",
      "dl", "dt", "dd",
      "h1", "h2", "h3", "h4", "h5", "h6", "h7",
      "form", "fieldset", "input", "textarea", "label", "button"
    ],

    nonSelfClosingTags:["textarea", "script"]

  }])
}<commit_msg>semicolons, so that people don't get the vapors<commit_after>Jbob = function(providedArgs) {
  var defaults = {tags:[], nonSelfClosingTags:[]};
  var args = {};
  for (key in defaults) {
    if (providedArgs[key]) {
      args[key] = providedArgs[key];
    } else {
      args[key] = defaults[key];
    }
  }

  function include(arr, thing) {
    for (var i=0; i<arr.length; i++) {
      if (arr[i] == thing) {
        return true;
      }
    }
    return false;
  }

  function openTag(tagName, attributesStr) {
    return "<" + tagName + attributesStr + ">";
  }

  function closeTag(tagName) {
    return "</" + tagName + ">";
  }

  function selfCloseTag(tagName, attributesStr) {
    return "<" + tagName + attributesStr + "/>";
  }

  function isTag(str) {
    return str.replace(/\n/g, "").match(/^\s*<.*\/\w*>\s*$/);
  }

  function firstArgIsAttributes(args) {
    return typeof args[0] == "object" && !(args[0] instanceof Array);
  }

  function makeAttributesStr(attributes) {
    var attrs = [];
    for (var key in attributes) {
      attrs.push(key + "=\"" + attributes[key] + "\"");
    }
    attrs.sort();

    return (attrs.length>0 ? " " : "") + attrs.join(" ");
  }

  function argumentsAsArray(arguments, startPos) {
    var arr = [];
    for(var i=startPos; i<arguments.length; i++) {
      arr.push(arguments[i]);
    }

    return arr;
  }

  function flattenArray(arr) {
    var newArr = [];
    for(var i=0; i<arr.length; i++) {
      var value = arr[i];
      if (value instanceof Array) {
        var innerArr = flattenArray(value);
        for(var j=0; j<innerArr.length; j++) {
          newArr.push(innerArr[j]);
        }
      } else {
        newArr.push(arr[i]);
      }
    }
    return newArr;
  }

  function tagFunction(tagName) {
    return function() {
      var theFirstArgIsAttributes = firstArgIsAttributes(arguments);
      var attributesStr = theFirstArgIsAttributes ? makeAttributesStr(arguments[0]) : "";
      var inners = flattenArray(argumentsAsArray(arguments, theFirstArgIsAttributes ? 1 : 0));

      var parts = [];

      if (inners.length >= 1) {
        parts.push(openTag(tagName, attributesStr));

        //todo: make this optional
        if (isTag(inners[0])) parts.push("\n");

        for(var i=0; i<inners.length; i++) {
          var inner = inners[i];
          parts.push(inner);
        }

        parts.push(closeTag(tagName));

        //todo: cache nonclosing answers? (perf)
      } else if (include(args.nonSelfClosingTags, tagName)) {
        parts.push(openTag(tagName, attributesStr));
        parts.push(closeTag(tagName));

      } else {
        parts.push(selfCloseTag(tagName, attributesStr));
      }

      //todo: make this optional
      parts.push("\n");

      return parts.join("");
    }
  }

  for (var i=0; i<args.tags.length; i++) {
    var tagName = args.tags[i];
    this[tagName] = tagFunction(tagName);
  }

  return null;
};

Jbob.htmlTags = function(target) {
  Jbob.apply(target, [{
    tags: [
      "html", "head", "body", "script", "meta", "title", "link",
      "div", "p", "span", "a", "img", "br", "hr",
      "table", "tr", "th", "td", "thead", "tbody",
      "ul", "ol", "li",
      "dl", "dt", "dd",
      "h1", "h2", "h3", "h4", "h5", "h6", "h7",
      "form", "fieldset", "input", "textarea", "label", "button"
    ],

    nonSelfClosingTags:["textarea", "script"]

  }]);
};<|endoftext|>


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

'use strict';
var VirtioDevice = require('./device');
var runtime = require('../../core');

function initializeRNGDevice(pciDevice) {
  var ioSpace = pciDevice.getBAR(0).resource;
  var irq = pciDevice.getIRQ();
  var allocator = runtime.allocator;

  var features = {};

  var dev = new VirtioDevice('rng', ioSpace, allocator);
  dev.setDriverAck();

  var driverFeatures = {};

  var deviceFeatures = dev.readDeviceFeatures(driverFeatures);

  if (!dev.writeGuestFeatures(features, driverFeatures, deviceFeatures)) {
    debug('[virtio] driver is unable to start');
    return;
  }

  var QUEUE_ID_REQ = 0;

  var reqQueue = dev.queueSetup(QUEUE_ID_REQ);

  function fillRequestQueue(length) {
    if (reqQueue.descriptorTable.descriptorsAvailable) {
      if (!reqQueue.placeBuffers([new Uint8Array(length || 1)], true)) {
        debug('[virtio rng] error placing descriptor buffers');
      }
    }

    if (reqQueue.isNotificationNeeded()) {
      dev.queueNotify(QUEUE_ID_REQ);
    }
  }

  runtime.driver.rng = {
    getRand: function() {
      if (!cb) {
        cb = function() {};
      }

      fillRequestQueue(1);
      dev.hasPendingIRQ();
      return reqQueue.getBuffer();
    },
    getRandLength: function(length) {
      fillRequestQueue(length || 1);
      dev.hasPendingIRQ();
      return reqQueue.getBuffer();
    },
    randomBytes: function(length) {
      var retbuf = null;
      length = length || 1;
      fillRequestQueue(length);
      dev.hasPendingIRQ();
      var u8 = reqQueue.getBuffer();
      retbuf = new Buffer(u8.length);
      for (let k in u8) {
        retbuf.writeUInt8(u8[k], k);
      }
      return retbuf;
    }
  };

  dev.setDriverReady();
}

module.exports = initializeRNGDevice;
<commit_msg>Add optional callback to randomBytes<commit_after>// Copyright 2014-2015 runtime.js project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';
var VirtioDevice = require('./device');
var runtime = require('../../core');

function initializeRNGDevice(pciDevice) {
  var ioSpace = pciDevice.getBAR(0).resource;
  var irq = pciDevice.getIRQ();
  var allocator = runtime.allocator;

  var features = {};

  var dev = new VirtioDevice('rng', ioSpace, allocator);
  dev.setDriverAck();

  var driverFeatures = {};

  var deviceFeatures = dev.readDeviceFeatures(driverFeatures);

  if (!dev.writeGuestFeatures(features, driverFeatures, deviceFeatures)) {
    debug('[virtio] driver is unable to start');
    return;
  }

  var QUEUE_ID_REQ = 0;

  var reqQueue = dev.queueSetup(QUEUE_ID_REQ);

  function fillRequestQueue(length) {
    if (reqQueue.descriptorTable.descriptorsAvailable) {
      if (!reqQueue.placeBuffers([new Uint8Array(length || 1)], true)) {
        debug('[virtio rng] error placing descriptor buffers');
      }
    }

    if (reqQueue.isNotificationNeeded()) {
      dev.queueNotify(QUEUE_ID_REQ);
    }
  }

  runtime.driver.rng = {
    getRand: function() {
      if (!cb) {
        cb = function() {};
      }

      fillRequestQueue(1);
      dev.hasPendingIRQ();
      return reqQueue.getBuffer();
    },
    getRandLength: function(length) {
      fillRequestQueue(length || 1);
      dev.hasPendingIRQ();
      return reqQueue.getBuffer();
    },
    randomBytes: function(length, cb) {
      length = length || 1;
      fillRequestQueue(length);
      dev.hasPendingIRQ();
      if (cb) {
        reqQueue.fetchBuffers(function(u8) {
          var tmp = new Buffer(u8.length);
          for (let k in u8) {
            tmp.writeUInt8(u8[k], k);
          };
          cb(tmp);
        });
      } else {
        var u8 = reqQueue.getBuffer();
        var retbuf = new Buffer(u8.length);
        for (let k in u8) {
          retbuf.writeUInt8(u8[k], k);
        }
        return retbuf;
      }
    }
  };

  dev.setDriverReady();
}

module.exports = initializeRNGDevice;
<|endoftext|>


<commit_before>'use strict';

var console = chrome.extension.getBackgroundPage().console;

var parseTime = function (timeStamp, format) {
    var date = new Date(timeStamp);
    var o = {
        'M+' : date.getMonth() + 1, //month
        'D+' : date.getDate(), //day
        'h+' : date.getHours(), //hour
        'm+' : date.getMinutes(), //minute
        's+' : date.getSeconds(), //second
        'S' : date.getMilliseconds() //millisecond
    }

    if(/(Y+)/.test(format)) {
        format = format.replace(RegExp.$1,
            (date.getFullYear() + '').substr(4 - RegExp.$1.length));
    }

    for(var k in o) {
        if (new RegExp('('+ k +')').test(format)) {
            format = format.replace(RegExp.$1,
                RegExp.$1.length == 1 ? o[k] : ('00'+ o[k]).substr((''+ o[k]).length));
        }
    }
    return format;
};

//获取商店名，如嘿尔社，元食等等。
var getShops = function (date) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/getMembersAndOrder.html',
        type : 'GET',
        dataType: 'json',
        data : {
            cid: '1648',
            date: date,
            mealType: 3
        }
    });
};
//获取菜单：如洋葱鸭胸肉套餐。
var getMenus = function (shopId, date) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/getMenu.html',
        type : 'GET',
        dataType: 'json',
        data : {
            mid: shopId,
            date: date,
            type: 3
        }
    });
};
//下订单
var saveOrder = function (foodId, date) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/saveOrder.html',
        type : 'POST',
        dataType: 'json',
        data : {
            items: foodId + ':1',
            addrId: 13,
            mealType: 3,
            date: date
        }
    })
};
//删除订单
var deleteOrder = function (orderId) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/deleteOrder.html',
        type : 'POST',
        dataType: 'json',
        data : {
            orderId: orderId
        }
    })
};

var order = function (date) {
    var shopName, menuName, orderId;

    getShops(date)
    .then(function (json) {
        if (json.data.order && json.data.order.id) {
            orderId = json.data.order.id;
            window.localStorage.setItem('cjdOrderDate', date);
            window.localStorage.setItem('cjdOrderMenu', json.data.order.menus);
            return $.Deferred().reject('已有订单');
        } else {
            var $members = $(json.data.members).find('.nav-item');
            var shops = [];
            $members.each(function (k, v) {
                var $dom = $(v);
                shops[$dom.text()] = $dom.data('id');
            });
            var keys = Object.keys(shops);
            if (keys.indexOf('嘿尔社') > -1) {
                shopName = '嘿尔社';
            } else {
                shopName = keys[0];
            }
            return $.when(getMenus(shops[shopName], date), getMenus(shops['元食'], date));
        }

    }, function (json) {
        console.log(json);
    })
    .then(function (json1, json2) {
        var $menu1 = $(json1[0].data);
        var $menu2 = $(json2[0].data);
        var menu = {};
        $menu1.each(function (k, v) {
            var $dom = $(v);
            var title = $dom.find('.title').text();
            menu[title] = $dom.data('id');
        });
        $menu2.each(function (k, v) {
            var $dom = $(v);
            var title = $dom.find('.title').text();
            menu[title] = $dom.data('id');
        });

        var menuKey = Object.keys(menu);
        for (var i in menu) {
            //正向匹配校园大排和蛋黄子排选择，反向匹配沙拉，碰见沙拉则过滤。
            if (menu[i] === 15407 || menu[i] === 16588) {
                menuName = i;
                return saveOrder(menu[i], date);
            } else if (i.indexOf('沙拉') > -1) {
                menuKey.splice(i, 1);
            }
        }
        menuName = menuKey[0];
        return saveOrder(menu[menuKey[0]], date);
    }, function (json) {
        console.log(json);
    })
    .then(function (json) {
        //notification
        if (+json.status === 1) {
            orderId = json.result;
            window.localStorage.setItem('cjdOrderDate', date)
            window.localStorage.setItem('cjdOrderMenu', menuName);
            var notification = new Notification('恭喜你订餐成功', {
                body: '你订了' + shopName + '的' + menuName,
                icon: 'http://img.souche.com/20160126/png/8b99c8a30b73ff4edba7b69ec60c3b37.png'
            });
            notification.onclick = function() {
                window.open('http://wos.chijidun.com/order/index.html')
            };
        } else {
            var notification = new Notification('订单失败', {
                body: '点击这里手动订菜吧',
                icon: 'http://img.souche.com/20160126/png/8b99c8a30b73ff4edba7b69ec60c3b37.png'
            });
            window.localStorage.setItem('cjdOrderDate', date)
            window.localStorage.setItem('cjdOrderMenu', '暂无订单');
            notification.onclick = function() {
                window.open('http://wos.chijidun.com/order/index.html')
            };
        }
    }, function (json) {
        console.log(json);
    });
};

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {

    if(tab.url != undefined && changeInfo.status == 'complete'){
        var date = new Date();
        var hour = date.getHours();
        var day = parseTime(date.getTime(), 'YYYY-MM-DD');
        //检查今天是否已有订单用，值为一个字符串代表日期
        var orderDate = window.localStorage.getItem('cjdOrderDate');
        console.log('orderDate:' + orderDate + ' hour:' + hour + ' weekDay:' + date.getDay());
        if (hour >= 9 && hour <= 14 && day !== orderDate &&
            date.getDay() !== 0 && date.getDay() !== 6) {

            order(day);

        }
    }
});

<commit_msg>更新规则，允许匹配元食中的子排<commit_after>'use strict';

var console = chrome.extension.getBackgroundPage().console;

var parseTime = function (timeStamp, format) {
    var date = new Date(timeStamp);
    var o = {
        'M+' : date.getMonth() + 1, //month
        'D+' : date.getDate(), //day
        'h+' : date.getHours(), //hour
        'm+' : date.getMinutes(), //minute
        's+' : date.getSeconds(), //second
        'S' : date.getMilliseconds() //millisecond
    }

    if(/(Y+)/.test(format)) {
        format = format.replace(RegExp.$1,
            (date.getFullYear() + '').substr(4 - RegExp.$1.length));
    }

    for(var k in o) {
        if (new RegExp('('+ k +')').test(format)) {
            format = format.replace(RegExp.$1,
                RegExp.$1.length == 1 ? o[k] : ('00'+ o[k]).substr((''+ o[k]).length));
        }
    }
    return format;
};

//获取商店名，如嘿尔社，元食等等。
var getShops = function (date) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/getMembersAndOrder.html',
        type : 'GET',
        dataType: 'json',
        data : {
            cid: '1648',
            date: date,
            mealType: 3
        }
    });
};
//获取菜单：如洋葱鸭胸肉套餐。
var getMenus = function (shopId, date) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/getMenu.html',
        type : 'GET',
        dataType: 'json',
        data : {
            mid: shopId,
            date: date,
            type: 3
        }
    });
};
//下订单
var saveOrder = function (foodId, date) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/saveOrder.html',
        type : 'POST',
        dataType: 'json',
        data : {
            items: foodId + ':1',
            addrId: 13,
            mealType: 3,
            date: date
        }
    })
};
//删除订单
var deleteOrder = function (orderId) {
    return $.ajax({
        url: 'http://wos.chijidun.com/order/deleteOrder.html',
        type : 'POST',
        dataType: 'json',
        data : {
            orderId: orderId
        }
    })
};

var order = function (date) {
    var shopName, menuName, orderId;

    getShops(date)
    .then(function (json) {
        if (json.data.order && json.data.order.id) {
            orderId = json.data.order.id;
            window.localStorage.setItem('cjdOrderDate', date);
            window.localStorage.setItem('cjdOrderMenu', json.data.order.menus);
            return $.Deferred().reject('已有订单');
        } else {
            var $members = $(json.data.members).find('.nav-item');
            var shops = [];
            $members.each(function (k, v) {
                var $dom = $(v);
                shops[$dom.text()] = $dom.data('id');
            });
            var keys = Object.keys(shops);
            if (keys.indexOf('嘿尔社') > -1) {
                shopName = '嘿尔社';
            } else {
                shopName = keys[0];
            }
            return $.when(getMenus(shops[shopName], date), getMenus(shops['元食'], date));
        }

    }, function (json) {
        console.log(json);
    })
    .then(function (json1, json2) {
        var $menu1 = $(json1[0].data);
        var $menu2 = $(json2[0].data);
        var menu = {};
        $menu1.each(function (k, v) {
            var $dom = $(v);
            var title = $dom.find('.title').text();
            menu[title] = $dom.data('id');
        });
        $menu2.each(function (k, v) {
            var $dom = $(v);
            var title = $dom.find('.title').text();
            menu[title] = $dom.data('id');
        });

        var menuKey = Object.keys(menu);
        for (var i in menu) {
            //正向匹配校园大排和蛋黄仔排选择，反向匹配沙拉，碰见沙拉则过滤。
            if (menu[i] === 15407 || menu[i] === 16588) {
                menuName = i;
                return saveOrder(menu[i], date);
            } else if (i.indexOf('沙拉') > -1) {
                menuKey.splice(i, 1);
            }
        }
        menuName = menuKey[0];
        return saveOrder(menu[menuKey[0]], date);
    }, function (json) {
        console.log(json);
    })
    .then(function (json) {
        //notification
        if (+json.status === 1) {
            orderId = json.result;
            window.localStorage.setItem('cjdOrderDate', date)
            window.localStorage.setItem('cjdOrderMenu', menuName);
            var notification = new Notification('恭喜你订餐成功', {
                body: '你订了' + shopName + '的' + menuName,
                icon: 'http://img.souche.com/20160126/png/8b99c8a30b73ff4edba7b69ec60c3b37.png'
            });
            notification.onclick = function() {
                window.open('http://wos.chijidun.com/order/index.html')
            };
        } else {
            var notification = new Notification('订单失败', {
                body: '点击这里手动订菜吧',
                icon: 'http://img.souche.com/20160126/png/8b99c8a30b73ff4edba7b69ec60c3b37.png'
            });
            window.localStorage.setItem('cjdOrderDate', date)
            window.localStorage.setItem('cjdOrderMenu', '暂无订单');
            notification.onclick = function() {
                window.open('http://wos.chijidun.com/order/index.html')
            };
        }
    }, function (json) {
        console.log(json);
    });
};

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {

    if(tab.url != undefined && changeInfo.status == 'complete'){
        var date = new Date();
        var hour = date.getHours();
        var day = parseTime(date.getTime(), 'YYYY-MM-DD');
        //检查今天是否已有订单用，值为一个字符串代表日期
        var orderDate = window.localStorage.getItem('cjdOrderDate');
        console.log('orderDate:' + orderDate + ' hour:' + hour + ' weekDay:' + date.getDay());
        if (hour >= 9 && hour <= 14 && day !== orderDate &&
            date.getDay() !== 0 && date.getDay() !== 6) {

            order(day);

        }
    }
});

<|endoftext|>


<commit_before>/*!
    Copyright (C) 2016 Google Inc.
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
*/

(function (can) {
  var ADMIN_PERMISSION;
  var _CONDITIONS_MAP = {
    contains: function (instance, args) {
      var value = Permission._resolve_permission_variable(args.value);
      var list_value = instance[args.list_property];
      var i;
      for (i = 0; i < list_value.length; i++) {
        if (list_value[i].id == value.id) {
          return true;
        }
      }
      return false;
    },
    is: function (instance, args) {
      var value = Permission._resolve_permission_variable(args.value);
      var property_value = instance[args.property_name];
      if (property_value instanceof can.Stub) {
        property_value = property_value.reify();
      }
      return value == property_value;
    },
    'in': function (instance, args) {
      var value = Permission._resolve_permission_variable(args.value);
      var property_value = instance[args.property_name];
      if (property_value instanceof can.Stub) {
        property_value = property_value.reify();
      }
      return value.indexOf(property_value) >= 0;
    },
    forbid: function (instance, args, action) {
      var blacklist = args.blacklist[action] || [];
      return blacklist.indexOf(instance.type) < 0;
    }
  };
  var permissions_compute = can.compute(GGRC.permissions);

  can.Construct('Permission', {

    _admin_permission_for_context: function (context_id) {
      return new Permission(
      ADMIN_PERMISSION.action, ADMIN_PERMISSION.resource_type, context_id);
    },

    _all_resource_permission: function (permission) {
      return new Permission(
      permission.action, ADMIN_PERMISSION.resource_type, permission.context_id);
    },

    _permission_match: function (permissions, permission) {
      var resource_types = permissions[permission.action] || {};
      var resource_type = resource_types[permission.resource_type] || {};
      var contexts = resource_type.contexts || [];

      return (contexts.indexOf(permission.context_id) > -1);
    },

    _is_allowed: function (permissions, permission) {
      if (!permissions) {
        return false; // ?
      }
      if (this._permission_match(
            permissions,
            new Permission(
              permission.action,
              permission.resource_type, null))) {
        return true;
      }
      if (this._permission_match(permissions, permission)) {
        return true;
      }
      if (this._permission_match(permissions,
          this._all_resource_permission(permission))) {
        return true;
      }
      if (this._permission_match(permissions, ADMIN_PERMISSION)) {
        return true;
      }
      if (this._permission_match(permissions,
          this._admin_permission_for_context(permission.context_id))) {
        return true;
      }
      // Check for System Admin permission
      if (this._permission_match(permissions,
          this._admin_permission_for_context(0))) {
        return true;
      }
      return false;
    },

    _resolve_permission_variable: function (value) {
      if ($.type(value) == 'string') {
        if (value[0] == '$') {
          if (value == '$current_user') {
            return CMS.Models.get_instance('Person', GGRC.current_user.id);
          }
          throw new Error('unknown permission variable: ' + value);
        }
      }
      return value;
    },

    _is_allowed_for: function (permissions, instance, action) {
      // Check for admin permission
      var checkAdmin = function (contextId) {
        var permission = this._admin_permission_for_context(contextId);
        var conditions;
        var i;
        var condition;
        if (this._permission_match(permissions, permission)) {
          conditions = _.toArray(_.exists(permissions,
            permission.action,
            permission.resource_type,
            'conditions',
            contextId));
          if (!conditions.length) {
            return true;
          }
          for (i = 0; i < conditions.length; i++) {
            condition = conditions[i];
            if (_CONDITIONS_MAP[condition.condition](
                instance, condition.terms, action)) {
              return true;
            }
          }
          return false;
        }
        return false;
      }.bind(this);

      var action_obj = permissions[action] || {};
      var instance_type = instance.constructor ?
                          instance.constructor.shortName :
                          instance.type;
      var type_obj = action_obj[instance_type] || {};
      var conditions_by_context = type_obj.conditions || {};
      var resources = type_obj.resources || [];
      var context = instance.context || {id: null};
      var conditions = conditions_by_context[context.id];
      var condition;
      var i;

      if (checkAdmin(0) || checkAdmin(null)) {
        return true;
      }

      if (~resources.indexOf(instance.id)) {
        return true;
      }

      if (!conditions && contexts_by_type.indexOf(context.id) > -1) {
        return true;
      }

      if (!this._is_allowed(permissions,
          new Permission(action, instance_type, null)) &&
        !this._is_allowed(permissions,
          new Permission(action, instance_type, context.id))) {
        return false;
      }
      // Check any conditions applied per instance
      if (!conditions) {
        return false;
      }
      if (conditions.length === 0) {
        return true;
      }
      for (i = 0; i < conditions.length; i++) {
        condition = conditions[i];
        if (_CONDITIONS_MAP[condition.condition](
            instance, condition.terms, action)) {
          return true;
        }
      }
      return false;
    },

    is_allowed: function (action, resource_type, context_id) {
      return this._is_allowed(
        permissions_compute(), new this(action, resource_type, context_id));
    },

    is_allowed_for: function (action, resource) {
      return this._is_allowed_for(permissions_compute(), resource, action);
    },

    is_allowed_any: function (action, resource_type) {
      var allowed = this.is_allowed(action, resource_type);
      var perms = permissions_compute();

      if (!allowed) {
        allowed = _.exists(perms, action, resource_type, 'contexts', 'length');
      }
      return !!allowed;
    },

    page_context_id: function () {
      var page_instance = GGRC.page_instance();
      return (page_instance && page_instance.context &&
              page_instance.context.id) || null;
    },

    refresh: function () {
      return $.ajax({
        url: '/permissions',
        type: 'get',
        dataType: 'json'
      }).then(function (perm) {
        permissions_compute(perm);
        GGRC.permissions = perm;
      });
    }
  }, {
    // prototype
    setup: function (action, resource_type, context_id) {
      this.action = action;
      this.resource_type = resource_type;
      this.context_id = context_id;
      return this;
    }
  });

  ADMIN_PERMISSION = new Permission('__GGRC_ADMIN__', '__GGRC_ALL__', 0);
})(this.can);
<commit_msg>Add missing variable with object_type contexts<commit_after>/*!
    Copyright (C) 2016 Google Inc.
    Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>
*/

(function (can) {
  var ADMIN_PERMISSION;
  var _CONDITIONS_MAP = {
    contains: function (instance, args) {
      var value = Permission._resolve_permission_variable(args.value);
      var list_value = instance[args.list_property];
      var i;
      for (i = 0; i < list_value.length; i++) {
        if (list_value[i].id == value.id) {
          return true;
        }
      }
      return false;
    },
    is: function (instance, args) {
      var value = Permission._resolve_permission_variable(args.value);
      var property_value = instance[args.property_name];
      if (property_value instanceof can.Stub) {
        property_value = property_value.reify();
      }
      return value == property_value;
    },
    'in': function (instance, args) {
      var value = Permission._resolve_permission_variable(args.value);
      var property_value = instance[args.property_name];
      if (property_value instanceof can.Stub) {
        property_value = property_value.reify();
      }
      return value.indexOf(property_value) >= 0;
    },
    forbid: function (instance, args, action) {
      var blacklist = args.blacklist[action] || [];
      return blacklist.indexOf(instance.type) < 0;
    }
  };
  var permissions_compute = can.compute(GGRC.permissions);

  can.Construct('Permission', {

    _admin_permission_for_context: function (context_id) {
      return new Permission(
      ADMIN_PERMISSION.action, ADMIN_PERMISSION.resource_type, context_id);
    },

    _all_resource_permission: function (permission) {
      return new Permission(
      permission.action, ADMIN_PERMISSION.resource_type, permission.context_id);
    },

    _permission_match: function (permissions, permission) {
      var resource_types = permissions[permission.action] || {};
      var resource_type = resource_types[permission.resource_type] || {};
      var contexts = resource_type.contexts || [];

      return (contexts.indexOf(permission.context_id) > -1);
    },

    _is_allowed: function (permissions, permission) {
      if (!permissions) {
        return false; // ?
      }
      if (this._permission_match(
            permissions,
            new Permission(
              permission.action,
              permission.resource_type, null))) {
        return true;
      }
      if (this._permission_match(permissions, permission)) {
        return true;
      }
      if (this._permission_match(permissions,
          this._all_resource_permission(permission))) {
        return true;
      }
      if (this._permission_match(permissions, ADMIN_PERMISSION)) {
        return true;
      }
      if (this._permission_match(permissions,
          this._admin_permission_for_context(permission.context_id))) {
        return true;
      }
      // Check for System Admin permission
      if (this._permission_match(permissions,
          this._admin_permission_for_context(0))) {
        return true;
      }
      return false;
    },

    _resolve_permission_variable: function (value) {
      if ($.type(value) == 'string') {
        if (value[0] == '$') {
          if (value == '$current_user') {
            return CMS.Models.get_instance('Person', GGRC.current_user.id);
          }
          throw new Error('unknown permission variable: ' + value);
        }
      }
      return value;
    },

    _is_allowed_for: function (permissions, instance, action) {
      // Check for admin permission
      var checkAdmin = function (contextId) {
        var permission = this._admin_permission_for_context(contextId);
        var conditions;
        var i;
        var condition;
        if (this._permission_match(permissions, permission)) {
          conditions = _.toArray(_.exists(permissions,
            permission.action,
            permission.resource_type,
            'conditions',
            contextId));
          if (!conditions.length) {
            return true;
          }
          for (i = 0; i < conditions.length; i++) {
            condition = conditions[i];
            if (_CONDITIONS_MAP[condition.condition](
                instance, condition.terms, action)) {
              return true;
            }
          }
          return false;
        }
        return false;
      }.bind(this);

      var action_obj = permissions[action] || {};
      var instance_type = instance.constructor ?
                          instance.constructor.shortName :
                          instance.type;
      var type_obj = action_obj[instance_type] || {};
      var conditions_by_context = type_obj.conditions || {};
      var resources = type_obj.resources || [];
      var context = instance.context || {id: null};
      var conditions = conditions_by_context[context.id];
      var contexts_by_type = type_obj.contexts || [];
      var condition;
      var i;

      if (checkAdmin(0) || checkAdmin(null)) {
        return true;
      }

      if (~resources.indexOf(instance.id)) {
        return true;
      }

      if (!conditions && contexts_by_type.indexOf(context.id) > -1) {
        return true;
      }

      if (!this._is_allowed(permissions,
          new Permission(action, instance_type, null)) &&
        !this._is_allowed(permissions,
          new Permission(action, instance_type, context.id))) {
        return false;
      }
      // Check any conditions applied per instance
      if (!conditions) {
        return false;
      }
      if (conditions.length === 0) {
        return true;
      }
      for (i = 0; i < conditions.length; i++) {
        condition = conditions[i];
        if (_CONDITIONS_MAP[condition.condition](
            instance, condition.terms, action)) {
          return true;
        }
      }
      return false;
    },

    is_allowed: function (action, resource_type, context_id) {
      return this._is_allowed(
        permissions_compute(), new this(action, resource_type, context_id));
    },

    is_allowed_for: function (action, resource) {
      return this._is_allowed_for(permissions_compute(), resource, action);
    },

    is_allowed_any: function (action, resource_type) {
      var allowed = this.is_allowed(action, resource_type);
      var perms = permissions_compute();

      if (!allowed) {
        allowed = _.exists(perms, action, resource_type, 'contexts', 'length');
      }
      return !!allowed;
    },

    page_context_id: function () {
      var page_instance = GGRC.page_instance();
      return (page_instance && page_instance.context &&
              page_instance.context.id) || null;
    },

    refresh: function () {
      return $.ajax({
        url: '/permissions',
        type: 'get',
        dataType: 'json'
      }).then(function (perm) {
        permissions_compute(perm);
        GGRC.permissions = perm;
      });
    }
  }, {
    // prototype
    setup: function (action, resource_type, context_id) {
      this.action = action;
      this.resource_type = resource_type;
      this.context_id = context_id;
      return this;
    }
  });

  ADMIN_PERMISSION = new Permission('__GGRC_ADMIN__', '__GGRC_ALL__', 0);
})(this.can);
<|endoftext|>


<commit_before>/**
 * Player Entity
 */
game.PlayerEntity = me.Entity.extend({

    /**
     * constructor
     */
    init:function (x, y, settings) {
        // call the constructor
        this._super(me.Entity, 'init', [x, y , settings]);

        this.body.gravity = 0;
        this.body.vel.y = -5;

        // viewport follows our position
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);
        // update even when outside of the viewport
        this.alwaysUpdate = true;
    },

    /**
     * update the entity
     */
    update : function (dt) {

        if(me.input.isKeyPressed('left')) {
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
        } else if(me.input.isKeyPressed('right')) {
            this.body.vel.x += this.body.accel.x * me.timer.tick;
        } else {
            this.body.vel.x = 0;
        }

        // TODO increment velocity

        // apply physics to the body (this moves the entity)
        this.body.update(dt);

        // handle collisions against other shapes
        me.collision.check(this);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0);
    },

   /**
     * colision handler
     * (called when colliding with other objects)
     */
    onCollision : function (response, other) {
        // Make all other objects solid
        return true;
    }
});

/* Hole Entity */
game.HoleEntity = me.CollectableEntity.extend({

    init: function(x, y, settings) {
        // call the parent constructor
        this._super(me.CollectableEntity, 'init', [x, y, settings]);
    },

    onCollision : function (response, other) {
        // TODO lose points
        this.body.setCollisionMask(me.collision.types.NO_OBJECT);

        return false;
    }

});
<commit_msg>Add velocity<commit_after>/**
 * Player Entity
 */
game.PlayerEntity = me.Entity.extend({

    /**
     * constructor
     */
    init:function (x, y, settings) {
        // call the constructor
        this._super(me.Entity, 'init', [x, y , settings]);

        this.body.gravity = 0;

        this.body.setVelocity(5, 5);
        this.body.vel.y = -3;

        // viewport follows our position
        me.game.viewport.follow(this.pos, me.game.viewport.AXIS.BOTH);
        // update even when outside of the viewport
        this.alwaysUpdate = true;
    },

    /**
     * update the entity
     */
    update : function (dt) {

        if(me.input.isKeyPressed('left')) {
            this.body.vel.x -= this.body.accel.x * me.timer.tick;
        } else if(me.input.isKeyPressed('right')) {
            this.body.vel.x += this.body.accel.x * me.timer.tick;
        } else {
            this.body.vel.x = 0;
        }

        // TODO increment velocity

        // apply physics to the body (this moves the entity)
        this.body.update(dt);

        // handle collisions against other shapes
        me.collision.check(this);

        // return true if we moved or if the renderable was updated
        return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0);
    },

   /**
     * colision handler
     * (called when colliding with other objects)
     */
    onCollision : function (response, other) {
        // Make all other objects solid
        return true;
    }
});

/* Hole Entity */
game.HoleEntity = me.CollectableEntity.extend({

    init: function(x, y, settings) {
        // call the parent constructor
        this._super(me.CollectableEntity, 'init', [x, y, settings]);
    },

    onCollision : function (response, other) {
        // TODO lose points
        this.body.setCollisionMask(me.collision.types.NO_OBJECT);

        return false;
    }

});
<|endoftext|>


<commit_before>/**
 * Circular-JSON code:
 * Copyright (C) 2013 by WebReflection
 * Modified by Jelle De Loecker
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
module.exports = function BlastJSON(Blast, Collection) {

	var safeStartWithSpecialCharRG,
	    escapedSafeSpecialChar,
	    safeSpecialCharRG,
	    safeSpecialChar,
	    specialCharRg,
	    specialChar,
	    getregex,
	    iso8061;

	specialChar = '~';
	safeSpecialChar = '\\x' + ('0' + specialChar.charCodeAt(0).toString(16)).slice(-2);
	escapedSafeSpecialChar = '\\' + safeSpecialChar;
	specialCharRg = new RegExp(safeSpecialChar, 'g');
	safeSpecialCharRG = new RegExp(escapedSafeSpecialChar, 'g');

	safeStartWithSpecialCharRG = new RegExp('(?:^|([^\\\\]))' + escapedSafeSpecialChar);

	iso8061 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/;
	getregex = /^\/(.*)\/(.*)/;

	/**
	 * Return a string representing the source code of the object.
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.0
	 * @version  0.1.0
	 *
	 * @return   {String}
	 */
	Blast.defineStatic('JSON', 'toSource', function toSource() {
		return 'JSON';
	}, true);

	/**
	 * Generate a replacer function
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Function}
	 */
	function generateReplacer(root, replacer) {

		var seenByConstructor,
		    constructorMap,
		    seenObjects,
		    seenMap,
		    chain,
		    isObj,
		    path,
		    last,
		    temp,
		    i;

		isObj = typeof root === 'object';

		// Don't create a replacer if the root isn't an object
		if (isObj === false || root == null) {
			return;
		}

		seenByConstructor = {};
		constructorMap = {};

		seenObjects = [root];
		seenMap = [specialChar];

		chain = [];
		path = [];

		last = root;

		seenByConstructor[root.constructor.name] = [root];
		constructorMap[root.constructor.name] = [0];

		return function dryReplacer(key, value) {

			var nameType,
			    valType,
			    j;

			// Process the value to a possible given replacer function
			if (replacer != null) {
				value = replacer.call(this, key, value);
			}

			// Get the type of the value after possible `replacer` ran
			valType = typeof value;

			if (key !== '') {

				if (value != null && valType === 'object') {

					// Get the name of the constructor
					nameType = value.constructor.name;

					// Create the map if it doesn't exist yet
					if (seenByConstructor[nameType] == null) {
						seenByConstructor[nameType] = [];
						constructorMap[nameType] = [];
					}

					if (chain.length) {

						// See if the current item is actually a property of the
						// current active item in the chain
						if (last[key] !== value) {

							// If it's not, the current active item is done
							chain.pop();

							// Also remove its name from the path
							path.pop();
						}
					}

					// Now see if this object has been seen before
					if (seenByConstructor[nameType].length) {
						i = seenByConstructor[nameType].indexOf(value);
					} else {
						i = -1;
					}

					if (i < 0) {

						// Store the object in the seen array and return the index
						i = seenObjects.push(value) - 1;
						j = seenByConstructor[nameType].push(value) - 1;
						constructorMap[nameType][j] = i;

						// Key cannot contain specialChar but could be not a string
						path.push(('' + key).replace(specialCharRg, safeSpecialChar));

						seenMap[i] = specialChar + path.join(specialChar);

						if (value.constructor.name == 'RegExp') {
							value = {dry: 'regexp', value: value.toString()};
						} else if (typeof value.toDry === 'function') {
							value = value.toDry();
							value.dry = 'toDry';
							value.drypath = path.slice(0);
						}
					} else {
						value = seenMap[constructorMap[nameType][i]];
					}
				} else {
					path.pop();

					if (valType === 'string') {
						// Make sure the "special char" doesn't mess things up
						value = value.replace(safeSpecialChar, escapedSafeSpecialChar)
						             .replace(specialChar, safeSpecialChar);
					} else if (valType === 'number') {

						// Allow infinite values
						if (!isFinite(value)) {
							if (value > 0) {
								value = {dry: '+Infinity'};
							} else {
								value = {dry: '-Infinity'};
							}
						}
					}
				}
			}

			last = value;

			// Push the current object to the chain,
			// it is now the active item
			chain.push(value);

			return value;
		};
	};

	/**
	 * Generate reviver function
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Function}
	 */
	function generateReviver(reviver, undryPaths) {

		return function dryReviver(key, value) {

			var valType = typeof value,
			    constructor,
			    temp;

			if (valType === 'string') {
				if (value.charAt(0) === specialChar) {
					return new String(value.slice(1));
				} else if (value.match(iso8061)) {
					return new Date(value);
				}
			} else if (value && valType == 'object' && value.dry != null) {

				if (value.dry == 'toDry') {

					constructor = Collection.Object.path(Blast.Globals, value.path);

					// Undry this element, but don't put it in the parsed object yet
					if (constructor && typeof constructor.unDry === 'function') {
						value.undried = constructor.unDry(value.value);
					}

					undryPaths[value.drypath.join(specialChar)] = value;
				} else if (value.dry == 'regexp' && value.value) {
					return RegExp.apply(undefined, getregex.exec(value.value).slice(1));
				} else if (value.dry == '+Infinity') {
					return Infinity;
				} else if (value.dry == '-Infinity') {
					return -Infinity;
				}
			}

			if (valType === 'string') {
				value = value.replace(safeStartWithSpecialCharRG, '$1' + specialChar)
				             .replace(escapedSafeSpecialChar, safeSpecialChar);
			}

			if (reviver == null) {
				return value;
			}

			return reviver.call(this, key, value);
		};
	};

	/**
	 * Regenerate an array
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Array}
	 */
	function regenerateArray(root, current, retrieve, undryPaths) {

		var length = current.length,
		    i;

		for (i = 0; i < length; i++) {
			current[i] = regenerate(root, current[i], retrieve, undryPaths);
		}

		return current;
	};

	/**
	 * Regenerate an object
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Object}
	 */
	function regenerateObject(root, current, retrieve, undryPaths) {

		var key;

		for (key in current) {
			if (current.hasOwnProperty(key)) {
				current[key] = regenerate(root, current[key], retrieve, undryPaths);
			}
		}

		return current;
	};

	/**
	 * Regenerate a value
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Mixed}
	 */
	function regenerate(root, current, retrieve, undryPaths) {

		var temp,
		    i;

		if (current instanceof Array) {
			return regenerateArray(root, current, retrieve, undryPaths);
		}

		if (current instanceof String) {

			if (current.length) {
				if (undryPaths[current]) {
					return undryPaths[current].undried;
				}

				if (retrieve.hasOwnProperty(current)) {
					temp = retrieve[current];
				} else {
					temp = retrieve[current] = retrieveFromPath(root, current.split(specialChar));
				}

				return temp;
			} else {
				return root;
			}
		}

		if (current instanceof Object) {
			return regenerateObject(root, current, retrieve, undryPaths);
		}

		return current;
	};

	/**
	 * Retrieve from path.
	 * Set the given value, but only if the containing object exists.
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Mixed}
	 */
	function retrieveFromPath(current, keys, value) {

		var length = keys.length,
		    prev,
		    key,
		    i;

		for (i = 0; i < length; i++) {

			// Normalize the key
			key = keys[i].replace(safeSpecialCharRG, specialChar);
			prev = current;

			if (current) {
				current = current[key];
			} else {
				return undefined;
			}
		}

		if (arguments.length === 3) {
			prev[key] = value;
			current = value;
		}

		return current;
	};

	/**
	 * Dry it
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {String}
	 */
	Blast.defineStatic('JSON', 'dry', function dry(value, replacer, space) {
		return JSON.stringify(value, generateReplacer(value, replacer), space);
	});

	/**
	 * Undry string
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Mixed}
	 */
	Blast.defineStatic('JSON', 'undry', function undry(text, reviver) {

		var undryPaths = {},
		    result,
		    path;

		result = JSON.parse(text, generateReviver(reviver, undryPaths));

		// Only now can we resolve paths
		result = regenerate(result, result, {}, undryPaths);

		// Now we can replace all the undried values
		for (path in undryPaths) {
			Collection.Object.setPath(result, undryPaths[path].drypath, undryPaths[path].undried);
		}

		return result;
	});

};<commit_msg>fix: JSON.dry and JSON.undry handle difficult structures ok now<commit_after>/**
 * Circular-JSON code:
 * Copyright (C) 2013 by WebReflection
 * Modified by Jelle De Loecker
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
module.exports = function BlastJSON(Blast, Collection) {

	var safeStartWithSpecialCharRG,
	    escapedSafeSpecialChar,
	    safeSpecialCharRG,
	    safeSpecialChar,
	    specialCharRg,
	    specialChar,
	    getregex,
	    iso8061;

	specialChar = '~';
	safeSpecialChar = '\\x' + ('0' + specialChar.charCodeAt(0).toString(16)).slice(-2);
	escapedSafeSpecialChar = '\\' + safeSpecialChar;
	specialCharRg = new RegExp(safeSpecialChar, 'g');
	safeSpecialCharRG = new RegExp(escapedSafeSpecialChar, 'g');

	safeStartWithSpecialCharRG = new RegExp('(?:^|([^\\\\]))' + escapedSafeSpecialChar);

	iso8061 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/;
	getregex = /^\/(.*)\/(.*)/;

	/**
	 * Return a string representing the source code of the object.
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.0
	 * @version  0.1.0
	 *
	 * @return   {String}
	 */
	Blast.defineStatic('JSON', 'toSource', function toSource() {
		return 'JSON';
	}, true);

	/**
	 * Generate a replacer function
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Function}
	 */
	function generateReplacer(root, replacer) {

		var seenByConstructor,
		    constructorMap,
		    seenObjects,
		    seenMap,
		    chain,
		    isObj,
		    path,
		    last,
		    temp,
		    i;

		isObj = typeof root === 'object';

		// Don't create a replacer if the root isn't an object
		if (isObj === false || root == null) {
			return;
		}

		seenByConstructor = {};
		constructorMap = {};

		seenObjects = [root];
		seenMap = [specialChar];

		chain = [];
		path = [];

		last = root;

		seenByConstructor[root.constructor.name] = [root];
		constructorMap[root.constructor.name] = [0];

		return function dryReplacer(key, value) {

			var nameType,
			    valType,
			    temp,
			    len,
			    j;

			// Process the value to a possible given replacer function
			if (replacer != null) {
				value = replacer.call(this, key, value);
			}

			// Get the type of the value after possible `replacer` ran
			valType = typeof value;

			if (key !== '') {

				if (value != null && valType === 'object') {

					// Get the name of the constructor
					nameType = value.constructor.name;

					// Create the map if it doesn't exist yet
					if (seenByConstructor[nameType] == null) {
						seenByConstructor[nameType] = [];
						constructorMap[nameType] = [];
					}

					while (len = chain.length) {

						temp = chain[len-1];

						// If the item is found on the current chain link
						if (temp[key] === value) {
							break;
						} else {
							// If it was not, remove this link from the chain
							chain.pop();
							path.pop();
						}

					}

					// Now see if this object has been seen before
					if (seenByConstructor[nameType].length) {
						i = seenByConstructor[nameType].indexOf(value);
					} else {
						i = -1;
					}

					if (i < 0) {

						// Store the object in the seen array and return the index
						i = seenObjects.push(value) - 1;
						j = seenByConstructor[nameType].push(value) - 1;
						constructorMap[nameType][j] = i;

						// Key cannot contain specialChar but could be not a string
						path.push(('' + key).replace(specialCharRg, safeSpecialChar));

						seenMap[i] = specialChar + path.join(specialChar);

						if (value.constructor.name == 'RegExp') {
							value = {dry: 'regexp', value: value.toString()};
						} else if (typeof value.toDry === 'function') {
							value = value.toDry();
							value.dry = 'toDry';
							value.drypath = path.slice(0);
						}
					} else {
						value = seenMap[constructorMap[nameType][i]];
					}
				} else {

					if (valType === 'string') {
						// Make sure the "special char" doesn't mess things up
						value = value.replace(safeSpecialChar, escapedSafeSpecialChar)
						             .replace(specialChar, safeSpecialChar);
					} else if (valType === 'number') {

						// Allow infinite values
						if (!isFinite(value)) {
							if (value > 0) {
								value = {dry: '+Infinity'};
							} else {
								value = {dry: '-Infinity'};
							}
						}
					}
				}
			}

			last = value;

			// Push the current object to the chain,
			// it is now the active item
			if (value != null & typeof value == 'object') {
				chain.push(value);
			}

			return value;
		};
	};

	/**
	 * Generate reviver function
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Function}
	 */
	function generateReviver(reviver, undryPaths) {

		return function dryReviver(key, value) {

			var valType = typeof value,
			    constructor,
			    temp;

			if (valType === 'string') {
				if (value.charAt(0) === specialChar) {
					return new String(value.slice(1));
				} else if (value.match(iso8061)) {
					return new Date(value);
				}
			} else if (value && valType == 'object' && value.dry != null) {

				if (value.dry == 'toDry') {

					constructor = Collection.Object.path(Blast.Globals, value.path);

					// Undry this element, but don't put it in the parsed object yet
					if (constructor && typeof constructor.unDry === 'function') {
						value.undried = constructor.unDry(value.value);
					}

					undryPaths[value.drypath.join(specialChar)] = value;
				} else if (value.dry == 'regexp' && value.value) {
					return RegExp.apply(undefined, getregex.exec(value.value).slice(1));
				} else if (value.dry == '+Infinity') {
					return Infinity;
				} else if (value.dry == '-Infinity') {
					return -Infinity;
				}
			}

			if (valType === 'string') {
				value = value.replace(safeStartWithSpecialCharRG, '$1' + specialChar)
				             .replace(escapedSafeSpecialChar, safeSpecialChar);
			}

			if (reviver == null) {
				return value;
			}

			return reviver.call(this, key, value);
		};
	};

	/**
	 * Regenerate an array
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Array}
	 */
	function regenerateArray(root, current, chain, retrieve, undryPaths) {

		var length = current.length,
		    i;

		for (i = 0; i < length; i++) {
			// Only regenerate if it's not in the chain
			if (chain.indexOf(current[i]) == -1) {
				current[i] = regenerate(root, current[i], chain, retrieve, undryPaths);
			}
		}

		return current;
	};

	/**
	 * Regenerate an object
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Object}
	 */
	function regenerateObject(root, current, chain, retrieve, undryPaths) {

		var key;

		for (key in current) {
			if (current.hasOwnProperty(key)) {
				// Only regenerate if it's not in the cain
				if (chain.indexOf(current[key]) == -1) {
					current[key] = regenerate(root, current[key], chain, retrieve, undryPaths);
				}
			}
		}

		return current;
	};

	/**
	 * Regenerate a value
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Mixed}
	 */
	function regenerate(root, current, chain, retrieve, undryPaths) {

		var temp,
		    i;

		chain.push(current);

		if (current instanceof Array) {
			return regenerateArray(root, current, chain, retrieve, undryPaths);
		}

		if (current instanceof String) {

			if (current.length) {
				if (undryPaths[current]) {
					return undryPaths[current].undried;
				}

				if (retrieve.hasOwnProperty(current)) {
					temp = retrieve[current];
				} else {
					temp = retrieve[current] = retrieveFromPath(root, current.split(specialChar));
				}

				return temp;
			} else {
				return root;
			}
		}

		if (current instanceof Object) {
			return regenerateObject(root, current, chain, retrieve, undryPaths);
		}

		chain.pop();

		return current;
	};

	/**
	 * Retrieve from path.
	 * Set the given value, but only if the containing object exists.
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Mixed}
	 */
	function retrieveFromPath(current, keys, value) {

		var length = keys.length,
		    prev,
		    key,
		    i;

		for (i = 0; i < length; i++) {

			// Normalize the key
			key = keys[i].replace(safeSpecialCharRG, specialChar);
			prev = current;

			if (current) {
				current = current[key];
			} else {
				return undefined;
			}
		}

		if (arguments.length === 3) {
			prev[key] = value;
			current = value;
		}

		return current;
	};

	/**
	 * Dry it
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {String}
	 */
	Blast.defineStatic('JSON', 'dry', function dry(value, replacer, space) {
		return JSON.stringify(value, generateReplacer(value, replacer), space);
	});

	/**
	 * Undry string
	 *
	 * @author   Jelle De Loecker   <jelle@codedor.be>
	 * @since    0.1.4
	 * @version  0.1.4
	 *
	 * @return   {Mixed}
	 */
	Blast.defineStatic('JSON', 'undry', function undry(text, reviver) {

		var undryPaths = {},
		    retrieve = {},
		    result,
		    path;

		result = JSON.parse(text, generateReviver(reviver, undryPaths));

		for (path in undryPaths) {
			undryPaths[path].undried = regenerate(result, undryPaths[path].undried, [], retrieve, undryPaths)
		}

		// Only now can we resolve paths
		result = regenerate(result, result, [], retrieve, undryPaths);

		// Now we can replace all the undried values
		for (path in undryPaths) {
			Collection.Object.setPath(result, undryPaths[path].drypath, undryPaths[path].undried);
		}

		return result;
	});

};<|endoftext|>