<commit_before>define([
  'mesh/Mesh'
], function (Mesh) {

  'use strict';

  var Import = {};

  /** Import OBJ file */
  Import.importOBJ = function (data, gl) {
    var meshes = [];
    var vAr = [];
    var cAr = [];
    var cArMrgb = [];
    var mAr = [];
    var mArMat = [];
    var texAr = [];
    var fAr = [];
    var uvfAr = [];
    var offsetVertices = 0;
    var offsetTexCoords = 0;
    var nbVertices = 0;
    var nbTexCoords = 0;
    var lines = data.split('\n');
    var split = [];
    var inv255 = 1.0 / 255;
    var nbLength = lines.length;
    for (var i = 0; i < nbLength; ++i) {
      var line = lines[i].trim();
      if (line.startsWith('o ')) {
        if (meshes.length > 0) {
          Import.initMeshOBJ(meshes[meshes.length - 1], vAr, fAr, cAr, mAr, texAr, uvfAr, cArMrgb, mArMat);
          offsetVertices = nbVertices;
          offsetTexCoords = nbTexCoords;
        }
        meshes.push(new Mesh(gl));
      } else if (line.startsWith('v ')) {
        split = line.split(/\s+/);
        vAr.push(parseFloat(split[1]), parseFloat(split[2]), parseFloat(split[3]));
        if (split[4])
          cAr.push(parseFloat(split[4]), parseFloat(split[5]), parseFloat(split[6]));
        ++nbVertices;
      } else if (line.startsWith('#MRGB ')) {
        // zbrush-like vertex color
        split = line.split(/\s+/);
        var blockMRGB = split[1];
        for (var m = 2, mlen = blockMRGB.length; m < mlen; m += 8) {
          var hex = parseInt(blockMRGB.substr(m, 6), 16);
          cArMrgb.push((hex >> 16) * inv255, (hex >> 8 & 0xff) * inv255, (hex & 0xff) * inv255);
        }
      } else if (line.startsWith('#MAT ')) {
        // zbrush-like vertex material
        split = line.split(/\s+/);
        var blockMAT = split[1];
        for (var n = 0, nlen = blockMAT.length; n < nlen; n += 6) {
          var hex2 = parseInt(blockMAT.substr(n, 6), 16);
          mArMat.push((hex2 >> 16) * inv255, (hex2 >> 8 & 0xff) * inv255, (hex2 & 0xff) * inv255);
        }
      } else if (line.startsWith('vt ')) {
        split = line.split(/\s+/);
        texAr.push(parseFloat(split[1]), parseFloat(split[2]));
        ++nbTexCoords;
      } else if (line.startsWith('f ')) {
        split = line.split(/\s+/);
        if (split.length !== 4 && split.length !== 5) // triangles and quads only
          continue;
        var sp1 = split[1].split('/');
        var sp2 = split[2].split('/');
        var sp3 = split[3].split('/');
        var isQuad = split.length > 4;

        var iv1 = parseInt(sp1[0], 10);
        var iv2 = parseInt(sp2[0], 10);
        var iv3 = parseInt(sp3[0], 10);
        var iv4 = isQuad ? parseInt(split[4].split('/')[0], 10) : undefined;
        if (isQuad && (iv4 === iv1 || iv4 === iv2 || iv4 === iv3))
          continue;
        if (iv1 === iv2 || iv1 === iv3 || iv2 === iv3)
          continue;
        iv1 = (iv1 < 0 ? iv1 + nbVertices : iv1 - 1) - offsetVertices;
        iv2 = (iv2 < 0 ? iv2 + nbVertices : iv2 - 1) - offsetVertices;
        iv3 = (iv3 < 0 ? iv3 + nbVertices : iv3 - 1) - offsetVertices;
        if (isQuad) iv4 = (iv4 < 0 ? iv4 + nbVertices : iv4 - 1) - offsetVertices;
        fAr.push(iv1, iv2, iv3, isQuad ? iv4 : -1);

        if (sp1[1]) {
          var uv1 = parseInt(sp1[1], 10);
          var uv2 = parseInt(sp2[1], 10);
          var uv3 = parseInt(sp3[1], 10);
          var uv4 = isQuad ? parseInt(split[4].split('/')[1], 10) : undefined;
          uv1 = (uv1 < 0 ? uv1 + nbTexCoords : uv1 - 1) - offsetTexCoords;
          uv2 = (uv2 < 0 ? uv2 + nbTexCoords : uv2 - 1) - offsetTexCoords;
          uv3 = (uv3 < 0 ? uv3 + nbTexCoords : uv3 - 1) - offsetTexCoords;
          if (isQuad) uv4 = (uv4 < 0 ? uv4 + nbTexCoords : uv4 - 1) - offsetTexCoords;
          uvfAr.push(uv1, uv2, uv3, isQuad ? uv4 : -1);
        }
      }
    }
    if (meshes.length === 0) meshes[0] = new Mesh(gl);
    Import.initMeshOBJ(meshes[meshes.length - 1], vAr, fAr, cAr, mAr, texAr, uvfAr, cArMrgb, mArMat);
    return meshes;
  };

  Import.initMeshOBJ = function (mesh, vAr, fAr, cAr, mAr, texAr, uvfAr, cArMrgb, mArMat) {
    mesh.setVertices(new Float32Array(vAr));
    mesh.setFaces(new Int32Array(fAr));

    if (cArMrgb.length === vAr.length) mesh.setColors(new Float32Array(cArMrgb));
    else if (cAr.length === vAr.length) mesh.setColors(new Float32Array(cAr));

    if (mArMat.length === vAr.length) mesh.setMaterials(new Float32Array(mArMat));
    else if (mAr.length === vAr.length) mesh.setMaterials(new Float32Array(mAr));

    if (texAr.length > 0 && uvfAr.length === fAr.length)
      mesh.initTexCoordsDataFromOBJData(texAr, uvfAr);

    vAr.length = fAr.length = 0;
    cArMrgb.length = cAr.length = 0;
    mArMat.length = mAr.length = 0;
    texAr.length = uvfAr.length = 0;
  };

  return Import;
});<commit_msg>Handles n gon in obj parsing<commit_after>define([
  'mesh/Mesh'
], function (Mesh) {

  'use strict';

  var Import = {};

  /** Import OBJ file */
  Import.importOBJ = function (data, gl) {
    var meshes = [];
    var vAr = [];
    var cAr = [];
    var cArMrgb = [];
    var mAr = [];
    var mArMat = [];
    var texAr = [];
    var fAr = [];
    var uvfAr = [];
    var offsetVertices = 0;
    var offsetTexCoords = 0;
    var nbVertices = 0;
    var nbTexCoords = 0;
    var lines = data.split('\n');
    var split = [];
    var inv255 = 1.0 / 255;
    var nbLength = lines.length;
    for (var i = 0; i < nbLength; ++i) {
      var line = lines[i].trim();
      if (line.startsWith('o ')) {
        if (meshes.length > 0) {
          Import.initMeshOBJ(meshes[meshes.length - 1], vAr, fAr, cAr, mAr, texAr, uvfAr, cArMrgb, mArMat);
          offsetVertices = nbVertices;
          offsetTexCoords = nbTexCoords;
        }
        meshes.push(new Mesh(gl));
      } else if (line.startsWith('v ')) {
        split = line.split(/\s+/);
        vAr.push(parseFloat(split[1]), parseFloat(split[2]), parseFloat(split[3]));
        if (split[4])
          cAr.push(parseFloat(split[4]), parseFloat(split[5]), parseFloat(split[6]));
        ++nbVertices;
      } else if (line.startsWith('#MRGB ')) {
        // zbrush-like vertex color
        split = line.split(/\s+/);
        var blockMRGB = split[1];
        for (var m = 2, mlen = blockMRGB.length; m < mlen; m += 8) {
          var hex = parseInt(blockMRGB.substr(m, 6), 16);
          cArMrgb.push((hex >> 16) * inv255, (hex >> 8 & 0xff) * inv255, (hex & 0xff) * inv255);
        }
      } else if (line.startsWith('#MAT ')) {
        // zbrush-like vertex material
        split = line.split(/\s+/);
        var blockMAT = split[1];
        for (var n = 0, nlen = blockMAT.length; n < nlen; n += 6) {
          var hex2 = parseInt(blockMAT.substr(n, 6), 16);
          mArMat.push((hex2 >> 16) * inv255, (hex2 >> 8 & 0xff) * inv255, (hex2 & 0xff) * inv255);
        }
      } else if (line.startsWith('vt ')) {
        split = line.split(/\s+/);
        texAr.push(parseFloat(split[1]), parseFloat(split[2]));
        ++nbTexCoords;
      } else if (line.startsWith('f ')) {
        split = line.split(/\s+/);
        var nbVerts = split.length - 1;
        if (nbVerts < 3) // at least 3 vertices
          continue;

        var nbPrim = Math.ceil(nbVerts / 2) - 1;
        // quandrangulate polygons (+ 1 tri)
        for (var j = 0; j < nbPrim; ++j) {
          var id1 = j + 1;
          var id2 = j + 2;
          var id3 = nbVerts - id1;
          var id4 = nbVerts - j;
          if (id3 === id2) {
            id3 = id4;
            id4 = -1;
          }

          var sp1 = split[id1].split('/');
          var sp2 = split[id2].split('/');
          var sp3 = split[id3].split('/');
          var isQuad = id4 >= 0;
          var sp4;
          if (isQuad) sp4 = split[id4].split('/');

          var iv1 = parseInt(sp1[0], 10);
          var iv2 = parseInt(sp2[0], 10);
          var iv3 = parseInt(sp3[0], 10);
          var iv4 = isQuad ? parseInt(sp4[0], 10) : undefined;
          if (isQuad && (iv4 === iv1 || iv4 === iv2 || iv4 === iv3))
            continue;
          if (iv1 === iv2 || iv1 === iv3 || iv2 === iv3)
            continue;
          iv1 = (iv1 < 0 ? iv1 + nbVertices : iv1 - 1) - offsetVertices;
          iv2 = (iv2 < 0 ? iv2 + nbVertices : iv2 - 1) - offsetVertices;
          iv3 = (iv3 < 0 ? iv3 + nbVertices : iv3 - 1) - offsetVertices;
          if (isQuad) iv4 = (iv4 < 0 ? iv4 + nbVertices : iv4 - 1) - offsetVertices;
          fAr.push(iv1, iv2, iv3, isQuad ? iv4 : -1);

          if (sp1[1]) {
            var uv1 = parseInt(sp1[1], 10);
            var uv2 = parseInt(sp2[1], 10);
            var uv3 = parseInt(sp3[1], 10);
            var uv4 = isQuad ? parseInt(sp4[1], 10) : undefined;
            uv1 = (uv1 < 0 ? uv1 + nbTexCoords : uv1 - 1) - offsetTexCoords;
            uv2 = (uv2 < 0 ? uv2 + nbTexCoords : uv2 - 1) - offsetTexCoords;
            uv3 = (uv3 < 0 ? uv3 + nbTexCoords : uv3 - 1) - offsetTexCoords;
            if (isQuad) uv4 = (uv4 < 0 ? uv4 + nbTexCoords : uv4 - 1) - offsetTexCoords;
            uvfAr.push(uv1, uv2, uv3, isQuad ? uv4 : -1);
          }
        }
      }
    }
    if (meshes.length === 0) meshes[0] = new Mesh(gl);
    Import.initMeshOBJ(meshes[meshes.length - 1], vAr, fAr, cAr, mAr, texAr, uvfAr, cArMrgb, mArMat);
    return meshes;
  };

  Import.initMeshOBJ = function (mesh, vAr, fAr, cAr, mAr, texAr, uvfAr, cArMrgb, mArMat) {
    mesh.setVertices(new Float32Array(vAr));
    mesh.setFaces(new Int32Array(fAr));

    if (cArMrgb.length === vAr.length) mesh.setColors(new Float32Array(cArMrgb));
    else if (cAr.length === vAr.length) mesh.setColors(new Float32Array(cAr));

    if (mArMat.length === vAr.length) mesh.setMaterials(new Float32Array(mArMat));
    else if (mAr.length === vAr.length) mesh.setMaterials(new Float32Array(mAr));

    if (texAr.length > 0 && uvfAr.length === fAr.length)
      mesh.initTexCoordsDataFromOBJData(texAr, uvfAr);

    vAr.length = fAr.length = 0;
    cArMrgb.length = cAr.length = 0;
    mArMat.length = mAr.length = 0;
    texAr.length = uvfAr.length = 0;
  };

  return Import;
});<|endoftext|>


