<commit_before>"use strict";

const whilst = require("async/whilst");
const request = require('request');
const moment = require('moment');
const db = require('../../database');

module.exports = (callback, userid, query, options) => {

    var last = new Date(db.queue.get('hosts.last').value()).toISOString();

    request(`https://tmi.twitch.tv/hosts?include_logins=1&target=${userid}`,
        options, (err, response, body) => {

            if (err) {
                console.log(err);
                callback(null, 0);
            } else if (response.statusCode == 200) {

                let json = JSON.parse(body),
                    hosts = json.hosts,
                    i = 0,
                    length = hosts.length,
                    array = [];

                if (length) {
                    whilst(() => {
                            return i < length;
                        },
                        (callback) => {
                            let host = hosts[i],
                                name = parseInt(host.host_login),
                                id = host.host_id,
                                date = new Date().toISOString(),
                                blocked = db.blacklist.get('list').find({
                                    id
                                }).value();

                            request(`https://api.twitch.tv/kraken/channels/${name}`,
                                options, (error, response, body) => {

                                    if (!error && response.statusCode == 200) {
                                        var json = JSON.parse(body),
                                            name = json.display_name;

                                        if (!blocked) {
                                            array.push({
                                                name,
                                                date
                                            });
                                        } else {
                                            //console.log(id + ' is blocked!');
                                        }
                                    }
                                    i = i + 1;
                                    callback(null, i);
                                });
                        },
                        (err, n) => {
                            if (err) {
                                console.log(err);
                                callback(null, 0);
                            } else {
                                if (array.length) {
                                    callback(null, array);
                                } else {
                                    callback(null, 0);
                                }
                            }
                        }
                    );
                } else {
                    callback(null, 0);
                }
            } else {
                console.log(`TWITCH: Hosts error code ${response.statusCode}`);
                callback(null, 0);
            }
        });
};
<commit_msg>APIv5 fix<commit_after>"use strict";

const whilst = require("async/whilst");
const request = require('request');
const moment = require('moment');
const db = require('../../database');

module.exports = (callback, userid, query, options) => {

    var last = new Date(db.queue.get('hosts.last').value()).toISOString();

    request(`https://tmi.twitch.tv/hosts?include_logins=1&target=${userid}`,
        options, (err, response, body) => {

            if (err) {
                console.log(err);
                callback(null, 0);
            } else if (response.statusCode == 200) {

                let json = JSON.parse(body),
                    hosts = json.hosts,
                    i = 0,
                    length = hosts.length,
                    array = [];

                if (length) {
                    whilst(() => {
                            return i < length;
                        },
                        (callback) => {
                            let host = hosts[i],
                                name = parseInt(host.host_login),
                                id = host.host_id,
                                date = new Date().toISOString(),
                                blocked = db.blacklist.get('list').find({
                                    id
                                }).value();

                            request(`https://api.twitch.tv/kraken/channels/${id}`,
                                options, (err, response, body) => {

                                    if (err) {
                                        console.log(err);
                                        i = i + 1;
                                        callback(null, i);
                                    } else if (response.statusCode == 200) {
                                        var json = JSON.parse(body),
                                            name = json.display_name;

                                        if (!blocked) {
                                            array.push({
                                                name,
                                                date
                                            });
                                        } else {
                                            //console.log(id + ' is blocked!');
                                        }
                                    }
                                    i = i + 1;
                                    callback(null, i);
                                });
                        },
                        (err, n) => {
                            if (err) {
                                console.log(err);
                                callback(null, 0);
                            } else {
                                if (array.length) {
                                    callback(null, array);
                                } else {
                                    callback(null, 0);
                                }
                            }
                        }
                    );
                } else {
                    callback(null, 0);
                }
            } else {
                console.log(`TWITCH: Hosts error code ${response.statusCode}`);
                callback(null, 0);
            }
        });
};
<|endoftext|>


<commit_before>/**
 * AngulateJS v0.1.0
 * Copyright 2013, Hybrid Labs
 * License: MIT
 */

;
(function(global) {
  'use strict';

  var angular = global.angular;
  var angulate = global.angulate = angular.module('angulate', []);
  var templates = {};

  /* Helpers */

  function exception(element) {
    var args = Array.prototype.slice.call(arguments);

    if (angular.isObject(element)) {
      console.error('Element:', element);
      args.shift();
    }
    throw args.join(' ');
  }

  function leave($animate, element) {
    if (element.parent().length) {
      $animate.leave(element);
    }
  }

  function enter($animate, element, after) {
    if (!element.parent().length) {
      $animate.enter(element, null, after);
    }
  }

  function attr(element, attrs) {
    var attr;
    angular.forEach(attrs.$attr, function(a) {
      if (a[0] === ':') {
        if (attr) {
          exception(element, 'Element has multiple bindings');
        }
        attr = a.slice(1);
      }
    });

    if (!attr) {
      exception(element, 'Element has no binding attribute')
    }
    return attr;
  }

  function registerTemplate(name, element) {
    if (angular.isString(element)) {
      element = angular.element(document.querySelector('#' + element));
    }
    templates[name] = element;
  }

  /* Directives */

  bindDirective.$inject = ['$compile', '$animate', '$parse'];
  function bindDirective($compile, $animate, $parse) {
    function forkElement(element, attr, attrValue, scope) {
      var clone = element.clone()
        .attr(attr, attrValue)
        .removeAttr('bind');

      $compile(clone)(scope);
      return {
        element: clone,
        scope: scope
      };
    }

    function equalityScope(scope) {
      // Patch $watch and $watchCollection to use object equality
      var _$watch = scope.$watch;

      scope.$watch = function $watch(watch, listener) {
        return _$watch.apply(this, [watch, listener, true]);
      };

      scope.$watchCollection = function $watchCollection(watch, listener) {
        return _$watch.apply(this, [watch, listener, true]);
      };

      return scope;
    }

    function repeatScopeSearch(scope, name, level) {
      if (!scope) {
        return undefined;
      }

      return scope._v && scope._v[name] != undefined ?
        (new Array(level + 1)).join('$parent.') + '_v.' + name :
        repeatScopeSearch(scope.$parent, name, level + 1);
    }

    function link(scope, element, attrs) {
      var bind = attr(element, attrs);
      var repeatScopeValue = scope._v == undefined ? undefined :
        repeatScopeSearch(scope, bind, 0);

      if (element.attr('model')) {
        // Replace this element with a clone with ng-model
        var model = forkElement(element, 'ng-model', bind,
          scope.$parent);

        element.replaceWith(model.element);
      }
      else {
        var display = element.css('display');
        var bindName = angular.isFunction($parse(bind)(scope)) ?
          bind + '(this)' : bind;

        var repeat = '_v in ' + bindName + ' track by ' +
          (attrs.track || '$index');

        // Create repeat element after this element
        repeat = forkElement(element, 'ng-repeat', repeat,
          equalityScope(scope.$parent.$new()));

        element.after(repeat.element);

        // Watch changes and adjust view depending bind data type
        scope.$watch(bindName, function bindWatch(v) {
          if (element.attr('leaf')) {
            element.text(v == undefined ? '' : v);
            repeat.scope[bind] = null;
          }
          else {
            if (!v) {
              leave($animate, element);
              return;
            }

            element.css('display', display);
            if (angular.isArray(v)) {
              // Propagate data from parent scope
              delete repeat.scope[bind];
              leave($animate, element);
            }
            else {
              // Hide data from parent scope
              repeat.scope[bind] = null;
              enter($animate, element, repeat.element);

              // Extend scope binding
              if (angular.isObject(v)) {
                angular.extend(scope, v);
              }
            }
          }
        }, true);

        // Extend repeat scope binding
        if (repeatScopeValue) {
          scope.$watch(repeatScopeValue, function repeatScopeWatch(v) {
            scope[bind] = v;
          });
        }
      }
    }

    return {
      restrict: 'EA',
      scope: true,
      compile: function(element, attr) {
        var model = ['INPUT', 'SELECT'];
        var tag = element.prop('tagName').toUpperCase();
        if (model.indexOf(tag) != -1) {
          attr.$set('model', true);
        }
        else {
          attr.$set('model', undefined);
          if (element.contents().length == 0) {
            attr.$set('leaf', true);
          }
          else {
            attr.$set('leaf', undefined);
          }
        }
        return link;
      }
    }
  }

  ifDirective.$inject = ['$animate', '$parse'];
  function ifDirective($animate, $parse) {
    return {
      restrict: 'EA',
      link: function(scope, element, attrs) {
        var condition = attr(element, attrs);
        var conditionName = angular.isFunction($parse(condition)(scope)) ?
          condition + '(this)' : condition;

        var negate = attrs.not != undefined;
        var marker = negate ?
          document.createComment('if: ' + conditionName) :
          document.createComment('if not: ' + conditionName);

        // Insert marker to track DOM location
        marker = angular.element(marker);
        element.after(marker);
        element.remove();
        marker.after(element);

        scope.$watch(conditionName, function ifWatch(v) {
          if (negate ? !v : v) {
            enter($animate, element, marker);
          }
          else {
            leave($animate, element);
          }
        }, true);
      }
    }
  }

  function templateDirective() {
    return {
      restrict: 'EA',
      compile: function(element, attrs) {
        var name = attr(element, attrs);
        element.replaceWith(
          angular.element('<script type="text/x-avalon-template">')
            .html(element.html())
        );

        registerTemplate(name, element);
      }
    }
  }

  function componentDirective() {
    return {
      restrict: 'EA',
      controller: ['$scope', '$element', '$attrs', '$injector',
        function scopeController($scope, $element, $attrs, $injector) {
          var controller = global[attr($element, $attrs)];
          if (controller) {
            $injector.invoke(controller, this, {
              $scope: $scope,
              $element: $element
            });
          }
        }
      ],
      compile: function(element, attrs) {
        var name = attr(element, attrs);
        if (!templates[name]) {
          exception(element, 'Template not found', name);
        }
        element.html(templates[name].html());
      }
    }
  }

  // Register directives
  angulate.directive('bind', bindDirective);
  angulate.directive('if', ifDirective);
  angulate.directive('template', templateDirective);
  angulate.directive('component', componentDirective);

  // Pre-create for Internet Explorer (IE)
  document.createElement('bind');
  document.createElement('if');
  document.createElement('template');
  document.createElement('component');

  /* Public */

  angulate.registerTemplate = registerTemplate;
})(this);
<commit_msg>Angulate: cleanup equalityScope<commit_after>/**
 * AngulateJS v0.1.0
 * Copyright 2013, Hybrid Labs
 * License: MIT
 */

