<commit_before>var fs = require('fs');
var chalk = require('chalk');
var RateLimiter = require('limiter').RateLimiter;

BOT.limiter = new RateLimiter(BOT.getRate(), 30 * 1000, true);

BOT.getCommand = function (command) {
    if (BOT.commands.hasOwnProperty(command)) {
        return BOT.commands[command];
    }
    return false;
}

BOT.getCurrentTimestampFormat = function () {
    var datetime = new Date().toISOString().slice(0, 19);
    return "[" + datetime.replaceAt(10, ' ') + "]";
}

BOT.isMe = function (user) {
    return BOT.settings.name.toLowerCase() == user.toLowerCase();
}

BOT.getLogPrefix = function () {
    return chalk.yellow.bold("[" + BOT.settings.botname + "] ");
}

BOT.logInfo = function (message) {
    console.log(BOT.getLogPrefix() + chalk.bgCyan.white.bold(BOT.getCurrentTimestampFormat()) + " " + message);
}

BOT.logError = function (message) {
    console.log(BOT.getLogPrefix() + chalk.bgRed.white.bold(BOT.getCurrentTimestampFormat()) + " " + message);
}

BOT.logSuccess = function (message) {
    console.log(BOT.getLogPrefix() + chalk.bgGreen.white.bold(BOT.getCurrentTimestampFormat()) + " " + message);
}

BOT.logMessage = function (message) {
    BOT.logInfo(message);
    var data = BOT.getCurrentTimestampFormat() + " " + message + "\n";
    fs.appendFile('bot.log', data, function (err) {
        if (err) BOT.logInfo('error: ' + err);
    });
}

BOT.say = function (message, retryIfFailed) {
    BOT.limiter.removeTokens(1, function (err, remaining) {
        if (remaining < 0) {
            if (retryIfFailed) {
                BOT.sayLater(message, true);
                return BOT.logInfo('Trying to send messages too quickly, retrying!');
            } else {
                return BOT.logError('Trying to send messages too quickly, skipping!');
            }
        }

        BOT.logSuccess("Sending message: " + message);
        //BOT.client.say(BOT.settings.channel, message);
    });
}

BOT.sayLater = function (message, retryIfFailed) {
    setTimeout(function () {
        BOT.say(message, retryIfFailed);
    }, BOT.rates.interval());
}

BOT.runCommandLater = function (cmd, user, args) {
    setTimeout(function () {
        cmd(user, args);
    }, BOT.rates.interval());
}

BOT.hasTriggerFor = function (message) {
    for (var trigger in BOT.triggers) {
        if (BOT.triggers.hasOwnProperty(trigger)) {
            if (trigger == message.toLowerCase()) return true;
        }
    }
    return false;
}

BOT.getTriggerFor = function (message) {
    return BOT.triggers[message.toLowerCase()];
}

/**
 * Add a replace method to the String prototype
 *
 * @param index
 * @param character
 * @returns {string} with replaced character
 */
String.prototype.replaceAt = function (index, character) {
    return this.substr(0, index) + character + this.substr(index + character.length);
}
<commit_msg>That was just for testing, shouldn't be commented. Whoops.<commit_after>var fs = require('fs');
var chalk = require('chalk');
var RateLimiter = require('limiter').RateLimiter;

BOT.limiter = new RateLimiter(BOT.getRate(), 30 * 1000, true);

BOT.getCommand = function (command) {
    if (BOT.commands.hasOwnProperty(command)) {
        return BOT.commands[command];
    }
    return false;
}

BOT.getCurrentTimestampFormat = function () {
    var datetime = new Date().toISOString().slice(0, 19);
    return "[" + datetime.replaceAt(10, ' ') + "]";
}

BOT.isMe = function (user) {
    return BOT.settings.name.toLowerCase() == user.toLowerCase();
}

BOT.getLogPrefix = function () {
    return chalk.yellow.bold("[" + BOT.settings.botname + "] ");
}

BOT.logInfo = function (message) {
    console.log(BOT.getLogPrefix() + chalk.bgCyan.white.bold(BOT.getCurrentTimestampFormat()) + " " + message);
}

BOT.logError = function (message) {
    console.log(BOT.getLogPrefix() + chalk.bgRed.white.bold(BOT.getCurrentTimestampFormat()) + " " + message);
}

BOT.logSuccess = function (message) {
    console.log(BOT.getLogPrefix() + chalk.bgGreen.white.bold(BOT.getCurrentTimestampFormat()) + " " + message);
}

BOT.logMessage = function (message) {
    BOT.logInfo(message);
    var data = BOT.getCurrentTimestampFormat() + " " + message + "\n";
    fs.appendFile('bot.log', data, function (err) {
        if (err) BOT.logInfo('error: ' + err);
    });
}

BOT.say = function (message, retryIfFailed) {
    BOT.limiter.removeTokens(1, function (err, remaining) {
        if (remaining < 0) {
            if (retryIfFailed) {
                BOT.sayLater(message, true);
                return BOT.logInfo('Trying to send messages too quickly, retrying!');
            } else {
                return BOT.logError('Trying to send messages too quickly, skipping!');
            }
        }

        BOT.logSuccess("Sending message: " + message);
        BOT.client.say(BOT.settings.channel, message);
    });
}

BOT.sayLater = function (message, retryIfFailed) {
    setTimeout(function () {
        BOT.say(message, retryIfFailed);
    }, BOT.rates.interval());
}

BOT.runCommandLater = function (cmd, user, args) {
    setTimeout(function () {
        cmd(user, args);
    }, BOT.rates.interval());
}

BOT.hasTriggerFor = function (message) {
    for (var trigger in BOT.triggers) {
        if (BOT.triggers.hasOwnProperty(trigger)) {
            if (trigger == message.toLowerCase()) return true;
        }
    }
    return false;
}

BOT.getTriggerFor = function (message) {
    return BOT.triggers[message.toLowerCase()];
}

/**
 * Add a replace method to the String prototype
 *
 * @param index
 * @param character
 * @returns {string} with replaced character
 */
String.prototype.replaceAt = function (index, character) {
    return this.substr(0, index) + character + this.substr(index + character.length);
}
<|endoftext|>


<commit_before>/* Main DOM event-handlers */
import {
  switchActiveTab,
  navigateResults,
  injectTabsInList,
  deleteTab,
} from './dom-utils';
import {
  deleteButton,
  searchInput,
  tabList,
} from './constants';
import filterResults from './search';
import { deletedTabsCache } from './caches';

const reduceKeysToObj = obj => (acc, key) => Object.assign({}, acc, {
  [key]: obj[key],
});
const filterEnableKey = key => key !== 'enableFuzzySearch';
export function configureSearch({ getState, loadedTabs }) {
  const { fuzzy } = getState();
  const { enableFuzzySearch } = fuzzy;
  const fuzzySettings = Object.keys(fuzzy)
    .filter(filterEnableKey)
    .reduce(reduceKeysToObj(fuzzy), {});
  const actualSearchSettings = enableFuzzySearch
    ? fuzzySettings
    : Object.assign({}, fuzzySettings, { threshold: 0 });
  return function updateSearchResults(event) {
    const isSearchEmpty = searchInput.value.length === 0;
    // If input is empty hide the button
    if (isSearchEmpty) {
      deleteButton.classList.add('hidden');
    } else {
      deleteButton.classList.remove('hidden');
    }
    const query = event.target.value.trim().toLowerCase();
    const getSearchResults = isSearchEmpty
      ? x => x
      : filterResults(query, actualSearchSettings);
    return Promise.resolve(
      loadedTabs.filter(({ id }) => !deletedTabsCache().includes(id)),
    )
      .then(getSearchResults)
      .then(injectTabsInList);
  };
}

export function clearInput(event) {
  event.target.value = '';
  tabList.childNodes[0].focus();
}

export function handleKeyDown(event) {
  switch (event.key) {
    case 'Control':
      break;
    case 'Delete':
    case 'Backspace':
      if (event.ctrlKey && document.activeElement !== searchInput) {
        const tabId = parseInt(document.activeElement.dataset.id, 10);
        deleteTab(tabId);
      }
      break;
    case 'Tab':
    case 'ArrowDown':
    case 'ArrowUp':
      event.preventDefault();
    case 'ArrowRight':
    case 'ArrowLeft':
      navigateResults(event.key);
      break;
    case 'Enter':
      event.preventDefault();

      // If we're pressing enter from the searchbar
      if (document.activeElement !== searchInput
        && 'id' in tabList.childNodes[0].dataset) {
        switchActiveTab(tabList.childNodes[0].dataset.id);
      } else {
        switchActiveTab(document.activeElement.dataset.id);
      }
      break;
    case 'Escape':
      // This only works in chrome, in firefox it always closes the window
      if (searchInput.value.length === 0) {
        window.close();
      } else {
        clearInput(searchInput);
      }
      break;
    default:
      searchInput.focus();
      break;
  }
}

export function handleTabClick(event) {
  const tabId = parseInt(event.currentTarget.dataset.id, 10);
  if (event.ctrlKey) {
    deleteTab(tabId, true);
  } else {
    switchActiveTab(tabId);
  }
}
<commit_msg>Handle empty queries in filterResults<commit_after>/* Main DOM event-handlers */
import {
  switchActiveTab,
  navigateResults,
  injectTabsInList,
  deleteTab,
} from './utils/dom';
import {
  deleteButton,
  searchInput,
  tabList,
} from './constants';
import filterResults from './search';

const reduceKeysToObj = obj => (acc, key) => Object.assign({}, acc, {
  [key]: obj[key],
});
const filterEnableKey = key => key !== 'enableFuzzySearch';

export function configureSearch({ getState, loadedTabs }) {
  const { fuzzy, general } = getState();
  const { enableFuzzySearch } = fuzzy;
  const fuzzySettings = Object.keys(fuzzy)
    .filter(filterEnableKey)
    .reduce(reduceKeysToObj(fuzzy), {});
  const actualSearchSettings = enableFuzzySearch
    ? fuzzySettings
    : Object.assign({}, fuzzySettings, { threshold: 0 });
  return function updateSearchResults(event = { currentTarget: { value: '' } }) {
    const isSearchEmpty = event.currentTarget.value.length === 0;
    // If input is empty hide the button
    if (isSearchEmpty) {
      deleteButton.classList.add('hidden');
    } else {
      deleteButton.classList.remove('hidden');
    }
    const query = event.currentTarget.value.trim().toLowerCase();
    return Promise.resolve(loadedTabs)
      .then(filterResults(query, actualSearchSettings, general))
      .then(injectTabsInList);
  };
}

export function clearInput(event) {
  event.target.value = '';
  tabList.childNodes[0].focus();
}

export function handleKeyDown(event) {
  switch (event.key) {
    case 'Control':
      break;
    case 'Delete':
    case 'Backspace':
      if (event.ctrlKey && document.activeElement !== searchInput) {
        const tabId = parseInt(document.activeElement.dataset.id, 10);
        deleteTab(tabId);
      }
      break;
    case 'Tab':
    case 'ArrowDown':
    case 'ArrowUp':
      event.preventDefault();
    case 'ArrowRight':
    case 'ArrowLeft':
      navigateResults(event.key);
      break;
    case 'Enter':
      event.preventDefault();

      // If we're pressing enter from the searchbar
      if (document.activeElement !== searchInput
        && 'id' in tabList.childNodes[0].dataset) {
        switchActiveTab(tabList.childNodes[0].dataset.id);
      } else {
        switchActiveTab(document.activeElement.dataset.id);
      }
      break;
    case 'Escape':
      // This only works in chrome, in firefox it always closes the window
      if (searchInput.value.length === 0) {
        window.close();
      } else {
        clearInput(searchInput);
      }
      break;
    default:
      searchInput.focus();
      break;
  }
}