<commit_before>(function(){
  var Mediator = function(){};

  Mediator.prototype = {
    _callbacks: { Predicates: [] },

    Add: function(condition, fn){
      if(typeof condition === "function"){
        this._callbacks.Predicates.push([condition, fn]);

        return;
      }

      if(typeof condition === "number"){
        if(!this._callbacks[condition]){
          this._callbacks[condition] = [];
        }

        this._callbacks[condition].push(fn);

        return;
      }

      throw("Must be a predicate or response data type integer.");
    },

    Remove: function(condition, fn){
      if(this._callbacks.Predicates.length > 0 && typeof condition == "function"){
        var counter = 0;
        for(var x in this._callbacks.Predicates){
          if(this._callbacks.Predicates[x][0] == condition && (!fn || fn == this._callbacks.Predicates[x])){
            this._callbacks.Predicates.splice(counter, 1);
            counter--;
          }

          counter++;
        }

        return;
      }

      if(this._callbacks[condition]){
        if(!fn){
          this._callbacks[condition] = [];
          return;
        }

        for(var y in this._callbacks[condition]) {
          if(this._callbacks[condition][y] == fn){
            this._callbacks[condition].splice(y,1);
          }
        }
      }
    },

    Call: function(data){
      if(data.Type !== undefined && this._callbacks[data.Type]){
        for(var x in this._callbacks[data.Type]){
          this._callbacks[data.Type][x](data);

        }
      }

      for(var y in this._callbacks.Predicates){
        if(this._callbacks.Predicates[y][0](data)){
          this._callbacks.Predicates[y][1](data);
        }
      }
    }
  }

  window.Mediator = Mediator.prototype;;
})(window);
<commit_msg>Spacing cleanup<commit_after>(function(){
  var Mediator = function(){};

  Mediator.prototype = {
    _callbacks: { Predicates: [] },

    Add: function(condition, fn){
      if(typeof condition === "function"){
        this._callbacks.Predicates.push([condition, fn]);
        return;
      }

      if(typeof condition === "number"){
        if(!this._callbacks[condition]){
          this._callbacks[condition] = [];
        }

        this._callbacks[condition].push(fn);
        return;
      }

      throw("Must be a predicate or response data type integer.");
    },

    Remove: function(condition, fn){
      if(this._callbacks.Predicates.length > 0 && typeof condition == "function"){
        var counter = 0;
        for(var x in this._callbacks.Predicates){
          if(this._callbacks.Predicates[x][0] == condition && (!fn || fn == this._callbacks.Predicates[x])){
            this._callbacks.Predicates.splice(counter, 1);
            counter--;
          }

          counter++;
        }

        return;
      }

      if(this._callbacks[condition]){
        if(!fn){
          this._callbacks[condition] = [];
          return;
        }

        for(var y in this._callbacks[condition]) {
          if(this._callbacks[condition][y] == fn){
            this._callbacks[condition].splice(y,1);
          }
        }
      }
    },

    Call: function(data){
      if(data.Type !== undefined && this._callbacks[data.Type]){
        for(var x in this._callbacks[data.Type]){
          this._callbacks[data.Type][x](data);

        }
      }

      for(var y in this._callbacks.Predicates){
        if(this._callbacks.Predicates[y][0](data)){
          this._callbacks.Predicates[y][1](data);
        }
      }
    }
  }

  window.Mediator = Mediator.prototype;;
})(window);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define */

define(function (require, exports, module) {
    "use strict";

    var FileSystemEntry = require("filesystem/FileSystemEntry"),
        FileSystemError = require("filesystem/FileSystemError");

    /*
     * @constructor
     * Model for a File.
     *
     * This class should *not* be instantiated directly. Use FileSystem.getFileForPath,
     * FileSystem.resolve, or Directory.getContents to create an instance of this class.
     *
     * See the FileSystem class for more details.
     *
     * @param {!string} fullPath The full path for this File.
     * @param {!FileSystem} fileSystem The file system associated with this File.
     */
    function File(fullPath, fileSystem) {
        this._isFile = true;
        FileSystemEntry.call(this, fullPath, fileSystem);
    }

    File.prototype = Object.create(FileSystemEntry.prototype);
    File.prototype.constructor = File;
    File.prototype.parentClass = FileSystemEntry.prototype;

    /**
     * Contents of this file.
     */
    File.prototype._contents = null;

    /**
     * Consistency hash for this file. Reads and writes update this value, and
     * writes confirm the hash before overwriting existing files.
     */
    File.prototype._hash = null;

    /**
     * Clear any cached data for this file. Note that this explicitly does NOT
     * clear the file's hash.
     * @private
     */
    File.prototype._clearCachedData = function () {
        FileSystemEntry.prototype._clearCachedData.apply(this);
        this._contents = null;
    };

    /**
     * Read a file.
     *
     * @param {Object=} options Currently unused.
     * @param {function (?string, string=, FileSystemStats=)} callback Callback that is passed the
     *              FileSystemError string or the file's contents and its stats.
     */
    File.prototype.read = function (options, callback) {
        if (typeof (options) === "function") {
            callback = options;
            options = {};
        }

        // We don't need to check isWatched() here because contents are only saved
        // for watched files. Note that we need to explicitly test this._contents
        // for a default value; otherwise it could be the empty string, which is
        // falsey.
        if (this._contents !== null && this._stat) {
            callback(null, this._contents, this._stat);
            return;
        }

        var watched = this._isWatched();
        if (watched) {
            options.stat = this._stat;
        }

        this._impl.readFile(this._path, options, function (err, data, stat) {
            if (err) {
                this._clearCachedData();
                callback(err);
                return;
            }

            // Only cache data for watched files
            if (watched) {
                this._stat = stat;
                this._hash = stat._hash;
                this._contents = data;
            }

            callback(err, data, stat);
        }.bind(this));
    };

    /**
     * Write a file.
     *
     * @param {string} data Data to write.
     * @param {object=} options Currently unused.
     * @param {!function (?string, FileSystemStats=)=} callback Callback that is passed the
     *              FileSystemError string or the file's new stats.
     */
    File.prototype.write = function (data, options, callback) {
        if (typeof (options) === "function") {
            callback = options;
            options = {};
        }

        callback = callback || function () {};

        // Request a consistency check if the file is watched and the write is not blind
        var watched = this._isWatched();
        if (watched && !options.blind) {
            options.hash = this._hash;
        }

        // Block external change events until after the write has finished
        this._fileSystem._beginChange();

        this._impl.writeFile(this._path, data, options, function (err, stat, created) {
            if (err) {
                this._clearCachedData();
                try {
                    callback(err);
                    return;
                } finally {
                    // Always unblock external change events
                    this._fileSystem._endChange();
                }
            }

            // Only cache data for watched files
            if (watched) {
                this._stat = stat;
                this._hash = stat._hash;
                this._contents = data;
            }

            if (created) {
                var parent = this._fileSystem.getDirectoryForPath(this.parentPath);
                this._fileSystem._handleDirectoryChange(parent, function (added, removed) {
                    try {
                        // Notify the caller
                        callback(null, stat);
                    } finally {
                        // If the write succeeded, fire a synthetic change event
                        this._fileSystem._fireChangeEvent(parent, added, removed);

                        // Always unblock external change events
                        this._fileSystem._endChange();
                    }
                }.bind(this));
            } else {
                try {
                    // Notify the caller
                    callback(null, stat);
                } finally {
                    // existing file modified
                    this._fileSystem._fireChangeEvent(this);

                    // Always unblock external change events
                    this._fileSystem._endChange();
                }
            }
        }.bind(this));
    };

    // Export this class
    module.exports = File;
});
<commit_msg>Always save the file hash, even when not watched.<commit_after>/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define */