;
(function(global) {
  'use strict';

  var angular = global.angular;
  var angulate = global.angulate = angular.module('angulate', []);
  var templates = {};

  /* Helpers */

  function exception(element) {
    var args = Array.prototype.slice.call(arguments);

    if (angular.isObject(element)) {
      console.error('Element:', element);
      args.shift();
    }
    throw args.join(' ');
  }

  function leave($animate, element) {
    if (element.parent().length) {
      $animate.leave(element);
    }
  }

  function enter($animate, element, after) {
    if (!element.parent().length) {
      $animate.enter(element, null, after);
    }
  }

  function attr(element, attrs) {
    var attr;
    angular.forEach(attrs.$attr, function(a) {
      if (a[0] === ':') {
        if (attr) {
          exception(element, 'Element has multiple bindings');
        }
        attr = a.slice(1);
      }
    });

    if (!attr) {
      exception(element, 'Element has no binding attribute')
    }
    return attr;
  }

  function equalityScope(scope) {
    // Patch $watch and $watchCollection to use object equality
    var _$watch = scope.$watch;

    scope.$watch = function $watch(watch, listener) {
      return _$watch.apply(this, [watch, listener, true]);
    };

    scope.$watchCollection = function $watchCollection(watch, listener) {
      return _$watch.apply(this, [watch, listener, true]);
    };

    return scope;
  }

  function registerTemplate(name, element) {
    if (angular.isString(element)) {
      element = angular.element(document.querySelector('#' + element));
    }
    templates[name] = element;
  }

  /* Directives */

  bindDirective.$inject = ['$compile', '$animate', '$parse'];
  function bindDirective($compile, $animate, $parse) {
    function forkElement(element, attr, attrValue, scope) {
      var clone = element.clone()
        .attr(attr, attrValue)
        .removeAttr('bind');

      $compile(clone)(scope);
      return {
        element: clone,
        scope: scope
      };
    }

    function repeatScopeSearch(scope, name, level) {
      if (!scope) {
        return undefined;
      }

      return scope._v && scope._v[name] != undefined ?
        (new Array(level + 1)).join('$parent.') + '_v.' + name :
        repeatScopeSearch(scope.$parent, name, level + 1);
    }

    function link(scope, element, attrs) {
      var bind = attr(element, attrs);
      var repeatScopeValue = scope._v == undefined ? undefined :
        repeatScopeSearch(scope, bind, 0);

      if (element.attr('model')) {
        // Replace this element with a clone with ng-model
        var model = forkElement(element, 'ng-model', bind,
          scope.$parent);

        element.replaceWith(model.element);
      }
      else {
        var display = element.css('display');
        var bindName = angular.isFunction($parse(bind)(scope)) ?
          bind + '(this)' : bind;

        var repeat = '_v in ' + bindName + ' track by ' +
          (attrs.track || '$index');

        // Create repeat element after this element
        repeat = forkElement(element, 'ng-repeat', repeat,
          equalityScope(scope.$parent.$new()));

        element.after(repeat.element);

        // Watch changes and adjust view depending bind data type
        scope.$watch(bindName, function bindWatch(v) {
          if (element.attr('leaf')) {
            element.text(v == undefined ? '' : v);
            repeat.scope[bind] = null;
          }
          else {
            if (!v) {
              leave($animate, element);
              return;
            }

            element.css('display', display);
            if (angular.isArray(v)) {
              // Propagate data from parent scope
              delete repeat.scope[bind];
              leave($animate, element);
            }
            else {
              // Hide data from parent scope
              repeat.scope[bind] = null;
              enter($animate, element, repeat.element);

              // Extend scope binding
              if (angular.isObject(v)) {
                angular.extend(scope, v);
              }
            }
          }
        }, true);

        // Extend repeat scope binding
        if (repeatScopeValue) {
          scope.$watch(repeatScopeValue, function repeatScopeWatch(v) {
            scope[bind] = v;
          });
        }
      }
    }

    return {
      restrict: 'EA',
      scope: true,
      compile: function(element, attr) {
        var model = ['INPUT', 'SELECT'];
        var tag = element.prop('tagName').toUpperCase();
        if (model.indexOf(tag) != -1) {
          attr.$set('model', true);
        }
        else {
          attr.$set('model', undefined);
          if (element.contents().length == 0) {
            attr.$set('leaf', true);
          }
          else {
            attr.$set('leaf', undefined);
          }
        }
        return link;
      }
    }
  }

  ifDirective.$inject = ['$animate', '$parse'];
  function ifDirective($animate, $parse) {
    return {
      restrict: 'EA',
      link: function(scope, element, attrs) {
        var condition = attr(element, attrs);
        var conditionName = angular.isFunction($parse(condition)(scope)) ?
          condition + '(this)' : condition;

        var negate = attrs.not != undefined;
        var marker = negate ?
          document.createComment('if: ' + conditionName) :
          document.createComment('if not: ' + conditionName);

        // Insert marker to track DOM location
        marker = angular.element(marker);
        element.after(marker);
        element.remove();
        marker.after(element);

        scope.$watch(conditionName, function ifWatch(v) {
          if (negate ? !v : v) {
            enter($animate, element, marker);
          }
          else {
            leave($animate, element);
          }
        }, true);
      }
    }
  }

  function templateDirective() {
    return {
      restrict: 'EA',
      compile: function(element, attrs) {
        var name = attr(element, attrs);
        element.replaceWith(
          angular.element('<script type="text/x-avalon-template">')
            .html(element.html())
        );

        registerTemplate(name, element);
      }
    }
  }

  function componentDirective() {
    return {
      restrict: 'EA',
      controller: ['$scope', '$element', '$attrs', '$injector',
        function scopeController($scope, $element, $attrs, $injector) {
          var controller = global[attr($element, $attrs)];
          if (controller) {
            $injector.invoke(controller, this, {
              $scope: $scope,
              $element: $element
            });
          }
        }
      ],
      compile: function(element, attrs) {
        var name = attr(element, attrs);
        if (!templates[name]) {
          exception(element, 'Template not found', name);
        }
        element.html(templates[name].html());
      }
    }
  }

  // Register directives
  angulate.directive('bind', bindDirective);
  angulate.directive('if', ifDirective);
  angulate.directive('template', templateDirective);
  angulate.directive('component', componentDirective);

  // Pre-create for Internet Explorer (IE)
  document.createElement('bind');
  document.createElement('if');
  document.createElement('template');
  document.createElement('component');

  /* Public */

  angulate.registerTemplate = registerTemplate;
})(this);
<|endoftext|>


<commit_before>
/**
 * Parse the each expression to detect how to map the collection data to the children tags
 * @param   { String } expr - string passed in the each attribute
 * @returns { Object } object needed to check how the items in the collection
 * should be mapped to the children tags
 *
 * { key, i in items} -> { key, pos, val }
 *
 */
function loopKeys(expr) {
  var b0 = brackets(0),
    els = expr.trim().slice(b0.length).match(/^\s*(\S+?)\s*(?:,\s*(\S+))?\s+in\s+(.+)$/)
  return els ? { key: els[1], pos: els[2], val: b0 + els[3] } : { val: expr }
}

/**
 * Convert the item looped into an object used to extend the child tag properties
 * @param   { Object } expr - object containing the keys used to extend the children tags
 * @param   { * } key - value to assign to the new object returned
 * @param   { * } val - value containing the position of the item in the array
 * @returns { Object } - new object containing the values of the original item
 *
 * The variables 'key' and 'val' are arbitrary.
 * They depend on the collection type looped (Array, Object)
 * and on the expression used on the each tag
 *
 */
function mkitem(expr, key, val) {
  var item = {}
  item[expr.key] = key
  if (expr.pos) item[expr.pos] = val
  return item
}

/**
 * Unmount the redundant tags
 * @param   { Array } items - array containing the current items to loop
 * @param   { Array } tags - array containing all the children tags
 */
function unmountRedundant(items, tags) {

  var i = tags.length - 1,
    j = items.length - 1

  while (i > j) {
    var t = tags[i]
    tags.splice(i, 1)
    t.unmount()
    i --
  }
}

/**
 * Move the nested custom tags in non custom loop tags
 * @param   { Object } child - non custom loop tag
 * @param   { Number } i - current position of the loop tag
 */
function moveNestedTags(child, i) {
  Object.keys(child.tags).forEach(function(tagName) {
    var tag = child.tags[tagName]
    if (isArray(tag))
      each(tag, function (t) {
        moveChildTag(t, tagName, i)
      })
    else
      moveChildTag(tag, tagName, i)
  })
}

/**
 * Adds the elements for a virtual tag
 * @param { Tag } tag - the tag whose root's children will be inserted or appended
 * @param { Node } src - the node that will do the inserting or appending
 * @param { Tag } target - only if inserting, insert before this tag's first child
 */
function addVirtual(tag, src, target) {
  var el = tag._root
  tag._virts = []
  while (el) {
    var sib = el.nextSibling
    if (target)
      src.insertBefore(el, target._root)
    else
      src.appendChild(el)

    tag._virts.push(el) // hold for unmounting
    el = sib
  }
}

/**
 * Move virtual tag and all child nodes
 * @param { Tag } tag - first child reference used to start move
 * @param { Node } src  - the node that will do the inserting
 * @param { Tag } target - insert before this tag's first child
 * @param { Number } len - how many child nodes to move
 */
function moveVirtual(tag, src, target, len) {
  var el = tag._root
  for (var i = 0; i < len; i++) {
    var sib = el.nextSibling
    src.insertBefore(el, target._root)
    el = sib
  }
}

/**
 * Manage tags having the 'each'
 * @param   { Object } dom - DOM node we need to loop
 * @param   { Tag } parent - parent tag instance where the dom node is contained
 * @param   { String } expr - string contained in the 'each' attribute
 */