export function handleTabClick(event) {
  const { id, type } = event.currentTarget.dataset;
  const tabId = parseInt(event.currentTarget.dataset.id, 10);
  if (event.ctrlKey) {
    deleteTab(tabId, true);
  } else {
    switchActiveTab(tabId);
  }
}
<|endoftext|>


<commit_before>
  basis.require('basis.data');
  basis.require('basis.data.dataset');

 /**
  * @namespace basis.data.dataset
  */

  var namespace = this.path;

  //
  // import names
  //

  var Class = basis.Class;
  var DataObject = basis.data.Object;
  var Slot = basis.data.Slot;
  var SourceDataset = basis.data.dataset.SourceDataset;

  var $undef = basis.fn.$undef;
  var $true = basis.fn.$true;
  var defaultRule = basis.getter($undef);

  //
  // main part
  //

 /**
  * Returns delta object
  * @param {Array.<basis.data.DataObject>} inserted
  * @param {Array.<basis.data.DataObject>} deleted
  * @return {object|boolean}
  */
  function getDelta(inserted, deleted){
    var delta = {};
    var result;

    if (inserted && inserted.length)
      result = delta.inserted = inserted;

    if (deleted && deleted.length)
      result = delta.deleted = deleted;

    if (result)
      return delta;
  }

  var VectorFn = basis.Class(null, { extendConstructor_: true });

  var Count = VectorFn.subclass({
    className: namespace + '.Count',
    add: function(curValue, value){
      return curValue + !!value;
    },
    remove: function(curValue, value){
      return curValue - !!value;
    },
    update: function(curValue, oldValue, newValue){
      return curValue - !!oldValue + !!newValue;
    }
  });

  var Sum = VectorFn.subclass({
    className: namespace + '.Sum',
    add: function(curValue, value){
      return curValue + value;
    },
    remove: function(curValue, value){
      return curValue - value;
    },
    update: function(curValue, oldValue, newValue){
      return curValue - oldValue + newValue;
    }
  });

  var fnPreset_ = {};
  function FnConstructor(BaseClass, getter, events){
    if (!Class.isClass(BaseClass) || !BaseClass.isSubclassOf(VectorFn))
      throw 'Wrong class for index constructor';

    getter = basis.getter(getter);
    events = events || 'update';

    if (typeof events != 'string')
      throw 'Events must be a event names space separated string';

    events = events.qw().sort();

    var fnId = [BaseClass.basisClassId_, getter.basisGetterId_, events].join('_');
    var fnConstructor = fnPreset_[fnId];

    if (fnConstructor)
      return fnConstructor;

    //
    // Create new constructor
    //

    var eventMap = {};
    for (var i = 0; i < events.length; i++)
      eventMap[events[i]] = true;

    return fnPreset_[fnId] = new BaseClass({
      updateEvents: eventMap,
      valueGetter: getter
    });
  }

  function fnConstructor(FnClass){
    return function(getter, events){
      return new FnConstructor(FnClass, getter || $true, events);
    };
  }

  var sum = fnConstructor(Sum);
  var count = fnConstructor(Count);

  //////////
  //
  //

  function recalcSourceObject(dataset, sourceObjectInfo){
    var calcs = dataset.calcs;
    var updateData = {};
    var member = dataset.memberMap_[sourceObjectInfo.key];
    var item = member.item;

    for (var calcName in calcs)
    {
      var calc = calcs[calcName];
      var value = calc.valueGetter(sourceObjectInfo.object);
      updateData[calcName] = calc.update(item.data[calcName] || 0, sourceObjectInfo.values[calcName], value, member);
      sourceObjectInfo.values[calcName] = value;
    }

    item.update(updateData); // TODO: store items and update aside
  }

  function changeSourceObjectKey(dataset, newKey, sourceObjectInfo, recalc){
    var objectId = sourceObjectInfo.object.basisObjectId;
    var oldMember = dataset.memberMap_[sourceObjectInfo.key];
    var newMember = dataset.memberMap_[newKey];
    var calcs = dataset.calcs;
    var inserted;
    var deleted;

    //
    // remove from old member
    //
    var oldItem = oldMember.item;

    // delete references
    delete oldMember[objectId];

    // process member
    if (--oldMember.count == 0)
    {
      // delete
      delete dataset.memberMap_[sourceObjectInfo.key];
      deleted = oldItem;
    }
    else
    {
      // update item
      var updateData = {};

      for (var calcName in calcs)                  // cur value            what remove                 count of values
        updateData[calcName] = calcs[calcName].remove(oldItem.data[calcName], sourceObjectInfo.values[calcName], oldMember);

      oldItem.update(updateData); // TODO: store items and update aside
    }

    //
    // recalc
    //
    if (recalc)
      for (var calcName in calcs)
        sourceObjectInfo.values[calcName] = calcs[calcName].valueGetter(sourceObjectInfo.object);

    //
    // add create or update new member
    //

    var newItem;
    // create member if necessary
    if (!newMember)
    {
      newItem = new Item({
        key: newKey
      });
      newMember = {
        count: 0,
        item: newItem
      };
      dataset.memberMap_[newKey] = newMember;
      inserted = newItem;

      if (dataset.slots_[newKey])
        dataset.slots_[newKey].setDelegate(newItem);
    }
    else
      newItem = newMember.item;

    newMember[objectId] = sourceObjectInfo;
    newMember.count++;

    var updateData = {};

    for (var calcName in calcs)               // cur value                    what remove         count of values
      updateData[calcName] = calcs[calcName].add(newItem.data[calcName] || 0, sourceObjectInfo.values[calcName], newMember);

    newItem.update(updateData); // TODO: store items and update aside

    // update key

    newItem.key = newKey;
    sourceObjectInfo.key = newKey;

    //
    return {
      inserted: inserted,
      deleted: deleted
    };
  }

  var VECTOR_ITEM_HANDLER = {
    update: function(object){
      var sourceObjectInfo = this.sourceMap_[object.basisObjectId];
      var key = this.rule(object);

      if (sourceObjectInfo.key !== key)
      {
        var delta = changeSourceObjectKey(this, key, sourceObjectInfo, true);
        if (delta = getDelta(delta.inserted && [delta.inserted], delta.deleted && [delta.deleted]))
          this.event_datasetChanged(delta);
      }
      else
        recalcSourceObject(this, sourceObjectInfo);
    }
  };

  var VECTOR_SOURCE_HANDLER = {
    datasetChanged: function(sender, delta){
      var sourceInserted = delta.inserted;
      var sourceDeleted = delta.deleted;
      var memberMap = this.memberMap_;
      var sourceMap = this.sourceMap_;
      var calcs = this.calcs;
      var inserted = [];
      var deleted = [];

      if (sourceInserted)
        for (var i = 0, object; object = sourceInserted[i]; i++)
        {
          var objectId = object.basisObjectId;
          var key = this.rule(object);
          var member = this.memberMap_[key];
          var item;

          // create member if necessary
          if (!member)
          {
            item = new Item({
              key: key
            });
            member = {
              count: 0,
              item: item
            };
            this.memberMap_[key] = member;
            inserted.push(item);

            if (this.slots_[key])
              this.slots_[key].setDelegate(item);
          }
          else
            item = member.item;

          // create source object and registrate it
          var sourceObjectInfo = {
            key: key,
            object: object,
            values: {}
          };

          sourceMap[objectId] = sourceObjectInfo;

          member[objectId] = sourceObjectInfo;
          member.count++;

          // add handler
          object.addHandler(VECTOR_ITEM_HANDLER, this);

          var updateData = {};
          for (var calcName in calcs)
          {
            var calc = calcs[calcName];
            var value = calc.valueGetter(object);
            sourceObjectInfo.values[calcName] = value;
                                    // cur value              what remove         count of values
            updateData[calcName] = calc.add(item.data[calcName] || 0, value, member);
          }

          item.update(updateData); // TODO: store items and update aside
        }

      if (sourceDeleted)
        for (var i = 0, object; object = sourceDeleted[i]; i++)
        {
          var objectId = object.basisObjectId;
          var sourceObjectInfo = sourceMap[objectId];
          var member = memberMap[sourceObjectInfo.key];
          var item = member.item;

          // delete references
          delete sourceMap[objectId];
          delete member[objectId];

          // remove handler
          object.removeHandler(VECTOR_ITEM_HANDLER, this);

          // process member
          if (--member.count == 0)
          {
            // delete
            delete memberMap[sourceObjectInfo.key];
            deleted.push(item);

            if (this.slots_[item.key])
            {
              // update item
              var updateData = {};

              for (var calcName in calcs)          // cur value            what remove                 count of values
                updateData[calcName] = calcs[calcName].remove(item.data[calcName], sourceObjectInfo.values[calcName], member);

              item.update(updateData); // TODO: store items and update aside
            }
          }
          else
          {
            // update item
            var updateData = {};

            for (var calcName in calcs)          // cur value            what remove                 count of values
              updateData[calcName] = calcs[calcName].remove(item.data[calcName], sourceObjectInfo.values[calcName], member);

            item.update(updateData); // TODO: store items and update aside
          }
        }

      // fire event
      if (delta = getDelta(inserted, deleted))
        this.event_datasetChanged(delta);
    }
  };

  var Item = Class(DataObject, {
    className: namespace + '.Item',
    isTarget: true,
    key: undefined
  });

  var Vector = Class(SourceDataset, {
    className: namespace + '.Vector',
   /**
    * @type {Object}
    */
    calcs: null,
    slots_: null,

    rule: defaultRule,

    event_datasetChanged: function(delta){
      SourceDataset.prototype.event_datasetChanged.call(this, delta);

      // destroy deleted
      if (delta.deleted)
        delta.deleted.forEach(function(item){
          item.destroy();
        });
    },

    listen: {
      source: VECTOR_SOURCE_HANDLER
    },

   /**
    * @inheritDoc
    */
    init: function(){
      // process calcs
      var calcs = this.calcs;
      this.calcs = {};
      for (var key in calcs)
      {
        var calc = calcs[key];
        if (calc instanceof VectorFn == false)
          calc = sum(calc);
        this.calcs[key] = calc;
      }

      this.slots_ = {};

      // inherit
      SourceDataset.prototype.init.call(this);
    },

    get: function(key){
      var member = this.memberMap_[key];
      if (member)
        return member.item;
    },
    getSlot: function(key){
      var slot = this.slots_[key];
      if (!slot)
      {
        slot = new Slot({
          key: key,
          delegate: this.get(key)
        });
        this.slots_[key] = slot;
      }
      return slot;
    },

    setRule: function(rule){
      if (typeof rule != 'function')
        rule = defaultRule;

      if (this.rule !== rule)
      {
        this.rule = rule;
        this.applyRule();
      }
    },

    setCalc: function(name, newCalc){
      if (newCalc && newCalc instanceof VectorFn == false)
        newCalc = sum(newCalc);

	    var oldCalc = this.calcs[name];
      if (oldCalc != newCalc)
      {
        var sourceMap = this.sourceMap_;

  	    if (newCalc)
  	    {
          this.calcs[name] = newCalc;

          var newValues = {};
          for (var objectId in sourceMap)
          {
            var sourceObjectInfo = sourceMap[objectId];
            var key = sourceObjectInfo.key;
            var member = this.memberMap_[key];

            if (!newValues[key])
            {
              newValues[key] = {
                item: member.item,
                value: 0
              }
            }

            sourceObjectInfo.values[name] = newCalc.valueGetter(sourceObjectInfo.object);
            newValues[key].value = newCalc.add(newValues[key].value || 0, sourceObjectInfo.values[name], member);
          }

          var updateData = {};
          for (var key in newValues)
          {
            updateData[name] = newValues[key].value;
            newValues[key].item.update(updateData);
          }
        }
        else
        {
          delete this.calcs[name];

          for (var objectId in sourceMap)
            delete sourceMap[objectId].values[name];

          var resetData = {};
          resetData[name] = undefined;
          for (var i = 0, item, items = this.getItems(); item = items[i]; i++)
            item.update(resetData);
        }
      }
    },

    applyRule: function(scope){
      var inserted = [];
      var deleted = [];
      var delta;

     if (!scope)
       scope = this.sourceMap_;

      for (var objectId in scope)
      {
        var sourceObjectInfo = scope[objectId];
        var newKey = this.rule(sourceObjectInfo.object);
        if (newKey !== sourceObjectInfo.key)
        {
          delta = changeSourceObjectKey(this, newKey, sourceObjectInfo, true);
          if (delta.inserted)
            inserted.push(delta.inserted);
          if (delta.deleted)
            deleted.push(delta.deleted);
        }
        else
          recalcSourceObject(this, sourceObjectInfo);
      }

      if (delta = getDelta(inserted, deleted))
        this.event_datasetChanged(delta);
    }
  });

  module.exports = {
    Vector: Vector,

    count: count,
    sum: sum
  };