define(function (require, exports, module) {
    "use strict";

    var FileSystemEntry = require("filesystem/FileSystemEntry"),
        FileSystemError = require("filesystem/FileSystemError");

    /*
     * @constructor
     * Model for a File.
     *
     * This class should *not* be instantiated directly. Use FileSystem.getFileForPath,
     * FileSystem.resolve, or Directory.getContents to create an instance of this class.
     *
     * See the FileSystem class for more details.
     *
     * @param {!string} fullPath The full path for this File.
     * @param {!FileSystem} fileSystem The file system associated with this File.
     */
    function File(fullPath, fileSystem) {
        this._isFile = true;
        FileSystemEntry.call(this, fullPath, fileSystem);
    }

    File.prototype = Object.create(FileSystemEntry.prototype);
    File.prototype.constructor = File;
    File.prototype.parentClass = FileSystemEntry.prototype;

    /**
     * Contents of this file.
     */
    File.prototype._contents = null;

    /**
     * Consistency hash for this file. Reads and writes update this value, and
     * writes confirm the hash before overwriting existing files.
     */
    File.prototype._hash = null;

    /**
     * Clear any cached data for this file. Note that this explicitly does NOT
     * clear the file's hash.
     * @private
     */
    File.prototype._clearCachedData = function () {
        FileSystemEntry.prototype._clearCachedData.apply(this);
        this._contents = null;
    };

    /**
     * Read a file.
     *
     * @param {Object=} options Currently unused.
     * @param {function (?string, string=, FileSystemStats=)} callback Callback that is passed the
     *              FileSystemError string or the file's contents and its stats.
     */
    File.prototype.read = function (options, callback) {
        if (typeof (options) === "function") {
            callback = options;
            options = {};
        }

        // We don't need to check isWatched() here because contents are only saved
        // for watched files. Note that we need to explicitly test this._contents
        // for a default value; otherwise it could be the empty string, which is
        // falsey.
        if (this._contents !== null && this._stat) {
            callback(null, this._contents, this._stat);
            return;
        }

        var watched = this._isWatched();
        if (watched) {
            options.stat = this._stat;
        }

        this._impl.readFile(this._path, options, function (err, data, stat) {
            if (err) {
                this._clearCachedData();
                callback(err);
                return;
            }

            // Always store the hash
            this._hash = stat._hash;

            // Only cache data for watched files
            if (watched) {
                this._stat = stat;
                this._contents = data;
            }

            callback(err, data, stat);
        }.bind(this));
    };

    /**
     * Write a file.
     *
     * @param {string} data Data to write.
     * @param {object=} options Currently unused.
     * @param {!function (?string, FileSystemStats=)=} callback Callback that is passed the
     *              FileSystemError string or the file's new stats.
     */
    File.prototype.write = function (data, options, callback) {
        if (typeof (options) === "function") {
            callback = options;
            options = {};
        }

        callback = callback || function () {};

        // Request a consistency check if the file is watched and the write is not blind
        var watched = this._isWatched();
        if (watched && !options.blind) {
            options.hash = this._hash;
        }

        // Block external change events until after the write has finished
        this._fileSystem._beginChange();

        this._impl.writeFile(this._path, data, options, function (err, stat, created) {
            if (err) {
                this._clearCachedData();
                try {
                    callback(err);
                    return;
                } finally {
                    // Always unblock external change events
                    this._fileSystem._endChange();
                }
            }

            // Always store the hash
            this._hash = stat._hash;

            // Only cache data for watched files
            if (watched) {
                this._stat = stat;
                this._contents = data;
            }

            if (created) {
                var parent = this._fileSystem.getDirectoryForPath(this.parentPath);
                this._fileSystem._handleDirectoryChange(parent, function (added, removed) {
                    try {
                        // Notify the caller
                        callback(null, stat);
                    } finally {
                        // If the write succeeded, fire a synthetic change event
                        this._fileSystem._fireChangeEvent(parent, added, removed);

                        // Always unblock external change events
                        this._fileSystem._endChange();
                    }
                }.bind(this));
            } else {
                try {
                    // Notify the caller
                    callback(null, stat);
                } finally {
                    // existing file modified
                    this._fileSystem._fireChangeEvent(this);

                    // Always unblock external change events
                    this._fileSystem._endChange();
                }
            }
        }.bind(this));
    };

    // Export this class
    module.exports = File;
});
<|endoftext|>


<commit_before>(function (root, factory) {
  if(typeof define === 'function' && define.amd) {
    define(['knockout'], factory);
  } else {
    factory(root.ko);
  }
}(this, function(ko) {
  ko.bindingHandlers.bindHtml = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
      ko.unwrap(valueAccessor());
      ko.applyBindingsToDescendants(bindingContext.$data, element);
    }
  };

  ko.bindingHandlers.bindHtml.preprocess = function(value, name, addBinding) {
      addBinding('html', value);
      return value;
  };
}));
<commit_msg>Add a code comment. Reorganized code for clarity.<commit_after>(function (root, factory) {
  if(typeof define === 'function' && define.amd) {
    // Support AMD modules
    define(['knockout'], factory);
  } else {
    factory(root.ko);
  }
}(this, function(ko) {
  ko.bindingHandlers.bindHtml.preprocess = function(value, name, addBinding) {
    addBinding('html', value);
    return value;
  };

  ko.bindingHandlers.bindHtml = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
      ko.unwrap(valueAccessor());
      ko.applyBindingsToDescendants(bindingContext.$data, element);
    }
  };
}));
<|endoftext|>


<commit_before>'use strict';

const React = require('react');

import { createStore } from 'redux'
import loadPlayers from './actions/codex';
import Root from './containers/Root'
import { syncHistoryWithStore } from 'react-router-redux'
import { browserHistory } from 'react-router'
import configureStore from './store/configureStore'

require('./theme/style.scss');

let store = configureStore()
const history = syncHistoryWithStore(browserHistory, store)

console.log(store.getState());

let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

const units = [
  {name: 'Unit', role: 'Jack', cost: 10}
];

//store.dispatch(loadPlayers(units));
store.dispatch({
  type: 'LOAD_PLAYERS',
  units
});

export default <Root store={store} history={history} />;
<commit_msg>Corrected imports<commit_after>'use strict';

const React = require('react');

import { createStore } from 'redux'
import { loadPlayers } from './actions/codex';
import Root from './containers/Root'
import { syncHistoryWithStore } from 'react-router-redux'
import { browserHistory } from 'react-router'
import configureStore from './store/configureStore'

require('./theme/style.scss');

let store = configureStore()
const history = syncHistoryWithStore(browserHistory, store)

console.log(store.getState());

let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

const units = [
  {name: 'Unit', role: 'Jack', cost: 10}
];

store.dispatch(loadPlayers(units));

export default <Root store={store} history={history} />;
<|endoftext|>


<commit_before>describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(false).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(FILL_ME_IN);
  });
});
<commit_msg>Expects file completed<commit_after>describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(true).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = 2;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = 2;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = "2";
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(2);
  });
});
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe("Harley");
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect('They are Pinky and the Brain Brain Brain Brain').toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2014);
    expect(meglomaniac.calculateAge()).toBe(44);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(true);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(false);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>AboutObjects test 7 done.<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe("Harley");
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect('They are Pinky and the Brain Brain Brain Brain').toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2014);
    expect(meglomaniac.calculateAge()).toBe(44);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(true);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(false);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(false);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(true);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(false);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>/*!
 * viewport
 * Version: 0.0.1
 * Date: 2016/7/21
 * https://github.com/Nuintun/viewport
 *
 * Original Author: http://www.jsbug.com/lab/samples/viewport/
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/Nuintun/viewport/blob/master/LICENSE
 */

'use strict';

var is = require('./is');
var $ = require('jquery');

// id expando
var expando = 0;

/**
 * patch the threshold like css
 * - 1            ==> top: 1, right: 1, bottom: 1, left: 1
 * - [1]          ==> top: 1, right: 1, bottom: 1, left: 1
 * - [1, 2]       ==> top: 1, right: 2, bottom: 1, left: 2
 * - [1, 2, 3]    ==> top: 1, right: 2, bottom: 3, left: 2
 * - [1, 2, 3, 4] ==> top: 1, right: 2, bottom: 3, left: 4
 * @param threshold
 * @param absolute
 * @returns {*}
 */
function patchThreshold(threshold, absolute){
  if (is.number(threshold) && !is.nan(threshold) && !is.infinite(threshold)) {
    if (absolute) {
      threshold = Math.abs(threshold);
    }

    threshold = [threshold, threshold, threshold, threshold];
  } else if (is.array(threshold)) {
    var value;
    var set = [];
    var length = threshold.length;

    for (var i = 0; i < length; i++) {
      if (set.length < 4) {
        value = threshold[i];

        if (is.number(value) && !is.nan(value) && !is.infinite(value)) {
          set.push(absolute ? Math.abs(value) : value);
        }
      } else {
        break;
      }
    }

    switch (set.length) {
      case 0:
        threshold = [0, 0, 0, 0];
        break;
      case 1:
        threshold = [set[0], set[0], set[0], set[0]];
        break;
      case 2:
        threshold = [set[0], set[1], set[0], set[1]];
        break;
      case 3:
        threshold = [set[0], set[1], set[2], set[1]];
        break;
      default:
        threshold = set;
        break;
    }
  } else {
    threshold = [0, 0, 0, 0];
  }

  return threshold;
}

/**
 * patch the viewport if it is the window object
 * @param viewport
 * @returns {*}
 */
function patchViewport(viewport){
  if (window !== window && is.element(viewport)) {
    throw new Error('Viewport must be window or a HTMLElement');
  }

  return viewport === window
    ? (document.compatMode == 'CSS1Compat' ? document.documentElement : document.body)
    : viewport;
}

/**
 * Viewport
 * @param viewport
 * @param options
 * @constructor
 */
function Viewport(viewport, options){
  var context = this;

  context.events = {};
  context.id = expando++;
  context.viewport = $(patchViewport(viewport));

  // init
  context.__initOptions(options);
  context.__findTarget();
  context.__init();
}

/**
 * @type {{
 *   __init: Viewport.__init,
 *   __changeViewport: Viewport.__changeViewport,
 *   __initOptions: Viewport.__initOptions,
 *   __findTarget: Viewport.__findTarget,
 *   __filterTargetInViewport: Viewport.__filterTargetInViewport,
 *   on: Viewport.on, off: Viewport.off,
 *   emit: Viewport.emit,
 *   refresh: Viewport.refresh,
 *   destroy: Viewport.destroy
 * }}
 */
