<commit_before>var the_long_cat = new LongCat('the_long_cat');

window.requestAnimationFrame = window.requestAnimationFrame
                            || window.mozRequestAnimationFrame
                            || window.webkitRequestAnimationFrame
                            || window.msRequestAnimationFrame
                            || function(cb) { window.setTimeout(cb, 1000/60); };

// Rather use window.performance if it's available.
// It has sub-millisecond precision, while Date.now only has milliseconds.
var rtc = window.performance || Date;
var t0 = rtc.now();

function mainloop() {
  var t = rtc.now();
  var dt = 0.001*(t - t0);

  // When the tab gets hidden, this animate loop is not called, which is good
  // as it pauses the game. But when the tab gets visible again, the dt is huge:
  // as large as the tab was hidden. We don't want this, as it undoes the pause.
  // so we only update on small dt.
  if (dt < 0.5) {
      the_long_cat.update(dt)

      // TODO: More updates (background)
  }

  // For the next timestep.
  t0 = t;
  window.requestAnimationFrame(mainloop);
}
window.requestAnimationFrame(mainloop);
<commit_msg>More whitespace<commit_after>var the_long_cat = new LongCat('the_long_cat');

window.requestAnimationFrame = window.requestAnimationFrame
                            || window.mozRequestAnimationFrame
                            || window.webkitRequestAnimationFrame
                            || window.msRequestAnimationFrame
                            || function(cb) { window.setTimeout(cb, 1000/60); };

// Rather use window.performance if it's available.
// It has sub-millisecond precision, while Date.now only has milliseconds.
var rtc = window.performance || Date;
var t0 = rtc.now();

function mainloop() {
  var t = rtc.now();
  var dt = 0.001*(t - t0);

  // When the tab gets hidden, this animate loop is not called, which is good
  // as it pauses the game. But when the tab gets visible again, the dt is huge:
  // as large as the tab was hidden. We don't want this, as it undoes the pause.
  // so we only update on small dt.
  if (dt < 0.5) {
    the_long_cat.update(dt)

    // TODO: More updates (background)
  }

  // For the next timestep.
  t0 = t;
  window.requestAnimationFrame(mainloop);
}
window.requestAnimationFrame(mainloop);
<|endoftext|>


<commit_before>/**
  @module ember-data
*/

import {
  RecordArray,
  FilteredRecordArray,
  AdapterPopulatedRecordArray
} from "ember-data/system/record-arrays";
import {
  MapWithDefault
} from "ember-data/system/map";
import OrderedSet from "ember-data/system/ordered-set";
var get = Ember.get;
var forEach = Ember.EnumerableUtils.forEach;
var indexOf = Ember.EnumerableUtils.indexOf;

/**
  @class RecordArrayManager
  @namespace DS
  @private
  @extends Ember.Object
*/
export default Ember.Object.extend({
  init: function() {
    this.filteredRecordArrays = MapWithDefault.create({
      defaultValue: function() { return []; }
    });

    this.liveRecordArrays = MapWithDefault.create({
      defaultValue: (typeClass) => {
        return this.createRecordArray(typeClass);
      }
    });

    this.changedRecords = [];
    this._adapterPopulatedRecordArrays = [];
  },

  recordDidChange: function(record) {
    if (this.changedRecords.push(record) !== 1) { return; }

    Ember.run.schedule('actions', this, this.updateRecordArrays);
  },

  recordArraysForRecord: function(record) {
    record._recordArrays = record._recordArrays || OrderedSet.create();
    return record._recordArrays;
  },

  /**
    This method is invoked whenever data is loaded into the store by the
    adapter or updated by the adapter, or when a record has changed.

    It updates all record arrays that a record belongs to.

    To avoid thrashing, it only runs at most once per run loop.

    @method updateRecordArrays
  */
  updateRecordArrays: function() {
    forEach(this.changedRecords, function(record) {
      if (record.isDeleted()) {
        this._recordWasDeleted(record);
      } else {
        this._recordWasChanged(record);
      }
    }, this);

    this.changedRecords.length = 0;
  },

  _recordWasDeleted: function (record) {
    var recordArrays = record._recordArrays;

    if (!recordArrays) { return; }

    recordArrays.forEach(function(array) {
      array.removeInternalModel(record);
    });

    record._recordArrays = null;
  },

  _recordWasChanged: function (record) {
    var typeClass = record.type;
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    var filter;

    forEach(recordArrays, function(array) {
      filter = get(array, 'filterFunction');
      this.updateFilterRecordArray(array, filter, typeClass, record);
    }, this);
  },

  //Need to update live arrays on loading
  recordWasLoaded: function(record) {
    var typeClass = record.type;
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    var filter;

    forEach(recordArrays, function(array) {
      filter = get(array, 'filterFunction');
      this.updateFilterRecordArray(array, filter, typeClass, record);
    }, this);

    if (this.liveRecordArrays.has(typeClass)) {
      var liveRecordArray = this.liveRecordArrays.get(typeClass);
      this._addRecordToRecordArray(liveRecordArray, record);
    }
  },
  /**
    Update an individual filter.

    @method updateFilterRecordArray
    @param {DS.FilteredRecordArray} array
    @param {Function} filter
    @param {DS.Model} typeClass
    @param {InternalModel} record
  */
  updateFilterRecordArray: function(array, filter, typeClass, record) {
    var shouldBeInArray = filter(record.getRecord());
    var recordArrays = this.recordArraysForRecord(record);

    if (shouldBeInArray) {
      this._addRecordToRecordArray(array, record);
    } else {
      recordArrays.delete(array);
      array.removeInternalModel(record);
    }
  },

  _addRecordToRecordArray: function(array, record) {
    var recordArrays = this.recordArraysForRecord(record);
    if (!recordArrays.has(array)) {
      array.addInternalModel(record);
      recordArrays.add(array);
    }
  },

  populateLiveRecordArray: function(array, modelName) {
    var typeMap = this.store.typeMapFor(modelName);
    var records = typeMap.records;
    var record;

    for (var i = 0, l = records.length; i < l; i++) {
      record = records[i];

      if (!record.isDeleted() && !record.isEmpty()) {
        this._addRecordToRecordArray(array, record);
      }
    }
  },

  /**
    This method is invoked if the `filterFunction` property is
    changed on a `DS.FilteredRecordArray`.

    It essentially re-runs the filter from scratch. This same
    method is invoked when the filter is created in th first place.

    @method updateFilter
    @param {Array} array
    @param {String} modelName
    @param {Function} filter
  */
  updateFilter: function(array, modelName, filter) {
    var typeMap = this.store.typeMapFor(modelName);
    var records = typeMap.records;
    var record;

    for (var i = 0, l = records.length; i < l; i++) {
      record = records[i];

      if (!record.isDeleted() && !record.isEmpty()) {
        this.updateFilterRecordArray(array, filter, modelName, record);
      }
    }
  },

  /**
    Get the `DS.RecordArray` for a type, which contains all loaded records of
    given type.

    @method liveRecordArrayFor
    @param {Class} typeClass
    @return {DS.RecordArray}
  */
  liveRecordArrayFor: function(typeClass) {
    return this.liveRecordArrays.get(typeClass);
  },

  /**
    Create a `DS.RecordArray` for a type.

    @method createRecordArray
    @param {Class} typeClass
    @return {DS.RecordArray}
  */
  createRecordArray: function(typeClass) {
    var array = RecordArray.create({
      type: typeClass,
      content: Ember.A(),
      store: this.store,
      isLoaded: true,
      manager: this
    });

    return array;
  },

  /**
    Create a `DS.FilteredRecordArray` for a type and register it for updates.

    @method createFilteredRecordArray
    @param {DS.Model} typeClass
    @param {Function} filter
    @param {Object} query (optional
    @return {DS.FilteredRecordArray}
  */
  createFilteredRecordArray: function(typeClass, filter, query) {
    var array = FilteredRecordArray.create({
      query: query,
      type: typeClass,
      content: Ember.A(),
      store: this.store,
      manager: this,
      filterFunction: filter
    });

    this.registerFilteredRecordArray(array, typeClass, filter);

    return array;
  },

  /**
    Create a `DS.AdapterPopulatedRecordArray` for a type with given query.

    @method createAdapterPopulatedRecordArray
    @param {DS.Model} typeClass
    @param {Object} query
    @return {DS.AdapterPopulatedRecordArray}
  */
  createAdapterPopulatedRecordArray: function(typeClass, query) {
    var array = AdapterPopulatedRecordArray.create({
      type: typeClass,
      query: query,
      content: Ember.A(),
      store: this.store,
      manager: this
    });

    this._adapterPopulatedRecordArrays.push(array);

    return array;
  },

  /**
    Register a RecordArray for a given type to be backed by
    a filter function. This will cause the array to update
    automatically when records of that type change attribute
    values or states.

    @method registerFilteredRecordArray
    @param {DS.RecordArray} array
    @param {DS.Model} typeClass
    @param {Function} filter
  */
  registerFilteredRecordArray: function(array, typeClass, filter) {
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    recordArrays.push(array);

    this.updateFilter(array, typeClass, filter);
  },

  /**
    Unregister a RecordArray.
    So manager will not update this array.

    @method unregisterRecordArray
    @param {DS.RecordArray} array
  */
  unregisterRecordArray: function(array) {
    var typeClass = array.type;

    // unregister filtered record array
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    var index = indexOf(recordArrays, array);
    if (index !== -1) {
      recordArrays.splice(index, 1);

    // unregister live record array
    } else if (this.liveRecordArrays.has(typeClass)) {
      var liveRecordArrayForType = this.liveRecordArrayFor(typeClass);
      if (array === liveRecordArrayForType) {
        this.liveRecordArrays.remove(typeClass);
      }
    }
  },

  willDestroy: function() {
    this._super.apply(this, arguments);

    this.filteredRecordArrays.forEach(function(value) {
      forEach(flatten(value), destroy);
    });
    forEach(this.liveRecordArrays, destroy);
    forEach(this._adapterPopulatedRecordArrays, destroy);
  }
});

function destroy(entry) {
  entry.destroy();
}

function flatten(list) {
  var length = list.length;
  var result = Ember.A();

  for (var i = 0; i < length; i++) {
    result = result.concat(list[i]);
  }

  return result;
}
<commit_msg>Use Map.prototype.delete instead of Map.prototype.remove<commit_after>/**
  @module ember-data
*/

import {
  RecordArray,
  FilteredRecordArray,
  AdapterPopulatedRecordArray
} from "ember-data/system/record-arrays";
import {
  MapWithDefault
} from "ember-data/system/map";
import OrderedSet from "ember-data/system/ordered-set";
var get = Ember.get;
var forEach = Ember.EnumerableUtils.forEach;
var indexOf = Ember.EnumerableUtils.indexOf;