function _each(dom, parent, expr) {

  // remove the each property from the original tag
  remAttr(dom, 'each')

  var mustReorder = typeof getAttr(dom, 'no-reorder') !== T_STRING || remAttr(dom, 'no-reorder'),
    tagName = getTagName(dom),
    impl = __tagImpl[tagName] || { tmpl: dom.outerHTML },
    useRoot = SPECIAL_TAGS_REGEX.test(tagName),
    root = dom.parentNode,
    isSpecialTag = SPECIAL_TAGS_REGEX.test(tagName),
    ref = document.createTextNode(''),
    child = getTag(dom),
    tags = [],
    oldItems = [],
    checksum,
    isVirtual = dom.tagName == 'VIRTUAL'

  // parse the each expression
  expr = loopKeys(expr)

  // insert a marked where the loop tags will be injected
  root.insertBefore(ref, dom)

  // clean template code
  parent.one('before-mount', function () {

    // remove the original DOM node
    dom.parentNode.removeChild(dom)
    if (root.stub) root = parent.root

  }).on('update', function () {
    // get the new items collection
    var items = tmpl(tmpl.parse(expr.val), parent),
      // create a fragment to hold the new DOM nodes to inject in the parent tag
      frag = document.createDocumentFragment()

    // object loop. any changes cause full redraw
    if (!isArray(items)) {
      checksum = items ? JSON.stringify(items) : ''
      items = !items ? [] :
        Object.keys(items).map(function (key) {
          return mkitem(expr, key, items[key])
        })
    }

    // loop all the new items
    each(items, function(item, i) {
      // reorder only if the items are objects
      var _mustReorder = mustReorder && item instanceof Object,
        oldPos = oldItems.indexOf(item),
        pos = ~oldPos && _mustReorder ? oldPos : i,
        // does a tag exist in this position?
        tag = tags[pos]

      item = !checksum && expr.key ? mkitem(expr, item, i) : item

      // new tag
      if (!~oldPos || !tag) {

        tag = new Tag(impl, {
          parent: parent,
          isLoop: true,
          hasImpl: !!__tagImpl[tagName],
          root: useRoot ? root : dom.cloneNode(),
          item: item
        }, dom.innerHTML)

        tag.mount()
        if (isVirtual) tag._root = tag.root.firstChild // save reference for further moves or inserts
        // this tag must be appended
        if (i == tags.length) {
          if (isVirtual)
            addVirtual(tag, frag)
          else frag.appendChild(tag.root)
        }
        // this tag must be insert
        else {
          if (isVirtual)
            addVirtual(tag, root, tags[i])
          else root.insertBefore(tag.root, tags[i].root)
          oldItems.splice(i, 0, item)
        }

        tags.splice(i, 0, tag)
        pos = i // handled here so no move
      } else tag.update(item)

      // reorder the tag if it's not located in its previous position
      if (pos !== i && _mustReorder) {
        // update the DOM
        if (isVirtual)
          moveVirtual(tag, root, tags[i], dom.childNodes.length)
        else root.insertBefore(tag.root, tags[i].root)
        // update the position attribute if it exists
        if (expr.pos)
          tag[expr.pos] = i
        // move the old tag instance
        tags.splice(i, 0, tags.splice(pos, 1)[0])
        // move the old item
        oldItems.splice(i, 0, oldItems.splice(pos, 1)[0])
        // if the loop tags are not custom
        // we need to move all their custom tags into the right position
        if (!child) moveNestedTags(tag, i)
      }

      // cache the original item to use it in the events bound to this node
      // and its children
      tag._item = item
      // cache the real parent tag internally
      defineProperty(tag, '_parent', parent)

    })

    // remove the redundant tags
    unmountRedundant(items, tags)

    // insert the new nodes
    if (isSpecialTag) root.appendChild(frag)
    else root.insertBefore(frag, ref)

    // set the 'tags' property of the parent tag
    // if child is 'undefined' it means that we don't need to set this property
    // for example:
    // we don't need store the `myTag.tags['div']` property if we are looping a div tag
    // but we need to track the `myTag.tags['child']` property looping a custom child node named `child`
    if (child) parent.tags[tagName] = tags

    // clone the items array
    oldItems = items.slice()

  })

}
<commit_msg>updated: more readable unmountRedundant function<commit_after>
/**
 * Parse the each expression to detect how to map the collection data to the children tags
 * @param   { String } expr - string passed in the each attribute
 * @returns { Object } object needed to check how the items in the collection
 * should be mapped to the children tags
 *
 * { key, i in items} -> { key, pos, val }
 *
 */
function loopKeys(expr) {
  var b0 = brackets(0),
    els = expr.trim().slice(b0.length).match(/^\s*(\S+?)\s*(?:,\s*(\S+))?\s+in\s+(.+)$/)
  return els ? { key: els[1], pos: els[2], val: b0 + els[3] } : { val: expr }
}

/**
 * Convert the item looped into an object used to extend the child tag properties
 * @param   { Object } expr - object containing the keys used to extend the children tags
 * @param   { * } key - value to assign to the new object returned
 * @param   { * } val - value containing the position of the item in the array
 * @returns { Object } - new object containing the values of the original item
 *
 * The variables 'key' and 'val' are arbitrary.
 * They depend on the collection type looped (Array, Object)
 * and on the expression used on the each tag
 *
 */
function mkitem(expr, key, val) {
  var item = {}
  item[expr.key] = key
  if (expr.pos) item[expr.pos] = val
  return item
}

/**
 * Unmount the redundant tags
 * @param   { Array } items - array containing the current items to loop
 * @param   { Array } tags - array containing all the children tags
 */
function unmountRedundant(items, tags) {

  var i = tags.length,
    j = items.length

  while (i > j) {
    var t = tags[--i]
    tags.splice(i, 1)
    t.unmount()
  }
}

/**
 * Move the nested custom tags in non custom loop tags
 * @param   { Object } child - non custom loop tag
 * @param   { Number } i - current position of the loop tag
 */
function moveNestedTags(child, i) {
  Object.keys(child.tags).forEach(function(tagName) {
    var tag = child.tags[tagName]
    if (isArray(tag))
      each(tag, function (t) {
        moveChildTag(t, tagName, i)
      })
    else
      moveChildTag(tag, tagName, i)
  })
}

/**
 * Adds the elements for a virtual tag
 * @param { Tag } tag - the tag whose root's children will be inserted or appended
 * @param { Node } src - the node that will do the inserting or appending
 * @param { Tag } target - only if inserting, insert before this tag's first child
 */
function addVirtual(tag, src, target) {
  var el = tag._root
  tag._virts = []
  while (el) {
    var sib = el.nextSibling
    if (target)
      src.insertBefore(el, target._root)
    else
      src.appendChild(el)

    tag._virts.push(el) // hold for unmounting
    el = sib
  }
}

/**
 * Move virtual tag and all child nodes
 * @param { Tag } tag - first child reference used to start move
 * @param { Node } src  - the node that will do the inserting
 * @param { Tag } target - insert before this tag's first child
 * @param { Number } len - how many child nodes to move
 */
function moveVirtual(tag, src, target, len) {
  var el = tag._root
  for (var i = 0; i < len; i++) {
    var sib = el.nextSibling
    src.insertBefore(el, target._root)
    el = sib
  }
}

/**
 * Manage tags having the 'each'
 * @param   { Object } dom - DOM node we need to loop
 * @param   { Tag } parent - parent tag instance where the dom node is contained
 * @param   { String } expr - string contained in the 'each' attribute
 */
function _each(dom, parent, expr) {

  // remove the each property from the original tag
  remAttr(dom, 'each')

  var mustReorder = typeof getAttr(dom, 'no-reorder') !== T_STRING || remAttr(dom, 'no-reorder'),
    tagName = getTagName(dom),
    impl = __tagImpl[tagName] || { tmpl: dom.outerHTML },
    useRoot = SPECIAL_TAGS_REGEX.test(tagName),
    root = dom.parentNode,
    isSpecialTag = SPECIAL_TAGS_REGEX.test(tagName),
    ref = document.createTextNode(''),
    child = getTag(dom),
    tags = [],
    oldItems = [],
    checksum,
    isVirtual = dom.tagName == 'VIRTUAL'

  // parse the each expression
  expr = loopKeys(expr)

  // insert a marked where the loop tags will be injected
  root.insertBefore(ref, dom)

  // clean template code
  parent.one('before-mount', function () {

    // remove the original DOM node
    dom.parentNode.removeChild(dom)
    if (root.stub) root = parent.root

  }).on('update', function () {
    // get the new items collection
    var items = tmpl(tmpl.parse(expr.val), parent),
      // create a fragment to hold the new DOM nodes to inject in the parent tag
      frag = document.createDocumentFragment()

    // object loop. any changes cause full redraw
    if (!isArray(items)) {
      checksum = items ? JSON.stringify(items) : ''
      items = !items ? [] :
        Object.keys(items).map(function (key) {
          return mkitem(expr, key, items[key])
        })
    }

    // loop all the new items
    each(items, function(item, i) {
      // reorder only if the items are objects
      var _mustReorder = mustReorder && item instanceof Object,
        oldPos = oldItems.indexOf(item),
        pos = ~oldPos && _mustReorder ? oldPos : i,
        // does a tag exist in this position?
        tag = tags[pos]

      item = !checksum && expr.key ? mkitem(expr, item, i) : item

      // new tag
      if (!~oldPos || !tag) {

        tag = new Tag(impl, {
          parent: parent,
          isLoop: true,
          hasImpl: !!__tagImpl[tagName],
          root: useRoot ? root : dom.cloneNode(),
          item: item
        }, dom.innerHTML)

        tag.mount()
        if (isVirtual) tag._root = tag.root.firstChild // save reference for further moves or inserts
        // this tag must be appended
        if (i == tags.length) {
          if (isVirtual)
            addVirtual(tag, frag)
          else frag.appendChild(tag.root)
        }
        // this tag must be insert
        else {
          if (isVirtual)
            addVirtual(tag, root, tags[i])
          else root.insertBefore(tag.root, tags[i].root)
          oldItems.splice(i, 0, item)
        }

        tags.splice(i, 0, tag)
        pos = i // handled here so no move
      } else tag.update(item)

      // reorder the tag if it's not located in its previous position
      if (pos !== i && _mustReorder) {
        // update the DOM
        if (isVirtual)
          moveVirtual(tag, root, tags[i], dom.childNodes.length)
        else root.insertBefore(tag.root, tags[i].root)
        // update the position attribute if it exists
        if (expr.pos)
          tag[expr.pos] = i
        // move the old tag instance
        tags.splice(i, 0, tags.splice(pos, 1)[0])
        // move the old item
        oldItems.splice(i, 0, oldItems.splice(pos, 1)[0])
        // if the loop tags are not custom
        // we need to move all their custom tags into the right position
        if (!child) moveNestedTags(tag, i)
      }

      // cache the original item to use it in the events bound to this node
      // and its children
      tag._item = item
      // cache the real parent tag internally
      defineProperty(tag, '_parent', parent)

    })

    // remove the redundant tags
    unmountRedundant(items, tags)

    // insert the new nodes
    if (isSpecialTag) root.appendChild(frag)
    else root.insertBefore(frag, ref)

    // set the 'tags' property of the parent tag
    // if child is 'undefined' it means that we don't need to set this property
    // for example:
    // we don't need store the `myTag.tags['div']` property if we are looping a div tag
    // but we need to track the `myTag.tags['child']` property looping a custom child node named `child`
    if (child) parent.tags[tagName] = tags

    // clone the items array
    oldItems = items.slice()

  })

}
<|endoftext|>