Viewport.prototype = {
  __init: function (){
    // delay trigger the scroll or resize event.
    var timer;
    var context = this;
    var id = context.id;
    var options = context.options;
    var viewport = context.viewport;
    var scrollTop = viewport.scrollTop();
    var scrollLeft = viewport.scrollLeft();
    var namespace = '.viewport-' + id;

    viewport.on(
      'scroll' + namespace + ' resize' + namespace,
      function (){
        clearTimeout(timer);

        timer = setTimeout(function (){
          // trigger the viewchange event internally.
          var event = context.__changeViewport(scrollTop, scrollLeft);

          // cahce scroll position
          scrollTop = event.scrollTop;
          scrollLeft = event.scrollLeft;
        }, options.delay);
      }
    );

    // init event
    context.__changeViewport(scrollTop, scrollLeft);
  },
  __changeViewport: function (vertical, horizontal){
    var context = this;
    var options = context.options;
    var viewport = context.viewport;
    var thresholdBorderReaching = options.thresholdBorderReaching;

    if (!viewport.is(':visible')) return;

    var width = viewport.innerWidth();
    var height = viewport.innerHeight();
    var scrollWidth = viewport[0].scrollWidth;
    var scrollHeight = viewport[0].scrollHeight;

    // event
    var event = {};

    // scrollbar position
    event.scrollTop = viewport.scrollTop();
    event.scrollLeft = viewport.scrollLeft();
    event.offsetY = event.scrollTop - vertical;
    event.offsetX = event.scrollLeft - horizontal;

    // event type
    event.type = 'viewchange';

    // target
    event.target = context.__filterTargetInViewport(width, height);

    // calculate viewport border reaching detail infos
    event.top = event.scrollTop - thresholdBorderReaching[0] <= 0;
    event.right = width + event.scrollLeft + thresholdBorderReaching[1] >= scrollWidth;
    event.bottom = height + event.scrollTop + thresholdBorderReaching[2] >= scrollHeight;
    event.left = event.scrollLeft - thresholdBorderReaching[3] <= 0;

    // emit view change event
    context.emit(event.type, event);

    // return scrollbar position
    return event;
  },
  __initOptions: function (options){
    options = $.extend({
      delay: 150,
      target: null,
      threshold: 0,
      skipHidden: true,
      thresholdBorderReaching: 0
    }, options);

    options.threshold = patchThreshold(options.threshold);
    options.thresholdBorderReaching = patchThreshold(options.thresholdBorderReaching, true);

    this.options = options;
  },
  __findTarget: function (){
    var context = this;
    var options = context.options;
    var target = options.target;
    var viewport = context.viewport;

    if (is.string(target)) {
      target = viewport.find(target);
    } else if (is.element(target) && $.contains(viewport[0], target)) {
      target = $(target);
    } else if (target instanceof $) {
      target = $.grep(target, function (element){
        return $.contains(viewport[0], element);
      });
    } else {
      target = null;
    }

    context.target = target;
  },
  __filterTargetInViewport: function (width, height){
    var rect;
    var result = [];
    var context = this;
    var target = context.target;

    // target is null
    if (target === null) return result;

    var options = context.options;
    var threshold = options.threshold;
    var skipHidden = options.skipHidden;

    // get viewport height and width
    var viewport = context.viewport;

    // adjust the offsetTop and offsetLeft
    var viewportRect = viewport[0].getBoundingClientRect();
    var offsetTop = viewportRect.top + Math.round((parseInt(viewport.css('border-top-width')) || 0));
    var offsetLeft = viewportRect.left + Math.round((parseInt(viewport.css('border-left-width')) || 0));

    // filter elements by their rect info
    target.each(function (index, element){
      rect = element.getBoundingClientRect();

      // hidden element
      if (rect.top == 0 && rect.bottom == 0 && rect.left == 0 && rect.right == 0) {
        if (!skipHidden) {
          result.push(element);
        }
      } else {
        // visible element
        var top = rect.top - offsetTop;
        var bottom = rect.bottom - offsetTop;
        var left = rect.left - offsetLeft;
        var right = rect.right - offsetLeft;

        // adjust position
        if (
          !(top - threshold[0] >= height
          || right + threshold[1] <= 0
          || bottom + threshold[2] <= 0
          || left - threshold[3] >= width)
        ) {
          result.push(element);
        }
      }
    });

    return result;
  },
  on: function (event, handler){
    var context = this;

    context.events[event] = context.events[event]
      || $.Callbacks('memory stopOnFalse');

    context.events[event].add(handler);

    return context;
  },
  off: function (event, handler){
    var context = this;

    switch (arguments.length) {
      case 0:
        context.events = {};
        break;
      case 1:
        delete context.events[event];
        break;
      default:
        context.events[event] && context.events[event].remove(handler);
        break;
    }

    return context;
  },
  emit: function (event){
    var context = this;
    var data = [].slice.call(arguments, 1);

    context.events[event] = context.events[event]
      || $.Callbacks('memory stopOnFalse');

    this.events[event].fireWith(context, data);

    return context;
  },
  refresh: function (){
    var context = this;
    var viewport = context.viewport;

    context.__findTarget();
    context.__changeViewport(viewport.scrollTop(), viewport.scrollLeft());

    return context;
  },
  destroy: function (){
    var context = this;
    var viewport = context.viewport;
    var namespace = '.viewport-' + context.id;

    // off event listen
    viewport.off('scroll' + namespace);
    viewport.off('resize' + namespace);
  }
};

// exports
module.exports = Viewport;
<commit_msg>update files<commit_after>/*!
 * viewport
 * Version: 0.0.1
 * Date: 2016/7/21
 * https://github.com/Nuintun/viewport
 *
 * Original Author: http://www.jsbug.com/lab/samples/viewport/
 *
 * This is licensed under the MIT License (MIT).
 * For details, see: https://github.com/Nuintun/viewport/blob/master/LICENSE
 */

'use strict';

var is = require('./is');
var $ = require('jquery');

// id expando
var expando = 0;

/**
 * patch the threshold like css
 * - 1            ==> top: 1, right: 1, bottom: 1, left: 1
 * - [1]          ==> top: 1, right: 1, bottom: 1, left: 1
 * - [1, 2]       ==> top: 1, right: 2, bottom: 1, left: 2
 * - [1, 2, 3]    ==> top: 1, right: 2, bottom: 3, left: 2
 * - [1, 2, 3, 4] ==> top: 1, right: 2, bottom: 3, left: 4
 * @param threshold
 * @param absolute
 * @returns {*}
 */
function patchThreshold(threshold, absolute){
  if (is.number(threshold) && !is.nan(threshold) && !is.infinite(threshold)) {
    if (absolute) {
      threshold = Math.abs(threshold);
    }

    threshold = [threshold, threshold, threshold, threshold];
  } else if (is.array(threshold)) {
    var value;
    var set = [];
    var length = threshold.length;

    for (var i = 0; i < length; i++) {
      if (set.length < 4) {
        value = threshold[i];

        if (is.number(value) && !is.nan(value) && !is.infinite(value)) {
          set.push(absolute ? Math.abs(value) : value);
        }
      } else {
        break;
      }
    }

    switch (set.length) {
      case 0:
        threshold = [0, 0, 0, 0];
        break;
      case 1:
        threshold = [set[0], set[0], set[0], set[0]];
        break;
      case 2:
        threshold = [set[0], set[1], set[0], set[1]];
        break;
      case 3:
        threshold = [set[0], set[1], set[2], set[1]];
        break;
      default:
        threshold = set;
        break;
    }
  } else {
    threshold = [0, 0, 0, 0];
  }

  return threshold;
}

/**
 * patch the viewport if it is the window object
 * @param viewport
 * @returns {*}
 */
function patchViewport(viewport){
  if (window !== window && is.element(viewport)) {
    throw new Error('Viewport must be window or a HTMLElement');
  }

  return viewport === window
    ? (document.compatMode == 'CSS1Compat' ? document.documentElement : document.body)
    : viewport;
}

/**
 * Viewport
 * @param viewport
 * @param options
 * @constructor
 */
function Viewport(viewport, options){
  var context = this;

  context.events = {};
  context.id = expando++;
  context.viewport = $(patchViewport(viewport));

  // init
  context.__initOptions(options);
  context.__findTarget();
  context.__init();
}

/**
 * @type {{
 *   __init: Viewport.__init,
 *   __changeViewport: Viewport.__changeViewport,
 *   __initOptions: Viewport.__initOptions,
 *   __findTarget: Viewport.__findTarget,
 *   __filterTargetInViewport: Viewport.__filterTargetInViewport,
 *   on: Viewport.on, off: Viewport.off,
 *   emit: Viewport.emit,
 *   refresh: Viewport.refresh,
 *   destroy: Viewport.destroy
 * }}
 */