/**
  @class RecordArrayManager
  @namespace DS
  @private
  @extends Ember.Object
*/
export default Ember.Object.extend({
  init: function() {
    this.filteredRecordArrays = MapWithDefault.create({
      defaultValue: function() { return []; }
    });

    this.liveRecordArrays = MapWithDefault.create({
      defaultValue: (typeClass) => {
        return this.createRecordArray(typeClass);
      }
    });

    this.changedRecords = [];
    this._adapterPopulatedRecordArrays = [];
  },

  recordDidChange: function(record) {
    if (this.changedRecords.push(record) !== 1) { return; }

    Ember.run.schedule('actions', this, this.updateRecordArrays);
  },

  recordArraysForRecord: function(record) {
    record._recordArrays = record._recordArrays || OrderedSet.create();
    return record._recordArrays;
  },

  /**
    This method is invoked whenever data is loaded into the store by the
    adapter or updated by the adapter, or when a record has changed.

    It updates all record arrays that a record belongs to.

    To avoid thrashing, it only runs at most once per run loop.

    @method updateRecordArrays
  */
  updateRecordArrays: function() {
    forEach(this.changedRecords, function(record) {
      if (record.isDeleted()) {
        this._recordWasDeleted(record);
      } else {
        this._recordWasChanged(record);
      }
    }, this);

    this.changedRecords.length = 0;
  },

  _recordWasDeleted: function (record) {
    var recordArrays = record._recordArrays;

    if (!recordArrays) { return; }

    recordArrays.forEach(function(array) {
      array.removeInternalModel(record);
    });

    record._recordArrays = null;
  },

  _recordWasChanged: function (record) {
    var typeClass = record.type;
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    var filter;

    forEach(recordArrays, function(array) {
      filter = get(array, 'filterFunction');
      this.updateFilterRecordArray(array, filter, typeClass, record);
    }, this);
  },

  //Need to update live arrays on loading
  recordWasLoaded: function(record) {
    var typeClass = record.type;
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    var filter;

    forEach(recordArrays, function(array) {
      filter = get(array, 'filterFunction');
      this.updateFilterRecordArray(array, filter, typeClass, record);
    }, this);

    if (this.liveRecordArrays.has(typeClass)) {
      var liveRecordArray = this.liveRecordArrays.get(typeClass);
      this._addRecordToRecordArray(liveRecordArray, record);
    }
  },
  /**
    Update an individual filter.

    @method updateFilterRecordArray
    @param {DS.FilteredRecordArray} array
    @param {Function} filter
    @param {DS.Model} typeClass
    @param {InternalModel} record
  */
  updateFilterRecordArray: function(array, filter, typeClass, record) {
    var shouldBeInArray = filter(record.getRecord());
    var recordArrays = this.recordArraysForRecord(record);

    if (shouldBeInArray) {
      this._addRecordToRecordArray(array, record);
    } else {
      recordArrays.delete(array);
      array.removeInternalModel(record);
    }
  },

  _addRecordToRecordArray: function(array, record) {
    var recordArrays = this.recordArraysForRecord(record);
    if (!recordArrays.has(array)) {
      array.addInternalModel(record);
      recordArrays.add(array);
    }
  },

  populateLiveRecordArray: function(array, modelName) {
    var typeMap = this.store.typeMapFor(modelName);
    var records = typeMap.records;
    var record;

    for (var i = 0, l = records.length; i < l; i++) {
      record = records[i];

      if (!record.isDeleted() && !record.isEmpty()) {
        this._addRecordToRecordArray(array, record);
      }
    }
  },

  /**
    This method is invoked if the `filterFunction` property is
    changed on a `DS.FilteredRecordArray`.

    It essentially re-runs the filter from scratch. This same
    method is invoked when the filter is created in th first place.

    @method updateFilter
    @param {Array} array
    @param {String} modelName
    @param {Function} filter
  */
  updateFilter: function(array, modelName, filter) {
    var typeMap = this.store.typeMapFor(modelName);
    var records = typeMap.records;
    var record;

    for (var i = 0, l = records.length; i < l; i++) {
      record = records[i];

      if (!record.isDeleted() && !record.isEmpty()) {
        this.updateFilterRecordArray(array, filter, modelName, record);
      }
    }
  },

  /**
    Get the `DS.RecordArray` for a type, which contains all loaded records of
    given type.

    @method liveRecordArrayFor
    @param {Class} typeClass
    @return {DS.RecordArray}
  */
  liveRecordArrayFor: function(typeClass) {
    return this.liveRecordArrays.get(typeClass);
  },

  /**
    Create a `DS.RecordArray` for a type.

    @method createRecordArray
    @param {Class} typeClass
    @return {DS.RecordArray}
  */
  createRecordArray: function(typeClass) {
    var array = RecordArray.create({
      type: typeClass,
      content: Ember.A(),
      store: this.store,
      isLoaded: true,
      manager: this
    });

    return array;
  },

  /**
    Create a `DS.FilteredRecordArray` for a type and register it for updates.

    @method createFilteredRecordArray
    @param {DS.Model} typeClass
    @param {Function} filter
    @param {Object} query (optional
    @return {DS.FilteredRecordArray}
  */
  createFilteredRecordArray: function(typeClass, filter, query) {
    var array = FilteredRecordArray.create({
      query: query,
      type: typeClass,
      content: Ember.A(),
      store: this.store,
      manager: this,
      filterFunction: filter
    });

    this.registerFilteredRecordArray(array, typeClass, filter);

    return array;
  },

  /**
    Create a `DS.AdapterPopulatedRecordArray` for a type with given query.

    @method createAdapterPopulatedRecordArray
    @param {DS.Model} typeClass
    @param {Object} query
    @return {DS.AdapterPopulatedRecordArray}
  */
  createAdapterPopulatedRecordArray: function(typeClass, query) {
    var array = AdapterPopulatedRecordArray.create({
      type: typeClass,
      query: query,
      content: Ember.A(),
      store: this.store,
      manager: this
    });

    this._adapterPopulatedRecordArrays.push(array);

    return array;
  },

  /**
    Register a RecordArray for a given type to be backed by
    a filter function. This will cause the array to update
    automatically when records of that type change attribute
    values or states.

    @method registerFilteredRecordArray
    @param {DS.RecordArray} array
    @param {DS.Model} typeClass
    @param {Function} filter
  */
  registerFilteredRecordArray: function(array, typeClass, filter) {
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    recordArrays.push(array);

    this.updateFilter(array, typeClass, filter);
  },

  /**
    Unregister a RecordArray.
    So manager will not update this array.

    @method unregisterRecordArray
    @param {DS.RecordArray} array
  */
  unregisterRecordArray: function(array) {
    var typeClass = array.type;

    // unregister filtered record array
    var recordArrays = this.filteredRecordArrays.get(typeClass);
    var index = indexOf(recordArrays, array);
    if (index !== -1) {
      recordArrays.splice(index, 1);

    // unregister live record array
    } else if (this.liveRecordArrays.has(typeClass)) {
      var liveRecordArrayForType = this.liveRecordArrayFor(typeClass);
      if (array === liveRecordArrayForType) {
        this.liveRecordArrays.delete(typeClass);
      }
    }
  },

  willDestroy: function() {
    this._super.apply(this, arguments);

    this.filteredRecordArrays.forEach(function(value) {
      forEach(flatten(value), destroy);
    });
    forEach(this.liveRecordArrays, destroy);
    forEach(this._adapterPopulatedRecordArrays, destroy);
  }
});

function destroy(entry) {
  entry.destroy();
}

function flatten(list) {
  var length = list.length;
  var result = Ember.A();

  for (var i = 0; i < length; i++) {
    result = result.concat(list[i]);
  }

  return result;
}
<|endoftext|>


<commit_before>'use strict';

Ember.SimpleAuth.Stores.LocalStorage = Ember.SimpleAuth.Stores.Base.extend({
  storageKeyPrefix: 'ember_simple_auth:',

  init: function() {
    this.bindToStorageEvents();
  },

  persist: function(properties) {
    for (var property in properties) {
      var key = this.buildStorageKey(property);
      localStorage.setItem(key, properties[property]);
    }
  },

  restore: function() {
    var _this = this;
    var properties = {};
    this.knownKeys().forEach(function(key) {
      var originalKey = key.replace(_this.storageKeyPrefix, '');
      properties[originalKey] = localStorage.getItem(key);
    });
    return properties;
  },

  clear: function() {
    this.knownKeys().forEach(function(key) {
      localStorage.removeItem(key);
    });
  },

  /**
    @method buildStorageKey
    @private
  */
  buildStorageKey: function(property) {
    return this.storageKeyPrefix + property;
  },

  /**
    @method knownKeys
    @private
  */
  knownKeys: function(callback) {
    var keys = Ember.A([]);
    for (var i = 0, l = localStorage.length; i < l; i++) {
      var key = localStorage.key(i);
      if (key.indexOf(this.storageKeyPrefix) === 0) {
        keys.push(key);
      }
    }
    return keys;
  },

  bindToStorageEvents: function() {
    var _this = this;
    Ember.$(window).bind('storage', function() {
      var properties = _this.restore();
      this.trigger('ember-simple-auth:session-updated', properties);
    });
  }
});
<commit_msg>API docs for the local storage store<commit_after>'use strict';

/**
  Store that saves its data in the browser's `localStorage`.

  @class LocalStorage
  @namespace Ember.SimpleAuth.Stores
  @extends Ember.SimpleAuth.Stores.Base
  @constructor
*/
Ember.SimpleAuth.Stores.LocalStorage = Ember.SimpleAuth.Stores.Base.extend({
  /**
    The prefix to use for the store's keys so they can be distinguished from
    other keys.

    @property storageKeyPrefix
    @type String
    @default 'ember_simple_auth:'
  */
  storageKeyPrefix: 'ember_simple_auth:',

  /**
    @method init
    @private
  */
  init: function() {
    this.bindToStorageEvents();
  },

  /**
    Persists the `properties` in the `localStorage`.

    @method persist
    @param {Object} properties The properties to persist
  */
  persist: function(properties) {
    for (var property in properties) {
      var key = this.buildStorageKey(property);
      localStorage.setItem(key, properties[property]);
    }
  },

  /**
    Restores all properties currently saved in the `localStorage` identified by
    the `storageKeyPrefix`.

    @method restore
    @return {Object} All properties currently persisted in the session cookies
  */
  restore: function() {
    var _this = this;
    var properties = {};
    this.knownKeys().forEach(function(key) {
      var originalKey = key.replace(_this.storageKeyPrefix, '');
      properties[originalKey] = localStorage.getItem(key);
    });
    return properties;
  },

  /**
    Clears the store by deleting all `localStorage` keys prefixed with the
    `storageKeyPrefix`.

    @method clear
  */
  clear: function() {
    this.knownKeys().forEach(function(key) {
      localStorage.removeItem(key);
    });
  },

  /**
    @method buildStorageKey
    @private
  */
  buildStorageKey: function(property) {
    return this.storageKeyPrefix + property;
  },

  /**
    @method knownKeys
    @private
  */
  knownKeys: function(callback) {
    var keys = Ember.A([]);
    for (var i = 0, l = localStorage.length; i < l; i++) {
      var key = localStorage.key(i);
      if (key.indexOf(this.storageKeyPrefix) === 0) {
        keys.push(key);
      }
    }
    return keys;
  },

  /**
    @method bindToStorageEvents
    @private
  */
  bindToStorageEvents: function() {
    var _this = this;
    Ember.$(window).bind('storage', function() {
      var properties = _this.restore();
      this.trigger('ember-simple-auth:session-updated', properties);
    });
  }
});
<|endoftext|>