<commit_before>(function (B, when) {
    if (typeof require == "function" && typeof module == "object") {
        B = require("buster-core");
        when = require("when");
    }

    var current = [];
    var bspec = {};

    function supportRequirement(property) {
        return function (requirements) {
            return {
                describe: function () {
                    var context = bspec.describe.apply(bspec, arguments);
                    context[property] = requirements;
                    return context;
                }
            };
        };
    }

    bspec.ifAllSupported = supportRequirement("requiresSupportForAll");
    bspec.ifAnySupported = supportRequirement("requiresSupportForAny");
    bspec.ifSupported = bspec.ifAllSupported;

    function addContext(parent, name, spec) {
        var context = bspec.describe.context.create(name, spec, parent).parse();
        parent.contexts.push(context);
        return context;
    }

    function createContext(name, spec) {
        var context = bspec.describe.context.create(name, spec).parse();
        if (bspec.describe.onCreate) { bspec.describe.onCreate(context); }
        return context;
    }

    function asyncContext(name, callback) {
        var d = when.defer();
        callback(function (spec) {
            d.resolver.resolve(createContext(name, spec));
        });
        return d.promise;
    }

    bspec.describe = function (name, spec) {
        if (current.length > 0) {
            return addContext(current[current.length - 1], name, spec);
        }
        if (spec && spec.length > 0) {
            return asyncContext(name, spec);
        }
        return createContext(name, spec);
    };

    B.extend(bspec.describe, B.eventEmitter);

    bspec.it = function (name, func) {
        var context = current[current.length - 1];

        var spec = {
            name: name,
            func: arguments.length == 3 ? arguments[2] : func,
            context: context
        };

        spec.deferred = typeof func != "function";
        spec.comment = spec.deferred ? func : "";
        context.tests.push(spec);
        return spec;
    };

    bspec.itEventually = function (name, comment, func) {
        if (typeof comment == "function") {
            func = comment;
            comment = "";
        }

        return bspec.it(name, comment, func);
    };

    bspec.before = function (func) {
        var context = current[current.length - 1];
        context.setUp = func;
    };

    bspec.after = function (func) {
        var context = current[current.length - 1];
        context.tearDown = func;
    };

    bspec.describe.context = {
        create: function (name, spec, parent) {
            if (!name || typeof name != "string") {
                throw new Error("Spec name required");
            }

            if (!spec || typeof spec != "function") {
                throw new Error("spec should be a function");
            }

            var context = B.create(this);
            context.name = name;
            context.parent = parent;
            context.spec = spec;

            return context;
        },

        parse: function () {
            if (!this.spec) {
                return this;
            }

            this.testCase = {
                before: bspec.before,
                after: bspec.after,
                it: bspec.it,
                itEventually: bspec.itEventually,
                describe: bspec.describe
            };

            this.tests = [];
            current.push(this);
            this.contexts = [];
            this.spec.call(this.testCase);
            current.pop();
            delete this.spec;

            return this;
        }
    };

    var g = typeof global != "undefined" && global || this;

    bspec.expose = function (env) {
        env = env || g;
        env.describe = bspec.describe;
        env.it = bspec.it;
        env.itEventually = bspec.itEventually;
        env.before = bspec.before;
        env.after = bspec.after;
    };

    if (typeof module == "object") {
        module.exports = bspec;
    } else {
        B.spec = bspec;
    }
}(this.buster, this.when));
<commit_msg>Less this.buster<commit_after>(function (B, when) {
    if (typeof require == "function" && typeof module == "object") {
        B = require("buster-core");
        when = require("when");
    }

    var current = [];
    var bspec = {};

    function supportRequirement(property) {
        return function (requirements) {
            return {
                describe: function () {
                    var context = bspec.describe.apply(bspec, arguments);
                    context[property] = requirements;
                    return context;
                }
            };
        };
    }

    bspec.ifAllSupported = supportRequirement("requiresSupportForAll");
    bspec.ifAnySupported = supportRequirement("requiresSupportForAny");
    bspec.ifSupported = bspec.ifAllSupported;

    function addContext(parent, name, spec) {
        var context = bspec.describe.context.create(name, spec, parent).parse();
        parent.contexts.push(context);
        return context;
    }

    function createContext(name, spec) {
        var context = bspec.describe.context.create(name, spec).parse();
        if (bspec.describe.onCreate) { bspec.describe.onCreate(context); }
        return context;
    }

    function asyncContext(name, callback) {
        var d = when.defer();
        callback(function (spec) {
            d.resolver.resolve(createContext(name, spec));
        });
        return d.promise;
    }

    bspec.describe = function (name, spec) {
        if (current.length > 0) {
            return addContext(current[current.length - 1], name, spec);
        }
        if (spec && spec.length > 0) {
            return asyncContext(name, spec);
        }
        return createContext(name, spec);
    };

    B.extend(bspec.describe, B.eventEmitter);

    bspec.it = function (name, func) {
        var context = current[current.length - 1];

        var spec = {
            name: name,
            func: arguments.length == 3 ? arguments[2] : func,
            context: context
        };

        spec.deferred = typeof func != "function";
        spec.comment = spec.deferred ? func : "";
        context.tests.push(spec);
        return spec;
    };

    bspec.itEventually = function (name, comment, func) {
        if (typeof comment == "function") {
            func = comment;
            comment = "";
        }

        return bspec.it(name, comment, func);
    };

    bspec.before = function (func) {
        var context = current[current.length - 1];
        context.setUp = func;
    };

    bspec.after = function (func) {
        var context = current[current.length - 1];
        context.tearDown = func;
    };

    bspec.describe.context = {
        create: function (name, spec, parent) {
            if (!name || typeof name != "string") {
                throw new Error("Spec name required");
            }

            if (!spec || typeof spec != "function") {
                throw new Error("spec should be a function");
            }

            var context = B.create(this);
            context.name = name;
            context.parent = parent;
            context.spec = spec;

            return context;
        },

        parse: function () {
            if (!this.spec) {
                return this;
            }

            this.testCase = {
                before: bspec.before,
                after: bspec.after,
                it: bspec.it,
                itEventually: bspec.itEventually,
                describe: bspec.describe
            };

            this.tests = [];
            current.push(this);
            this.contexts = [];
            this.spec.call(this.testCase);
            current.pop();
            delete this.spec;

            return this;
        }
    };

    var g = typeof global != "undefined" && global || this;

    bspec.expose = function (env) {
        env = env || g;
        env.describe = bspec.describe;
        env.it = bspec.it;
        env.itEventually = bspec.itEventually;
        env.before = bspec.before;
        env.after = bspec.after;
    };

    if (typeof module == "object") {
        module.exports = bspec;
    } else {
        B.spec = bspec;
    }
}(typeof buster !== "undefined" ? buster : {},
  typeof when === "function" ? when : function () {}));
<|endoftext|>


<commit_before>var scrypt = require("scrypt");
var name2Key = require("kamelladjutant-common").name2Key;

var notMe = function(client) {
    return function(other) {
        return client !== other;
    }
}
var roommates = function(client) {
    if (!client.room) {
        return function() {
            return false;
        };
    } else {
        return function(other) {
            return client !== other && client.room == other.room;
        }
    }
}

var callbacksFactory = function(log, redisClient) {
    return {
        // mop: maybe create a room class which handles all the clients.filter stuff etc.
        createNullStateCallbacks: function(client, clients, changeToConnectedFn) {
            return {
                // mop: WHOAAA...way too long that function beast :O need refactor :O
                "connect": function(data, replyFn) {
                    log.debug("Got data", data);
                    var room = data.roomname;
                    var redisKey = name2Key(room);
                    log.debug("Fetching", redisKey, "from redis");
                    redisClient.get(redisKey, function(err, rawData) {
                        if (err) {
                            log.error("Got error from redis", err);
                            return reply({"err": "INTERNAL_ERROR"});
                        }

                        if (rawData === null) {
                            return replyFn({"err": "notfound"});
                        }

                        var connectClient = function() {
                            if (clients.filter(roommates(client)).filter(function(otherClient) {
                                return otherClient.name == data.username;
                            }).length > 0) {
                                return replyFn({"err": "USERNAME_CONFLICT"});
                            }

                            client.room = data.roomname;
                            client.name = data.username;

                            clients.filter(roommates(client)).forEach(function(otherClient) {
                                otherClient.mopRpc.send("users", clients.filter(roommates(otherClient)).map(function(roommate) {
                                    return {"id": roommate.id, "name": roommate.name};
                                }));
                            });
                            changeToConnectedFn();
                            replyFn({"err": null});
                        }
                        var redisData = JSON.parse(rawData);
                        log.info("redis", rawData, redisData);
                        // mop: folding level is not yet deep enough to make me refacor it :O
                        if (redisData.password) {
                            scrypt.verifyHash(redisData.password, data.password, function(err, result) {
                                log.info("Verify", err, result);
                                if (!err) {
                                    connectClient();
                                } else {
                                    return replyFn({"err": "CREDENTIALS"});
                                }
                            });
                        } else {
                            connectClient();
                        }
                    });
                }
            };
        },
        createConnectedStateCallbacks: function(client, clients) {
            return {
                "users": function(data, replyFn) {
                    if (!client.room) {
                        replyFn(null);
                    } else {
                        var users = clients.filter(notMe(client)).filter(function(otherClient) {
                                return otherClient.room == client.room;
                            }).map(function(otherClient) {
                                return {"id": otherClient.id, "name": otherClient.name};
                            });
                        replyFn(users);
                    }
                },
                "initiate": function(data, initiateReplyFn) {
                    var peers = clients.filter(roommates(client)).filter(function(roommate) {
                        return roommate.id == data.id;
                    });
                    if (peers.length == 1) {
                        var peerData = {"id": client.id, "offerSDP": data.offerSDP, "offerCandidates": data.offerCandidates};
                        peers[0].mopRpc.send("initiate", peerData, function(answerRTCData) {
                            initiateReplyFn(answerRTCData, {"replyTimeout": 20000});
                        }, {"replyTimeout": 20000});
                    } else {
                        log.warn("Couldn't find user with id", data.id, "in room", client.room);
                    }
                }
            }
        }
    };
};
module.exports = callbacksFactory;
<commit_msg>Offer and answer candidates will be determined simulateously<commit_after>var scrypt = require("scrypt");
var name2Key = require("kamelladjutant-common").name2Key;

var notMe = function(client) {
    return function(other) {
        return client !== other;
    }
}
var roommates = function(client) {
    if (!client.room) {
        return function() {
            return false;
        };
    } else {
        return function(other) {
            return client !== other && client.room == other.room;
        }
    }
}