Viewport.prototype = {
  __init: function (){
    // delay trigger the scroll or resize event.
    var timer;
    var context = this;
    var id = context.id;
    var options = context.options;
    var viewport = context.viewport;
    var scrollTop = viewport.scrollTop();
    var scrollLeft = viewport.scrollLeft();
    var namespace = '.viewport-' + id;

    viewport.on(
      'scroll' + namespace + ' resize' + namespace,
      function (){
        clearTimeout(timer);

        timer = setTimeout(function (){
          // trigger the viewchange event internally.
          var event = context.__changeViewport(scrollTop, scrollLeft);

          // cahce scroll position
          scrollTop = event.scrollTop;
          scrollLeft = event.scrollLeft;
        }, options.delay);
      }
    );

    // init event
    context.__changeViewport(scrollTop, scrollLeft);
  },
  __changeViewport: function (vertical, horizontal){
    var context = this;
    var options = context.options;
    var viewport = context.viewport;
    var thresholdBorderReaching = options.thresholdBorderReaching;

    if (!viewport.is(':visible')) return;

    var width = viewport.innerWidth();
    var height = viewport.innerHeight();
    var scrollWidth = viewport[0].scrollWidth;
    var scrollHeight = viewport[0].scrollHeight;

    // event
    var event = {};

    // scrollbar position
    event.scrollTop = viewport.scrollTop();
    event.scrollLeft = viewport.scrollLeft();
    event.offsetY = event.scrollTop - vertical;
    event.offsetX = event.scrollLeft - horizontal;

    // event type
    event.type = 'viewchange';

    // target
    event.target = context.__filterTargetInViewport(width, height);

    // calculate viewport border reaching detail infos
    event.top = event.scrollTop - thresholdBorderReaching[0] <= 0;
    event.right = width + event.scrollLeft + thresholdBorderReaching[1] >= scrollWidth;
    event.bottom = height + event.scrollTop + thresholdBorderReaching[2] >= scrollHeight;
    event.left = event.scrollLeft - thresholdBorderReaching[3] <= 0;

    // emit view change event
    context.emit(event.type, event);

    // return scrollbar position
    return event;
  },
  __initOptions: function (options){
    options = $.extend({
      delay: 150,
      target: null,
      threshold: 0,
      skipHidden: true,
      thresholdBorderReaching: 0
    }, options);

    options.threshold = patchThreshold(options.threshold);
    options.thresholdBorderReaching = patchThreshold(options.thresholdBorderReaching, true);

    this.options = options;
  },
  __findTarget: function (){
    var context = this;
    var options = context.options;
    var target = options.target;
    var viewport = context.viewport;

    if (is.string(target)) {
      target = viewport.find(target);
    } else if (is.element(target) && $.contains(viewport[0], target)) {
      target = $(target);
    } else if (target instanceof $) {
      target = $.grep(target, function (element){
        return $.contains(viewport[0], element);
      });
    } else {
      target = null;
    }

    context.target = target;
  },
  __filterTargetInViewport: function (width, height){
    var result = [];
    var context = this;
    var target = context.target;

    // target is null
    if (target === null) return result;

    var options = context.options;
    var threshold = options.threshold;
    var skipHidden = options.skipHidden;

    // get viewport height and width
    var viewport = context.viewport;

    // adjust the offsetTop and offsetLeft
    var viewportRect = viewport[0].getBoundingClientRect();
    var offsetTop = viewportRect.top + Math.round((parseInt(viewport.css('border-top-width')) || 0));
    var offsetLeft = viewportRect.left + Math.round((parseInt(viewport.css('border-left-width')) || 0));

    // filter elements by their rect info
    target.each(function (index, element){
      var rect = element.getBoundingClientRect();

      // hidden element
      if (rect.top == 0 && rect.bottom == 0 && rect.left == 0 && rect.right == 0) {
        if (!skipHidden) {
          result.push(element);
        }
      } else {
        // visible element
        var top = rect.top - offsetTop;
        var bottom = rect.bottom - offsetTop;
        var left = rect.left - offsetLeft;
        var right = rect.right - offsetLeft;

        // adjust position
        if (
          !(top - threshold[0] >= height
          || right + threshold[1] <= 0
          || bottom + threshold[2] <= 0
          || left - threshold[3] >= width)
        ) {
          result.push(element);
        }
      }
    });

    return result;
  },
  on: function (event, handler){
    var context = this;

    context.events[event] = context.events[event]
      || $.Callbacks('memory stopOnFalse');

    context.events[event].add(handler);

    return context;
  },
  off: function (event, handler){
    var context = this;

    switch (arguments.length) {
      case 0:
        context.events = {};
        break;
      case 1:
        delete context.events[event];
        break;
      default:
        context.events[event] && context.events[event].remove(handler);
        break;
    }

    return context;
  },
  emit: function (event){
    var context = this;
    var data = [].slice.call(arguments, 1);

    context.events[event] = context.events[event]
      || $.Callbacks('memory stopOnFalse');

    this.events[event].fireWith(context, data);

    return context;
  },
  refresh: function (){
    var context = this;
    var viewport = context.viewport;

    context.__findTarget();
    context.__changeViewport(viewport.scrollTop(), viewport.scrollLeft());

    return context;
  },
  destroy: function (){
    var context = this;
    var viewport = context.viewport;
    var namespace = '.viewport-' + context.id;

    // off event listen
    viewport.off('scroll' + namespace);
    viewport.off('resize' + namespace);
  }
};