<commit_before>var E = '',
    TRUE = 'true',
    FALSE = 'false',
    /**
     * Default separator while retrieving values of multi-level keys.
     * @const
     * @type {string}
     */
    DEFAULT_SEPARATOR = '_', // default separator value constant

    /**
     * Accepts a string and replaces all non alphabetic characters with default separator and converts characters to
     * uppercase.
     *
     * @param {object}  key
     * @param {string=} [separator=}
     * @returns {string}
     */
    rekey = function (key, separator) {
        return key.toUpperCase().replace(/[^A-Z0-9]/g, separator || E);
    },

    /**
     * Stores the set of typecast functions to be applied when retrieving values from environment.
     *
     * @enum
     * @type {Objeck<function>}
     */
    typecasts = {
        'string': String,
        'number': Number,
        'undefined': String,
        'boolean': function (value) {
            value = (value && value.toString) ? value.toString().trim().toLowerCase() : value;

            if (!isNaN(value)) {
                return Number(value);
            }
            if (value === FALSE) {
                return false;
            }
            if (value === TRUE) {
                return true;
            }
        }
    },

    // main function that parses objects
    lift;

/**
 * Recursively traverses through objects and whenever native value types are encountered, replaces it with corresponding
 * data from environment variables.
 *
 * @param {object} obj
 * @param {string=} [namespace=] - Ensure that the namespace is pre-transformed. This improves performance.
 * @param {string=} [separator=_]
 * @param {function} transformer - The key name to pick data is forwarded as parameter and the value returned by the
 * transformer function is used to lookup environment variables.
 */
lift = function (obj, namespace, separator, transformer, _debug) {
    var key,
        cast,
        eKey;

    // iterate on each item in this object and operate on their keys.
    for (key in obj) {
        // only process keys that are owned by this object
        if (!obj.hasOwnProperty(key)) {
            continue;
        }

        // determine the type of the value and extract the casting function.
        cast = typecasts[typeof obj[key]];
        !cast && (obj[key] === null) && (cast = typecasts.undefined); // specially handle null

        // generate the equivalent environment key for the namespace
        eKey = (namespace || E) + separator + (transformer ? transformer(key, separator) : key);

        // if a cast function is there, it implies that native value is detected and we need to lookup environment
        if (cast) {
            // if environment has a defined variable, we replace the original value with this.
            if (process.env[eKey] !== undefined) {
                _debug && console.log('env-lift: %s =', eKey, cast(process.env[eKey]));
                obj[key] = cast(process.env[eKey]);
            }
        }
        // otherwise, we recurse into the value of the property
        else {
            lift(obj[key], eKey, separator, transformer, _debug);
        }
    }

    return obj;
};

module.exports = /** @lends module:env-lift */ {
    /**
     * Replaces values in `reference` object with equivalent definition of environment variables prefixed with
     * `namespace` and object's key path.
     *
     * @note This function mutes the original reference object.
     *
     * @param {string} namespace
     * @param {object} reference
     *
     * @example
     * require('env-lift').load('test', {
     *     port: 123,
     *     name: 'Sample Text'
     * });
     *
     * // if there is an environment variable TEST_PORT=8080
     * // The above would return: {
     * //     port: 8080,
     * //     name: 'Sample Text'
     * // }
     */
    load: function (namespace, reference, _debug) {
        return lift(reference, rekey(namespace || E, DEFAULT_SEPARATOR), DEFAULT_SEPARATOR, rekey, _debug ||
            !!process.env.ENV_LIFT_DEBUG);
    }
};
<commit_msg>Updated the debug logger to output cast values.<commit_after>var E = '',
    TRUE = 'true',
    FALSE = 'false',
    /**
     * Default separator while retrieving values of multi-level keys.
     * @const
     * @type {string}
     */
    DEFAULT_SEPARATOR = '_', // default separator value constant

    /**
     * Accepts a string and replaces all non alphabetic characters with default separator and converts characters to
     * uppercase.
     *
     * @param {object}  key
     * @param {string=} [separator=}
     * @returns {string}
     */
    rekey = function (key, separator) {
        return key.toUpperCase().replace(/[^A-Z0-9]/g, separator || E);
    },

    /**
     * Stores the set of typecast functions to be applied when retrieving values from environment.
     *
     * @enum
     * @type {Objeck<function>}
     */
    typecasts = {
        'string': String,
        'number': Number,
        'undefined': String,
        'boolean': function (value) {
            value = (value && value.toString) ? value.toString().trim().toLowerCase() : value;

            if (!isNaN(value)) {
                return Number(value);
            }
            if (value === FALSE) {
                return false;
            }
            if (value === TRUE) {
                return true;
            }
        }
    },

    // main function that parses objects
    lift;

/**
 * Recursively traverses through objects and whenever native value types are encountered, replaces it with corresponding
 * data from environment variables.
 *
 * @param {object} obj
 * @param {string=} [namespace=] - Ensure that the namespace is pre-transformed. This improves performance.
 * @param {string=} [separator=_]
 * @param {function} transformer - The key name to pick data is forwarded as parameter and the value returned by the
 * transformer function is used to lookup environment variables.
 */
lift = function (obj, namespace, separator, transformer, _debug) {
    var key,
        cast,
        eKey;

    // iterate on each item in this object and operate on their keys.
    for (key in obj) {
        // only process keys that are owned by this object
        if (!obj.hasOwnProperty(key)) {
            continue;
        }

        // determine the type of the value and extract the casting function.
        cast = typecasts[typeof obj[key]];
        !cast && (obj[key] === null) && (cast = typecasts.undefined); // specially handle null

        // generate the equivalent environment key for the namespace
        eKey = (namespace || E) + separator + (transformer ? transformer(key, separator) : key);

        // debug log
        _debug && (process.env[eKey] !== undefined) && console.log('env-lift: %s=%s', eKey, process.env[eKey],
            cast ? ('[' + cast(process.env[eKey]) + ']') : E) ;

        // if a cast function is there, it implies that native value is detected and we need to lookup environment
        if (cast) {
            // if environment has a defined variable, we replace the original value with this.
            if (process.env[eKey] !== undefined) {
                obj[key] = cast(process.env[eKey]);
            }
        }
        // otherwise, we recurse into the value of the property
        else {
            lift(obj[key], eKey, separator, transformer, _debug);
        }
    }

    return obj;
};

module.exports = /** @lends module:env-lift */ {
    /**
     * Replaces values in `reference` object with equivalent definition of environment variables prefixed with
     * `namespace` and object's key path.
     *
     * @note This function mutes the original reference object.
     *
     * @param {string} namespace
     * @param {object} reference
     *
     * @example
     * require('env-lift').load('test', {
     *     port: 123,
     *     name: 'Sample Text'
     * });
     *
     * // if there is an environment variable TEST_PORT=8080
     * // The above would return: {
     * //     port: 8080,
     * //     name: 'Sample Text'
     * // }
     */
    load: function (namespace, reference) {
        var debug = !!process.env.ENV_LIFT_DEBUG,
            nsKey = rekey(namespace || E, DEFAULT_SEPARATOR);

        debug && console.log('env-lift: debugging %s', nsKey);
        return lift(reference, nsKey, DEFAULT_SEPARATOR, rekey, debug);
    }
};
<|endoftext|>


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

'use strict';

async function main(projectId, location, processorId, filePath) {
  // [START documentai_quickstart]
  /**
   * TODO(developer): Uncomment these variables before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const location = 'YOUR_PROJECT_LOCATION'; // Format is 'us' or 'eu'
  // const processorId = 'YOUR_PROCESSOR_ID'; // Create processor in Cloud Console
  // const filePath = '/path/to/local/pdf';

  const {DocumentProcessorServiceClient} =
    require('@google-cloud/documentai').v1;

  // Instantiates a client
  const client = new DocumentProcessorServiceClient();

  async function quickstart() {
    // The full resource name of the processor, e.g.:
    // projects/project-id/locations/location/processor/processor-id
    // You must create new processors in the Cloud Console first
    const name = `projects/${projectId}/locations/${location}/processors/${processorId}`;

    // Read the file into memory.
    const fs = require('fs').promises;
    const imageFile = await fs.readFile(filePath);

    // Convert the image data to a Buffer and base64 encode it.
    const encodedImage = Buffer.from(imageFile).toString('base64');

    const request = {
      name,
      rawDocument: {
        content: encodedImage,
        mimeType: 'application/pdf',
      },
    };

    // Recognizes text entities in the PDF document
    const [result] = await client.processDocument(request);
    const {document} = result;

    // Get all of the document text as one big string
    const {text} = document;

    // Extract shards from the text field
    const getText = textAnchor => {
      if (!textAnchor.textSegments || textAnchor.textSegments.length === 0) {
        return '';
      }

      // First shard in document doesn't have startIndex property
      const startIndex = textAnchor.textSegments[0].startIndex || 0;
      const endIndex = textAnchor.textSegments[0].endIndex;

      return text.substring(startIndex, endIndex);
    };

    // Read the text recognition output from the processor
    console.log('The document contains the following paragraphs:');
    const [page1] = document.pages;
    const {paragraphs} = page1;

    for (const paragraph of paragraphs) {
      const paragraphText = getText(paragraph.layout.textAnchor);
      console.log(`Paragraph text:\n${paragraphText}`);
    }
  }
  // [END documentai_quickstart]
  await quickstart();
}

main(...process.argv.slice(2)).catch(err => {
  console.error(err);
  process.exitCode = 1;
});
<commit_msg>samples: Update quickstart.js (#189)<commit_after>/**
 * Copyright 2020, Google, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

async function main(projectId, location, processorId, filePath) {
  // [START documentai_quickstart]
  /**
   * TODO(developer): Uncomment these variables before running the sample.
   */
  // const projectId = 'YOUR_PROJECT_ID';
  // const location = 'YOUR_PROJECT_LOCATION'; // Format is 'us' or 'eu'
  // const processorId = 'YOUR_PROCESSOR_ID'; // Create processor in Cloud Console
  // const filePath = '/path/to/local/pdf';

  const {DocumentProcessorServiceClient} =
    require('@google-cloud/documentai').v1;

  // Instantiates a client
  // apiEndpoint regions available: eu-documentai.googleapis.com, us-documentai.googleapis.com (Required if using eu based processor)
  // const client = new DocumentProcessorServiceClient({apiEndpoint: 'eu-documentai.googleapis.com'});
  const client = new DocumentProcessorServiceClient();

  async function quickstart() {
    // The full resource name of the processor, e.g.:
    // projects/project-id/locations/location/processor/processor-id
    // You must create new processors in the Cloud Console first
    const name = `projects/${projectId}/locations/${location}/processors/${processorId}`;

    // Read the file into memory.
    const fs = require('fs').promises;
    const imageFile = await fs.readFile(filePath);

    // Convert the image data to a Buffer and base64 encode it.
    const encodedImage = Buffer.from(imageFile).toString('base64');

    const request = {
      name,
      rawDocument: {
        content: encodedImage,
        mimeType: 'application/pdf',
      },
    };

    // Recognizes text entities in the PDF document
    const [result] = await client.processDocument(request);
    const {document} = result;

    // Get all of the document text as one big string
    const {text} = document;

    // Extract shards from the text field
    const getText = textAnchor => {
      if (!textAnchor.textSegments || textAnchor.textSegments.length === 0) {
        return '';
      }

      // First shard in document doesn't have startIndex property
      const startIndex = textAnchor.textSegments[0].startIndex || 0;
      const endIndex = textAnchor.textSegments[0].endIndex;

      return text.substring(startIndex, endIndex);
    };

    // Read the text recognition output from the processor
    console.log('The document contains the following paragraphs:');
    const [page1] = document.pages;
    const {paragraphs} = page1;

    for (const paragraph of paragraphs) {
      const paragraphText = getText(paragraph.layout.textAnchor);
      console.log(`Paragraph text:\n${paragraphText}`);
    }
  }
  // [END documentai_quickstart]
  await quickstart();
}