var callbacksFactory = function(log, redisClient) {
    return {
        // mop: maybe create a room class which handles all the clients.filter stuff etc.
        createNullStateCallbacks: function(client, clients, changeToConnectedFn) {
            return {
                // mop: WHOAAA...way too long that function beast :O need refactor :O
                "connect": function(data, replyFn) {
                    log.debug("Got data", data);
                    var room = data.roomname;
                    var redisKey = name2Key(room);
                    log.debug("Fetching", redisKey, "from redis");
                    redisClient.get(redisKey, function(err, rawData) {
                        if (err) {
                            log.error("Got error from redis", err);
                            return reply({"err": "INTERNAL_ERROR"});
                        }

                        if (rawData === null) {
                            return replyFn({"err": "notfound"});
                        }

                        var connectClient = function() {
                            if (clients.filter(roommates(client)).filter(function(otherClient) {
                                return otherClient.name == data.username;
                            }).length > 0) {
                                return replyFn({"err": "USERNAME_CONFLICT"});
                            }

                            client.room = data.roomname;
                            client.name = data.username;

                            clients.filter(roommates(client)).forEach(function(otherClient) {
                                otherClient.mopRpc.send("users", clients.filter(roommates(otherClient)).map(function(roommate) {
                                    return {"id": roommate.id, "name": roommate.name};
                                }));
                            });
                            changeToConnectedFn();
                            replyFn({"err": null});
                        }
                        var redisData = JSON.parse(rawData);
                        log.info("redis", rawData, redisData);
                        // mop: folding level is not yet deep enough to make me refacor it :O
                        if (redisData.password) {
                            scrypt.verifyHash(redisData.password, data.password, function(err, result) {
                                log.info("Verify", err, result);
                                if (!err) {
                                    connectClient();
                                } else {
                                    return replyFn({"err": "CREDENTIALS"});
                                }
                            });
                        } else {
                            connectClient();
                        }
                    });
                }
            };
        },
        createConnectedStateCallbacks: function(client, clients) {
            return {
                "users": function(data, replyFn) {
                    if (!client.room) {
                        replyFn(null);
                    } else {
                        var users = clients.filter(notMe(client)).filter(function(otherClient) {
                                return otherClient.room == client.room;
                            }).map(function(otherClient) {
                                return {"id": otherClient.id, "name": otherClient.name};
                            });
                        replyFn(users);
                    }
                },
                "initiate": function(data, answerSDPFn) {
                    var peers = clients.filter(roommates(client)).filter(function(roommate) {
                        return roommate.id == data.id;
                    });
                    if (peers.length == 1) {
                        var peerData = {"id": client.id, "offerSDP": data.offerSDP};
                        // mop: :S:S:S the power (AND CONFUSION) of mop-rpc
                        peers[0].mopRpc.send("initiate", peerData, function(answerSDP, offerCandidatesFn) {
                            answerSDPFn(answerSDP, function(offerCandidates, answerCandidatesFn) {
                                offerCandidatesFn(offerCandidates, function(answerCandidates) {
                                    answerCandidatesFn(answerCandidates);
                                }, {"replyTimeout": 20000});
                            }, {"replyTimeout": 20000});
                        }, {"replyTimeout": 20000});
                    } else {
                        log.warn("Couldn't find user with id", data.id, "in room", client.room);
                    }
                }
            }
        }
    };
};
module.exports = callbacksFactory;
<|endoftext|>


<commit_before>// Load the cache with HTTP headers as the key and camel case headers as the value in

const fs = require('fs');
const headerToCamelCache = JSON.parse(fs.readFileSync('lib/headersToCamelCase.json').toString());

// Load the cache with camel case headers as the key and HTP headers as the value in

const camelToHeaderCache = JSON.parse(fs.readFileSync('lib/camelCaseToHeaders.json').toString());

/**
 * Parses an object using the specified parse function
 * @param {function} parseFunction the parsing function to use
 * @param {object} object the object to parse
 */
const parseObject = (parseFunction, object) => {

	// Map the object's keys

	const objectKeys = Object.keys(object);
	const newObjectKeys = Object.keys(object).map(parseFunction);

	// Create a new object with the values

	const toReturn = { };
	for (let i = 0; i < newObjectKeys.length; i++) {
		toReturn[newObjectKeys[i]] = object[objectKeys[i]];
	}

	return toReturn;
};

module.exports = {
	/**
	 * Converts the object's HTTP header keys keys to `camelCase`
	 * @param {Object.<string, string>} object the object to convert
	 * @return {Object.<string, string>} the converted object
	 */
	'headerObjectToCamel': object => parseObject(module.exports.headerStringToCamel, object),
	/**
	 * Converts the passed in HTTP header key string to `camelCase`
	 * @param {string} object the object to convert to a string
	 * @return {string} the converted string
	 */
	'headerStringToCamel': string => {

		// Check the cache for the passed in string

		const cachedCamelCaseHeader = headerToCamelCache[string];
		if (cachedCamelCaseHeader) {

			// Return the cached header if it is present

			return cachedCamelCaseHeader;
		}

		// If the header is not cached, parse it

		// Split the dashes
		// ex. 'x-requested-with' becomes ['x', 'requested', 'with'], 'cache-control' becomes ['cache', 'control'], etc.

		const splitHeaders = string.split('-');

		// The start of the current header name is the first in the array, NOT CAPATALIZED
		// ex. 'x' in 'x-requested-with'

		var camelCaseHeader = splitHeaders[0];

		// Loop through the array

		for (let i = 1; i < splitHeaders.length; i++) {

			// Capatalize the first letter and add it on to the camelCaseHeader variable

			const currentWord = splitHeaders[i];
			camelCaseHeader += currentWord.charAt(0).toUpperCase() + currentWord.substring(1);
		}

		return camelCaseHeader;
	},
	/**
	 * Converts the object's `camelCase` header keys keys to HTTP formatted keys
	 * @param {Object.<string, string>} object the object to convert
	 * @return {Object.<string, string>} the converted object
	 */
	'camelObjectToHeader': object => parseObject(module.exports.camelStringToHeader, object),
	/** Converts the passed in HTTP header key string to `camelCase`
	 * @param {string} object the object to convert to a string
	 * @return {string} the converted string
	 */
	'camelStringToHeader': string => {

		// Check the cache for the passed in string

		const cachedHttpHeader = camelToHeaderCache[string];
		if (cachedHttpHeader) {

			// Return the cached header if it is present

			return cachedHttpHeader;
		}

		// If the header is not cached, parse it

		// Loop through the string and create an array of strings (ex. 'xRequestedWith' gets converted to ['x', 'requested', 'with'])

		const stringChars = string.split("");

		/**
		 * The final header, to be returned.
		 */
		var header = stringChars[0].toUpperCase();

		 for (let i = 1; i < stringChars.length; i++) {

			 // Check if the current char is uppercase, if so, add a '-' and the current letter

			 if (stringChars[i].toUpperCase() === stringChars[i]) {
				header += '-' + stringChars[i];
			 } else {

				// If not, then just add the letter

				header += stringChars[i];

			 }
		 }

		 return header;
	}
};<commit_msg>Fixed file not found error on startup<commit_after>// Load the cache with HTTP headers as the key and camel case headers as the value in

const fs = require('fs'),
path = require('path');
const headerToCamelCache = JSON.parse(fs.readFileSync(path.join(__dirname + '/headersToCamelCase.json')).toString());

// Load the cache with camel case headers as the key and HTP headers as the value in

const camelToHeaderCache = JSON.parse(fs.readFileSync(path.join(__dirname + '/camelCaseToHeaders.json')).toString());

/**
 * Parses an object using the specified parse function
 * @param {function} parseFunction the parsing function to use
 * @param {object} object the object to parse
 */
const parseObject = (parseFunction, object) => {

	// Map the object's keys

	const objectKeys = Object.keys(object);
	const newObjectKeys = Object.keys(object).map(parseFunction);

	// Create a new object with the values

	const toReturn = { };
	for (let i = 0; i < newObjectKeys.length; i++) {
		toReturn[newObjectKeys[i]] = object[objectKeys[i]];
	}

	return toReturn;
};

module.exports = {
	/**
	 * Converts the object's HTTP header keys keys to `camelCase`
	 * @param {Object.<string, string>} object the object to convert
	 * @return {Object.<string, string>} the converted object
	 */
	'headerObjectToCamel': object => parseObject(module.exports.headerStringToCamel, object),
	/**
	 * Converts the passed in HTTP header key string to `camelCase`
	 * @param {string} object the object to convert to a string
	 * @return {string} the converted string
	 */
	'headerStringToCamel': string => {

		// Check the cache for the passed in string

		const cachedCamelCaseHeader = headerToCamelCache[string];
		if (cachedCamelCaseHeader) {

			// Return the cached header if it is present

			return cachedCamelCaseHeader;
		}

		// If the header is not cached, parse it

		// Split the dashes
		// ex. 'x-requested-with' becomes ['x', 'requested', 'with'], 'cache-control' becomes ['cache', 'control'], etc.

		const splitHeaders = string.split('-');

		// The start of the current header name is the first in the array, NOT CAPATALIZED
		// ex. 'x' in 'x-requested-with'

		var camelCaseHeader = splitHeaders[0];

		// Loop through the array

		for (let i = 1; i < splitHeaders.length; i++) {

			// Capatalize the first letter and add it on to the camelCaseHeader variable

			const currentWord = splitHeaders[i];
			camelCaseHeader += currentWord.charAt(0).toUpperCase() + currentWord.substring(1);
		}

		return camelCaseHeader;
	},
	/**
	 * Converts the object's `camelCase` header keys keys to HTTP formatted keys
	 * @param {Object.<string, string>} object the object to convert
	 * @return {Object.<string, string>} the converted object
	 */
	'camelObjectToHeader': object => parseObject(module.exports.camelStringToHeader, object),
	/** Converts the passed in HTTP header key string to `camelCase`
	 * @param {string} object the object to convert to a string
	 * @return {string} the converted string
	 */
	'camelStringToHeader': string => {

		// Check the cache for the passed in string

		const cachedHttpHeader = camelToHeaderCache[string];
		if (cachedHttpHeader) {

			// Return the cached header if it is present

			return cachedHttpHeader;
		}

		// If the header is not cached, parse it

		// Loop through the string and create an array of strings (ex. 'xRequestedWith' gets converted to ['x', 'requested', 'with'])

		const stringChars = string.split("");

		/**
		 * The final header, to be returned.
		 */
		var header = stringChars[0].toUpperCase();

		 for (let i = 1; i < stringChars.length; i++) {

			 // Check if the current char is uppercase, if so, add a '-' and the current letter

			 if (stringChars[i].toUpperCase() === stringChars[i]) {
				header += '-' + stringChars[i];
			 } else {

				// If not, then just add the letter

				header += stringChars[i];

			 }
		 }

		 return header;
	}
};<|endoftext|>