// exports
module.exports = Viewport;
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var megalomaniac;

    beforeEach(function () {
       megalomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(megalomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(megalomaniac.henchwoman).toBe("Harley");
      expect(megalomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var megalomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = megalomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date();
    var currentYear = (currentDate.getFullYear());
    var megalomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2015);
    expect(megalomaniac.calculateAge()).toBe(45);
  });

  describe("'in' keyword", function () {
    var megalomaniac;
    beforeEach(function () {
      megalomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in megalomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in megalomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var megalomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in megalomaniac).toBe(FILL_ME_IN);

    megalomaniac.secretary = "Agent Smith";
    expect("secretary" in megalomaniac).toBe(FILL_ME_IN);

    delete megalomaniac.henchman;
    expect("henchman" in megalomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
      function Circle(radius)
      {
        this.radius = radius;
      }

      var simpleCircle = new Circle(10);
      var colouredCircle = new Circle(5);
      colouredCircle.colour = "red";

      expect(simpleCircle.colour).toBe(FILL_ME_IN);
      expect(colouredCircle.colour).toBe(FILL_ME_IN);

      Circle.prototype.describe = function () {
        return "This circle has a radius of: " + this.radius;
      };

      expect(simpleCircle.describe()).toBe(FILL_ME_IN);
      expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>3/9 24/53<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var megalomaniac;

    beforeEach(function () {
       megalomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(megalomaniac.mastermind).toBe("Joker");
    });

    it("should confirm that properties are case sensitive", function () {
      expect(megalomaniac.henchwoman).toBe("Harley");
      expect(megalomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var megalomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = megalomaniac.battleCry(4);
    expect("They are Pinky and the Brain Brain Brain Brain").toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date();
    var currentYear = (currentDate.getFullYear());
    var megalomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2015);
    expect(megalomaniac.calculateAge()).toBe(45);
  });

  describe("'in' keyword", function () {
    var megalomaniac;
    beforeEach(function () {
      megalomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in megalomaniac;

      expect(hasBomb).toBe(true);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in megalomaniac;

      expect(hasDetonator).toBe(false);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var megalomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in megalomaniac).toBe(FILL_ME_IN);

    megalomaniac.secretary = "Agent Smith";
    expect("secretary" in megalomaniac).toBe(FILL_ME_IN);

    delete megalomaniac.henchman;
    expect("henchman" in megalomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
      function Circle(radius)
      {
        this.radius = radius;
      }

      var simpleCircle = new Circle(10);
      var colouredCircle = new Circle(5);
      colouredCircle.colour = "red";

      expect(simpleCircle.colour).toBe(FILL_ME_IN);
      expect(colouredCircle.colour).toBe(FILL_ME_IN);

      Circle.prototype.describe = function () {
        return "This circle has a radius of: " + this.radius;
      };

      expect(simpleCircle.describe()).toBe(FILL_ME_IN);
      expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<|endoftext|>


<commit_before>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe(FILL_ME_IN);
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe(FILL_ME_IN);
      expect(meglomaniac.henchWoman).toBe(FILL_ME_IN);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect(FILL_ME_IN).toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(FILL_ME_IN);
    expect(meglomaniac.calculateAge()).toBe(FILL_ME_IN);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(FILL_ME_IN);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(FILL_ME_IN);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(FILL_ME_IN);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(FILL_ME_IN);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(FILL_ME_IN);
    expect(colouredCircle.colour).toBe(FILL_ME_IN);

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe(FILL_ME_IN);
    expect(colouredCircle.describe()).toBe(FILL_ME_IN);
  });
});
<commit_msg>Resolve object koans<commit_after>describe("About Objects", function () {

  describe("Properties", function () {
    var meglomaniac;

    beforeEach(function () {
       meglomaniac = {  mastermind: "Joker", henchwoman: "Harley" };
    });

    it("should confirm objects are collections of properties", function () {
      expect(meglomaniac.mastermind).toBe('Joker');
    });

    it("should confirm that properties are case sensitive", function () {
      expect(meglomaniac.henchwoman).toBe('Harley');
      expect(meglomaniac.henchWoman).toBe(undefined);
    });
  });

  it("should know properties that are functions act like methods", function () {
    var meglomaniac = {
      mastermind : "Brain",
      henchman: "Pinky",
      battleCry: function (noOfBrains) {
        return "They are " + this.henchman + " and the" +
          Array(noOfBrains + 1).join(" " + this.mastermind);
      }
    };

    var battleCry = meglomaniac.battleCry(4);
    expect('They are Pinky and the Brain Brain Brain Brain').toMatch(battleCry);
  });

  it("should confirm that when a function is attached to an object, 'this' refers to the object", function () {
    var currentDate = new Date()
    var currentYear = (currentDate.getFullYear());
    var meglomaniac = {
      mastermind: "James Wood",
      henchman: "Adam West",
      birthYear: 1970,
      calculateAge: function () {
        return currentYear - this.birthYear;
      }
    };

    expect(currentYear).toBe(2014);
    expect(meglomaniac.calculateAge()).toBe(44);
  });

  describe("'in' keyword", function () {
    var meglomaniac;
    beforeEach(function () {
      meglomaniac = {
        mastermind: "The Monarch",
        henchwoman: "Dr Girlfriend",
        theBomb: true
      };
    });

    it("should have the bomb", function () {

      var hasBomb = "theBomb" in meglomaniac;

      expect(hasBomb).toBe(true);
    });

    it("should not have the detonator however", function () {

      var hasDetonator = "theDetonator" in meglomaniac;

      expect(hasDetonator).toBe(false);
    });
  });

  it("should know that properties can be added and deleted", function () {
    var meglomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" };

    expect("secretary" in meglomaniac).toBe(false);

    meglomaniac.secretary = "Agent Smith";
    expect("secretary" in meglomaniac).toBe(true);

    delete meglomaniac.henchman;
    expect("henchman" in meglomaniac).toBe(false);
  });

  it("should use prototype to add to all objects", function () {
    function Circle(radius)
    {
      this.radius = radius;
    }

    var simpleCircle = new Circle(10);
    var colouredCircle = new Circle(5);
    colouredCircle.colour = "red";

    expect(simpleCircle.colour).toBe(undefined);
    expect(colouredCircle.colour).toBe('red');

    Circle.prototype.describe = function () {
      return "This circle has a radius of: " + this.radius;
    };

    expect(simpleCircle.describe()).toBe('This circle has a radius of: 10');
    expect(colouredCircle.describe()).toBe('This circle has a radius of: 5');
  });
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
var config = require(__dirname + '/config.js');
var twitterbot = require(__dirname + '/twitterbot.js');
var gitbot = require(__dirname + '/gitbot.js');
var pomodoro = require(__dirname + '/pomodoro.js');
var ansiArt = require('ansi-art').default;

var path = require('path');
var notifier = require('node-notifier');
var spawn = require('child_process').spawn;
var shellescape = require('shell-escape');
var blessed = require('blessed');
var contrib = require('blessed-contrib');
var chalk = require('chalk');
var bunnySay = require('sign-bunny');
var yosay = require('yosay');
var weather = require('weather-js');

var inPomodoroMode = false;

var screen = blessed.screen(
    {fullUnicode: true, // emoji or bust
     smartCSR: true,
     autoPadding: true,
     title: config.terminal_title
    });

// Quit on Escape, q, or Control-C.
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

// Refresh on r, or Control-R.
screen.key(['r', 'C-r'], function(ch, key) {
  tick();
});

screen.key(['s', 'C-s'], function(ch, key) {
  if (!inPomodoroMode) {
    return;
  } else if (pomodoroObject.isStopped()) {
    pomodoroObject.start();
  } else if (pomodoroObject.isPaused()) {
    pomodoroObject.resume();
  } else {
    pomodoroObject.pause();
    pomodoroHandlers.onTick();
  }
});

screen.key(['e', 'C-e'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.stop();
    pomodoroHandlers.onTick();
  }
});

screen.key(['u', 'C-u'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.updateRunningDuration();
    pomodoroHandlers.onTick();
  }
});

screen.key(['b', 'C-b'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.updateBreakDuration();
    pomodoroHandlers.onTick()
  }
});

screen.key(['p', 'C-p'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.stop();
    inPomodoroMode = false;
    doTheTweets();
    parrotBox.removeLabel('');
  } else {
    parrotBox.setLabel(' 🍅 ');
    inPomodoroMode = true;
    pomodoroHandlers.onTick()
  }
});

var grid = new contrib.grid({rows: 12, cols: 12, screen: screen});

// grid.set(row, col, rowSpan, colSpan, obj, opts)
var weatherBox = grid.set(0, 8, 2, 4, blessed.box, makeScrollBox(' 🌤 '));
var todayBox = grid.set(0, 0, 6, 6, blessed.box, makeScrollBox(' 📝  Last 24 hours '));
var weekBox = grid.set(6, 0, 6, 6, blessed.box, makeScrollBox(' 📝  Week '));
var commits = grid.set(0, 6, 6, 2, contrib.bar, makeGraphBox('Commits'));
var parrotBox = grid.set(6, 6, 6, 6, blessed.box, makeScrollBox(''));

var tweetBoxes = {}
tweetBoxes[config.twitter[1]] = grid.set(2, 8, 2, 4, blessed.box, makeBox(' 💖 '));
tweetBoxes[config.twitter[2]] = grid.set(4, 8, 2, 4, blessed.box, makeBox(' 💬 '));

tick();
setInterval(tick, 1000 * 60 * config.updateInterval);

function tick() {
  doTheWeather();
  doTheTweets();
  doTheCodes();
}

function doTheWeather() {
  weather.find({search: config.weather, degreeType: config.celsius ? 'C' : 'F'}, function(err, result) {
    if (result && result[0] && result[0].current) {
      var json = result[0];
      // TODO: add emoji for this thing.
      var skytext = json.current.skytext.toLowerCase();
      var currentDay = json.current.day;
      var degreetype = json.location.degreetype;
      var forecastString = '';
      for (var i = 0; i < json.forecast.length; i++) {
        var forecast = json.forecast[i];
        if (forecast.day === currentDay) {
          var skytextforecast = forecast.skytextday.toLowerCase();
          forecastString = `Today, it will be ${skytextforecast} with a forecast high of ${forecast.high}°${degreetype} and a low of ${forecast.low}°${degreetype}.`;
        }
      }
      weatherBox.content = `In ${json.location.name} it's ${json.current.temperature}°${degreetype} and ${skytext} right now. ${forecastString}`;
    } else {
      weatherBox.content = 'Having trouble fetching the weather for you :(';
    }
  });
}

function doTheTweets() {
  for (var which in config.twitter) {
    // Gigantor hack: first twitter account gets spoken by the party parrot.
    if (which == 0) {
      if (inPomodoroMode) {
        return;
      }
      twitterbot.getTweet(config.twitter[which]).then(function(tweet) {
        parrotBox.content = getAnsiArt(tweet.text)
        screen.render();
      },function(error) {
        // Just in case we don't have tweets.
        parrotBox.content = getAnsiArt('Hi! You\'re doing great!!!')
        screen.render();
      });
    } else {
      twitterbot.getTweet(config.twitter[which]).then(function(tweet) {
        tweetBoxes[tweet.bot.toLowerCase()].content = tweet.text;
        screen.render();
      },function(error) {
        tweetBoxes[config.twitter[1]].content =
        tweetBoxes[config.twitter[2]].content =
        'Can\'t read Twitter without some API keys  🐰. Maybe try the scraping version instead?';
      });
    }
  }
}

function doTheCodes() {
  var todayCommits = 0;
  var weekCommits = 0;

  // show loading message while loading commits
  todayBox.content = weekBox.content = '⏳ one second please...tiny commit bot is looking for tiny commits! ⏳';
  screen.render();

  function getCommits(data, box) {
    var content = colorizeLog(data || '');
    box.content += content;
    var commitRegex = /(.......) (- .*)/g;
    return (box && box.content) ? (box.content.match(commitRegex) || []).length : '0';
  }

  gitbot.findGitRepos(config.repos, config.depth-1, (err, allRepos) => {
    if (err) {
      return todayBox.content = err;
      screen.render();
    }
    gitbot.getCommitsFromRepos(allRepos, 1, (err, data) => {
      if (err) {
        return todayBox.content = err;
        screen.render();
      }
      todayBox.content = '';
      todayCommits = getCommits(`${data}`, todayBox);
      updateCommitsGraph(todayCommits, weekCommits);
      screen.render();
    });
    gitbot.getCommitsFromRepos(allRepos, 7, (err, data) => {
      if (err) {
        return weekBox.content = err;
        screen.render();
      }
      weekBox.content = '';
      weekCommits = getCommits(`${data}`, weekBox);
      updateCommitsGraph(todayCommits, weekCommits);
      screen.render();
    });
  });
}

function makeBox(label) {
  return {
    label: label,
    tags: true,
    // draggable: true,
    border: {
      type: 'line'  // or bg
    },
    style: {
      fg: 'white',
      border: { fg: 'cyan' },
      hover: { border: { fg: 'green' }, }
    }
  };
}

function makeScrollBox(label) {
  var options = makeBox(label);
  options.scrollable = true;
  options.scrollbar = { ch:' ' };
  options.style.scrollbar = { bg: 'green', fg: 'white' }
  options.keys = true;
  options.vi = true;
  options.alwaysScroll = true;
  options.mouse = true;
  return options;
}

function makeGraphBox(label) {
  var options = makeBox(label);
  options.barWidth= 5;
  options.xOffset= 4;
  options.maxHeight= 10;
  return options;
}

function updateCommitsGraph(today, week) {
  commits.setData({titles: ['24h', 'week'], data: [today, week]})
}

function colorizeLog(text) {
  var lines = text.split('\n');
  var regex = /(.......) (- .*) (\(.*\)) (<.*>)/i;
  var nothingRegex = /Seems like .* did nothing/i;
  for (var i = 0; i < lines.length; i++) {
    // If it's a path
    if (lines[i][0] === '/') {
      lines[i] = formatRepoName(lines[i], '/')
    } else if(lines[i][0] === '\\') {
      lines[i] = formatRepoName(lines[i], '\\')
    } else {
      // It may be a mean "seems like .. did nothing!" message. Skip it
      var nothing = lines[i].match(nothingRegex);
      if (nothing) {
        lines[i] = '';
        continue;
      }

      // It's a commit.
      var matches = lines[i].match(regex);
      if (matches) {
        lines[i] = chalk.red(matches[1]) + ' ' + matches[2] + ' ' +
            chalk.green(matches[3])
      }
    }
  }
  return lines.join('\n');
}

function formatRepoName(line, divider) {
  var repoPath = config.repos
    .sort((a, b) => a.length < b.length) // Longest repo repoPath first
    .find(repo => line.startsWith(repo));
  var repoRootPath = chalk.yellow(path.basename(repoPath) + divider);
  var repoChildPath = chalk.yellow.bold(
    line.replace(repoPath, '').replace(new RegExp(`^${divider}`), '')
  );
  return `\n${repoRootPath}${repoChildPath}`;
}

function llamaSay(text) {
  return `
    ${text}
    ∩∩
　（･ω･）
　　│ │
　　│ └─┐○
　  ヽ　　　丿
　　 　∥￣∥`;
}

function catSay(text) {
  return `
      ${text}

      ♪ ガンバレ! ♪
  ミ ゛ミ ∧＿∧ ミ゛ミ
  ミ ミ ( ・∀・ )ミ゛ミ
   ゛゛ ＼　　　／゛゛
   　　 　i⌒ヽ ｜
  　　 　 (＿) ノ
   　　　　　 ∪`
    ;
}

function getAnsiArt(textToSay) {
  var artFileRegex = /.ansi$/;

  // If config.say is custom art file path, then return custom art
  if (artFileRegex.test(config.say)) {
    return ansiArt.get({ filePath: config.say, speechText: textToSay });
  }

  var ansiOptions = {
    artName: config.say,
    speechText: textToSay,
    speechBubbleOptions: {
      boxWidth: parrotBox.width < 70 ? parrotBox.width - 4 : parrotBox.width * 0.7,
      boxType: 'classic'
    }
  };

  switch (config.say) {
    case 'bunny' : return bunnySay(textToSay);
    case 'llama' : return llamaSay(textToSay);
    case 'cat'   : return catSay(textToSay);
    case 'yeoman': return yosay(textToSay);
    default : return ansiArt.get(ansiOptions);
  }
}

var pomodoroHandlers = {
  onTick: function() {
    if (!inPomodoroMode) return;
    var remainingTime = pomodoroObject.getRemainingTime();

    var statusText = '';
    if (pomodoroObject.isInBreak()) {
      statusText = ' (Break Started) ';
    } else if (pomodoroObject.isStopped()) {
      statusText = ' (Press "s" to start) ';
    } else if (pomodoroObject.isPaused()) {
      statusText = ' (Press "s" to resume) ';
    }

    var content = `In Pomodoro Mode: ${remainingTime} ${statusText}`;
    var metaData = `Duration: ${pomodoroObject.getRunningDuration()} Minutes,  Break Time: ${pomodoroObject.getBreakDuration()} Minutes\n`;
    metaData += 'commands: \n s - start/pause/resume \n e - stop \n u - update duration \n b - update break time';
    parrotBox.content = getAnsiArt(content) + metaData;
    screen.render();
  },

  onBreakStarts: function() {
    if (inPomodoroMode) {
      notifier.notify({
        title: 'Pomodoro Alert',
        message: 'Break Time!',
        sound: true,
        timeout: 30,
      });
    }
  },

  onBreakEnds: function() {
    if (inPomodoroMode) {
      notifier.notify({
        title: 'Pomodoro Alert',
        message: 'Break Time Ends!',
        sound: true,
        timeout: 30,
      });
    }
  },

  runningDuration: parseInt(config.runningDuration, 10),

  breakDuration: parseInt(config.breakDuration, 10),
}

var pomodoroObject = pomodoro(pomodoroHandlers);
<commit_msg>blessed doesn't seem to like emoji in that content<commit_after>#!/usr/bin/env node
var config = require(__dirname + '/config.js');
var twitterbot = require(__dirname + '/twitterbot.js');
var gitbot = require(__dirname + '/gitbot.js');
var pomodoro = require(__dirname + '/pomodoro.js');
var ansiArt = require('ansi-art').default;

var path = require('path');
var notifier = require('node-notifier');
var spawn = require('child_process').spawn;
var shellescape = require('shell-escape');
var blessed = require('blessed');
var contrib = require('blessed-contrib');
var chalk = require('chalk');
var bunnySay = require('sign-bunny');
var yosay = require('yosay');
var weather = require('weather-js');

var inPomodoroMode = false;

var screen = blessed.screen(
    {fullUnicode: true, // emoji or bust
     smartCSR: true,
     autoPadding: true,
     title: config.terminal_title
    });

// Quit on Escape, q, or Control-C.
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

// Refresh on r, or Control-R.
screen.key(['r', 'C-r'], function(ch, key) {
  tick();
});

screen.key(['s', 'C-s'], function(ch, key) {
  if (!inPomodoroMode) {
    return;
  } else if (pomodoroObject.isStopped()) {
    pomodoroObject.start();
  } else if (pomodoroObject.isPaused()) {
    pomodoroObject.resume();
  } else {
    pomodoroObject.pause();
    pomodoroHandlers.onTick();
  }
});

screen.key(['e', 'C-e'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.stop();
    pomodoroHandlers.onTick();
  }
});

screen.key(['u', 'C-u'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.updateRunningDuration();
    pomodoroHandlers.onTick();
  }
});

screen.key(['b', 'C-b'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.updateBreakDuration();
    pomodoroHandlers.onTick()
  }
});