main(...process.argv.slice(2)).catch(err => {
  console.error(err);
  process.exitCode = 1;
});
<|endoftext|>


<commit_before>"use strict";

var $btnMail = $("#btn-mail");

$btnMail.removeAttr("disabled");

$btnMail.click(function (evt) {
  evt.preventDefault();
  Swal.fire({
    title: 'Email',
    html: "Vous pouvez m'envoyer un mail à anthony@dumas.cc !",
    imageUrl: './images/mail.jpg',
    imageWidth: 400,
    imageHeight: 200,
    imageAlt: 'Custom image',
    animation: false
  });
});<commit_msg>Utilisation de mailto: sur le bouton<commit_after>"use strict";

var $btnMail = $("#btn-mail");

$btnMail.removeAttr("disabled");

$btnMail.click(function (evt) {
  evt.preventDefault();
  Swal.fire({
    title: 'Email',
    html: "Vous pouvez m'envoyer un mail à anthony@dumas.cc !",
    imageUrl: './images/mail.jpg',
    imageWidth: 400,
    imageHeight: 200,
    imageAlt: 'Custom image',
    animation: false
  });
});<|endoftext|>


<commit_before>'use strict';

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const Tray = electron.Tray;

let mainWindow = null;
let appIcon = null;
app.commandLine.appendSwitch('enable-transparent-visuals');
app.on('ready', () => {
  mainWindow = new BrowserWindow({
                                  width: 300,
                                  height: 400,
                                  frame: false,
                                  x: 1000,
                                  y: 0
                                  });
  appIcon = new Tray('assets/krypton.jpeg');

  mainWindow.webContents.openDevTools();

  mainWindow.loadURL(`file://${__dirname}/index.html`);
});

const windowEvents = {
  renderPomo(){
    mainWindow.maximize();
    mainWindow.setResizable(false);
    mainWindow.setMovable(false);
    mainWindow.setMinimizable(false);
    mainWindow.setClosable(true);
    mainWindow.setAlwaysOnTop(true);
    mainWindow.setSkipTaskbar(true);
    mainWindow.setIgnoreMouseEvents(true);
    mainWindow.setVisibleOnAllWorkspaces(true);
    mainWindow.setAutoHideMenuBar(true);
  },

  renderMain() {
    mainWindow.setBounds({width: 300,
                          height: 400,
                          frame: false,
                          x: 1000,
                          y: 0
                          });
    mainWindow.setResizable(true);
    mainWindow.setMovable(true);
    mainWindow.setClosable(true);
    mainWindow.setAlwaysOnTop(false);
    mainWindow.setSkipTaskbar(false);
    mainWindow.setClosable(true);
    mainWindow.setIgnoreMouseEvents(false);
    mainWindow.setVisibleOnAllWorkspaces(false);
    mainWindow.setAutoHideMenuBar(false);
  }
};

exports.windowEvents = windowEvents;
<commit_msg>tray icon now opens and closes app<commit_after>'use strict';

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const Tray = electron.Tray;

let mainWindow = null;
let appIcon = null;
let active = true;

app.commandLine.appendSwitch('enable-transparent-visuals');
app.on('ready', () => {
  mainWindow = new BrowserWindow({
                                  width: 300,
                                  height: 400,
                                  frame: false,
                                  x: 1000,
                                  y: 0
                                  });
  appIcon = new Tray('assets/krypton.jpeg');

  appIcon.on('click', function(){
    active = !active;
    active ? windowEvents.renderMain() : windowEvents.hideMain();
  });

  mainWindow.webContents.openDevTools();

  mainWindow.loadURL(`file://${__dirname}/index.html`);
});

const windowEvents = {
  renderPomo(){
    mainWindow.maximize();
    mainWindow.setResizable(false);
    mainWindow.setMovable(false);
    mainWindow.setMinimizable(false);
    mainWindow.setClosable(true);
    mainWindow.setAlwaysOnTop(true);
    mainWindow.setSkipTaskbar(true);
    mainWindow.setIgnoreMouseEvents(true);
    mainWindow.setVisibleOnAllWorkspaces(true);
    mainWindow.setAutoHideMenuBar(true);
  },

  renderMain() {
    mainWindow.setBounds({width: 300,
                          height: 400,
                          frame: false,
                          x: 1000,
                          y: 0
                          });
    mainWindow.setResizable(true);
    mainWindow.setMovable(true);
    mainWindow.setClosable(true);
    mainWindow.setAlwaysOnTop(false);
    mainWindow.setSkipTaskbar(false);
    mainWindow.setClosable(true);
    mainWindow.setIgnoreMouseEvents(false);
    mainWindow.setVisibleOnAllWorkspaces(false);
    mainWindow.setAutoHideMenuBar(false);
    mainWindow.show();
  },

  hideMain() {
    mainWindow.hide();
  }
};

exports.windowEvents = windowEvents;
<|endoftext|>


<commit_before>'use strict';

const config = require('../config');
const CronJob = require('cron').CronJob;
const Fetcher = require('./fetcher');
const Promise = require("bluebird");

class Main {
  constructor(ds) {
    let self = this;
    this.banks = {};
    this.banksId = {};
    this.prices = {};
    this.needReloadPrice = false;

    this.ds = ds;
    this.fetcher = new Fetcher(self);

    this.initBankNames();
    this.initLastPrices();

    // Fetch currecy price every 15 minutes
    new CronJob('0 */15 * * * *', function() {
      self.fetchAllCurrency();
    }, null, true);
  }

  initBankNames() {
    let self = this;
    self.ds.bank.findAndCountAll()
      .then((res) => {
        if (res.count > 0) {
          self.initBankMap(res.rows);
          console.log('Loaded', res.rows.length, 'banks.');
        } else {
          return self.insertBankNames();
        }
      });
  }

  insertBankNames() {
    let self = this;
    return this.fetcher.fetchBankNames()
      .then((names) => {
        if (names.length) {
          return self.ds.bank.bulkCreate(names);
        }
      })
      .then((banks) => {
        if (banks.length) {
          self.initBankMap(banks);
          console.log('Inserted', banks.length, 'banks.');
        } else {
          console.warn('Cannot fetch bank names.');
        }
      });
  }

  initBankMap(banks) {
    let self = this;
    banks.forEach(bank => {
      self.banks[bank.id] = bank.name;
      self.banksId[bank.name] = bank.id;
    });
  }

  initLastPrices() {
    let self = this;
    config.availCurrencies.forEach(c => {
      self.prices[c] = [];
    })
    let sql = 'SELECT DISTINCT ON (code, bank) ' +
      'code, bank, stt, snt, btt, bnt ' +
      'FROM histories ORDER BY code, bank, ts DESC';
    return self.ds.sequelize.query(sql, {
      type: self.ds.sequelize.QueryTypes.SELECT,
      raw: true
    })
    .then((prices) => {
      let count = 0;
      prices.forEach(price => {
        self.prices[price.code][price.bank] = price;
        delete price.code;
        delete price.bank;
        count++;
      });
      console.log('Loaded', count, 'records.');
    });
  }

  fetchAllCurrency() {
    let self = this;
    self.needReloadPrice = false;
    return Promise.map(config.availCurrencies, (code) => {
      return self.insertCurrency(code).delay(1000);
    }, {concurrency: 1})
    .then(function() {
      console.log('Finished fetch all currencies');
      if (self.needReloadPrice) {
        self.initLastPrices();
      }
    });
  }

  insertCurrency(code) {
    let self = this;
    return self.fetcher.fetchCurrency(code)
      .then((prices) => {
        if (!prices.length) {
          return false;
        }
        let count = 0;
        prices.forEach(price => {
          let bank = self.prices[price.code][price.bank];
          if (!bank || (bank.stt !== price.stt || bank.btt !== price.btt ||
            bank.snt !== price.snt || bank.bnt !== price.bnt)) {
            self.ds.history.create(price);
            count++;
          }
        });
        if (count > 0) {
          self.needReloadPrice = true;
          console.log('Inserted', count, code, 'records.');
        }
      });
  }
}

module.exports = Main;
<commit_msg>Add listCurrency<commit_after>'use strict';

const config = require('../config');
const CronJob = require('cron').CronJob;
const Fetcher = require('./fetcher');
const Promise = require("bluebird");

class Main {
  constructor(ds) {
    let self = this;
    this.banks = {};
    this.banksId = {};
    this.prices = {};
    this.bestPrices = {};
    this.needReloadPrice = false;

    this.ds = ds;
    this.fetcher = new Fetcher(self);

    this.initBankNames();
    this.initLastPrices();

    // Fetch currecy price every 15 minutes
    new CronJob('0 */15 * * * *', function() {
      self.fetchAllCurrency();
    }, null, true);
  }

  initBankNames() {
    let self = this;
    self.ds.bank.findAndCountAll()
      .then((res) => {
        if (res.count > 0) {
          self.initBankMap(res.rows);
          console.log('Loaded', res.rows.length, 'banks.');
        } else {
          return self.insertBankNames();
        }
      });
  }

  insertBankNames() {
    let self = this;
    return this.fetcher.fetchBankNames()
      .then((names) => {
        if (names.length) {
          return self.ds.bank.bulkCreate(names);
        }
      })
      .then((banks) => {
        if (banks.length) {
          self.initBankMap(banks);
          console.log('Inserted', banks.length, 'banks.');
        } else {
          console.warn('Cannot fetch bank names.');
        }
      });
  }

  initBankMap(banks) {
    let self = this;
    banks.forEach(bank => {
      self.banks[bank.id] = bank.name;
      self.banksId[bank.name] = bank.id;
    });
  }

  initLastPrices() {
    let self = this;
    self.bestPrices = {};
    config.availCurrencies.forEach(c => {
      self.prices[c] = [];
      self.bestPrices[c] = {stt: -999, snt: -999, btt: 999, bnt: 999};
    })
    let sql = 'SELECT DISTINCT ON (code, bank) ' +
      'code, bank, stt, snt, btt, bnt ' +
      'FROM histories ORDER BY code, bank, ts DESC';
    return self.ds.sequelize.query(sql, {
      type: self.ds.sequelize.QueryTypes.SELECT,
      raw: true
    })
    .then((prices) => {
      let count = 0;
      prices.forEach(price => {
        self.prices[price.code][price.bank] = price;
        self.initBestPrices(price);
        delete price.code;
        delete price.bank;
        count++;
      });
      console.log('Loaded', count, 'records.');
    });
  }