<commit_before>import program from 'commander';
import chalk from 'chalk';
import envinfo from 'envinfo';
import pkg from '../package.json';
import initiate from '../lib/initiate';
import { codeLog } from '../lib/helpers';
import add from '../lib/add';
import { migrate } from '../lib/migrate';

const logger = console;

if (process.argv[1].includes('getstorybook')) {
  logger.log(chalk.yellow('WARNING: getstorybook is deprecated.'));
  logger.log(chalk.yellow('The official command to install Storybook from now on is:\n'));
  codeLog(['sb init']);
  logger.log();
  initiate({}, pkg).then(() => process.exit(0));
} else {
  program
    .command('init')
    .description('Initialize Storybook into your project.')
    .option('-f --force', 'Forcely add storybook')
    .option('-s --skip-install', 'Skip installing deps')
    .option('-N --use-npm', 'Use npm to install deps')
    .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
    .option('-t --type <type>', 'Add Storybook for a specific project type')
    .option('-y --yes', 'Answer yes to all prompts')
    .action(options => initiate(options, pkg));

  program
    .command('add <addon>')
    .description('Add an addon to your Storybook')
    .option('-N --use-npm', 'Use NPM to build the Storybook server')
    .action((addonName, options) => add(addonName, options));

  program
    .command('info')
    .description('Prints debugging information about the local environment')
    .action(() => {
      logger.log(chalk.bold('\nEnvironment Info:'));
      envinfo
        .run({
          System: ['OS', 'CPU'],
          Binaries: ['Node', 'Yarn', 'npm'],
          Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
          npmGlobalPackages: '@storybook/*',
        })
        .then(logger.log);
    });

  program
    .command('migrate [migration]')
    .description('Run a storybook codemod migration on your source files')
    .option('-l --list', 'List available migrations')
    .option('-g --glob <glob>', 'Glob for files upon which to apply the migration', '**/*.js')
    .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
    .option(
      '-n --dry-run',
      'Dry run: verify the migration exists and show the files to which it will be applied'
    )
    .option(
      '-r --rename <from-to>',
      'Rename suffix of matching files after codemod has been applied, e.g. ".js:.ts"'
    )
    .action((migration, { configDir, glob, dryRun, list, rename, parser }) => {
      migrate(migration, { configDir, glob, dryRun, list, rename, parser, logger }).catch(err => {
        logger.error(err);
        process.exit(1);
      });
    });

  program.command('*', { noHelp: true }).action(cmd => {
    logger.error('Invalid command: %s.\nSee --help for a list of available commands.', cmd);
    process.exit(1);
  });

  program
  .usage('<command> [options]')
  .version(pkg.version)
  .parse(process.argv);

  if (!program.args.length) {
    program.help();
  }
}
<commit_msg>FIX linting<commit_after>import program from 'commander';
import chalk from 'chalk';
import envinfo from 'envinfo';
import pkg from '../package.json';
import initiate from '../lib/initiate';
import { codeLog } from '../lib/helpers';
import add from '../lib/add';
import { migrate } from '../lib/migrate';

const logger = console;

if (process.argv[1].includes('getstorybook')) {
  logger.log(chalk.yellow('WARNING: getstorybook is deprecated.'));
  logger.log(chalk.yellow('The official command to install Storybook from now on is:\n'));
  codeLog(['sb init']);
  logger.log();
  initiate({}, pkg).then(() => process.exit(0));
} else {
  program
    .command('init')
    .description('Initialize Storybook into your project.')
    .option('-f --force', 'Forcely add storybook')
    .option('-s --skip-install', 'Skip installing deps')
    .option('-N --use-npm', 'Use npm to install deps')
    .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
    .option('-t --type <type>', 'Add Storybook for a specific project type')
    .option('-y --yes', 'Answer yes to all prompts')
    .action(options => initiate(options, pkg));

  program
    .command('add <addon>')
    .description('Add an addon to your Storybook')
    .option('-N --use-npm', 'Use NPM to build the Storybook server')
    .action((addonName, options) => add(addonName, options));

  program
    .command('info')
    .description('Prints debugging information about the local environment')
    .action(() => {
      logger.log(chalk.bold('\nEnvironment Info:'));
      envinfo
        .run({
          System: ['OS', 'CPU'],
          Binaries: ['Node', 'Yarn', 'npm'],
          Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
          npmGlobalPackages: '@storybook/*',
        })
        .then(logger.log);
    });

  program
    .command('migrate [migration]')
    .description('Run a storybook codemod migration on your source files')
    .option('-l --list', 'List available migrations')
    .option('-g --glob <glob>', 'Glob for files upon which to apply the migration', '**/*.js')
    .option('-p --parser <babel | babylon | flow | ts | tsx>', 'jscodeshift parser')
    .option(
      '-n --dry-run',
      'Dry run: verify the migration exists and show the files to which it will be applied'
    )
    .option(
      '-r --rename <from-to>',
      'Rename suffix of matching files after codemod has been applied, e.g. ".js:.ts"'
    )
    .action((migration, { configDir, glob, dryRun, list, rename, parser }) => {
      migrate(migration, { configDir, glob, dryRun, list, rename, parser, logger }).catch(err => {
        logger.error(err);
        process.exit(1);
      });
    });

  program.command('*', { noHelp: true }).action(cmd => {
    logger.error('Invalid command: %s.\nSee --help for a list of available commands.', cmd);
    process.exit(1);
  });

  program
    .usage('<command> [options]')
    .version(pkg.version)
    .parse(process.argv);

  if (!program.args.length) {
    program.help();
  }
}
<|endoftext|>


<commit_before>/*
               ______                           ______  ____
              / ____/________  __  ______  ____/ / __ \/ __ )
             / / __/ ___/ __ \/ / / / __ \/ __  / / / / __  |
            / /_/ / /  / /_/ / /_/ / / / / /_/ / /_/ / /_/ /
            \____/_/   \____/\__,_/_/ /_/\__,_/_____/_____/

GroundDB is a thin layer providing Meteor offline database and methods

Concept, localstorage is simple wide spread but slow

GroundDB saves outstanding methods and minimongo into localstorage at window
unload, but can be configured to save at any changes and at certain interval(ms)

When the app loads GroundDB resumes methods and database changes

Regz. RaiX

*/

/* global Ground: true */
/* global EventEmitter: false */  // raix:eventemitter */
/* global Kernel: false */        // dispatch:kernel */
/* global LocalForage: false */   // raix:localforeage

//////////////////////////////// GROUND DATABASE ///////////////////////////////
Ground = {};

// Global helper for applying grounddb on a collection
Ground.Collection = class GroundCollection extends Mongo.Collection {

  constructor(name, {
    // Ground db options
    version=1.0,
    conflictHandler=UpdateLogic,
    // Default Mongo.Collection options
    connection=undefined,
    idGeneration='STRING',
    transform=undefined,
    _driver=undefined,
    _preventAutopublish=true // Mongo.Collection default is false
  } = {}) {

    if (name !== ''+name || name === '') {
      throw new Meteor.Error('missing-name', 'Ground.Collection requires a collection name');
    }

    super(name, { connection, idGeneration, transform, _driver, _preventAutopublish });

    // Rig an event handler on Meteor.Collection
    this.eventemitter = new EventState();

    // Count for pending write operations
    this.pendingWrites = new ProgressCount();

    // Count for pending read operations
    this.pendingReads = new ProgressCount();

    // Carry last updated at if supported by schema
    this.lastUpdatedAt = null;

    // Is this an offline client only database?
    this.offlineDatabase = (connection === null);

    this.isLoaded = false;

    // Create scoped storage
    this.storage = new LocalForage({
      name: name,
      version: 1.0 // options.version
    });

    // Overwrite default logic on connection
    if (this._connection) {
      // Instanciate update logic
      let updateLogic = new conflictHandler(this);

      this._connection._stores[ this._name ].update = (ddp) => {
        var mongoId = ddp.id && MongoID.idParse(ddp.id);
        var doc = ddp.id && this._collection.findOne(mongoId);

        // remove _id from document
        if (doc) delete doc._id;

        if (ddp.msg === 'replace') {
          if (ddp.replace) {
            if (doc) {
              let fields = DiffSequence.makeChangedFields(ddp.replace, doc);
              delete fields._id;
              updateLogic.changed(mongoId, fields, doc);
            } else {
              updateLogic.added(mongoId, ddp.replace);
            }
          } else {
            updateLogic.removed(mongoId, doc);
          }
        } else if (ddp.msg === 'added') {
          if (doc) {
            let fields = DiffSequence.makeChangedFields(ddp.fields, doc);
            delete fields._id;
            updateLogic.changed(mongoId, fields, doc);
          } else {
            updateLogic.added(mongoId, ddp.fields);
          }
        } else if (ddp.msg === 'changed') {
          if (doc) {
            // let fields = DiffSequence.makeChangedFields(ddp.fields, doc);
            updateLogic.changed(mongoId, ddp.fields, doc);
          } else {
            updateLogic.added(mongoId, ddp.fields);
          }
        } else if (ddp.msg === 'removed') {
          updateLogic.removed(mongoId, doc);
        }
      };

    } // EO Connection update overwrite

    // Auto store updates locally
    this.monitorChanges();

    // Load database from local storage
    this.loadDatabase();
  }

  loadDatabase() {
    // Then load the docs into minimongo
    this.pendingReads.inc();
    this.storage
      .ready(() => {

        this.storage
          .length()
          .then(len => {
            if (len === 0) {
              this.pendingReads.dec();
              Kernel.defer(() => {
                console.log('LOADED');
                this.isLoaded = true;
                this.emitState('loaded', { count: len });
              });
            } else {
              // Update progress
              this.pendingReads.inc(len);
              // Count handled documents
              let handled = 0;
              this.storage
                .iterate((doc, id) => {

                  Kernel.defer(() => {

                    // Add the document to minimongo
                    this._collection._docs._map[id] = doc;

                    // Update progress
                    this.pendingReads.dec();

                    // Check if all documetns have been handled
                    if (++handled === len) {
                      this.invalidate();
                      Kernel.defer(() => {
                        console.log('LOADED');
                        this.isLoaded = true;
                        this.emitState('loaded', { count: len });
                      });
                    }
                  });

                })
                .then(() => {
                  this.pendingReads.dec();
                });
            }

          });
      });
  }

  saveDocument(doc, remove) {
    if (this.isLoaded) {
      this.pendingWrites.inc();

      this.storage
        .ready(() => {

          if (remove) {
            this.storage
              .removeItem(doc._id)
              .then(() => {
                this.pendingWrites.dec();
              });
          } else {
            this.storage
              .setItem(doc._id, doc)
              .then(() => {
                this.pendingWrites.dec();
              });
          }

        });

    }
    // xxx: should we buffer changes?
  }

  getLastUpdated(doc) {
    var result = null;

    if (doc.updatedAt || doc.createdAt || doc.removedAt) {
      result = new Date(Math.max(doc.updatedAt || null, doc.createdAt || null, doc.removedAt || null));
    }

    return result;
  }

  setLastUpdated(lastUpdatedAt) {
    if (lastUpdatedAt) {
      if (this.lastUpdatedAt < lastUpdatedAt || !this.lastUpdatedAt) {
        this.lastUpdatedAt = lastUpdatedAt || null;
      }
    }
  }

  monitorChanges() {
    // Store documents to localforage
    this.find().observe({
      'added': doc => {
        this.setLastUpdated(this.getLastUpdated(doc));
        this.saveDocument(doc);
      },
      // If removedAt is set this means the document should be removed
      'changed': (doc, oldDoc) => {
        this.setLastUpdated(this.getLastUpdated(doc));

        if (this.lastUpdatedAt) {
          if (doc.removedAt && !oldDoc.removedAt) {
            // Remove the document completely
            this._collection.remove(doc._id);
            this.saveDocument(doc, true);
          } else {
            this.saveDocument(doc);
          }
        } else {
          this.saveDocument(doc);
        }
      },
      // If lastUpdated is supported by schema we should not use removed
      // any more - rather catch this in the changed event...
      'removed': doc => {
        if (!this.lastUpdatedAt) {
          this.saveDocument(doc, true); }
        }
    });
  }

  shutdown(callback) {
    // xxx: have a better lock / fence
    this.writeFence = true;

    return new Promise(resolve => {
      Tracker.autorun(c => {
        // Wait until all writes have been done
        if (this.pendingWrites.isDone()) {
          c.stop();

          if (typeof callback === 'function') callback();
          resolve();
        }
      });
    });
  }

  invalidate() {
    Object.keys(this._collection.queries)
      .forEach(key => {
        // this._collection.queries[key].changed();
      });
  }

  clear() {
    this.storage.clear();
    //this._collection.remove({}, { multi: true });
    this._collection._docs._map = {};
    this.invalidate();
  }
  //////////////////////////////////////////////////////////////////////////////
  // WRAP EVENTEMITTER API on prototype
  //////////////////////////////////////////////////////////////////////////////

  // Wrap the Event Emitter Api "on"
  on(/* arguments */) {
    return this.eventemitter.on(...arguments);
  }

  // Wrap the Event Emitter Api "once"
  once(/* arguments */) {
    return this.eventemitter.once(...arguments);
  }

  // Wrap the Event Emitter Api "off"
  off(/* arguments */) {
    return this.eventemitter.off(...arguments);
  }

  // Wrap the Event Emitter Api "emit"
  emit(/* arguments */) {
    return this.eventemitter.emit(...arguments);
  }

  // Wrap the Event Emitter Api "emit"
  emitState(/* arguments */) {
    return this.eventemitter.emitState(...arguments);
  }

  // // Add api helpers
  addListener(/* arguments */) {
    return this.eventemitter.on(...arguments);
  }

  removeListener(/* arguments */) {
    return this.eventemitter.off(...arguments);
  }

  removeAllListeners(/* arguments */) {
    return this.eventemitter.off(...arguments);
  }

  // // Add jquery like helpers
  one(/* arguments */) {
    return this.eventemitter.once(...arguments);
  }

  trigger(/* arguments */) {
    return this.eventemitter.emit(...arguments);
  }

};