<commit_msg>avg function implemented<commit_after>
  basis.require('basis.data');
  basis.require('basis.data.dataset');

 /**
  * @namespace basis.data.dataset
  */

  var namespace = this.path;

  //
  // import names
  //

  var Class = basis.Class;
  var DataObject = basis.data.Object;
  var Slot = basis.data.Slot;
  var SourceDataset = basis.data.dataset.SourceDataset;

  var $undef = basis.fn.$undef;
  var $true = basis.fn.$true;
  var defaultRule = basis.getter($undef);

  //
  // main part
  //

 /**
  * Returns delta object
  * @param {Array.<basis.data.DataObject>} inserted
  * @param {Array.<basis.data.DataObject>} deleted
  * @return {object|boolean}
  */
  function getDelta(inserted, deleted){
    var delta = {};
    var result;

    if (inserted && inserted.length)
      result = delta.inserted = inserted;

    if (deleted && deleted.length)
      result = delta.deleted = deleted;

    if (result)
      return delta;
  }

  var VectorFn = basis.Class(null, { extendConstructor_: true });

  var Count = VectorFn.subclass({
    className: namespace + '.Count',
    add: function(curValue, value){
      return curValue + !!value;
    },
    remove: function(curValue, value){
      return curValue - !!value;
    },
    update: function(curValue, oldValue, newValue){
      return curValue - !!oldValue + !!newValue;
    }
  });

  var Sum = VectorFn.subclass({
    className: namespace + '.Sum',
    add: function(curValue, value){
      return curValue + value;
    },
    remove: function(curValue, value){
      return curValue - value;
    },
    update: function(curValue, oldValue, newValue){
      return curValue - oldValue + newValue;
    }
  });

  var Avg = VectorFn.subclass({
    className: namespace + '.Avg',
    add: function(curValue, value, member){
      return (curValue * (member.count - 1) + (value || 0)) / member.count;
    },
    remove: function(curValue, value, member){
      return (curValue * (member.count + 1) - (value || 0)) / (member.count || 1);
    },
    update: function(curValue, oldValue, newValue, member){
      return ((curValue * member.count) - (oldValue || 0) + (newValue || 0)) / member.count;
    }
  });

  var fnPreset_ = {};
  function FnConstructor(BaseClass, getter, events){
    if (!Class.isClass(BaseClass) || !BaseClass.isSubclassOf(VectorFn))
      throw 'Wrong class for index constructor';

    getter = basis.getter(getter);
    events = events || 'update';

    if (typeof events != 'string')
      throw 'Events must be a event names space separated string';

    events = events.qw().sort();

    var fnId = [BaseClass.basisClassId_, getter.basisGetterId_, events].join('_');
    var fnConstructor = fnPreset_[fnId];

    if (fnConstructor)
      return fnConstructor;

    //
    // Create new constructor
    //

    var eventMap = {};
    for (var i = 0; i < events.length; i++)
      eventMap[events[i]] = true;

    return fnPreset_[fnId] = new BaseClass({
      updateEvents: eventMap,
      valueGetter: getter
    });
  }

  function fnConstructor(FnClass){
    return function(getter, events){
      return new FnConstructor(FnClass, getter || $true, events);
    };
  }

  var sum = fnConstructor(Sum);
  var count = fnConstructor(Count);
  var avg = fnConstructor(Avg);

  //////////
  //
  //

  function recalcSourceObject(dataset, sourceObjectInfo){
    var calcs = dataset.calcs;
    var updateData = {};
    var member = dataset.memberMap_[sourceObjectInfo.key];
    var item = member.item;

    for (var calcName in calcs)
    {
      var calc = calcs[calcName];
      var value = calc.valueGetter(sourceObjectInfo.object);
      updateData[calcName] = calc.update(item.data[calcName] || 0, sourceObjectInfo.values[calcName], value, member);
      sourceObjectInfo.values[calcName] = value;
    }

    item.update(updateData); // TODO: store items and update aside
  }

  function changeSourceObjectKey(dataset, newKey, sourceObjectInfo, recalc){
    var objectId = sourceObjectInfo.object.basisObjectId;
    var oldMember = dataset.memberMap_[sourceObjectInfo.key];
    var newMember = dataset.memberMap_[newKey];
    var calcs = dataset.calcs;
    var inserted;
    var deleted;

    //
    // remove from old member
    //
    var oldItem = oldMember.item;

    // delete references
    delete oldMember[objectId];

    // process member
    if (--oldMember.count == 0)
    {
      // delete
      delete dataset.memberMap_[sourceObjectInfo.key];
      deleted = oldItem;
    }
    else
    {
      // update item
      var updateData = {};

      for (var calcName in calcs)                  // cur value            what remove                 count of values
        updateData[calcName] = calcs[calcName].remove(oldItem.data[calcName], sourceObjectInfo.values[calcName], oldMember);

      oldItem.update(updateData); // TODO: store items and update aside
    }

    //
    // recalc
    //
    if (recalc)
      for (var calcName in calcs)
        sourceObjectInfo.values[calcName] = calcs[calcName].valueGetter(sourceObjectInfo.object);

    //
    // add create or update new member
    //

    var newItem;
    // create member if necessary
    if (!newMember)
    {
      newItem = new Item({
        key: newKey
      });
      newMember = {
        count: 0,
        item: newItem
      };
      dataset.memberMap_[newKey] = newMember;
      inserted = newItem;

      if (dataset.slots_[newKey])
        dataset.slots_[newKey].setDelegate(newItem);
    }
    else
      newItem = newMember.item;

    newMember[objectId] = sourceObjectInfo;
    newMember.count++;

    var updateData = {};

    for (var calcName in calcs)               // cur value                    what remove         count of values
      updateData[calcName] = calcs[calcName].add(newItem.data[calcName] || 0, sourceObjectInfo.values[calcName], newMember);

    newItem.update(updateData); // TODO: store items and update aside

    // update key

    newItem.key = newKey;
    sourceObjectInfo.key = newKey;

    //
    return {
      inserted: inserted,
      deleted: deleted
    };
  }

  var VECTOR_ITEM_HANDLER = {
    update: function(object){
      var sourceObjectInfo = this.sourceMap_[object.basisObjectId];
      var key = this.rule(object);

      if (sourceObjectInfo.key !== key)
      {
        var delta = changeSourceObjectKey(this, key, sourceObjectInfo, true);
        if (delta = getDelta(delta.inserted && [delta.inserted], delta.deleted && [delta.deleted]))
          this.event_datasetChanged(delta);
      }
      else
        recalcSourceObject(this, sourceObjectInfo);
    }
  };

  var VECTOR_SOURCE_HANDLER = {
    datasetChanged: function(sender, delta){
      var sourceInserted = delta.inserted;
      var sourceDeleted = delta.deleted;
      var memberMap = this.memberMap_;
      var sourceMap = this.sourceMap_;
      var calcs = this.calcs;
      var inserted = [];
      var deleted = [];

      if (sourceInserted)
        for (var i = 0, object; object = sourceInserted[i]; i++)
        {
          var objectId = object.basisObjectId;
          var key = this.rule(object);
          var member = this.memberMap_[key];
          var item;

          // create member if necessary
          if (!member)
          {
            item = new Item({
              key: key
            });
            member = {
              count: 0,
              item: item
            };
            this.memberMap_[key] = member;
            inserted.push(item);

            if (this.slots_[key])
              this.slots_[key].setDelegate(item);
          }
          else
            item = member.item;

          // create source object and registrate it
          var sourceObjectInfo = {
            key: key,
            object: object,
            values: {}
          };

          sourceMap[objectId] = sourceObjectInfo;

          member[objectId] = sourceObjectInfo;
          member.count++;

          // add handler
          object.addHandler(VECTOR_ITEM_HANDLER, this);

          var updateData = {};
          for (var calcName in calcs)
          {
            var calc = calcs[calcName];
            var value = calc.valueGetter(object);
            sourceObjectInfo.values[calcName] = value;
                                    // cur value              what remove         count of values
            updateData[calcName] = calc.add(item.data[calcName] || 0, value, member);
          }

          item.update(updateData); // TODO: store items and update aside
        }

      if (sourceDeleted)
        for (var i = 0, object; object = sourceDeleted[i]; i++)
        {
          var objectId = object.basisObjectId;
          var sourceObjectInfo = sourceMap[objectId];
          var member = memberMap[sourceObjectInfo.key];
          var item = member.item;

          // delete references
          delete sourceMap[objectId];
          delete member[objectId];

          // remove handler
          object.removeHandler(VECTOR_ITEM_HANDLER, this);

          // process member
          if (--member.count == 0)
          {
            // delete
            delete memberMap[sourceObjectInfo.key];
            deleted.push(item);

            if (this.slots_[item.key])
            {
              // update item
              var updateData = {};

              for (var calcName in calcs)          // cur value            what remove                 count of values
                updateData[calcName] = calcs[calcName].remove(item.data[calcName], sourceObjectInfo.values[calcName], member);

              item.update(updateData); // TODO: store items and update aside
            }
          }
          else
          {
            // update item
            var updateData = {};

            for (var calcName in calcs)          // cur value            what remove                 count of values
              updateData[calcName] = calcs[calcName].remove(item.data[calcName], sourceObjectInfo.values[calcName], member);

            item.update(updateData); // TODO: store items and update aside
          }
        }

      // fire event
      if (delta = getDelta(inserted, deleted))
        this.event_datasetChanged(delta);
    }
  };

  var Item = Class(DataObject, {
    className: namespace + '.Item',
    isTarget: true,
    key: undefined
  });

  var Vector = Class(SourceDataset, {
    className: namespace + '.Vector',
   /**
    * @type {Object}
    */
    calcs: null,
    slots_: null,

    rule: defaultRule,

    event_datasetChanged: function(delta){
      SourceDataset.prototype.event_datasetChanged.call(this, delta);

      // destroy deleted
      if (delta.deleted)
        delta.deleted.forEach(function(item){
          item.destroy();
        });
    },

    listen: {
      source: VECTOR_SOURCE_HANDLER
    },

   /**
    * @inheritDoc
    */
    init: function(){
      // process calcs
      var calcs = this.calcs;
      this.calcs = {};
      for (var key in calcs)
      {
        var calc = calcs[key];
        if (calc instanceof VectorFn == false)
          calc = sum(calc);
        this.calcs[key] = calc;
      }

      this.slots_ = {};

      // inherit
      SourceDataset.prototype.init.call(this);
    },

    get: function(key){
      var member = this.memberMap_[key];
      if (member)
        return member.item;
    },
    getSlot: function(key){
      var slot = this.slots_[key];
      if (!slot)
      {
        slot = new Slot({
          key: key,
          delegate: this.get(key)
        });
        this.slots_[key] = slot;
      }
      return slot;
    },

    setRule: function(rule){
      if (typeof rule != 'function')
        rule = defaultRule;

      if (this.rule !== rule)
      {
        this.rule = rule;
        this.applyRule();
      }
    },

    setCalc: function(name, newCalc){
      if (newCalc && newCalc instanceof VectorFn == false)
        newCalc = sum(newCalc);

	    var oldCalc = this.calcs[name];
      if (oldCalc != newCalc)
      {
        var sourceMap = this.sourceMap_;

  	    if (newCalc)
  	    {
          this.calcs[name] = newCalc;

          var newValues = {};
          for (var objectId in sourceMap)
          {
            var sourceObjectInfo = sourceMap[objectId];
            var key = sourceObjectInfo.key;
            var member = this.memberMap_[key];

            if (!newValues[key])
            {
              newValues[key] = {
                item: member.item,
                count: 0,
                value: 0
              }
            }

            member.count = (newValues[key] += 1);

            sourceObjectInfo.values[name] = newCalc.valueGetter(sourceObjectInfo.object);
            newValues[key].value = newCalc.add(newValues[key].value || 0, sourceObjectInfo.values[name], member);
          }

          var updateData = {};
          for (var key in newValues)
          {
            updateData[name] = newValues[key].value;
            newValues[key].item.update(updateData);
          }
        }
        else
        {
          delete this.calcs[name];

          for (var objectId in sourceMap)
            delete sourceMap[objectId].values[name];

          var resetData = {};
          resetData[name] = undefined;
          for (var i = 0, item, items = this.getItems(); item = items[i]; i++)
            item.update(resetData);
        }
      }
    },

    applyRule: function(scope){
      var inserted = [];
      var deleted = [];
      var delta;

     if (!scope)
       scope = this.sourceMap_;

      for (var objectId in scope)
      {
        var sourceObjectInfo = scope[objectId];
        var newKey = this.rule(sourceObjectInfo.object);
        if (newKey !== sourceObjectInfo.key)
        {
          delta = changeSourceObjectKey(this, newKey, sourceObjectInfo, true);
          if (delta.inserted)
            inserted.push(delta.inserted);
          if (delta.deleted)
            deleted.push(delta.deleted);
        }
        else
          recalcSourceObject(this, sourceObjectInfo);
      }

      if (delta = getDelta(inserted, deleted))
        this.event_datasetChanged(delta);
    }
  });

  module.exports = {
    Vector: Vector,

    count: count,
    sum: sum,
    avg: avg
  };