  initBestPrices(price) {
    let self = this;
    let code = this.bestPrices[price.code];
    ['stt', 'snt'].forEach((f) => {
      if (price[f] && price[f] > code[f]) {
        code[f] = price[f];
        code[f + 'b'] = +price.bank;
      }
    });
    ['btt', 'bnt'].forEach(f => {
      if (price[f] && price[f] < code[f]) {
        code[f] = price[f];
        code[f + 'b'] = +price.bank;
      }
    });
  }

  fetchAllCurrency() {
    let self = this;
    self.needReloadPrice = false;
    return Promise.map(config.availCurrencies, (code) => {
      return self.insertCurrency(code).delay(1000);
    }, {concurrency: 1})
    .then(function() {
      console.log('Finished fetch all currencies');
      if (self.needReloadPrice) {
        self.initLastPrices();
      }
    });
  }

  insertCurrency(code) {
    let self = this;
    return self.fetcher.fetchCurrency(code)
      .then((prices) => {
        if (!prices.length) {
          return false;
        }
        let count = 0;
        prices.forEach(price => {
          let bank = self.prices[price.code][price.bank];
          if (!bank || (bank.stt !== price.stt || bank.btt !== price.btt ||
            bank.snt !== price.snt || bank.bnt !== price.bnt)) {
            self.ds.history.create(price);
            count++;
          }
        });
        if (count > 0) {
          self.needReloadPrice = true;
          console.log('Inserted', count, code, 'records.');
        }
      });
  }

  listCurrency(code) {
    let self = this;
    if (config.availCurrencies.indexOf(code.toUpperCase()) > 0) {
      return self._listCurrency_sub(code);
    } else if (code.toUpperCase() === 'ALL') {
      let res = '';
      config.availCurrencies.forEach(code => {
        res += self._listCurrency_sub(code);
      });
      return res;
    }
  }

  _listCurrency_sub(code) {
    let self = this;
    let fields = ['stt', 'snt', 'btt', 'bnt'];
    let names = ['電匯銀行買入', '現鈔銀行買入', '電匯銀行賣出', '現鈔銀行賣出'];
    let price = self.bestPrices[code];
    let res = code + '\n';
    let i = 0;
    fields.forEach(f => {
      let bank = price[f + 'b'];
      if (bank) {
        res += names[i] + ': ' + price[f] + ' ' + self.banks[bank] + '\n';
      }
      i++;
    });
    return res;
  }
}

module.exports = Main;
<|endoftext|>


<commit_before>/*
 * command line interface for nfd
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var argv = require('yargs').argv;
var _ = require('underscore');
var cliTable = require('cli-table');
var nfdsdk = require('../../nfd-sdk/main')();
var prompt = require('prompt');
var cfg = require('./config');

var ProgressBar = require('progress');

var tableChars = { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': '',
                   'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': '',
                   'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': '',
                   'right': '' , 'right-mid': '' , 'middle': ' ' };
var tableStyle = { 'padding-left': 0, 'padding-right': 0 };
process.stdin.setEncoding('utf8');

var showHelp = function(args, cb) {
  console.log('');
  console.log('list systems                                      - list all systems in this instance');
  console.log('get dpeloyed                                      - get the deployed revision of this system');
  console.log('put system                                        - put a new revision of the system');
  console.log('put container                                     - put a new revision a container');
  console.log('create system <name> <namespace>                  - create a new blank system');
  console.log('delete system <systemid>                          - delete a system');
  console.log('deploy system <systemid> <revisionid>             - deploy a specific revision of this system');
  console.log('list revisions <systemid>                         - list revision history for this system');
  console.log('get revision <systemid> <revisionid>              - get a specific revision for a system');
  console.log('list containers <systemid>                        - list all containers in this system');
  console.log('build container <systemid> <containerid>          - build a specific container');
  console.log('add container <systemid>                          - add a new container');
  console.log('delete container <systemid> <continaerid>         - delete a container');
  console.log('list timeline <systemid>                          - list the timeline for this system');
  console.log('use host [port]                                   - use the given host and optional port');
  console.log('help                                              - show this');
  console.log('');
  cb();
};

var login = function(args, cb) {
  var config = cfg.getConfig();
  prompt.start();

  prompt.get([{name:'nfdlogin', description:'nfd username / password login (y/n)', pattern:'^[y|n|Y|N]$', required:true}], function(err, result) {

    if ('y' === result.nfdlogin.trim().toLowerCase()) {
      prompt.get([{name:'username', required:true}, {name:'password', required:true, hidden:true}], function(err, result) {
        nfdsdk.connect({host: config.host, port: config.port}, function() {
          nfdsdk.login(result.username, result.password, function(result) {
            if (result.user && result.user.token) {
              cfg.setToken(result.user.token);
              console.log('ok');
            }
            else {
              console.log('error: ' + result.why);
            }
            cb();
          });
        });
      });
    }
    else {
      prompt.get([{name:'token', description:'github access token', required:true}], function(err, result) {
        nfdsdk.connect({host: config.host, port: config.port}, function() {
          nfdsdk.ioHandlers(function(){}, function(err) {
            console.log(err.stderr);
            cb();
          });
          nfdsdk.githublogin(result.token, function(out) {
            if (out.user) {
              cfg.setToken(out.user.token);
            }
            else {
              console.log(JSON.stringify(out, null, 2));
            }
            cb();
          });
        });
      });
    }

  });

};

var listSystems = function(args, cb) {
  var table = new cliTable({chars: tableChars, style: tableStyle,
                            head: ['Name', 'Id'], colWidths: [30, 50]});
  nfdsdk.listSystems(function(systems) {
    _.each(systems, function(system) {
      table.push([system.name, system.id]);
    });
    console.log(table.toString());
    //console.log(JSON.stringify(systems, null, 2));
    cb();
  });
};

var listContainers = function(args, cb) {
  var table = new cliTable({chars: tableChars, style: tableStyle,
                            head: ['Name', 'Type', 'Id'], colWidths: [30, 15, 50]});
  nfdsdk.listContainers(args[2], function(containers) {
    _.each(containers, function(container) {
      table.push([container.name, container.type, container.id]);
    });
    console.log(table.toString());
    //console.log(JSON.stringify(containers, null, 2));
    cb();
  });
};

var getDeployed = function(args, cb) {
  nfdsdk.getDeployed(args[2], function(system) {
    console.log(JSON.stringify(system, null, 2));
    cb();
  });
};

var createSystem = function(args, cb) {
  nfdsdk.createSystem(args[2], args[3], function(system) {
    if (system.id) {
      console.log('ok');
    }
    else {
      console.log('error: unspecified');
    }
    //console.log(JSON.stringify(system, null, 2));
    cb();
  });
};

var deleteSystem = function(args, cb) {
  nfdsdk.deleteSystem(args[2], function(/*result*/) {
    console.log('ok');
    //console.log(JSON.stringify(result, null, 2));
    cb();
  });
};

var putSystem = function(args, cb) {
  var sys = '';
  process.stdin.on('readable', function() {
    sys += process.stdin.read();
  });

  process.stdin.on('end', function() {
    nfdsdk.putSystem(sys, function(response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
      cb();
    });
  });
};

var putContainer = function(args, cb) {
  var sys = '';
  process.stdin.on('readable', function() {
    sys += process.stdin.read();
  });

  process.stdin.on('end', function() {
    nfdsdk.putContainer(args[2], sys, function(response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
      cb();
    });
  });
};

var addContainer = function(args, cb) {
  prompt.start();
  prompt.get(['name', 'type'], function(err, result) {
    var container = {'name': result.name,
                     'type': result.type,
                     'specific': {}};

    nfdsdk.addContainer(args[2], JSON.stringify(container), function(response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
      cb();
    });
  });
};

var deleteContainer = function(args, cb) {
  nfdsdk.deleteContainer(args[2], args[3], function(response) {
    console.log(response.result);
    if (response.err) { console.log(response.err); }
    //console.log(JSON.stringify(response, null, 2));
    cb();
  });
};

var buildContainer = function(args, cb) {
  nfdsdk.buildContainer(args[2], args[3],function(response) {
    console.log();
    if (response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
    }
    cb();
  });
};

var listRevisions = function(args, cb) {
  var table = new cliTable({chars: tableChars, style: tableStyle,
                            head: ['Revision', 'deployed', 'description'], colWidths: [50, 10, 100]});
  nfdsdk.listRevisions(args[2], function(revisions) {
    _.each(revisions, function(revision) {
      table.push([revision.guid, revision.deployed, revision.description]);
    });
    console.log(table.toString());
    cb();
  });
};

var getRevision = function(args, cb) {
  nfdsdk.getRevision(args[2], args[3], function(revisions) {
    console.log(JSON.stringify(revisions, null, 2));
    cb();
  });
};

var addToTimeline = function(cb) {
  var entry = '';
  process.stdin.on('readable', function() {
    entry += process.stdin.read();
  });

  process.stdin.on('end', function() {
    nfdsdk.addToTimeline(entry, function(result) {
      console.log(JSON.stringify(result, null, 2));
      cb();
    });
  });
};

var listTimeline = function(systemId, containerId, cb) {
  nfdsdk.timeline(systemId, containerId, function(result) {
    console.log(JSON.stringify(result, null, 2));
    cb();
  });
};

var deploySystem = function(args, cb) {
  nfdsdk.deploySystem(args[2], args[3], function(result) {
    if (result) {
      console.log(JSON.stringify(result, null, 2));
    }
    cb();
  });
};

var logout = function(args, cb) {
  cfg.clearToken();
  cb();
};

/*
 * revoke will revoke all remote access to a system and reset secrets
 */
var revoke = function(args, cb) {
};

var useSystem = function(args, cb) {
  var port = args[2];
  var config;

  if (!port) {
    port = 3223;
  }
  if (args[1]) {
    cfg.use(args[1], port);
  }
  else {
    config = cfg.getConfig();
    console.log('using: ' + config.host + ' ' + config.port);
  }
  cb();
};

var map = {list: {systems: listSystems,
                  containers: listContainers,
                  revisions: listRevisions,
                  timeline: listTimeline},
           get: {deployed: getDeployed,
                 revision: getRevision},
           put: {system: putSystem,
                 container: putContainer},
           create: {system: createSystem},
           add: {container: addContainer,
                 timeline: addToTimeline},
           delete: {system: deleteSystem,
                    container: deleteContainer},
           build: {container: buildContainer},
           deploy: {system: deploySystem},
           login: login,
           logout: logout,
           use: useSystem,
           help: showHelp};

var runCommand = function(cmd, cb) {
  if (map[cmd[0]] && _.isFunction(map[cmd[0]])) {
    map[cmd[0]](cmd, function() {
      cb();
    });
  }
  else if (map[cmd[0]] && map[cmd[0]][cmd[1]] && _.isFunction(map[cmd[0]][cmd[1]])) {
    map[cmd[0]][cmd[1]](cmd, function() {
      cb();
    });
  }
  else {
    console.log('error: command not available');
    cb();
  }
};