/**
 * Default update logic - for conflict handling "server-win"
 *
 * This class can be used as a base for building custom conflict
 * handlers.
 */
UpdateLogic = class UpdateLogic {

  constructor(collection) {
    this.collection = collection;
  }

  added(id, doc) {
    this.collection._collection.insert(_.extend({ _id: id }, doc));
  }

  changed(id, fields, oldDoc) {
    if (!_.empty(fields)) {
      this.collection._collection.update({ _id: id }, this.modifier(fields));
    }
  }

  removed(id, oldDoc) {
    this.collection._collection.remove({ _id: id });
  }

  modifier(fields) {
    var mod = {};
    _.each(fields, (value, key) => {
      if (value === undefined) {
        if (!mod.$unset)
          mod.$unset = {};
        mod.$unset[key] = 1;
      } else {
        if (!mod.$set)
          mod.$set = {};
        mod.$set[key] = value;
      }
    });

    return mod;
  }
};
<commit_msg>wrong Underscore naming<commit_after>/*
               ______                           ______  ____
              / ____/________  __  ______  ____/ / __ \/ __ )
             / / __/ ___/ __ \/ / / / __ \/ __  / / / / __  |
            / /_/ / /  / /_/ / /_/ / / / / /_/ / /_/ / /_/ /
            \____/_/   \____/\__,_/_/ /_/\__,_/_____/_____/

GroundDB is a thin layer providing Meteor offline database and methods

Concept, localstorage is simple wide spread but slow

GroundDB saves outstanding methods and minimongo into localstorage at window
unload, but can be configured to save at any changes and at certain interval(ms)

When the app loads GroundDB resumes methods and database changes

Regz. RaiX

*/

/* global Ground: true */
/* global EventEmitter: false */  // raix:eventemitter */
/* global Kernel: false */        // dispatch:kernel */
/* global LocalForage: false */   // raix:localforeage

//////////////////////////////// GROUND DATABASE ///////////////////////////////
Ground = {};

// Global helper for applying grounddb on a collection
Ground.Collection = class GroundCollection extends Mongo.Collection {

  constructor(name, {
    // Ground db options
    version=1.0,
    conflictHandler=UpdateLogic,
    // Default Mongo.Collection options
    connection=undefined,
    idGeneration='STRING',
    transform=undefined,
    _driver=undefined,
    _preventAutopublish=true // Mongo.Collection default is false
  } = {}) {

    if (name !== ''+name || name === '') {
      throw new Meteor.Error('missing-name', 'Ground.Collection requires a collection name');
    }

    super(name, { connection, idGeneration, transform, _driver, _preventAutopublish });

    // Rig an event handler on Meteor.Collection
    this.eventemitter = new EventState();

    // Count for pending write operations
    this.pendingWrites = new ProgressCount();

    // Count for pending read operations
    this.pendingReads = new ProgressCount();

    // Carry last updated at if supported by schema
    this.lastUpdatedAt = null;

    // Is this an offline client only database?
    this.offlineDatabase = (connection === null);

    this.isLoaded = false;

    // Create scoped storage
    this.storage = new LocalForage({
      name: name,
      version: 1.0 // options.version
    });

    // Overwrite default logic on connection
    if (this._connection) {
      // Instanciate update logic
      let updateLogic = new conflictHandler(this);

      this._connection._stores[ this._name ].update = (ddp) => {
        var mongoId = ddp.id && MongoID.idParse(ddp.id);
        var doc = ddp.id && this._collection.findOne(mongoId);

        // remove _id from document
        if (doc) delete doc._id;

        if (ddp.msg === 'replace') {
          if (ddp.replace) {
            if (doc) {
              let fields = DiffSequence.makeChangedFields(ddp.replace, doc);
              delete fields._id;
              updateLogic.changed(mongoId, fields, doc);
            } else {
              updateLogic.added(mongoId, ddp.replace);
            }
          } else {
            updateLogic.removed(mongoId, doc);
          }
        } else if (ddp.msg === 'added') {
          if (doc) {
            let fields = DiffSequence.makeChangedFields(ddp.fields, doc);
            delete fields._id;
            updateLogic.changed(mongoId, fields, doc);
          } else {
            updateLogic.added(mongoId, ddp.fields);
          }
        } else if (ddp.msg === 'changed') {
          if (doc) {
            // let fields = DiffSequence.makeChangedFields(ddp.fields, doc);
            updateLogic.changed(mongoId, ddp.fields, doc);
          } else {
            updateLogic.added(mongoId, ddp.fields);
          }
        } else if (ddp.msg === 'removed') {
          updateLogic.removed(mongoId, doc);
        }
      };

    } // EO Connection update overwrite

    // Auto store updates locally
    this.monitorChanges();

    // Load database from local storage
    this.loadDatabase();
  }

  loadDatabase() {
    // Then load the docs into minimongo
    this.pendingReads.inc();
    this.storage
      .ready(() => {

        this.storage
          .length()
          .then(len => {
            if (len === 0) {
              this.pendingReads.dec();
              Kernel.defer(() => {
                console.log('LOADED');
                this.isLoaded = true;
                this.emitState('loaded', { count: len });
              });
            } else {
              // Update progress
              this.pendingReads.inc(len);
              // Count handled documents
              let handled = 0;
              this.storage
                .iterate((doc, id) => {

                  Kernel.defer(() => {

                    // Add the document to minimongo
                    this._collection._docs._map[id] = doc;

                    // Update progress
                    this.pendingReads.dec();

                    // Check if all documetns have been handled
                    if (++handled === len) {
                      this.invalidate();
                      Kernel.defer(() => {
                        console.log('LOADED');
                        this.isLoaded = true;
                        this.emitState('loaded', { count: len });
                      });
                    }
                  });

                })
                .then(() => {
                  this.pendingReads.dec();
                });
            }

          });
      });
  }

  saveDocument(doc, remove) {
    if (this.isLoaded) {
      this.pendingWrites.inc();

      this.storage
        .ready(() => {

          if (remove) {
            this.storage
              .removeItem(doc._id)
              .then(() => {
                this.pendingWrites.dec();
              });
          } else {
            this.storage
              .setItem(doc._id, doc)
              .then(() => {
                this.pendingWrites.dec();
              });
          }

        });

    }
    // xxx: should we buffer changes?
  }

  getLastUpdated(doc) {
    var result = null;

    if (doc.updatedAt || doc.createdAt || doc.removedAt) {
      result = new Date(Math.max(doc.updatedAt || null, doc.createdAt || null, doc.removedAt || null));
    }

    return result;
  }

  setLastUpdated(lastUpdatedAt) {
    if (lastUpdatedAt) {
      if (this.lastUpdatedAt < lastUpdatedAt || !this.lastUpdatedAt) {
        this.lastUpdatedAt = lastUpdatedAt || null;
      }
    }
  }

  monitorChanges() {
    // Store documents to localforage
    this.find().observe({
      'added': doc => {
        this.setLastUpdated(this.getLastUpdated(doc));
        this.saveDocument(doc);
      },
      // If removedAt is set this means the document should be removed
      'changed': (doc, oldDoc) => {
        this.setLastUpdated(this.getLastUpdated(doc));

        if (this.lastUpdatedAt) {
          if (doc.removedAt && !oldDoc.removedAt) {
            // Remove the document completely
            this._collection.remove(doc._id);
            this.saveDocument(doc, true);
          } else {
            this.saveDocument(doc);
          }
        } else {
          this.saveDocument(doc);
        }
      },
      // If lastUpdated is supported by schema we should not use removed
      // any more - rather catch this in the changed event...
      'removed': doc => {
        if (!this.lastUpdatedAt) {
          this.saveDocument(doc, true); }
        }
    });
  }

  shutdown(callback) {
    // xxx: have a better lock / fence
    this.writeFence = true;

    return new Promise(resolve => {
      Tracker.autorun(c => {
        // Wait until all writes have been done
        if (this.pendingWrites.isDone()) {
          c.stop();

          if (typeof callback === 'function') callback();
          resolve();
        }
      });
    });
  }

  invalidate() {
    Object.keys(this._collection.queries)
      .forEach(key => {
        // this._collection.queries[key].changed();
      });
  }

  clear() {
    this.storage.clear();
    //this._collection.remove({}, { multi: true });
    this._collection._docs._map = {};
    this.invalidate();
  }
  //////////////////////////////////////////////////////////////////////////////
  // WRAP EVENTEMITTER API on prototype
  //////////////////////////////////////////////////////////////////////////////

  // Wrap the Event Emitter Api "on"
  on(/* arguments */) {
    return this.eventemitter.on(...arguments);
  }

  // Wrap the Event Emitter Api "once"
  once(/* arguments */) {
    return this.eventemitter.once(...arguments);
  }

  // Wrap the Event Emitter Api "off"
  off(/* arguments */) {
    return this.eventemitter.off(...arguments);
  }

  // Wrap the Event Emitter Api "emit"
  emit(/* arguments */) {
    return this.eventemitter.emit(...arguments);
  }

  // Wrap the Event Emitter Api "emit"
  emitState(/* arguments */) {
    return this.eventemitter.emitState(...arguments);
  }

  // // Add api helpers
  addListener(/* arguments */) {
    return this.eventemitter.on(...arguments);
  }

  removeListener(/* arguments */) {
    return this.eventemitter.off(...arguments);
  }

  removeAllListeners(/* arguments */) {
    return this.eventemitter.off(...arguments);
  }

  // // Add jquery like helpers
  one(/* arguments */) {
    return this.eventemitter.once(...arguments);
  }

  trigger(/* arguments */) {
    return this.eventemitter.emit(...arguments);
  }

};