<|endoftext|>


<commit_before>// Include some plugins and stuff
var gulp = require('gulp');
var $ = require("gulp-load-plugins")();
var each = require('through');
var lazypipe = require('lazypipe');

var latestSlides = [];
// Any reusable paths / globs go here; trying to keep things DRY
var paths = {};
paths.source = './slides/src/';
paths.imagesDir = paths.source + 'images/';
paths.images = [paths.imagesDir + '*.png', paths.imagesDir + '*.jpg'];
paths.slides = './slides/*.md';
paths.scriptsDir = paths.source + 'scripts/';
paths.scripts = paths.scriptsDir + '*.coffee';
paths.rootScript = paths.scriptsDir + 'index.coffee';
paths.stylesDir = paths.source + 'styles/';
paths.styles = paths.stylesDir + '*.less';
paths.rootStylesheet = paths.stylesDir + 'index.less';
paths.templates = paths.source + 'templates/*.jade';

paths.output = './output/';
paths.outputHtmlDir = './';
paths.outputHtml = paths.outputHtmlDir + '*.html';
paths.outputImageDir = paths.output + 'images/';
paths.outputScriptsDir = paths.output + 'scripts/';

/*
* Resusable pipelines
*/
var pipes = {
    minifyAndStoreScripts: lazypipe()
//        .pipe(minifyJs)
        .pipe(gulp.dest, paths.outputScriptsDir)
};

/*
* Main tasks
*/

gulp.task('default', ['compile']);

gulp.task('compile', ['images', 'scripts', 'styles', 'templates']);

gulp.task('watch', ['compile'], function() {
    gulp.watch(paths.images, ['images']);
    gulp.watch(paths.scripts, ['scripts']);
    gulp.watch(paths.styles, ['styles']);
    gulp.watch([paths.slides, paths.templates], ['templates']);
});

gulp.task('clean', function(done){
	gulp.src(paths.output)
        .pipe($.clean())
        .on('end', done);
});

gulp.task('validate', function(done){
	gulp.src(paths.outputHtml)
        .pipe($.w3cjs())
        .on('end', done);
});

/*
* Secondary level tasks
*/

gulp.task('images', function(done){
	gulp.src(paths.images)
	    .pipe(gulp.dest(paths.outputImageDir))
        .on('end', done);
});

gulp.task('parse-slides', function(done){
	latestSlides = []; // reset

	gulp.src(paths.slides)
        .pipe($.frontMatter())
        .pipe($.markdown())
        .pipe(each(function(slide){
            latestSlides.push(slide);
        }))
        .on('end', done);
});

gulp.task('scripts', ['scripts-first-party', 'scripts-third-party']);

gulp.task('scripts-first-party', function(done){
	gulp.src(paths.rootScript, {read: false})
        .pipe($.browserify({
                transform: ['coffeeify'],
                extensions: ['.coffee']
            }))
        .pipe($.rename('index.js'))
        .pipe(pipes.minifyAndStoreScripts())
        .on('end', done);
});

gulp.task('scripts-third-party', function(done){
	$.bowerFiles()
        .pipe($.concat('third-party.js'))
        .pipe(pipes.minifyAndStoreScripts())
        .on('end', done);
});

gulp.task('templates', ['parse-slides'], function(done) {
    gulp.src(paths.templates)
        .pipe($.jade({
            locals: {
                slides: latestSlides
            }
        }))
        .pipe(gulp.dest(paths.outputHtmlDir))
        .on('end', done);
});

gulp.task('styles', function(done){
	gulp.src(paths.rootStylesheet)
        .pipe($.less())
        .pipe($.autoprefixer('last 2 versions'))
        .pipe(gulp.dest(paths.output))
        .on('end', done);
});<commit_msg>Throws error if gulp-bower-files fails<commit_after>// Include some plugins and stuff
var gulp = require('gulp');
var $ = require("gulp-load-plugins")();
var each = require('through');
var lazypipe = require('lazypipe');

var latestSlides = [];
// Any reusable paths / globs go here; trying to keep things DRY
var paths = {};
paths.source = './slides/src/';
paths.imagesDir = paths.source + 'images/';
paths.images = [paths.imagesDir + '*.png', paths.imagesDir + '*.jpg'];
paths.slides = './slides/*.md';
paths.scriptsDir = paths.source + 'scripts/';
paths.scripts = paths.scriptsDir + '*.coffee';
paths.rootScript = paths.scriptsDir + 'index.coffee';
paths.stylesDir = paths.source + 'styles/';
paths.styles = paths.stylesDir + '*.less';
paths.rootStylesheet = paths.stylesDir + 'index.less';
paths.templates = paths.source + 'templates/*.jade';

paths.output = './output/';
paths.outputHtmlDir = './';
paths.outputHtml = paths.outputHtmlDir + '*.html';
paths.outputImageDir = paths.output + 'images/';
paths.outputScriptsDir = paths.output + 'scripts/';

/*
* Resusable pipelines
*/
var pipes = {
    minifyAndStoreScripts: lazypipe()
//        .pipe(minifyJs)
        .pipe(gulp.dest, paths.outputScriptsDir)
};

/*
* Main tasks
*/

gulp.task('default', ['compile']);

gulp.task('compile', ['images', 'scripts', 'styles', 'templates']);

gulp.task('watch', ['compile'], function() {
    gulp.watch(paths.images, ['images']);
    gulp.watch(paths.scripts, ['scripts']);
    gulp.watch(paths.styles, ['styles']);
    gulp.watch([paths.slides, paths.templates], ['templates']);
});

gulp.task('clean', function(done){
	gulp.src(paths.output)
        .pipe($.clean())
        .on('end', done);
});

gulp.task('validate', function(done){
	gulp.src(paths.outputHtml)
        .pipe($.w3cjs())
        .on('end', done);
});

/*
* Secondary level tasks
*/

gulp.task('images', function(done){
	gulp.src(paths.images)
	    .pipe(gulp.dest(paths.outputImageDir))
        .on('end', done);
});

gulp.task('parse-slides', function(done){
	latestSlides = []; // reset

	gulp.src(paths.slides)
        .pipe($.frontMatter())
        .pipe($.markdown())
        .pipe(each(function(slide){
            latestSlides.push(slide);
        }))
        .on('end', done);
});

gulp.task('scripts', ['scripts-first-party', 'scripts-third-party']);

gulp.task('scripts-first-party', function(done){
	gulp.src(paths.rootScript, {read: false})
        .pipe($.browserify({
                transform: ['coffeeify'],
                extensions: ['.coffee']
            }))
        .pipe($.rename('index.js'))
        .pipe(pipes.minifyAndStoreScripts())
        .on('end', done);
});

gulp.task('scripts-third-party', function(done){
	$.bowerFiles()
        .pipe($.concat('third-party.js'))
        .pipe(pipes.minifyAndStoreScripts())
        .on('error', function(err){
            exit(err);
        })
        .on('end', done);
});

gulp.task('templates', ['parse-slides'], function(done) {
    gulp.src(paths.templates)
        .pipe($.jade({
            locals: {
                slides: latestSlides
            }
        }))
        .pipe(gulp.dest(paths.outputHtmlDir))
        .on('end', done);
});

gulp.task('styles', function(done){
	gulp.src(paths.rootStylesheet)
        .pipe($.less())
        .pipe($.autoprefixer('last 2 versions'))
        .pipe(gulp.dest(paths.output))
        .on('end', done);
});<|endoftext|>


<commit_before>// The HistreeStorage class has methods for accessing the the stored histrees
class HistreeStorage {

  constructor() {
    // The rootsDict is where we will store
    this.rootsDict = {
      // tabId: tree
    };
  }

  insertNodeIntoTreeByTabId(node, tabId) {
    // Ensure that the node has a children array
    node.children = node.children || [];

    // If this tab does not yet have a tree
    if (!(tabId in this.rootsDict)) {
      // Create a new tree for the tab
      this.rootsDict[tabId] = {
        root: node,
        currentNode: node
      }
    }
    // Else if the tab already has a tree
    else {
      console.log('this.rootsDict', this.rootsDict);
      var visitedNode = treeHasVisited(this.rootsDict[tabId].root, node);

      // If the node is already in the tree
      if (visitedNode) {
        // Set the node to be the current node
        this.rootsDict[tabId].currentNode = visitedNode;
      }
      else {
        // Else add the node as a child of the current node
        this.rootsDict[tabId].currentNode.children.push(node);
        // and set the current node to the new page
        this.rootsDict[tabId].currentNode = node;
      }
    }
  }

  getHistreeForTabId(tabId) {
    return this.rootsDict[tabId];
  }
}
<commit_msg>Remove console log<commit_after>// The HistreeStorage class has methods for accessing the the stored histrees
class HistreeStorage {

  constructor() {
    // The rootsDict is where we will store
    this.rootsDict = {
      // tabId: tree
    };
  }

  insertNodeIntoTreeByTabId(node, tabId) {
    // Ensure that the node has a children array
    node.children = node.children || [];

    // If this tab does not yet have a tree
    if (!(tabId in this.rootsDict)) {
      // Create a new tree for the tab
      this.rootsDict[tabId] = {
        root: node,
        currentNode: node
      }
    }
    // Else if the tab already has a tree
    else {
      // Check to see if the node is already in the tree
      var visitedNode = treeHasVisited(this.rootsDict[tabId].root, node);

      // If the node is already in the tree
      if (visitedNode) {
        // Set the node to be the current node
        this.rootsDict[tabId].currentNode = visitedNode;
      }
      else {
        // Else add the node as a child of the current node
        this.rootsDict[tabId].currentNode.children.push(node);
        // and set the current node to the new page
        this.rootsDict[tabId].currentNode = node;
      }
    }
  }