screen.key(['p', 'C-p'], function(ch, key) {
  if (inPomodoroMode) {
    pomodoroObject.stop();
    inPomodoroMode = false;
    doTheTweets();
    parrotBox.removeLabel('');
  } else {
    parrotBox.setLabel(' 🍅 ');
    inPomodoroMode = true;
    pomodoroHandlers.onTick()
  }
});

var grid = new contrib.grid({rows: 12, cols: 12, screen: screen});

// grid.set(row, col, rowSpan, colSpan, obj, opts)
var weatherBox = grid.set(0, 8, 2, 4, blessed.box, makeScrollBox(' 🌤 '));
var todayBox = grid.set(0, 0, 6, 6, blessed.box, makeScrollBox(' 📝  Last 24 hours '));
var weekBox = grid.set(6, 0, 6, 6, blessed.box, makeScrollBox(' 📝  Week '));
var commits = grid.set(0, 6, 6, 2, contrib.bar, makeGraphBox('Commits'));
var parrotBox = grid.set(6, 6, 6, 6, blessed.box, makeScrollBox(''));

var tweetBoxes = {}
tweetBoxes[config.twitter[1]] = grid.set(2, 8, 2, 4, blessed.box, makeBox(' 💖 '));
tweetBoxes[config.twitter[2]] = grid.set(4, 8, 2, 4, blessed.box, makeBox(' 💬 '));

tick();
setInterval(tick, 1000 * 60 * config.updateInterval);

function tick() {
  doTheWeather();
  doTheTweets();
  doTheCodes();
}

function doTheWeather() {
  weather.find({search: config.weather, degreeType: config.celsius ? 'C' : 'F'}, function(err, result) {
    if (result && result[0] && result[0].current) {
      var json = result[0];
      // TODO: add emoji for this thing.
      var skytext = json.current.skytext.toLowerCase();
      var currentDay = json.current.day;
      var degreetype = json.location.degreetype;
      var forecastString = '';
      for (var i = 0; i < json.forecast.length; i++) {
        var forecast = json.forecast[i];
        if (forecast.day === currentDay) {
          var skytextforecast = forecast.skytextday.toLowerCase();
          forecastString = `Today, it will be ${skytextforecast} with a forecast high of ${forecast.high}°${degreetype} and a low of ${forecast.low}°${degreetype}.`;
        }
      }
      weatherBox.content = `In ${json.location.name} it's ${json.current.temperature}°${degreetype} and ${skytext} right now. ${forecastString}`;
    } else {
      weatherBox.content = 'Having trouble fetching the weather for you :(';
    }
  });
}

function doTheTweets() {
  for (var which in config.twitter) {
    // Gigantor hack: first twitter account gets spoken by the party parrot.
    if (which == 0) {
      if (inPomodoroMode) {
        return;
      }
      twitterbot.getTweet(config.twitter[which]).then(function(tweet) {
        parrotBox.content = getAnsiArt(tweet.text)
        screen.render();
      },function(error) {
        // Just in case we don't have tweets.
        parrotBox.content = getAnsiArt('Hi! You\'re doing great!!!')
        screen.render();
      });
    } else {
      twitterbot.getTweet(config.twitter[which]).then(function(tweet) {
        tweetBoxes[tweet.bot.toLowerCase()].content = tweet.text;
        screen.render();
      },function(error) {
        tweetBoxes[config.twitter[1]].content =
        tweetBoxes[config.twitter[2]].content =
        'Can\'t read Twitter without some API keys  🐰. Maybe try the scraping version instead?';
      });
    }
  }
}

function doTheCodes() {
  var todayCommits = 0;
  var weekCommits = 0;

  // show loading message while loading commits.
  // Turns out blessed doesn't love it if there's emoji in this or if
  // the line is super long.
  todayBox.content = weekBox.content = 'tiny commit bot is looking for tiny commits! ';
  screen.render();

  function getCommits(data, box) {
    var content = colorizeLog(data || '');
    box.content += content;
    var commitRegex = /(.......) (- .*)/g;
    return (box && box.content) ? (box.content.match(commitRegex) || []).length : '0';
  }

  gitbot.findGitRepos(config.repos, config.depth-1, (err, allRepos) => {
    if (err) {
      return todayBox.content = err;
      screen.render();
    }
    gitbot.getCommitsFromRepos(allRepos, 1, (err, data) => {
      if (err) {
        return todayBox.content = err;
        screen.render();
      }
      todayBox.content = '';
      todayCommits = getCommits(`${data}`, todayBox);
      updateCommitsGraph(todayCommits, weekCommits);
      screen.render();
    });
    gitbot.getCommitsFromRepos(allRepos, 7, (err, data) => {
      if (err) {
        return weekBox.content = err;
        screen.render();
      }
      weekBox.content = '';
      weekCommits = getCommits(`${data}`, weekBox);
      updateCommitsGraph(todayCommits, weekCommits);
      screen.render();
    });
  });
}

function makeBox(label) {
  return {
    label: label,
    tags: true,
    // draggable: true,
    border: {
      type: 'line'  // or bg
    },
    style: {
      fg: 'white',
      border: { fg: 'cyan' },
      hover: { border: { fg: 'green' }, }
    }
  };
}

function makeScrollBox(label) {
  var options = makeBox(label);
  options.scrollable = true;
  options.scrollbar = { ch:' ' };
  options.style.scrollbar = { bg: 'green', fg: 'white' }
  options.keys = true;
  options.vi = true;
  options.alwaysScroll = true;
  options.mouse = true;
  return options;
}

function makeGraphBox(label) {
  var options = makeBox(label);
  options.barWidth= 5;
  options.xOffset= 4;
  options.maxHeight= 10;
  return options;
}

function updateCommitsGraph(today, week) {
  commits.setData({titles: ['24h', 'week'], data: [today, week]})
}

function colorizeLog(text) {
  var lines = text.split('\n');
  var regex = /(.......) (- .*) (\(.*\)) (<.*>)/i;
  var nothingRegex = /Seems like .* did nothing/i;
  for (var i = 0; i < lines.length; i++) {
    // If it's a path
    if (lines[i][0] === '/') {
      lines[i] = formatRepoName(lines[i], '/')
    } else if(lines[i][0] === '\\') {
      lines[i] = formatRepoName(lines[i], '\\')
    } else {
      // It may be a mean "seems like .. did nothing!" message. Skip it
      var nothing = lines[i].match(nothingRegex);
      if (nothing) {
        lines[i] = '';
        continue;
      }

      // It's a commit.
      var matches = lines[i].match(regex);
      if (matches) {
        lines[i] = chalk.red(matches[1]) + ' ' + matches[2] + ' ' +
            chalk.green(matches[3])
      }
    }
  }
  return lines.join('\n');
}

function formatRepoName(line, divider) {
  var repoPath = config.repos
    .sort((a, b) => a.length < b.length) // Longest repo repoPath first
    .find(repo => line.startsWith(repo));
  var repoRootPath = chalk.yellow(path.basename(repoPath) + divider);
  var repoChildPath = chalk.yellow.bold(
    line.replace(repoPath, '').replace(new RegExp(`^${divider}`), '')
  );
  return `\n${repoRootPath}${repoChildPath}`;
}

function llamaSay(text) {
  return `
    ${text}
    ∩∩
　（･ω･）
　　│ │
　　│ └─┐○
　  ヽ　　　丿
　　 　∥￣∥`;
}