var stdoutHandler = function(out) {
//  process.stdout.write("Downloading " + data.length + " bytes\r");
//  console.log(out.responseType + ':' + out.level + ': ' + out.stdout);
  process.stdout.write(out.responseType + ':' + out.level + ': ' + out.stdout + '\r\r');
};

var stderrHandler = function(err) {
  //console.log(err.responseType + ':' + err.level + ': ' + err.stderr);
};

var currentProgressMade = 0;
var pbar;
var curryProgressHandler = function(type) {
  return function(out) {
    if (out.level === 'progress') {
      if (out.stdout === 0) {
        currentProgressMade = 0;
        pbar = new ProgressBar(type + ' [:bar] :percent :etas', {
          complete: '=',
          incomplete: ' ',
          width: 50,
          total: 100
        });
      }
      else {
        pbar.tick(out.stdout - currentProgressMade);
        currentProgressMade = out.stdout;
      }
    }
    else if (out.level === 'warn' || out.level === 'error') {
      console.log();
      console.log(out.responseType + ':' + out.level + ': ' + out.stdout);
    }
  };
};

exports.main = function() {
  var config = cfg.getConfig();

  if (argv._[0] === 'help' || argv._[0] === 'use' || argv._[0] === 'login') {
    runCommand(argv._, function() {
      process.exit(0);
    });
  }
  else {
    nfdsdk.connect({host: config.host, port: config.port, token: config.token}, function() {
      if (argv._[0] === 'deploy') {
        nfdsdk.ioHandlers(curryProgressHandler('deploying'), stderrHandler);
      }
      else if (argv._[0] === 'build') {
        nfdsdk.ioHandlers(curryProgressHandler('building'), stderrHandler);
      }
      else {
        nfdsdk.ioHandlers(stdoutHandler, stderrHandler);
      }
      runCommand(argv._, function() {
        nfdsdk.quit(function() {
          process.exit(0);
        });
      });
    });
  }
};

<commit_msg>demo updates<commit_after>/*
 * command line interface for nfd
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var argv = require('yargs').argv;
var _ = require('underscore');
var cliTable = require('cli-table');
var nfdsdk = require('../../nfd-sdk/main')();
var prompt = require('prompt');
var cfg = require('./config');

var ProgressBar = require('progress');

var tableChars = { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': '',
                   'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': '',
                   'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': '',
                   'right': '' , 'right-mid': '' , 'middle': ' ' };
var tableStyle = { 'padding-left': 0, 'padding-right': 0 };
process.stdin.setEncoding('utf8');

var showHelp = function(args, cb) {
  console.log('');
  console.log('list systems                                      - list all systems in this instance');
  console.log('get deployed <systemid>                           - get the deployed revision of this system');
  console.log('put system                                        - put a new revision of the system');
  console.log('put container                                     - put a new revision a container');
  console.log('create system <name> <namespace>                  - create a new blank system');
  console.log('delete system <systemid>                          - delete a system');
  console.log('deploy system <systemid> <revisionid>             - deploy a specific revision of this system');
  console.log('list revisions <systemid>                         - list revision history for this system');
  console.log('get revision <systemid> <revisionid>              - get a specific revision for a system');
  console.log('list containers <systemid>                        - list all containers in this system');
  console.log('build container <systemid> <containerid>          - build a specific container');
  console.log('add container <systemid>                          - add a new container');
  console.log('delete container <systemid> <continaerid>         - delete a container');
  console.log('list timeline <systemid>                          - list the timeline for this system');
  console.log('use host [port]                                   - use the given host and optional port');
  console.log('help                                              - show this');
  console.log('login                                             - login to the nominated host');
  console.log('logout                                            - logout from the nominated host');
  console.log('');
  cb();
};

var login = function(args, cb) {
  var config = cfg.getConfig();
  prompt.start();

  prompt.get([{name:'nfdlogin', description:'nfd username / password login (y/n)', pattern:'^[y|n|Y|N]$', required:true}], function(err, result) {

    if ('y' === result.nfdlogin.trim().toLowerCase()) {
      prompt.get([{name:'username', required:true}, {name:'password', required:true, hidden:true}], function(err, result) {
        nfdsdk.connect({host: config.host, port: config.port}, function() {
          nfdsdk.login(result.username, result.password, function(result) {
            if (result.user && result.user.token) {
              cfg.setToken(result.user.token);
              console.log('ok');
            }
            else {
              console.log('error: ' + result.why);
            }
            cb();
          });
        });
      });
    }
    else {
      prompt.get([{name:'token', description:'github access token', required:true}], function(err, result) {
        nfdsdk.connect({host: config.host, port: config.port}, function() {
          nfdsdk.ioHandlers(function(){}, function(err) {
            console.log(err.stderr);
            cb();
          });
          nfdsdk.githublogin(result.token, function(out) {
            if (out.user) {
              cfg.setToken(out.user.token);
            }
            else {
              console.log(JSON.stringify(out, null, 2));
            }
            cb();
          });
        });
      });
    }

  });

};

var listSystems = function(args, cb) {
  var table = new cliTable({chars: tableChars, style: tableStyle,
                            head: ['Name', 'Id'], colWidths: [30, 50]});
  nfdsdk.listSystems(function(systems) {
    _.each(systems, function(system) {
      table.push([system.name, system.id]);
    });
    console.log(table.toString());
    //console.log(JSON.stringify(systems, null, 2));
    cb();
  });
};

var listContainers = function(args, cb) {
  var table = new cliTable({chars: tableChars, style: tableStyle,
                            head: ['Name', 'Type', 'Id', 'Version', 'Dependencies'], colWidths: [20, 15, 50, 15, 70]});
  nfdsdk.listContainers(args[2], function(containers) {
    var version;
    var deps;
    _.each(containers, function(container) {
      version = container.version || '';
      deps = container.dependencies || '';
      table.push([container.name, container.type, container.id, version, JSON.stringify(deps)]);
    });
    console.log(table.toString());
    //console.log(JSON.stringify(containers, null, 2));
    cb();
  });
};

var getDeployed = function(args, cb) {
  nfdsdk.getDeployed(args[2], function(system) {
    //console.log(system.guid + ' ' + system.description);
    console.log(JSON.stringify(system, null, 2));
    cb();
  });
};

var createSystem = function(args, cb) {
  nfdsdk.createSystem(args[2], args[3], function(system) {
    if (system.id) {
      console.log('ok');
    }
    else {
      console.log('error: unspecified');
    }
    //console.log(JSON.stringify(system, null, 2));
    cb();
  });
};

var deleteSystem = function(args, cb) {
  nfdsdk.deleteSystem(args[2], function(/*result*/) {
    console.log('ok');
    //console.log(JSON.stringify(result, null, 2));
    cb();
  });
};

var putSystem = function(args, cb) {
  var sys = '';
  process.stdin.on('readable', function() {
    sys += process.stdin.read();
  });

  process.stdin.on('end', function() {
    nfdsdk.putSystem(sys, function(response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
      cb();
    });
  });
};

var putContainer = function(args, cb) {
  var sys = '';
  process.stdin.on('readable', function() {
    sys += process.stdin.read();
  });

  process.stdin.on('end', function() {
    nfdsdk.putContainer(args[2], sys, function(response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
      cb();
    });
  });
};

var addContainer = function(args, cb) {
  prompt.start();
  prompt.get(['name', 'type'], function(err, result) {
    var container = {'name': result.name,
                     'type': result.type,
                     'specific': {}};

    nfdsdk.addContainer(args[2], JSON.stringify(container), function(response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
      cb();
    });
  });
};

var deleteContainer = function(args, cb) {
  nfdsdk.deleteContainer(args[2], args[3], function(response) {
    console.log(response.result);
    if (response.err) { console.log(response.err); }
    //console.log(JSON.stringify(response, null, 2));
    cb();
  });
};

var buildContainer = function(args, cb) {
  nfdsdk.buildContainer(args[2], args[3],function(response) {
    console.log();
    if (response) {
      console.log(response.result);
      if (response.err) { console.log(response.err); }
      //console.log(JSON.stringify(response, null, 2));
    }
    cb();
  });
};

var listRevisions = function(args, cb) {
  var table = new cliTable({chars: tableChars, style: tableStyle,
                            head: ['Revision', 'deployed', 'description'], colWidths: [50, 10, 100]});
  nfdsdk.listRevisions(args[2], function(revisions) {
    _.each(revisions, function(revision) {
      table.push([revision.guid, revision.deployed, revision.description]);
    });
    console.log(table.toString());
    cb();
  });
};

var getRevision = function(args, cb) {
  nfdsdk.getRevision(args[2], args[3], function(revisions) {
    console.log(JSON.stringify(revisions, null, 2));
    cb();
  });
};

var addToTimeline = function(cb) {
  var entry = '';
  process.stdin.on('readable', function() {
    entry += process.stdin.read();
  });

  process.stdin.on('end', function() {
    nfdsdk.addToTimeline(entry, function(result) {
      console.log(JSON.stringify(result, null, 2));
      cb();
    });
  });
};

var listTimeline = function(systemId, containerId, cb) {
  nfdsdk.timeline(systemId, containerId, function(result) {
    console.log(JSON.stringify(result, null, 2));
    cb();
  });
};

var deploySystem = function(args, cb) {
  nfdsdk.deploySystem(args[2], args[3], function(result) {
    if (result) {
      console.log(JSON.stringify(result, null, 2));
    }
    cb();
  });
};

var logout = function(args, cb) {
  cfg.clearToken();
  cb();
};

/*
 * revoke will revoke all remote access to a system and reset secrets
 */
var revoke = function(args, cb) {
};

var useSystem = function(args, cb) {
  var port = args[2];
  var config;

  if (!port) {
    port = 3223;
  }
  if (args[1]) {
    cfg.use(args[1], port);
  }
  else {
    config = cfg.getConfig();
    console.log('using: ' + config.host + ' ' + config.port);
  }
  cb();
};

var map = {list: {systems: listSystems,
                  containers: listContainers,
                  revisions: listRevisions,
                  timeline: listTimeline},
           get: {deployed: getDeployed,
                 revision: getRevision},
           put: {system: putSystem,
                 container: putContainer},
           create: {system: createSystem},
           add: {container: addContainer,
                 timeline: addToTimeline},
           delete: {system: deleteSystem,
                    container: deleteContainer},
           build: {container: buildContainer},
           deploy: {system: deploySystem},
           login: login,
           logout: logout,
           use: useSystem,
           help: showHelp};

var runCommand = function(cmd, cb) {
  if (map[cmd[0]] && _.isFunction(map[cmd[0]])) {
    map[cmd[0]](cmd, function() {
      cb();
    });
  }
  else if (map[cmd[0]] && map[cmd[0]][cmd[1]] && _.isFunction(map[cmd[0]][cmd[1]])) {
    map[cmd[0]][cmd[1]](cmd, function() {
      cb();
    });
  }
  else {
    console.log('error: command not available');
    cb();
  }
};

var stdoutHandler = function(out) {
//  process.stdout.write("Downloading " + data.length + " bytes\r");
//  console.log(out.responseType + ':' + out.level + ': ' + out.stdout);
  process.stdout.write(out.responseType + ':' + out.level + ': ' + out.stdout + '\r\r');
};