  getHistreeForTabId(tabId) {
    return this.rootsDict[tabId];
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Lazily required module dependencies
 */

var utils = require('lazy-cache')(require);
var fn = require;

require = utils;
require('arr-flatten', 'flatten');
require('to-object-path', 'toPath');
require('collection-visit', 'visit');
require('get-value', 'get');
require('set-value', 'set');
require('has-value', 'has');
require('kind-of', 'typeOf');
require = fn;

/**
 * Expose `utils` modules
 */

module.exports = utils;
<commit_msg>adds define-property<commit_after>'use strict';

/**
 * Lazily required module dependencies
 */

var utils = require('lazy-cache')(require);
var fn = require;

require = utils;
require('arr-flatten', 'flatten');
require('to-object-path', 'toPath');
require('collection-visit', 'visit');
require('define-property', 'define');
require('get-value', 'get');
require('set-value', 'set');
require('has-value', 'has');
require('kind-of', 'typeOf');
require = fn;

/**
 * Expose `utils` modules
 */

module.exports = utils;
<|endoftext|>


<commit_before>/**
 * Merge object b with object a.
 *
 * var a = { foo: 'bar' }
 *   , b = { foo: 'quux', bar: 'baz' };
 *
 * merge(a, b);
 * // => { foo: 'quux', bar: 'baz' }
 *
 * merge(a, b, true);
 * // => { foo: 'bar', bar: 'baz' }
 *
 * @param {Object} a
 * @param {Object} b
 * @param {Boolean} [noforce] Optionally, don't overwrite any existing keys in a found in b
 * @return {Object}
 */
function merge (a, b, noforce) {
  if (a && b && a === Object(a) && b === Object(b)) {
    for (var key in b) {
      if (noforce) {
        if (!a.hasOwnProperty(key)) a[key] = b[key];
      } else {
        a[key] = b[key]
      }
    }
  }
  return a;
};
exports.merge = merge;

/**
 * Create an array containing the unique members of an array.
 *
 * var array = ['a', 'b', 1, 2, 'a', 3 ];
 *
 * unique(array);
 * // => ['b', 1, 2, 'a', 3 ]
 *
 * @param {Array} array
 * @return {Array}
 */
function unique (array) {
  var a = [];
  var l = array.length;
  for (var i=0; i<l; i++) {
    for (var j=i+1; j<l; j++) {
      // If array[i] is found later in the array
      if (array[i] === array[j])
        j = ++i;
    }
    a.push(array[i]);
  }
  return a;
};
exports.unique = unique;

/**
 * Utility function to test for and extract a subkey.
 *
 * var obj = { '#': 'foo', 'bar': 'baz' };
 *
 * get(obj);
 * // => 'foo'
 *
 * get(obj, 'bar');
 * // => 'baz'
 *
 * @param {Object} obj
 * @param {String} [subkey="#"] By default, use the '#' key, but you may pass any key you like
 * @return Returns the value of the selected key or 'null' if undefined.
 */
function get(obj, subkey) {
  if (!subkey)
    subkey = '#';

  if (Array.isArray(obj))
    obj = obj[0];

  if (obj && obj[subkey])
    return obj[subkey];
  else
    return null;
}
exports.get = get;
<commit_msg>Add `resolve` for resolving paths with xml:base. Linting.<commit_after>
/**
 * Module dependencies.
 */
var URL = require('url')
  ;

/**
 * Merge object b with object a.
 *
 * var a = { foo: 'bar' }
 *   , b = { foo: 'quux', bar: 'baz' };
 *
 * merge(a, b);
 * // => { foo: 'quux', bar: 'baz' }
 *
 * merge(a, b, true);
 * // => { foo: 'bar', bar: 'baz' }
 *
 * @param {Object} a
 * @param {Object} b
 * @param {Boolean} [noforce] Optionally, don't overwrite any existing keys in a found in b
 * @return {Object}
 */
function merge (a, b, noforce) {
  if (a && b && a === Object(a) && b === Object(b)) {
    for (var key in b) {
      if (noforce) {
        if (!a.hasOwnProperty(key)) a[key] = b[key];
      } else {
        a[key] = b[key];
      }
    }
  }
  return a;
}
exports.merge = merge;

/**
 * Create an array containing the unique members of an array.
 *
 * var array = ['a', 'b', 1, 2, 'a', 3 ];
 *
 * unique(array);
 * // => ['b', 1, 2, 'a', 3 ]
 *
 * @param {Array} array
 * @return {Array}
 */
function unique (array) {
  var a = [];
  var l = array.length;
  for (var i=0; i<l; i++) {
    for (var j=i+1; j<l; j++) {
      // If array[i] is found later in the array
      if (array[i] === array[j])
        j = ++i;
    }
    a.push(array[i]);
  }
  return a;
}
exports.unique = unique;

/**
 * Utility function to test for and extract a subkey.
 *
 * var obj = { '#': 'foo', 'bar': 'baz' };
 *
 * get(obj);
 * // => 'foo'
 *
 * get(obj, 'bar');
 * // => 'baz'
 *
 * @param {Object} obj
 * @param {String} [subkey="#"] By default, use the '#' key, but you may pass any key you like
 * @return Returns the value of the selected key or 'null' if undefined.
 */
function get(obj, subkey) {
  if (!subkey)
    subkey = '#';

  if (Array.isArray(obj))
    obj = obj[0];

  if (obj && obj[subkey])
    return obj[subkey];
  else
    return null;
}
exports.get = get;

function resolve (baseUrl, pathUrl) {
  return URL.resolve(baseUrl, pathUrl);
}
exports.resolve = resolve;<|endoftext|>


<commit_before>import $ from 'jquery';
// 类型判定接口
import * as Is from './lib/is';

// 公开接口
export * from './lib/is';

// jquery 对象
export var win = $(window);
export var doc = $(document);

/**
 * 属性拷贝
 *
 * @export
 * @param {Object} target 目标对象
 * @param {Object} seed 继承对象
 * @param {Array} list 名单
 * @param {Boolean} isWhite 是否是白名单
 */
export function mix(target, seed, list, isWhite) {
  if (!Array.isArray(list)) {
    list = false;
  }

  var index;

  // Copy "all" properties including inherited ones.
  for (var prop in seed) {
    if (seed.hasOwnProperty(prop)) {
      // 检测白名单
      if (list) {
        index = list.indexOf(prop);

        // 区分黑白名单
        if (isWhite ? index === -1 : index !== -1) {
          continue;
        }
      }

      // 在 iPhone 1 代等设备的 Safari 中，prototype 也会被枚举出来，需排除
      if (prop !== 'prototype') {
        target[prop] = seed[prop];
      }
    }
  }

  return target;
}

// setPrototypeOf
var setPrototypeOf = Is.isNative(Object.setPrototypeOf) ? Object.setPrototypeOf : false;

/**
 * 继承
 *
 * @export
 * @param {Class} subClass
 * @param {Class} superClass
 * @param {Object} properties
 * @returns {subClass}
 */
export function inherits(subClass, superClass, properties) {
  var superPrototype = superClass.prototype;

  if (setPrototypeOf) {
    setPrototypeOf(subClass.prototype, superPrototype);
  } else {
    // 中转空白类，可以减少内存占用
    function T() {
      // Empty constructor
    }

    // 原型属性继承
    T.prototype = superPrototype;
    // 初始化实例
    subClass.prototype = new T();
  }

  // 混合属性
  properties && mix(subClass.prototype, properties);

  // 设置构造函数
  subClass.prototype.constructor = subClass;

  return subClass;
}

/**
 * 高性能 apply
 *
 * @param  {Function} func
 * @param  {Any} context
 * @param  {Array} args
 * call is faster than apply, optimize less than 6 args
 * https://github.com/micro-js/apply
 * http://blog.csdn.net/zhengyinhui100/article/details/7837127
 */
export function apply(func, context, args) {
  switch (args.length) {
    // faster
    case 0:
      return func.call(context);
    case 1:
      return func.call(context, args[0]);
    case 2:
      return func.call(context, args[0], args[1]);
    case 3:
      return func.call(context, args[0], args[1], args[2]);
    default:
      // slower
      return func.apply(context, args);
  }
}

// original getComputedStyle
var originalGetComputedStyle = window.getComputedStyle;

/**
 * getComputedStyle
 * @export
 * @param {HTMLElement} element
 * @param {String} prop
 * @returns {Object}
 * @see https://github.com/the-simian/ie8-getcomputedstyle/blob/master/index.js
 * @see https://github.com/twolfson/computedStyle/blob/master/lib/computedStyle.js
 * @see http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle
 */
export function getComputedStyle(element, prop) {
  var style =
    // If we have getComputedStyle
    originalGetComputedStyle ?
    // Query it
    // From CSS-Query notes, we might need (node, null) for FF
    originalGetComputedStyle(element, null) :
    // Otherwise, we are in IE and use currentStyle
    element.currentStyle;

  // 返回 getPropertyValue 方法
  return {
    /**
     * getPropertyValue
     * @param {String} prop
     */
    getPropertyValue: function(prop) {
      if (style) {
        // Original support
        if (style.getPropertyValue) {
          return style.getPropertyValue(prop);
        }

        // Switch to camelCase for CSSOM
        // DEV: Grabbed from jQuery
        // https://github.com/jquery/jquery/blob/1.9-stable/src/css.js#L191-L194
        // https://github.com/jquery/jquery/blob/1.9-stable/src/core.js#L593-L597
        prop = prop.replace(/-(\w)/gi, function(word, letter) {
          return letter.toUpperCase();
        });

        // Old IE
        if (style.getAttribute) {
          return style.getAttribute(prop);
        }

        // Read property directly
        return style[prop];
      }
    }
  };
}
<commit_msg>update files<commit_after>import $ from 'jquery';
// 类型判定接口
import * as Is from './lib/is';

// 公开接口
export * from './lib/is';

// jquery 对象
export var win = $(window);
export var doc = $(document);

/**
 * 属性拷贝
 *
 * @export
 * @param {Object} target 目标对象
 * @param {Object} seed 继承对象
 * @param {Array} list 名单
 * @param {Boolean} isWhite 是否是白名单
 */
export function mix(target, seed, list, isWhite) {
  if (!Array.isArray(list)) {
    list = false;
  }

  var index;

  // Copy "all" properties including inherited ones.
  for (var prop in seed) {
    if (seed.hasOwnProperty(prop)) {
      // 检测白名单
      if (list) {
        index = list.indexOf(prop);

        // 区分黑白名单
        if (isWhite ? index === -1 : index !== -1) {
          continue;
        }
      }

      // 在 iPhone 1 代等设备的 Safari 中，prototype 也会被枚举出来，需排除
      if (prop !== 'prototype') {
        target[prop] = seed[prop];
      }
    }
  }

  return target;
}

// 为了节省内存，使用一个共享的构造器
function TClass() {
  // 空白中转类，可以减少内存占用
}

// Object setPrototypeOf
var setPrototypeOf = Object.setPrototypeOf;

// not suport setPrototypeOf
if (!Is.isNative(setPrototypeOf)) {
  setPrototypeOf = null;
}

// Object create
var objectCreate = Object.create;

// not suport create
if (!Is.isNative(objectCreate)) {
  objectCreate = null;
}

/**
 * 继承
 *
 * @export
 * @param {Class} subClass
 * @param {Class} superClass
 * @param {Object} properties
 * @returns {subClass}
 */
export function inherits(subClass, superClass, properties) {
  var superPrototype = superClass.prototype;

  if (setPrototypeOf) {
    setPrototypeOf(subClass.prototype, superPrototype);
  } else if (objectCreate) {
    subClass.prototype = objectCreate(superPrototype);
  } else {
    // 原型属性继承
    TClass.prototype = superPrototype;
    // 初始化实例
    subClass.prototype = new TClass();
    // 不要保持一个 superClass 的杂散引用
    TClass.prototype = null;
  }

  // 混合属性
  properties && mix(subClass.prototype, properties);

  // 设置构造函数
  subClass.prototype.constructor = subClass;

  return subClass;
}

/**
 * 高性能 apply
 *
 * @param  {Function} func
 * @param  {Any} context
 * @param  {Array} args
 * call is faster than apply, optimize less than 6 args
 * https://github.com/micro-js/apply
 * http://blog.csdn.net/zhengyinhui100/article/details/7837127
 */
export function apply(func, context, args) {
  switch (args.length) {
    // faster
    case 0:
      return func.call(context);
    case 1:
      return func.call(context, args[0]);
    case 2:
      return func.call(context, args[0], args[1]);
    case 3:
      return func.call(context, args[0], args[1], args[2]);
    default:
      // slower
      return func.apply(context, args);
  }
}

// original getComputedStyle
var originalGetComputedStyle = window.getComputedStyle;

/**
 * getComputedStyle
 * @export
 * @param {HTMLElement} element
 * @param {String} prop
 * @returns {Object}
 * @see https://github.com/the-simian/ie8-getcomputedstyle/blob/master/index.js
 * @see https://github.com/twolfson/computedStyle/blob/master/lib/computedStyle.js
 * @see http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle
 */
export function getComputedStyle(element, prop) {
  var style =
    // If we have getComputedStyle
    originalGetComputedStyle ?
    // Query it
    // From CSS-Query notes, we might need (node, null) for FF
    originalGetComputedStyle(element, null) :
    // Otherwise, we are in IE and use currentStyle
    element.currentStyle;

  // 返回 getPropertyValue 方法
  return {
    /**
     * getPropertyValue
     * @param {String} prop
     */
    getPropertyValue: function(prop) {
      if (style) {
        // Original support
        if (style.getPropertyValue) {
          return style.getPropertyValue(prop);
        }

        // Switch to camelCase for CSSOM
        // DEV: Grabbed from jQuery
        // https://github.com/jquery/jquery/blob/1.9-stable/src/css.js#L191-L194
        // https://github.com/jquery/jquery/blob/1.9-stable/src/core.js#L593-L597
        prop = prop.replace(/-(\w)/gi, function(word, letter) {
          return letter.toUpperCase();
        });

        // Old IE
        if (style.getAttribute) {
          return style.getAttribute(prop);
        }

        // Read property directly
        return style[prop];
      }
    }
  };
}
<|endoftext|>


<commit_before>/**
* @license
* Copyright 2019 The FOAM Authors. All Rights Reserved.
* http://www.apache.org/licenses/LICENSE-2.0
*/

foam.CLASS({
  package: 'org.chartjs',
  name: 'HorizontalBarDAOChartView',
  extends: 'org.chartjs.AbstractChartView',

  implements: [
    'foam.mlang.Expressions'
  ],

  properties: [
    {
      class: 'DateTime',
      name: 'startDate'
    },
    {
      class: 'DateTime',
      name: 'endDate'
    },
    {
      class: 'Reference',
      of: 'net.nanopay.account.Account',
      name: 'account',
    },
    {
      class: 'Enum',
      of: 'net.nanopay.liquidity.ui.dashboard.DateFrequency',
      name: 'dateFrequency',
    },
    {
      class: 'Map',
      name: 'config',
      documentation: `
        The config map that is expected by chartjs. Structure and information can be found in chartjs.org's documentation.
      `,
      factory: function () {
        return {
          type: 'horizontalBar',
          options: {
            elements: {
              rectangle: {
                borderWidth: 2,
              }
            },
          },
          scales: {
            xAxes: [{
              barPercentage: 0.5,
              barThickness: 6,
              maxBarThickness: 8,
              gridLines: {
                  offsetGridLines: true
              }
            }]
          }
        };
      }
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'labelExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'xExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'yExpr',
    }
  ],

  reactions: [
    ['', 'propertyChange.account', 'dataUpdate'],
    ['', 'propertyChange.dateFrequency', 'dataUpdate'],
    ['', 'propertyChange.startDate', 'dataUpdate'],
    ['', 'propertyChange.endDate', 'dataUpdate'],
  ],

  listeners: [
    {
      name: 'dataUpdate',
      isFramed: true,
      code: function() {
        debugger;
        var self = this;
        var glang = {};
        glang = this.dateFrequency.glang.clone().copyFrom({
          delegate: net.nanopay.tx.model.Transaction.COMPLETION_DATE
        });

        self.data
          .where(
            this.AND(
              this.GTE(net.nanopay.tx.model.Transaction.COMPLETION_DATE, self.startDate),
              this.LTE(net.nanopay.tx.model.Transaction.COMPLETION_DATE, self.endDate)
            )
          )
          .select(this.GROUP_BY(glang, this.GROUP_BY(net.nanopay.tx.model.Transaction.TYPE, this.SUM(net.nanopay.tx.model.Transaction.AMOUNT))))
          .then(function(sink) {
            console.log(sink);
            var config = {};
            config = foam.Object.clone(self.config);
            debugger;
            config.data = {
              labels: sink.groupKeys.map(key => {
                return key.toLocaleDateString();
              }),
              datasets: [
                {
                  label: 'Cash In',
                  backgroundColor: '#b8e5b3',
                  data: Object.keys(sink.groups).map(key => sink.group[key]["AlternaCITransaction"].value)
                },
                {
                  label: 'Cash Out',
                  backgroundColor: '#f79393',
                  data: Object.keys(sink.groups).map(key => sink.group[key]["AlternaCOTransaction"].value)
                }
              ]
            };
            self.config = config;
          })
      }
    }
  ]
});
<commit_msg>Got the chart working now<commit_after>/**
* @license
* Copyright 2019 The FOAM Authors. All Rights Reserved.
* http://www.apache.org/licenses/LICENSE-2.0
*/

foam.CLASS({
  package: 'org.chartjs',
  name: 'HorizontalBarDAOChartView',
  extends: 'org.chartjs.AbstractChartView',

  implements: [
    'foam.mlang.Expressions'
  ],

  properties: [
    {
      class: 'Date',
      name: 'startDate'
    },
    {
      class: 'Date',
      name: 'endDate'
    },
    {
      class: 'Reference',
      of: 'net.nanopay.account.Account',
      name: 'account',
    },
    {
      class: 'Enum',
      of: 'net.nanopay.liquidity.ui.dashboard.DateFrequency',
      name: 'dateFrequency',
    },
    {
      class: 'Map',
      name: 'config',
      documentation: `
        The config map that is expected by chartjs. Structure and information can be found in chartjs.org's documentation.
      `,
      factory: function () {
        return {
          type: 'horizontalBar',
          options: {
            legend: {
              display: false
            },
            elements: {
              rectangle: {
                borderWidth: 2,
              }
            },
          },
          scales: {
            xAxes: [{
              barPercentage: 0.5,
              barThickness: 6,
              maxBarThickness: 8,
              gridLines: {
                  offsetGridLines: true
              }
            }]
          }
        };
      }
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'labelExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'xExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'yExpr',
    }
  ],

  reactions: [
    ['', 'propertyChange.account', 'dataUpdate'],
    ['', 'propertyChange.dateFrequency', 'dataUpdate'],
    ['', 'propertyChange.startDate', 'dataUpdate'],
    ['', 'propertyChange.endDate', 'dataUpdate'],
  ],

  listeners: [
    {
      name: 'dataUpdate',
      isFramed: true,
      code: function() {
        var self = this;
        var glang = {};
        glang = this.dateFrequency.glang.clone().copyFrom({
          delegate: net.nanopay.tx.model.Transaction.COMPLETION_DATE
        });

        self.data
          .where(
            this.AND(
              this.GTE(self.yExpr, self.startDate),
              this.LTE(self.yExpr, self.endDate)
            )
          )
          .select(this.GROUP_BY(glang, this.GROUP_BY(self.labelExpr, this.SUM(self.xExpr))))
          .then(function(sink) {
            self.config.data = { datasets: [] };
            var config = foam.Object.clone(self.config);
            config.data = {
              labels: sink.groupKeys.map(key => {
                return key.toLocaleDateString();
              }),
              datasets: [
                {
                  label: 'Cash In',
                  backgroundColor: '#b8e5b3',
                  data: Object.keys(sink.groups).map(key => {
                    return sink.groups[key].groups["AlternaCITransaction"]
                      ? sink.groups[key].groups["AlternaCITransaction"].value
                      : 0;
                  })
                },
                {
                  label: 'Cash Out',
                  backgroundColor: '#f79393',
                  data: Object.keys(sink.groups).map(key => {
                    return sink.groups[key].groups["AlternaCOTransaction"]
                      ? sink.groups[key].groups["AlternaCOTransaction"].value
                      : 0;
                  })
                }
              ]
            };
            self.config = config;
          })
      }
    }
  ]
});
<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');
var _ = require('underscore');
var chalk = require('chalk');
_.str = require('underscore.string');
_.mixin(_.str.exports());
var ngParseModule = require('ng-parse-module');

exports.JS_MARKER = "<!-- Add New Component JS Above -->";
exports.LESS_MARKER = "/* Add Component LESS Above */";

exports.ROUTE_MARKER = "/* Add New Routes Above */";
exports.STATE_MARKER = "/* Add New States Above */";

exports.addToFile = function (filename, lineToAdd, beforeMarker) {
    try {
        var fullPath = path.resolve(process.cwd(), filename);
        var fileSrc = fs.readFileSync(fullPath, 'utf8');

        var indexOf = fileSrc.indexOf(beforeMarker);
        var lineStart = fileSrc.substring(0, indexOf).lastIndexOf('\n') + 1;
        var indent = fileSrc.substring(lineStart, indexOf);
        fileSrc = fileSrc.substring(0, indexOf) + lineToAdd + "\n" + indent + fileSrc.substring(indexOf);

        fs.writeFileSync(fullPath, fileSrc);
    } catch (e) {
        throw e;
    }
};

exports.processTemplates = function (name, dir, type, that, defaultDir, configName, module) {

    if (!defaultDir) {
        defaultDir = 'templates'
    }
    if (!configName) {
        configName = type + 'Templates';
    }

    that.className = name + '_' + type;
    that.fileName = name + '.' + type;

    var templateDirectory = path.join(path.dirname(that.resolved), defaultDir);
    if (that.config.get(configName)) {
        templateDirectory = path.join(process.cwd(), that.config.get(configName));
    }

    _.chain(fs.readdirSync(templateDirectory))
        .filter(function (template) {
            return template[0] !== '.';
        })
        .each(function (template) {
            var customTemplateName = template.replace(type, that.fileName);
            var templateFile = path.join(templateDirectory, template);

            //create the file in respective folder
            if (_(customTemplateName).endsWith('-spec.js') ||
                _(customTemplateName).endsWith('_spec.js') ||
                _(customTemplateName).endsWith('-test.js') ||
                _(customTemplateName).endsWith('_test.js')) {
                var testDirLocation = dir; //dir.replace('app', 'test/specs');
                that.template(templateFile, path.join(testDirLocation, customTemplateName));
            } else {
                that.template(templateFile, path.join(dir, customTemplateName));
            }

            //inject the file reference into index.html/app.less/etc as appropriate
            exports.inject(path.join(dir, customTemplateName), that, module);
        });
};

exports.inject = function (filename, that, module) {
    //special case to skip unit tests
    if (_(filename).endsWith('-spec.js') ||
        _(filename).endsWith('_spec.js') ||
        _(filename).endsWith('-test.js') ||
        _(filename).endsWith('_test.js')) {
        return;
    }

    var ext = path.extname(filename);
    if (ext[0] === '.') {
        ext = ext.substring(1);
    }
    var config = that.config.get('inject')[ext];
    if (config) {
        var configFile = _.template(config.file)({
            module: path.basename(module.file, '.js')
        });
        var injectFileRef = filename;
        if (config.relativeToModule) {
            configFile = path.join(path.dirname(module.file), configFile);
            injectFileRef = path.relative(path.dirname(module.file), filename);
        }
        //Added by Tapas to add app folder in place
        if (injectFileRef.indexOf('app\\') > -1) {
            injectFileRef = injectFileRef.replace('app\\', '');
        }
        if (injectFileRef.indexOf('app/') > -1) {
            injectFileRef = injectFileRef.replace('app/', '');
        }

        injectFileRef = injectFileRef.replace(/\\/g, '/');
        var lineTemplate = _.template(config.template)({
            filename: injectFileRef
        });
        exports.addToFile(configFile, lineTemplate, config.marker);
        that.log.writeln(chalk.green(' updating') + ' %s', path.basename(configFile));
    }
};

exports.injectRoute = function (moduleFile, uirouter, name, route, routeUrl, that) {

    //Added by Tapas to add app folder in place
    if (routeUrl.indexOf('app\\') > -1) {
        routeUrl = routeUrl.replace('app\\', '');
    }
    if (routeUrl.indexOf('app/') > -1) {
        routeUrl = routeUrl.replace('app/', '');
    }
    routeUrl = routeUrl.replace(/\\/g, '/');

    if (uirouter) {
        var code = '$stateProvider.state(\'' + name + '\', {\n            url: \'' + route + '\',\n            templateUrl: \'' + routeUrl + '\'\n\t\t});';
        exports.addToFile(moduleFile, code, exports.STATE_MARKER);
    } else {
        exports.addToFile(moduleFile, '$routeProvider.when(\'' + route + '\',{templateUrl: \'' + routeUrl + '\'});', exports.ROUTE_MARKER);
    }

    that.log.writeln(chalk.green(' updating') + ' %s', path.basename(moduleFile));

};

exports.getParentModule = function (dir) {
    //starting this dir, find the first module and return parsed results
    if (fs.existsSync(dir)) {
        var files = fs.readdirSync(dir);
        for (var i = 0; i < files.length; i++) {
            if (path.extname(files[i]) !== '.js') {
                continue;
            }
            var results = ngParseModule.parse(path.join(dir, files[i]));
            if (results) {
                return results;
            }
        }
    }

    if (fs.existsSync(path.join(dir, '.yo-rc.json'))) {
        //if we're in the root of the project then bail
        return;
    }

    return exports.getParentModule(path.join(dir, '..'));
};

exports.askForModule = function (type, that, cb) {

    var modules = that.config.get('modules');
    var mainModule = ngParseModule.parse('app/app.js');
    mainModule.primary = true;

    if (!modules || modules.length === 0) {
        cb.bind(that)(mainModule);
        return;
    }

    var choices = _.pluck(modules, 'name');
    //Tapas: commented as no need to show main app module in the list
    //choices.unshift(mainModule.name + ' (Primary Application Module)');

    var prompts = [
        {
            name: 'module',
            message: 'Which module would you like to place the new ' + type + '?',
            type: 'list',
            choices: choices,
            default: 0
        }
    ];

    that.prompt(prompts, function (props) {

        var i = choices.indexOf(props.module);

        var fileName = modules[i].file.replace('.js', '.module.js');

        var module = ngParseModule.parse(fileName);
        //Tapas: No more required as we are not allowing user to add anything to main module
        /*if (i === 0) {
            module = mainModule;
        } else {
            module = ngParseModule.parse(modules[i-1].file);
        }*/

        cb.bind(that)(module);
    }.bind(that));

};

exports.askForDir = function (type, that, module, ownDir, cb) {

    that.module = module;
    that.appname = module.name;
    that.dir = path.dirname(module.file);

    var configedDir = that.config.get(type + 'Directory');
    if (!configedDir) {
        configedDir = '.';
    }
    var defaultDir = path.join(that.dir, configedDir, '/');
    defaultDir = path.relative(process.cwd(), defaultDir);

    if (ownDir) {
        defaultDir = path.join(defaultDir, that.name);
    }

    defaultDir = path.join(defaultDir, '/');

    var dirPrompt = [
        {
            name: 'dir',
            message: 'Where would you like to create the ' + type + ' files?',
            default: defaultDir,
            validate: function (dir) {
                if (!module.primary) {
                    //ensure dir is in module dir or subdir of it
                    dir = path.resolve(dir);
                    if (path.relative(that.dir, dir).substring(0, 2) === '..') {
                        return 'Files must be placed inside the module directory or a subdirectory of the module.'
                    }
                }
                return true;
            }
        }
    ];

    var dirPromptCallback = function (props) {

        that.dir = path.join(props.dir, '/');
        var dirToCreate = that.dir;
        if (ownDir) {
            dirToCreate = path.join(dirToCreate, '..');
        }

        if (!fs.existsSync(dirToCreate)) {
            that.prompt([{
                name: 'isConfirmed',
                type: 'confirm',
                message: chalk.cyan(dirToCreate) + ' does not exist.  Create it?'
            }], function (props) {
                if (props.isConfirmed) {
                    cb();
                } else {
                    that.prompt(dirPrompt, dirPromptCallback);
                }
            });
        } else if (ownDir && fs.existsSync(that.dir)) {
            //if the dir exists and this type of thing generally is inside its own dir, confirm it
            that.prompt([{
                name: 'isConfirmed',
                type: 'confirm',
                message: chalk.cyan(that.dir) + ' already exists.  Components of this type contain multiple files and are typically put inside directories of their own.  Continue?'
            }], function (props) {
                if (props.isConfirmed) {
                    cb();
                } else {
                    that.prompt(dirPrompt, dirPromptCallback);
                }
            });
        } else {
            cb();
        }

    };

    that.prompt(dirPrompt, dirPromptCallback);

};

exports.askForModuleAndDir = function (type, that, ownDir, cb) {
    exports.askForModule(type, that, function (module) {
        exports.askForDir(type, that, module, ownDir, cb);
    });
};

exports.getNameArg = function (that, args) {
    if (args.length > 0) {
        that.name = args[0];
    }
};

exports.addNamePrompt = function (that, prompts, type) {
    if (!that.name) {
        prompts.splice(0, 0, {
            name: 'name',
            message: 'Enter a name for the ' + type + '.',
            validate: function (input) {
                return true;
            }
        });
    }
}
<commit_msg>fixed .module.js filename error<commit_after>var path = require('path');
var fs = require('fs');
var _ = require('underscore');
var chalk = require('chalk');
_.str = require('underscore.string');
_.mixin(_.str.exports());
var ngParseModule = require('ng-parse-module');

exports.JS_MARKER = "<!-- Add New Component JS Above -->";
exports.LESS_MARKER = "/* Add Component LESS Above */";

exports.ROUTE_MARKER = "/* Add New Routes Above */";
exports.STATE_MARKER = "/* Add New States Above */";

exports.addToFile = function (filename, lineToAdd, beforeMarker) {
    try {
        var fullPath = path.resolve(process.cwd(), filename);
        var fileSrc = fs.readFileSync(fullPath, 'utf8');

        var indexOf = fileSrc.indexOf(beforeMarker);
        var lineStart = fileSrc.substring(0, indexOf).lastIndexOf('\n') + 1;
        var indent = fileSrc.substring(lineStart, indexOf);
        fileSrc = fileSrc.substring(0, indexOf) + lineToAdd + "\n" + indent + fileSrc.substring(indexOf);

        fs.writeFileSync(fullPath, fileSrc);
    } catch (e) {
        throw e;
    }
};

exports.processTemplates = function (name, dir, type, that, defaultDir, configName, module) {

    if (!defaultDir) {
        defaultDir = 'templates'
    }
    if (!configName) {
        configName = type + 'Templates';
    }

    that.className = name + '_' + type;
    that.fileName = name + '.' + type;

    var templateDirectory = path.join(path.dirname(that.resolved), defaultDir);
    if (that.config.get(configName)) {
        templateDirectory = path.join(process.cwd(), that.config.get(configName));
    }

    _.chain(fs.readdirSync(templateDirectory))
        .filter(function (template) {
            return template[0] !== '.';
        })
        .each(function (template) {
            var customTemplateName = template.replace(type, that.fileName);
            var templateFile = path.join(templateDirectory, template);

            //create the file in respective folder
            if (_(customTemplateName).endsWith('-spec.js') ||
                _(customTemplateName).endsWith('_spec.js') ||
                _(customTemplateName).endsWith('-test.js') ||
                _(customTemplateName).endsWith('_test.js')) {
                var testDirLocation = dir; //dir.replace('app', 'test/specs');
                that.template(templateFile, path.join(testDirLocation, customTemplateName));
            } else {
                that.template(templateFile, path.join(dir, customTemplateName));
            }

            //inject the file reference into index.html/app.less/etc as appropriate
            exports.inject(path.join(dir, customTemplateName), that, module);
        });
};

exports.inject = function (filename, that, module) {
    //special case to skip unit tests
    if (_(filename).endsWith('-spec.js') ||
        _(filename).endsWith('_spec.js') ||
        _(filename).endsWith('-test.js') ||
        _(filename).endsWith('_test.js')) {
        return;
    }

    var ext = path.extname(filename);
    if (ext[0] === '.') {
        ext = ext.substring(1);
    }
    var config = that.config.get('inject')[ext];
    if (config) {
        var configFile = _.template(config.file)({
            module: path.basename(module.file, '.js')
        });
        var injectFileRef = filename;
        if (config.relativeToModule) {
            configFile = path.join(path.dirname(module.file), configFile);
            injectFileRef = path.relative(path.dirname(module.file), filename);
        }
        //Added by Tapas to add app folder in place
        if (injectFileRef.indexOf('app\\') > -1) {
            injectFileRef = injectFileRef.replace('app\\', '');
        }
        if (injectFileRef.indexOf('app/') > -1) {
            injectFileRef = injectFileRef.replace('app/', '');
        }

        injectFileRef = injectFileRef.replace(/\\/g, '/');
        var lineTemplate = _.template(config.template)({
            filename: injectFileRef
        });
        exports.addToFile(configFile, lineTemplate, config.marker);
        that.log.writeln(chalk.green(' updating') + ' %s', path.basename(configFile));
    }
};

exports.injectRoute = function (moduleFile, uirouter, name, route, routeUrl, that) {

    //Added by Tapas to add app folder in place
    if (routeUrl.indexOf('app\\') > -1) {
        routeUrl = routeUrl.replace('app\\', '');
    }
    if (routeUrl.indexOf('app/') > -1) {
        routeUrl = routeUrl.replace('app/', '');
    }
    routeUrl = routeUrl.replace(/\\/g, '/');

    if (uirouter) {
        var code = '$stateProvider.state(\'' + name + '\', {\n            url: \'' + route + '\',\n            templateUrl: \'' + routeUrl + '\'\n\t\t});';
        exports.addToFile(moduleFile, code, exports.STATE_MARKER);
    } else {
        exports.addToFile(moduleFile, '$routeProvider.when(\'' + route + '\',{templateUrl: \'' + routeUrl + '\'});', exports.ROUTE_MARKER);
    }

    that.log.writeln(chalk.green(' updating') + ' %s', path.basename(moduleFile));

};

exports.getParentModule = function (dir) {
    //starting this dir, find the first module and return parsed results
    if (fs.existsSync(dir)) {
        var files = fs.readdirSync(dir);
        for (var i = 0; i < files.length; i++) {
            if (path.extname(files[i]) !== '.js') {
                continue;
            }
            var results = ngParseModule.parse(path.join(dir, files[i]));
            if (results) {
                return results;
            }
        }
    }

    if (fs.existsSync(path.join(dir, '.yo-rc.json'))) {
        //if we're in the root of the project then bail
        return;
    }

    return exports.getParentModule(path.join(dir, '..'));
};

exports.askForModule = function (type, that, cb) {

    var modules = that.config.get('modules');
    var mainModule = ngParseModule.parse('app/app.js');
    mainModule.primary = true;

    if (!modules || modules.length === 0) {
        cb.bind(that)(mainModule);
        return;
    }

    var choices = _.pluck(modules, 'name');
    //Tapas: commented as no need to show main app module in the list
    //choices.unshift(mainModule.name + ' (Primary Application Module)');

    var prompts = [
        {
            name: 'module',
            message: 'Which module would you like to place the new ' + type + '?',
            type: 'list',
            choices: choices,
            default: 0
        }
    ];

    that.prompt(prompts, function (props) {

        var i = choices.indexOf(props.module);

        var fileName = modules[i].file;

        if (fileName.indexOf('.module') == 0) {
            fileName = modules[i].file.replace('.js', '.module.js');
        }

        var module = ngParseModule.parse(fileName);

        cb.bind(that)(module);
    }.bind(that));

};

exports.askForDir = function (type, that, module, ownDir, cb) {

    that.module = module;
    that.appname = module.name;
    that.dir = path.dirname(module.file);

    var configedDir = that.config.get(type + 'Directory');
    if (!configedDir) {
        configedDir = '.';
    }
    var defaultDir = path.join(that.dir, configedDir, '/');
    defaultDir = path.relative(process.cwd(), defaultDir);

    if (ownDir) {
        defaultDir = path.join(defaultDir, that.name);
    }

    defaultDir = path.join(defaultDir, '/');

    var dirPrompt = [
        {
            name: 'dir',
            message: 'Where would you like to create the ' + type + ' files?',
            default: defaultDir,
            validate: function (dir) {
                if (!module.primary) {
                    //ensure dir is in module dir or subdir of it
                    dir = path.resolve(dir);
                    if (path.relative(that.dir, dir).substring(0, 2) === '..') {
                        return 'Files must be placed inside the module directory or a subdirectory of the module.'
                    }
                }
                return true;
            }
        }
    ];

    var dirPromptCallback = function (props) {

        that.dir = path.join(props.dir, '/');
        var dirToCreate = that.dir;
        if (ownDir) {
            dirToCreate = path.join(dirToCreate, '..');
        }

        if (!fs.existsSync(dirToCreate)) {
            that.prompt([{
                name: 'isConfirmed',
                type: 'confirm',
                message: chalk.cyan(dirToCreate) + ' does not exist.  Create it?'
            }], function (props) {
                if (props.isConfirmed) {
                    cb();
                } else {
                    that.prompt(dirPrompt, dirPromptCallback);
                }
            });
        } else if (ownDir && fs.existsSync(that.dir)) {
            //if the dir exists and this type of thing generally is inside its own dir, confirm it
            that.prompt([{
                name: 'isConfirmed',
                type: 'confirm',
                message: chalk.cyan(that.dir) + ' already exists.  Components of this type contain multiple files and are typically put inside directories of their own.  Continue?'
            }], function (props) {
                if (props.isConfirmed) {
                    cb();
                } else {
                    that.prompt(dirPrompt, dirPromptCallback);
                }
            });
        } else {
            cb();
        }

    };

    that.prompt(dirPrompt, dirPromptCallback);

};

exports.askForModuleAndDir = function (type, that, ownDir, cb) {
    exports.askForModule(type, that, function (module) {
        exports.askForDir(type, that, module, ownDir, cb);
    });
};

exports.getNameArg = function (that, args) {
    if (args.length > 0) {
        that.name = args[0];
    }
};

exports.addNamePrompt = function (that, prompts, type) {
    if (!that.name) {
        prompts.splice(0, 0, {
            name: 'name',
            message: 'Enter a name for the ' + type + '.',
            validate: function (input) {
                return true;
            }
        });
    }
}
<|endoftext|>


<commit_before>/*
Copyright 2016 LinkedIn Corp. 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.
*/

var express = require('express')
var serveStatic = require('serve-static')

var app = express()

app.use('/', serveStatic(__dirname + '/../../app'))
app.use('/exports', serveStatic(__dirname + '/../../../exports'))
app.listen(3000)
console.log('Serving Spaniel Test App on localhost:3000');
<commit_msg>Wait until test app is actually served to start testing<commit_after>/*
Copyright 2016 LinkedIn Corp. 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.
*/

var express = require('express')
var serveStatic = require('serve-static')

var app = express()

app.use('/', serveStatic(__dirname + '/../../app'))
app.use('/exports', serveStatic(__dirname + '/../../../exports'))
app.listen(3000, function() {
  console.log('Serving Spaniel Test App on localhost:3000');
});
<|endoftext|>


<commit_before>var chai = require('chai');
var path = require('path');
var fs = require('fs');
var spawn = require('child_process').spawn;
var module = require('module');

global.request = require('request');
global.chai = chai;
global.expect = chai.expect;
global.cwd = path.resolve(__dirname + '/../../src/server');
global.scenarios = path.resolve(__dirname + '/scenarios');
process.env.MONGO_PORT = 27020;
process.env.WOL_PORT = 4007;
process.env.MATCH_DELAY = 5; /* milliseconds */
global.url = 'http://localhost:'+ process.env.WOL_PORT;

console.log('Cleaning up mongodb test directory');
rm(__dirname + '/data/db/');

console.log('Starting mongodb instance..');
global.mongodb = spawn('mongod', [
    '--dbpath', __dirname +'/data/db',
    '--port', process.env.MONGO_PORT
]);

global.mongodb.stdout.on('data', function (data) {
    // console.log(data.toString());
    if (/waiting for connections on port/.test(data.toString())) {
        /* startup ladder */
        require(global.cwd + '/index');
    }
});

// mock player auth into always returning true
require(global.cwd + '/lib/player/auth');
var auth = require.resolve(global.cwd + '/lib/player/auth');
module._cache[auth].exports = function() {
    return {
        then: function(cb) {
            cb();
        }
    }
}

// directory cleanup
function rm(path) {
    if(fs.existsSync(path)) {
        fs.readdirSync(path).forEach(function(file){
            var curPath = path + '/' + file;
            if(fs.lstatSync(curPath).isDirectory()) {
                rm(curPath);
            } else {
                fs.unlinkSync(curPath);
            }
        });
    }
};
<commit_msg>switching to fs-extra; create test db dir<commit_after>var chai = require('chai');
var path = require('path');
var fs = require('fs-extra');
var spawn = require('child_process').spawn;
var module = require('module');

global.request = require('request');
global.chai = chai;
global.expect = chai.expect;
global.cwd = path.resolve(__dirname + '/../../src/server');
global.scenarios = path.resolve(__dirname + '/scenarios');
process.env.MONGO_PORT = 27020;
process.env.WOL_PORT = 4007;
process.env.MATCH_DELAY = 5; /* milliseconds */
global.url = 'http://localhost:'+ process.env.WOL_PORT;

console.log('Cleaning up mongodb test directory');
var dbpath = __dirname + '/data/db/';
if (!fs.existsSync(dbpath)) {
    fs.mkdirpSync(dbpath);
} else {
    fs.emptyDirSync(dbpath);
}

console.log('Starting mongodb instance..');
global.mongodb = spawn('mongod', [
    '--dbpath', __dirname +'/data/db',
    '--port', process.env.MONGO_PORT
]);

global.mongodb.stdout.on('data', function (data) {
    // console.log(data.toString());
    if (/waiting for connections on port/.test(data.toString())) {
        /* startup ladder */
        require(global.cwd + '/index');
    }
});

// mock player auth into always returning true
require(global.cwd + '/lib/player/auth');
var auth = require.resolve(global.cwd + '/lib/player/auth');
module._cache[auth].exports = function() {
    return {
        then: function(cb) {
            cb();
        }
    }
}
<|endoftext|>


<commit_before>/*
 TaskOnFly allows you easy manage your tasks and task lists on the fly from your mobile or desktop device.
 Copyright (C) 2014  Valerii Zinchenko

 This file is part of TaskOnFly.

 TaskOnFly is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 TaskOnFly is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with TaskOnFly.  If not, see <http://www.gnu.org/licenses/>.

 All source files are available at: http://github.com/valerii-zinchenko/TaskOnFly
*/

'use strict';

var utils = {
    deepCopy: function(target, source) {
        var key,
            value;

        for (key in source) {
            value = source[key];
            switch (Object.prototype.toString.call(value)) {
                case '[object Object]':
                    if (!target[key]) {
                        target[key] = {};
                    }
                    utils.deepCopy(target[key], value);
                    break;
                default :
                    target[key] = value
            }
        }

        return target;
    },
    deepExtend: function(target, source) {
        var key,
            value;

        for (key in source) {
            value = source[key];
            if (target.hasOwnProperty(key)) {
                if (typeof target[key] === 'object') {
                    utils.deepExtend(target[key], value);
                }
                continue;
            }

            switch (Object.prototype.toString.call(value)) {
                case '[object Object]':
                    if (!target[key]) {
                        target[key] = {};
                    }
                    utils.deepExtend(target[key], value);
                    break;
                default :
                    target[key] = value
            }
        }

        return target;
    },
    date: function(dateObj) {
        if (dateObj && dateObj.constructor !== Date) {
            throw new Error('Incorrect input argument type');
        }
        return (dateObj ? dateObj : new Date()).toISOString().slice(0,10);
    }
};

function Template(fnTemplate) {
    return fnTemplate.toString().match(/[^]*\/\*\*([^]*)\*\*\/\}$/)[1];
}

if (typeof module !== 'undefined' && module.exports) {
    module.exports = {
        utils: utils,
        Template: Template
    };
}<commit_msg>change HTML template mechanism<commit_after>/*
 TaskOnFly allows you easy manage your tasks and task lists on the fly from your mobile or desktop device.
 Copyright (C) 2014  Valerii Zinchenko

 This file is part of TaskOnFly.

 TaskOnFly is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 TaskOnFly is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with TaskOnFly.  If not, see <http://www.gnu.org/licenses/>.

 All source files are available at: http://github.com/valerii-zinchenko/TaskOnFly
*/

'use strict';

var utils = {
    deepCopy: function(target, source) {
        var key,
            value;

        for (key in source) {
            value = source[key];
            switch (Object.prototype.toString.call(value)) {
                case '[object Object]':
                    if (!target[key]) {
                        target[key] = {};
                    }
                    utils.deepCopy(target[key], value);
                    break;
                default :
                    target[key] = value
            }
        }

        return target;
    },
    deepExtend: function(target, source) {
        var key,
            value;

        for (key in source) {
            value = source[key];
            if (target.hasOwnProperty(key)) {
                if (typeof target[key] === 'object') {
                    utils.deepExtend(target[key], value);
                }
                continue;
            }

            switch (Object.prototype.toString.call(value)) {
                case '[object Object]':
                    if (!target[key]) {
                        target[key] = {};
                    }
                    utils.deepExtend(target[key], value);
                    break;
                default :
                    target[key] = value
            }
        }

        return target;
    },
    date: function(dateObj) {
        if (dateObj && dateObj.constructor !== Date) {
            throw new Error('Incorrect input argument type');
        }
        return (dateObj ? dateObj : new Date()).toISOString().slice(0,10);
    }
};

if (typeof module !== 'undefined' && module.exports) {
    module.exports = {
        utils: utils
    };
}<|endoftext|>