/**
 * Default update logic - for conflict handling "server-win"
 *
 * This class can be used as a base for building custom conflict
 * handlers.
 */
UpdateLogic = class UpdateLogic {

  constructor(collection) {
    this.collection = collection;
  }

  added(id, doc) {
    this.collection._collection.insert(_.extend({ _id: id }, doc));
  }

  changed(id, fields, oldDoc) {
    if (!_.isEmpty(fields)) {
      this.collection._collection.update({ _id: id }, this.modifier(fields));
    }
  }

  removed(id, oldDoc) {
    this.collection._collection.remove({ _id: id });
  }

  modifier(fields) {
    var mod = {};
    _.each(fields, (value, key) => {
      if (value === undefined) {
        if (!mod.$unset)
          mod.$unset = {};
        mod.$unset[key] = 1;
      } else {
        if (!mod.$set)
          mod.$set = {};
        mod.$set[key] = value;
      }
    });

    return mod;
  }
};
<|endoftext|>


<commit_before>goog.provide('clulib.cm.ComponentNode');

goog.require('goog.crypt.base64');
goog.require('goog.structs.Map');

/**
 * You should never use this class directly!
 * Look into [clulib.cm.Component] and [clulib.cm.ComponentManager] instead!
 *
 * @param {clulib.cm.ComponentManager} manager
 * @param {Element} element
 * @constructor
 */
clulib.cm.ComponentNode = function (manager, element) {
  /**
   * @type {clulib.cm.ComponentManager}
   * @private
   */
  this.manager_ = manager;

  /**
   * @type {Element}
   * @private
   */
  this.element_ = element;

  /**
   * @type {?clulib.cm.Component}
   * @private
   */
  this.component_ = null;

  /**
   * @type {?string}
   * @private
   */
  this.id_ = null;

  /**
   * @type {clulib.cm.ComponentNode}
   * @private
   */
  this.parent_ = null;

  /**
   * @type {goog.structs.Map<string, clulib.cm.ComponentNode>}
   * @private
   */
  this.children_ = new goog.structs.Map();

  /**
   * @type {number}
   * @private
   */
  this.depth_ = 0;

  /**
   * @type {string}
   * @private
   */
  this.type_ = this.element_.getAttribute(this.manager_.getTypeAttribute());

  /**
   * @type {?string}
   * @private
   */
  this.config_ = this.element_.getAttribute(this.manager_.getConfigAttribute());
};

/**
 * @param {clulib.cm.ComponentNode} node
 */
clulib.cm.ComponentNode.prototype.addChild = function (node) {
  node.parent_ = this;
  this.children_.set(node.getId(), node);
  this.component_.addChild(node.component_);
  node.setDepth(this.depth_ + 1);
};

/**
 * @param {number} depth
 */
clulib.cm.ComponentNode.prototype.setDepth = function (depth) {
  this.depth_ = depth;
  this.children_.forEach(node => node.setDepth(this.depth_ + 1));
};

/**
 * @returns {?clulib.cm.Component}
 */
clulib.cm.ComponentNode.prototype.getComponent = function () {
  return this.component_;
};

/**
 * @returns {number}
 */
clulib.cm.ComponentNode.prototype.getDepth = function () {
  return this.depth_;
};

/**
 * @returns {Element}
 */
clulib.cm.ComponentNode.prototype.getElement = function () {
  return this.element_;
};

/**
 * @returns {string}
 */
clulib.cm.ComponentNode.prototype.getType = function () {
  return this.type_;
};

/**
 * @returns {?string}
 */
clulib.cm.ComponentNode.prototype.getId = function () {
  return this.id_;
};

/**
 * @param {function(new:clulib.cm.Component)} constructor
 */
clulib.cm.ComponentNode.prototype.instantiate = function (constructor) {
  this.component_ = new constructor();

  this.id_ = this.component_.getId();
  this.element_.setAttribute(this.manager_.getIdAttribute(), this.id_);

  this.component_.manager = this.manager_;
  if (this.config_ != null)
    this.component_.setModel(JSON.parse(goog.crypt.base64.decodeString(this.config_)));

  this.component_.decorate(this.element_);
};

/**
 * @returns {Promise}
 */
clulib.cm.ComponentNode.prototype.initialize = function () {
  return this.component_.waitFor()
      .then(() => {
        this.component_.onInit();
        this.component_.onInitCompleter.resolve();
      });
};

clulib.cm.ComponentNode.prototype.dispose = function () {
  if (this.parent_ != null)
    this.parent_.children_.remove(this.getId());
};<commit_msg>fix: compiler warning<commit_after>goog.provide('clulib.cm.ComponentNode');

goog.require('goog.crypt.base64');
goog.require('goog.structs.Map');

/**
 * You should never use this class directly!
 * Look into [clulib.cm.Component] and [clulib.cm.ComponentManager] instead!
 *
 * @param {clulib.cm.ComponentManager} manager
 * @param {Element} element
 * @constructor
 */
clulib.cm.ComponentNode = function (manager, element) {
  /**
   * @type {clulib.cm.ComponentManager}
   * @private
   */
  this.manager_ = manager;

  /**
   * @type {Element}
   * @private
   */
  this.element_ = element;

  /**
   * @type {?clulib.cm.Component}
   * @private
   */
  this.component_ = null;

  /**
   * @type {?string}
   * @private
   */
  this.id_ = null;

  /**
   * @type {clulib.cm.ComponentNode}
   * @private
   */
  this.parent_ = null;

  /**
   * @type {goog.structs.Map<string, clulib.cm.ComponentNode>}
   * @private
   */
  this.children_ = new goog.structs.Map();

  /**
   * @type {number}
   * @private
   */
  this.depth_ = 0;

  /**
   * @type {string}
   * @private
   */
  this.type_ = this.element_.getAttribute(this.manager_.getTypeAttribute());

  /**
   * @type {?string}
   * @private
   */
  this.config_ = this.element_.getAttribute(this.manager_.getConfigAttribute());
};

/**
 * @param {clulib.cm.ComponentNode} node
 */
clulib.cm.ComponentNode.prototype.addChild = function (node) {
  node.parent_ = this;
  this.children_.set(node.getId(), node);
  this.component_.addChild(node.component_);
  node.setDepth(this.depth_ + 1);
};

/**
 * @param {number} depth
 */
clulib.cm.ComponentNode.prototype.setDepth = function (depth) {
  this.depth_ = depth;
  this.children_.forEach(node => node.setDepth(this.depth_ + 1));
};

/**
 * @returns {?clulib.cm.Component}
 */
clulib.cm.ComponentNode.prototype.getComponent = function () {
  return this.component_;
};

/**
 * @returns {number}
 */
clulib.cm.ComponentNode.prototype.getDepth = function () {
  return this.depth_;
};

/**
 * @returns {Element}
 */
clulib.cm.ComponentNode.prototype.getElement = function () {
  return this.element_;
};

/**
 * @returns {string}
 */
clulib.cm.ComponentNode.prototype.getType = function () {
  return this.type_;
};

/**
 * @returns {?string}
 */
clulib.cm.ComponentNode.prototype.getId = function () {
  return this.id_;
};

/**
 * @param {function(new:clulib.cm.Component)} constructor
 */
clulib.cm.ComponentNode.prototype.instantiate = function (constructor) {
  this.component_ = new constructor();

  this.id_ = this.component_.getId();
  this.element_.setAttribute(this.manager_.getIdAttribute(), /** @type {!string} */ (this.id_));

  this.component_.manager = this.manager_;
  if (this.config_ != null)
    this.component_.setModel(JSON.parse(goog.crypt.base64.decodeString(this.config_)));

  this.component_.decorate(this.element_);
};

/**
 * @returns {Promise}
 */
clulib.cm.ComponentNode.prototype.initialize = function () {
  return this.component_.waitFor()
      .then(() => {
        this.component_.onInit();
        this.component_.onInitCompleter.resolve();
      });
};

clulib.cm.ComponentNode.prototype.dispose = function () {
  if (this.parent_ != null)
    this.parent_.children_.remove(this.getId());
};<|endoftext|>