var stderrHandler = function(err) {
  if (err.stderr.indexOf('semver') !== -1) {
    console.log(err.responseType + ':' + err.level + ': ' + err.stderr);
  }
};

var currentProgressMade = 0;
var pbar;
var curryProgressHandler = function(type) {
  return function(out) {
    if (out.level === 'progress') {
      if (out.stdout === 0) {
        currentProgressMade = 0;
        pbar = new ProgressBar(type + ' [:bar] :percent :etas', {
          complete: '=',
          incomplete: ' ',
          width: 50,
          total: 100
        });
      }
      else {
        pbar.tick(out.stdout - currentProgressMade);
        currentProgressMade = out.stdout;
      }
    }
    else if (out.level === 'warn' || out.level === 'error') {
      console.log();
      console.log(out.responseType + ':' + out.level + ': ' + out.stdout);
    }
  };
};

exports.main = function() {
  var config = cfg.getConfig();

  if (argv._[0] === 'help' || argv._[0] === 'use' || argv._[0] === 'login') {
    runCommand(argv._, function() {
      process.exit(0);
    });
  }
  else {
    nfdsdk.connect({host: config.host, port: config.port, token: config.token}, function() {
      if (argv._[0] === 'deploy') {
        nfdsdk.ioHandlers(curryProgressHandler('deploying'), stderrHandler);
      }
      else if (argv._[0] === 'build') {
        nfdsdk.ioHandlers(curryProgressHandler('building'), stderrHandler);
      }
      else {
        nfdsdk.ioHandlers(stdoutHandler, stderrHandler);
      }
      runCommand(argv._, function() {
        nfdsdk.quit(function() {
          process.exit(0);
        });
      });
    });
  }
};

<|endoftext|>


<commit_before>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var fs = require('fs');
var _ = require('lodash');
var uuid = require('uuid');
var pwuid = require('pwuid');
var CREDENTIALS_FILE = 'credentials.json';

module.exports = function(options) {

  var readCredentials = function(cb) {
    fs.exists(options.credentialsPath + '/' + CREDENTIALS_FILE, function(exists) {
      if (exists) {
        fs.readFile(options.credentialsPath + '/' + CREDENTIALS_FILE, 'utf8', function(err, data) {
          if (err) { return cb(err); }
          cb(null, JSON.parse(data));
        });
      }
      else {
        cb(null, {});
      }
    });
  };

  var saveCredentials = function(user, cb) {
    readCredentials(function(err, users) {
      if (err) { return cb(err); }

      var exists = _.find(users, function(u) { return u.email === user.email; });
      if (exists) {
        user.token = exists.token;
        cb(null, user);
      }
      else {
        users[user.token] = user;
        fs.writeFile(options.credentialsPath + '/' + CREDENTIALS_FILE, JSON.stringify(users, null, 2), 'utf8', function(err) {
          cb(err, user);
        });
      }
    });
  };

  /**
   * get user credentials from ~/.gitconfig
   * and store against generated token
   * no authentication performed - ignores username and password
   */
  var login = function(username, password, cb) {
    var userInfo = pwuid();
    var user = {};
    var error = '~/.gitconfig not found, please configure git on this system';

    fs.readFile(userInfo.dir + '/.gitconfig', 'utf8', function(err, data) {
      if (err) { return cb(err); }

      _.each(data.split('\n'), function(line) {
        if (/email/g.test(line) || /name/g.test(line)) {
          var parts = line.split('=');
          user[parts[0].trim()] = parts[1].trim();
        }
      });

      if (user.email && user.name) {
        error = null;
        user.token = uuid.v4();
        saveCredentials(user, function(err, u) {
          cb(err, {user: u});
        });
      }
      else {
        cb(error, null);
      }
    });
  };

  /**
   * get user information from token
   */
  var userInfo = function(token, cb) {
    readCredentials(function(err, users) {
      if (err) { return cb(err); }
      cb(null, users[token]);
    });
  };

  return {
    login: login,
    userInfo: userInfo
  };
};

<commit_msg>Make `.gitconfig` `email` and `name` RegExp stricter<commit_after>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var fs = require('fs');
var _ = require('lodash');
var uuid = require('uuid');
var pwuid = require('pwuid');
var CREDENTIALS_FILE = 'credentials.json';

module.exports = function(options) {

  var readCredentials = function(cb) {
    fs.exists(options.credentialsPath + '/' + CREDENTIALS_FILE, function(exists) {
      if (exists) {
        fs.readFile(options.credentialsPath + '/' + CREDENTIALS_FILE, 'utf8', function(err, data) {
          if (err) { return cb(err); }
          cb(null, JSON.parse(data));
        });
      }
      else {
        cb(null, {});
      }
    });
  };

  var saveCredentials = function(user, cb) {
    readCredentials(function(err, users) {
      if (err) { return cb(err); }

      var exists = _.find(users, function(u) { return u.email === user.email; });
      if (exists) {
        user.token = exists.token;
        cb(null, user);
      }
      else {
        users[user.token] = user;
        fs.writeFile(options.credentialsPath + '/' + CREDENTIALS_FILE, JSON.stringify(users, null, 2), 'utf8', function(err) {
          cb(err, user);
        });
      }
    });
  };

  /**
   * get user credentials from ~/.gitconfig
   * and store against generated token
   * no authentication performed - ignores username and password
   */
  var login = function(username, password, cb) {
    var userInfo = pwuid();
    var user = {};
    var error = '~/.gitconfig not found, please configure git on this system';

    fs.readFile(userInfo.dir + '/.gitconfig', 'utf8', function(err, data) {
      if (err) { return cb(err); }

      _.each(data.split('\n'), function(line) {
        if (/^\s*email\s*=/g.test(line) || /^\s*name\s*=/g.test(line)) {
          var parts = line.split('=');
          user[parts[0].trim()] = parts[1].trim();
        }
      });

      if (user.email && user.name) {
        error = null;
        user.token = uuid.v4();
        saveCredentials(user, function(err, u) {
          cb(err, {user: u});
        });
      }
      else {
        cb(error, null);
      }
    });
  };

  /**
   * get user information from token
   */
  var userInfo = function(token, cb) {
    readCredentials(function(err, users) {
      if (err) { return cb(err); }
      cb(null, users[token]);
    });
  };

  return {
    login: login,
    userInfo: userInfo
  };
};

<|endoftext|>


<commit_before>// vim: set ts=2 sw=2:
"use strict";

let preloader = document.querySelector('.preloader');
let preloaderText = preloader.querySelector('.preloader__text');
let the_physics = new Physics();
let the_longcat = new LongCat(document.querySelector('.longcat'), the_physics);
let sections = setupSections();

function setupSections() {
  const allSections = document.querySelectorAll('.section');
  let sections = [];

  sections[0] = new WallSection(allSections[0], the_physics);
  sections[1] = new EarthSection(allSections[1], the_physics);
  sections[2] = new Section(allSections[2], the_physics);  // street
  sections[3] = new BuildingsSection(allSections[3], the_physics);
  sections[4] = new Section(allSections[4], the_physics); // clouds
  sections[5] = new Section(allSections[5], the_physics); // aerspace one
  sections[6] = new InfiniteStartSection(allSections[6], the_physics); // infinite start

  return sections;
}

window.requestAnimationFrame = window.requestAnimationFrame
                            || window.mozRequestAnimationFrame
                            || window.webkitRequestAnimationFrame
                            || window.msRequestAnimationFrame
                            || function(cb) { window.setTimeout(cb, 1000/60); };

const score_el = document.querySelector('.score__number');
const highs_el = document.querySelector('.score__number--high');

// Rather use window.performance if it's available.
// It has sub-millisecond precision, while Date.now only has milliseconds.
const rtc = window.performance || Date;
let t0 = rtc.now();

function mainloop() {
  let t = rtc.now();
  let dt = 0.001*(t - t0);  // from milliseconds to seconds

  // When the tab gets hidden, this animate loop is not called, which is good
  // as it pauses the game. But when the tab gets visible again, the dt is huge:
  // as large as the tab was hidden. We don't want this, as it undoes the pause.
  // so we only update on small dt.
  if (dt < 0.5) {
    dt = the_physics.update(dt);
    the_longcat.update(dt);

    sections.forEach(section => {
      section.update(dt);
    });

    // Update the titlebar according to the score.
    document.title = `Longcat is lo${'o'.repeat(the_physics.score)}ng!`

    // Update the score itself and the high-score.
    score_el.innerHTML = the_physics.score.toFixed(1);
    highs_el.innerHTML = the_physics.highscore.toFixed(1);
  }

  // For the next timestep.
  t0 = t;
  window.requestAnimationFrame(mainloop);
}
window.requestAnimationFrame(mainloop);

function raise_longcat(ev) {
  // remove preloader
  if(preloader) {
    document.body.removeChild(preloader);
    preloader = false;
  }
  // Avoid stuff like drag/drop selection etc.
  ev.preventDefault();

  // Avoid jump on these elements (share buttons)
  if (ev.target.classList.contains("button")) {
    return
  }

  // Meow when we get starteeeed!
  if (the_physics.score == 0) {
      the_longcat.meow();
  }

  the_physics.speedup();
}

function init() {
  // preloader to instructions
  preloader.classList.add('preloader--loaded');
  preloaderText.classList.add('preloader__text--loaded');
  preloaderText.innerHTML = 'click or tap as fast as you can !!!!';

  // A click raises the longcat!
  // Using mousedown event here because otherwise we'd allow drag-selection.
  window.addEventListener('mousedown', raise_longcat);
  // Using the touchend event because many things aren't permitted during start,
  // and because touch_click combos are complicated (http://stackoverflow.com/q/14486804).
  window.addEventListener('touchend', raise_longcat);

  function sharetxt() {
    const hs = the_physics.highscore, ht = the_physics.highscore_time;
    return `Beat my highscore of ${hs.toFixed(2)}km in ${ht.toFixed(2)}s!`;
  }

  const shareurl = encodeURIComponent("http://longcat.wtf");

  // Tweet score.
  document.querySelector('.tweet').addEventListener('click', ev => {
    ev.preventDefault();
    window.open(
      `http://twitter.com/intent/tweet?`
      + `text=${sharetxt()}`
      + `&url=${shareurl}`
      + `&hashtags=longcat,longcatwtf`
      , '_blank'
    );
  });

  // Share score on fb.
  // NOTE: It's not possible to pre-fill the message content anymore, unless
  // the user first authorized the app to write posts on FB itself.
  // See http://stackoverflow.com/a/5023658
  document.querySelector('.fb').addEventListener('click', ev => {
    ev.preventDefault();
    window.open(
      `https://www.facebook.com/dialog/feed?`
      + `app_id=223627144756559`
      + `&link=${shareurl}`
      + `&redirect_uri=${shareurl}`
      + `&display=popup`
      + `&caption=Longcat is loooong!`
      + `&description=%23longcat %23longcatwtf`
      + `&picture=http://longcat.wtf/assets/img/logo.jpg`
      + `&message=${sharetxt()}`  // This is the one that isn't supported anymore.
      + `&title=${sharetxt()}`  // So we put the score into the title instead.
      , '_blank'
    );
  });
}