function catSay(text) {
  return `
      ${text}

      ♪ ガンバレ! ♪
  ミ ゛ミ ∧＿∧ ミ゛ミ
  ミ ミ ( ・∀・ )ミ゛ミ
   ゛゛ ＼　　　／゛゛
   　　 　i⌒ヽ ｜
  　　 　 (＿) ノ
   　　　　　 ∪`
    ;
}

function getAnsiArt(textToSay) {
  var artFileRegex = /.ansi$/;

  // If config.say is custom art file path, then return custom art
  if (artFileRegex.test(config.say)) {
    return ansiArt.get({ filePath: config.say, speechText: textToSay });
  }

  var ansiOptions = {
    artName: config.say,
    speechText: textToSay,
    speechBubbleOptions: {
      boxWidth: parrotBox.width < 70 ? parrotBox.width - 4 : parrotBox.width * 0.7,
      boxType: 'classic'
    }
  };

  switch (config.say) {
    case 'bunny' : return bunnySay(textToSay);
    case 'llama' : return llamaSay(textToSay);
    case 'cat'   : return catSay(textToSay);
    case 'yeoman': return yosay(textToSay);
    default : return ansiArt.get(ansiOptions);
  }
}

var pomodoroHandlers = {
  onTick: function() {
    if (!inPomodoroMode) return;
    var remainingTime = pomodoroObject.getRemainingTime();

    var statusText = '';
    if (pomodoroObject.isInBreak()) {
      statusText = ' (Break Started) ';
    } else if (pomodoroObject.isStopped()) {
      statusText = ' (Press "s" to start) ';
    } else if (pomodoroObject.isPaused()) {
      statusText = ' (Press "s" to resume) ';
    }

    var content = `In Pomodoro Mode: ${remainingTime} ${statusText}`;
    var metaData = `Duration: ${pomodoroObject.getRunningDuration()} Minutes,  Break Time: ${pomodoroObject.getBreakDuration()} Minutes\n`;
    metaData += 'commands: \n s - start/pause/resume \n e - stop \n u - update duration \n b - update break time';
    parrotBox.content = getAnsiArt(content) + metaData;
    screen.render();
  },

  onBreakStarts: function() {
    if (inPomodoroMode) {
      notifier.notify({
        title: 'Pomodoro Alert',
        message: 'Break Time!',
        sound: true,
        timeout: 30,
      });
    }
  },

  onBreakEnds: function() {
    if (inPomodoroMode) {
      notifier.notify({
        title: 'Pomodoro Alert',
        message: 'Break Time Ends!',
        sound: true,
        timeout: 30,
      });
    }
  },

  runningDuration: parseInt(config.runningDuration, 10),

  breakDuration: parseInt(config.breakDuration, 10),
}

var pomodoroObject = pomodoro(pomodoroHandlers);
<|endoftext|>


<commit_before>import { execFile } from '../executive'
import Executable from './executable'

export default class PythonExecutable extends Executable {

  setExtras () {
    return Promise.all([
      this.detectInstaller(),
      this.setSysPath()
    ])
    .catch(error => {
      this.addError(error)
      return this
    })
  }

  cleanVersion () {
    return this.rawVersion.trim().match(/python ([\d.\-a-zA-Z]+)/i)[1]
  }

  setSysPath () {
    return new Promise((resolve, reject) => {
      let exportCmd = "import sys; print(':::'.join([path for path in sys.path if path]))"
      let params = ['-c', exportCmd]
      execFile(this.path, params, (error, stdout, stderr) => {
        if (error) {
          this.addError(error)
        } else {
          this.sysPath = stdout.trim().split(':::')
        }
        resolve(this)
      })
    })
  }

  pathContains (str) {
    return this.realpath.toLowerCase().indexOf(str.toLowerCase()) !== -1
  }

  isActivePython () {
    return new Promise((resolve, reject) => {
      let params = ['-c', '"import activestate"']
      execFile(this.path, params, (error, stdout) => {
        resolve(!error)
      })
    })
  }

  isWinPython () {
    return new Promise((resolve, reject) => {
      let params = ['-c', '"import winpython"']
      execFile(this.path, params, (error, stdout) => {
        resolve(!error)
      })
    })
  }

  isXyPython () {
    return new Promise((resolve, reject) => {
      let params = ['-m', 'pip', '--version']
      execFile(this.path, params, (error, stdout) => {
        if (error) {
          resolve(false)
        }
        resolve(stdout.indexOf('xy') !== -1)
      })
    })
  }

  detectInstaller () {
    return new Promise((resolve, reject) => {
      if (this.rawVersion && this.rawVersion.indexOf('Anaconda') !== -1) {
        this.installer = 'anaconda'
      }

      /* NB: The Miniconda one also says Continuum, but Anaconda is probably more popular */
      if (this.rawVersion && this.rawVersion.indexOf('Continuum') !== -1) {
        this.installer = 'anaconda'
      }

      if (this.realpath) {
        /* Custom Distributions */
        if (this.pathContains('Enthought')) { this.installer = 'canopy' }
        if (this.pathContains('Canopy')) { this.installer = 'canopy' }
        if (this.pathContains('anaconda')) { this.installer = 'anaconda' }
        if (this.pathContains('miniconda')) { this.installer = 'miniconda' }

        /* OS X */
        if (this.pathContains('Cellar')) { this.installer = 'homebrew' }
        /* Note the order on these! */
        /* Honestly though I guess we don't know, anything can install here */
        // if (this.pathContains('/Library/Frameworks/Python.framework')) { this.installer = 'Python.org' }
        // if (this.pathContains('/System/Library/Frameworks/Python.framework')) { this.installer = 'Default-OSX' }

        /* Windows */
        if (this.pathContains('APPDATA\\LOCAL\\PROGRAMS\\PYTHON')) { this.installer = 'pythonorg' }

        /* if nothing else, test for ActivePython/ActiveState since it isn't in --version */
        if (!this.installer) {
          return Promise.all([
            this.isActivePython(),
            this.isXyPython(),
            this.isWinPython()
          ]).then((values) => {
            if (values[0]) {
              this.installer = 'activepython'
            }
            if (values[1]) {
              this.installer = 'xy'
            }
            if (values[2]) {
              this.installer = 'winpython'
            }
            resolve(this)
          })
        } else {
          resolve(this)
        }
      }
    })
  }

  assureMergeable () {
    /* Need to set the version */
    return this.setVersion()
      .then(() => this.setSysPath())
      .catch(err => this.addError(err))
  }

  get mergeField () {
    // previously just .realpath
    return JSON.stringify({
      rawVersion: this.rawVersion,
      sysPath: this.sysPath
    })
  }

}
<commit_msg>fix activestate and winpython detection<commit_after>import { execFile } from '../executive'
import Executable from './executable'

export default class PythonExecutable extends Executable {

  setExtras () {
    return Promise.all([
      this.detectInstaller(),
      this.setSysPath()
    ])
    .catch(error => {
      this.addError(error)
      return this
    })
  }

  cleanVersion () {
    return this.rawVersion.trim().match(/python ([\d.\-a-zA-Z]+)/i)[1]
  }

  setSysPath () {
    return new Promise((resolve, reject) => {
      let exportCmd = "import sys; print(':::'.join([path for path in sys.path if path]))"
      let params = ['-c', exportCmd]
      execFile(this.path, params, (error, stdout, stderr) => {
        if (error) {
          this.addError(error)
        } else {
          this.sysPath = stdout.trim().split(':::')
        }
        resolve(this)
      })
    })
  }

  pathContains (str) {
    return this.realpath.toLowerCase().indexOf(str.toLowerCase()) !== -1
  }

  isActivePython () {
    return new Promise((resolve, reject) => {
      let params = ['-c', 'import activestate']
      execFile(this.path, params, (error, stdout) => {
        resolve(!error)
      })
    })
  }

  isWinPython () {
    return new Promise((resolve, reject) => {
      let params = ['-c', 'import winpython']
      execFile(this.path, params, (error, stdout) => {
        resolve(!error)
      })
    })
  }

  isXyPython () {
    return new Promise((resolve, reject) => {
      let params = ['-m', 'pip', '--version']
      execFile(this.path, params, (error, stdout) => {
        if (error) {
          resolve(false)
        }
        resolve(stdout.indexOf('xy') !== -1)
      })
    })
  }

  detectInstaller () {
    return new Promise((resolve, reject) => {
      if (this.rawVersion && this.rawVersion.indexOf('Anaconda') !== -1) {
        this.installer = 'anaconda'
      }

      /* NB: The Miniconda one also says Continuum, but Anaconda is probably more popular */
      if (this.rawVersion && this.rawVersion.indexOf('Continuum') !== -1) {
        this.installer = 'anaconda'
      }

      if (this.realpath) {
        /* Custom Distributions */
        if (this.pathContains('Enthought')) { this.installer = 'canopy' }
        if (this.pathContains('Canopy')) { this.installer = 'canopy' }
        if (this.pathContains('anaconda')) { this.installer = 'anaconda' }
        if (this.pathContains('miniconda')) { this.installer = 'miniconda' }

        /* OS X */
        if (this.pathContains('Cellar')) { this.installer = 'homebrew' }
        /* Note the order on these! */
        /* Honestly though I guess we don't know, anything can install here */
        // if (this.pathContains('/Library/Frameworks/Python.framework')) { this.installer = 'Python.org' }
        // if (this.pathContains('/System/Library/Frameworks/Python.framework')) { this.installer = 'Default-OSX' }

        /* Windows */
        if (this.pathContains('APPDATA\\LOCAL\\PROGRAMS\\PYTHON')) { this.installer = 'pythonorg' }

        /* if nothing else, test for ActivePython/ActiveState since it isn't in --version */
        if (!this.installer) {
          return Promise.all([
            this.isActivePython(),
            this.isXyPython(),
            this.isWinPython()
          ]).then((values) => {
            if (values[0]) {
              this.installer = 'activepython'
            }
            if (values[1]) {
              this.installer = 'xy'
            }
            if (values[2]) {
              this.installer = 'winpython'
            }
            resolve(this)
          })
        } else {
          resolve(this)
        }
      }
    })
  }

  assureMergeable () {
    /* Need to set the version */
    return this.setVersion()
      .then(() => this.setSysPath())
      .catch(err => this.addError(err))
  }

  get mergeField () {
    // previously just .realpath
    return JSON.stringify({
      rawVersion: this.rawVersion,
      sysPath: this.sysPath
    })
  }

}
<|endoftext|>