window.onload = function() {
  init();
};
<commit_msg>Taking stab at title flickering on iOS.<commit_after>// vim: set ts=2 sw=2:
"use strict";

let preloader = document.querySelector('.preloader');
let preloaderText = preloader.querySelector('.preloader__text');
let the_physics = new Physics();
let the_longcat = new LongCat(document.querySelector('.longcat'), the_physics);
let sections = setupSections();

function setupSections() {
  const allSections = document.querySelectorAll('.section');
  let sections = [];

  sections[0] = new WallSection(allSections[0], the_physics);
  sections[1] = new EarthSection(allSections[1], the_physics);
  sections[2] = new Section(allSections[2], the_physics);  // street
  sections[3] = new BuildingsSection(allSections[3], the_physics);
  sections[4] = new Section(allSections[4], the_physics); // clouds
  sections[5] = new Section(allSections[5], the_physics); // aerspace one
  sections[6] = new InfiniteStartSection(allSections[6], the_physics); // infinite start

  return sections;
}

window.requestAnimationFrame = window.requestAnimationFrame
                            || window.mozRequestAnimationFrame
                            || window.webkitRequestAnimationFrame
                            || window.msRequestAnimationFrame
                            || function(cb) { window.setTimeout(cb, 1000/60); };

const score_el = document.querySelector('.score__number');
const highs_el = document.querySelector('.score__number--high');

// Rather use window.performance if it's available.
// It has sub-millisecond precision, while Date.now only has milliseconds.
const rtc = window.performance || Date;
let t0 = rtc.now();

function mainloop() {
  let t = rtc.now();
  let dt = 0.001*(t - t0);  // from milliseconds to seconds

  // When the tab gets hidden, this animate loop is not called, which is good
  // as it pauses the game. But when the tab gets visible again, the dt is huge:
  // as large as the tab was hidden. We don't want this, as it undoes the pause.
  // so we only update on small dt.
  if (dt < 0.5) {
    dt = the_physics.update(dt);
    the_longcat.update(dt);

    sections.forEach(section => {
      section.update(dt);
    });

    // Update the titlebar according to the score.
    // Only update on change though, to avoid flickering on iOS.
    const title = `Longcat is lo${'o'.repeat(the_physics.score)}ng!`;
    if (document.title != title) {
      document.title = title;
    }

    // Update the score itself and the high-score.
    score_el.innerHTML = the_physics.score.toFixed(1);
    highs_el.innerHTML = the_physics.highscore.toFixed(1);
  }

  // For the next timestep.
  t0 = t;
  window.requestAnimationFrame(mainloop);
}
window.requestAnimationFrame(mainloop);

function raise_longcat(ev) {
  // remove preloader
  if(preloader) {
    document.body.removeChild(preloader);
    preloader = false;
  }
  // Avoid stuff like drag/drop selection etc.
  ev.preventDefault();

  // Avoid jump on these elements (share buttons)
  if (ev.target.classList.contains("button")) {
    return
  }

  // Meow when we get starteeeed!
  if (the_physics.score == 0) {
      the_longcat.meow();
  }

  the_physics.speedup();
}

function init() {
  // preloader to instructions
  preloader.classList.add('preloader--loaded');
  preloaderText.classList.add('preloader__text--loaded');
  preloaderText.innerHTML = 'click or tap as fast as you can !!!!';

  // A click raises the longcat!
  // Using mousedown event here because otherwise we'd allow drag-selection.
  window.addEventListener('mousedown', raise_longcat);
  // Using the touchend event because many things aren't permitted during start,
  // and because touch_click combos are complicated (http://stackoverflow.com/q/14486804).
  window.addEventListener('touchend', raise_longcat);

  function sharetxt() {
    const hs = the_physics.highscore, ht = the_physics.highscore_time;
    return `Beat my highscore of ${hs.toFixed(2)}km in ${ht.toFixed(2)}s!`;
  }

  const shareurl = encodeURIComponent("http://longcat.wtf");

  // Tweet score.
  document.querySelector('.tweet').addEventListener('click', ev => {
    ev.preventDefault();
    window.open(
      `http://twitter.com/intent/tweet?`
      + `text=${sharetxt()}`
      + `&url=${shareurl}`
      + `&hashtags=longcat,longcatwtf`
      , '_blank'
    );
  });

  // Share score on fb.
  // NOTE: It's not possible to pre-fill the message content anymore, unless
  // the user first authorized the app to write posts on FB itself.
  // See http://stackoverflow.com/a/5023658
  document.querySelector('.fb').addEventListener('click', ev => {
    ev.preventDefault();
    window.open(
      `https://www.facebook.com/dialog/feed?`
      + `app_id=223627144756559`
      + `&link=${shareurl}`
      + `&redirect_uri=${shareurl}`
      + `&display=popup`
      + `&caption=Longcat is loooong!`
      + `&description=%23longcat %23longcatwtf`
      + `&picture=http://longcat.wtf/assets/img/logo.jpg`
      + `&message=${sharetxt()}`  // This is the one that isn't supported anymore.
      + `&title=${sharetxt()}`  // So we put the score into the title instead.
      , '_blank'
    );
  });
}

window.onload = function() {
  init();
};
<|endoftext|>


<commit_before>import React from 'react';
import Routes from './routes';
import Route from './route';
import Link from './link';
import url from './url';
import makeHref from './make-href';

export function transitionTo(name, props) {
  var href = makeHref(name, props);
  url.push(href);
}

export function replaceWith(name, props) {
  var href = makeHref(name, props);
  url.replace(href);
}

export {
  Link,
  Route,
  location,
  Routes
};

<commit_msg>[added] router.getCurrentInfo<commit_after>import React from 'react';
import Routes from './routes';
import Route from './route';
import Link from './link';
import url from './url';
import makeHref from './make-href';
module store from './route-store';

export function transitionTo(name, props) {
  var href = makeHref(name, props);
  url.push(href);
}

export function replaceWith(name, props) {
  var href = makeHref(name, props);
  url.replace(href);
}

export function getCurrentInfo() {
  var active = store.getActive();
  var last = active[active.length - 1];
  return {
    name: last.route.props.name,
    params: last.params
  };
}

export {
  Link,
  Route,
  location,
  Routes
};

<|endoftext|>


<commit_before>'use babel'

export default {

  Hack: null,
  config: {
    pushFilesToServer: {
      type: 'boolean',
      default: true,
      description: 'Whether or not to push files to the remote server, disable in case of local mounts'
    },
    hackExecutablePath: {
      type: 'string',
      default: 'hh_client'
    }
  },

  activate: function() {
    this.Hack = require('./base')
    require('atom-package-deps').install('Atom-Hack')
  },
  provideHack: function() {
    return this.Hack
  },
  provideLinter: function() {
    const Path = require('path')
    const Linter = {
      grammarScopes: ['source.hack', 'source.html.hack'],
      scope: 'project',
      lintOnFly: false,
      formatError: (error) => {
        return {
          type: 'Error',
          filePath: this.Hack.convertPath(error.path, false),
          text: error.descr,
          range: [[error.line - 1, error.start - 1 ],[error.line - 1, error.end]]
        }
      },
      formatErrors: function(errors) {
        const toReturn = []
        errors.errors.forEach(error => {
          const errorEntry = Linter.formatError(error.message.shift())
          errorEntry.trace = error.message.map(Linter.formatError)
          errorEntry.trace.forEach(e => e.type = 'Trace')
          toReturn.push(errorEntry)
        })
        return toReturn
      },
      lint: textEditor => {
        const filePath = textEditor.getPath()
        if (!this.Hack.connected) {
          return []
        }
        return this.Hack.update(filePath).then(() => {
          return this.Hack.exec(atom.config.get('Atom-Hack.hackExecutablePath'), ['--json'], {cwd: Path.dirname(filePath), stream: 'stderr'})
        }).then(function(contents) {
          try {
            return Linter.formatErrors(JSON.parse(contents))
          } catch (err) {
            return []
          }
        })
      }
    }
    return Linter
  }
}
<commit_msg>:new: Implement jump to declaration<commit_after>'use babel'

const Path = require('path')
import {CompositeDisposable} from 'atom'

export default {

  Hack: null,
  config: {
    pushFilesToServer: {
      type: 'boolean',
      default: true,
      description: 'Whether or not to push files to the remote server, disable in case of local mounts'
    },
    hackExecutablePath: {
      type: 'string',
      default: 'hh_client'
    }
  },

  activate: function() {
    this.subscriptions = new CompositeDisposable
    this.Hack = require('./base')
    require('atom-package-deps').install('Atom-Hack')

    this.subscriptions.add(atom.commands.add('atom-text-editor[data-grammar~=hack]', 'symbols-view:go-to-declaration', () => {
      if (!this.Hack.connected) {
        return // No-Op
      }
      const textEditor = atom.workspace.getActiveTextEditor()
      if (!textEditor || !textEditor.getPath()) {
        return // Ignore
      }
      const position = textEditor.getCursorBufferPosition()
      const exePath = atom.config.get('Atom-Hack.hackExecutablePath')
      this.Hack.exec(exePath, ['--identify-function', (position.row + 1) + ':' + (position.column + 1)], {stdin: textEditor.getText(), cwd: Path.dirname(textEditor.getPath())})
        .then(contents => {
          if (!contents) {
            return // It must be an invalid position
          }
          this.Hack.exec(exePath, ['--search', contents, '--json'], {cwd: Path.dirname(textEditor.getPath())})
            .then(JSON.parse).then(contents => {
              atom.workspace.open(this.Hack.convertPath(contents[0].filename, false)).then(function() {
                atom.workspace.getActiveTextEditor().setCursorBufferPosition([contents[0].line - 1, contents[0].char_start - 1])
              })
            })
        })
    }))
  },
  deactivate: function() {
    this.subscriptions.dispose()
  },
  provideHack: function() {
    return this.Hack
  },
  provideLinter: function() {
    const Linter = {
      grammarScopes: ['source.hack', 'source.html.hack'],
      scope: 'project',
      lintOnFly: false,
      formatError: (error) => {
        return {
          type: 'Error',
          filePath: this.Hack.convertPath(error.path, false),
          text: error.descr,
          range: [[error.line - 1, error.start - 1 ],[error.line - 1, error.end]]
        }
      },
      formatErrors: function(errors) {
        const toReturn = []
        errors.errors.forEach(error => {
          const errorEntry = Linter.formatError(error.message.shift())
          errorEntry.trace = error.message.map(Linter.formatError)
          errorEntry.trace.forEach(e => e.type = 'Trace')
          toReturn.push(errorEntry)
        })
        return toReturn
      },
      lint: textEditor => {
        const filePath = textEditor.getPath()
        if (!this.Hack.connected) {
          return []
        }
        return this.Hack.update(filePath).then(() => {
          return this.Hack.exec(atom.config.get('Atom-Hack.hackExecutablePath'), ['--json'], {cwd: Path.dirname(filePath), stream: 'stderr'})
        }).then(function(contents) {
          try {
            return Linter.formatErrors(JSON.parse(contents))
          } catch (err) {
            return []
          }
        })
      }
    }
    return Linter
  }
}
<|endoftext|>