<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name ng.directive:ngRepeat
 *
 * @description
 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
 * instance gets its own scope, where the given loop variable is set to the current collection item,
 * and `$index` is set to the item index or key.
 *
 * Special properties are exposed on the local scope of each template instance, including:
 *
 * | Variable  | Type            | Details                                                                     |
 * |===========|=================|=============================================================================|
 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
 *
 * Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**,
 * **leave** and **move** effects.
 *
 *
 * # Special repeat start and end points
 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
 * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
 *
 * The example below makes use of this feature:
 *

 *
 *     Header {{ item }}
 *
 *

 *     Body {{ item }}
 *

 *
 *     Footer {{ item }}
 *
 *

 *
 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
 *

 *
 *     Header A
 *
 *

 *     Body A
 *

 *
 *     Footer A
 *
 *
 *     Header B
 *
 *

 *     Body B
 *

 *
 *     Footer B
 *
 *

 *
 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
 *
 * @animations
 * enter - when a new item is added to the list or when an item is revealed after a filter
 * leave - when an item is removed from the list or when an item is filtered out
 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
 *
 * @element ANY
 * @scope
 * @priority 1000
 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
 *   formats are currently supported:
 *
 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
 *     is a scope expression giving the collection to enumerate.
 *
 *     For example: `track in cd.tracks`.
 *
 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
 *     and `expression` is the scope expression giving the collection to enumerate.
 *
 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
 *
 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
 *     mapped to the same DOM element, which is not possible.)
 *
 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
 *     will be associated by item identity in the array.
 *
 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
 *     element in the same way ian the DOM.
 *
 *     For example: `item in items track by item.id` Is a typical pattern when the items come from the database. In this
 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
 *     property is same.
 *
 * @example
 * This example initializes the scope to a list of names and
 * then uses `ngRepeat` to display every person:
  <example animations="true">
    <file name="index.html">
      <div ng-init="friends = [
        {name:'John', age:25, gender:'boy'},
        {name:'Jessie', age:30, gender:'girl'},
        {name:'Johanna', age:28, gender:'girl'},
        {name:'Joy', age:15, gender:'girl'},
        {name:'Mary', age:28, gender:'girl'},
        {name:'Peter', age:95, gender:'boy'},
        {name:'Sebastian', age:50, gender:'boy'},
        {name:'Erika', age:27, gender:'girl'},
        {name:'Patrick', age:40, gender:'boy'},
        {name:'Samantha', age:60, gender:'girl'}
      ]">
        I have {{friends.length}} friends. They are:
        <input type="search" ng-model="q" placeholder="filter friends..." />

            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.

    </file>
    <file name="animations.css">
      .example-repeat-enter,
      .example-repeat-leave,
      .example-repeat-move {
        -webkit-transition:all linear 0.5s;
        -moz-transition:all linear 0.5s;
        -ms-transition:all linear 0.5s;
        -o-transition:all linear 0.5s;
        transition:all linear 0.5s;
      }

      .example-repeat-enter {
        line-height:0;
        opacity:0;
      }
      .example-repeat-enter.example-repeat-enter-active {
        line-height:20px;
        opacity:1;
      }

      .example-repeat-leave {
        opacity:1;
        line-height:20px;
      }
      .example-repeat-leave.example-repeat-leave-active {
        opacity:0;
        line-height:0;
      }

      .example-repeat-move { }
      .example-repeat-move.example-repeat-move-active { }
    </file>
    <file name="scenario.js">
       it('should render initial data set', function() {
         var r = using('.doc-example-live').repeater('ul li');
         expect(r.count()).toBe(10);
         expect(r.row(0)).toEqual(["1","John","25"]);
         expect(r.row(1)).toEqual(["2","Jessie","30"]);
         expect(r.row(9)).toEqual(["10","Samantha","60"]);
         expect(binding('friends.length')).toBe("10");
       });

       it('should update repeater when filter predicate changes', function() {
         var r = using('.doc-example-live').repeater('ul li');
         expect(r.count()).toBe(10);

         input('q').enter('ma');

         expect(r.count()).toBe(2);
         expect(r.row(0)).toEqual(["1","Mary","28"]);
         expect(r.row(1)).toEqual(["2","Samantha","60"]);
       });
      </file>
    </example>
 */
var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
  var NG_REMOVED = '$$NG_REMOVED';
  var ngRepeatMinErr = minErr('ngRepeat');
  return {
    transclude: 'element',
    priority: 1000,
    terminal: true,
    compile: function(element, attr, linker) {
      return function($scope, $element, $attr){
        var animate = $animator($scope, $attr);
        var expression = $attr.ngRepeat;
        var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
          trackByExp, trackByExpGetter, trackByIdFn, lhs, rhs, valueIdentifier, keyIdentifier,
          hashFnLocals = {$id: hashKey};

        if (!match) {
          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
            expression);
        }

        lhs = match[1];
        rhs = match[2];
        trackByExp = match[4];

        if (trackByExp) {
          trackByExpGetter = $parse(trackByExp);
          trackByIdFn = function(key, value, index) {
            // assign key, value, and $index to the locals so that they can be used in hash functions
            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
            hashFnLocals[valueIdentifier] = value;
            hashFnLocals.$index = index;
            return trackByExpGetter($scope, hashFnLocals);
          };
        } else {
          trackByIdFn = function(key, value) {
            return hashKey(value);
          }
        }

        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
        if (!match) {
          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
                                                                    lhs);
        }
        valueIdentifier = match[3] || match[1];
        keyIdentifier = match[2];

        // Store a list of elements from previous run. This is a hash where key is the item from the
        // iterator, and the value is objects with following properties.
        //   - scope: bound scope
        //   - element: previous element.
        //   - index: position
        var lastBlockMap = {};

        //watch props
        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
          var index, length,
              previousNode = $element[0],     // current position of the node
              nextNode,
              // Same as lastBlockMap but it has the current state. It will become the
              // lastBlockMap on the next iteration.
              nextBlockMap = {},
              arrayLength,
              childScope,
              key, value, // key/value of iteration
              trackById,
              collectionKeys,
              block,       // last object information {scope, element, id}
              nextBlockOrder = [];

          if (isArrayLike(collection)) {
            collectionKeys = collection;
          } else {
            // if object, extract keys, sort them and use to determine order of iteration over obj props
            collectionKeys = [];
            for (key in collection) {
              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
                collectionKeys.push(key);
              }
            }
            collectionKeys.sort();
          }

          arrayLength = collectionKeys.length;

          // locate existing items
          length = nextBlockOrder.length = collectionKeys.length;
          for(index = 0; index < length; index++) {
           key = (collection === collectionKeys) ? index : collectionKeys[index];
           value = collection[key];
           trackById = trackByIdFn(key, value, index);
           if(lastBlockMap.hasOwnProperty(trackById)) {
             block = lastBlockMap[trackById]
             delete lastBlockMap[trackById];
             nextBlockMap[trackById] = block;
             nextBlockOrder[index] = block;
           } else if (nextBlockMap.hasOwnProperty(trackById)) {
             // restore lastBlockMap
             forEach(nextBlockOrder, function(block) {
               if (block && block.startNode) lastBlockMap[block.id] = block;
             });
             // This is a duplicate and we need to throw an error
             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
                                                                                expression,       trackById);
           } else {
             // new never before seen block
             nextBlockOrder[index] = { id: trackById };
             nextBlockMap[trackById] = false;
           }
         }

          // remove existing items
          for (key in lastBlockMap) {
            if (lastBlockMap.hasOwnProperty(key)) {
              block = lastBlockMap[key];
              animate.leave(block.elements);
              forEach(block.elements, function(element) { element[NG_REMOVED] = true});
              block.scope.$destroy();
            }
          }

          // we are not using forEach for perf reasons (trying to avoid #call)
          for (index = 0, length = collectionKeys.length; index < length; index++) {
            key = (collection === collectionKeys) ? index : collectionKeys[index];
            value = collection[key];
            block = nextBlockOrder[index];

            if (block.startNode) {
              // if we have already seen this object, then we need to reuse the
              // associated scope/element
              childScope = block.scope;

              nextNode = previousNode;
              do {
                nextNode = nextNode.nextSibling;
              } while(nextNode && nextNode[NG_REMOVED]);

              if (block.startNode == nextNode) {
                // do nothing
              } else {
                // existing item which got moved
                animate.move(block.elements, null, jqLite(previousNode));
              }
              previousNode = block.endNode;
            } else {
              // new item which we don't know about
              childScope = $scope.$new();
            }

            childScope[valueIdentifier] = value;
            if (keyIdentifier) childScope[keyIdentifier] = key;
            childScope.$index = index;
            childScope.$first = (index === 0);
            childScope.$last = (index === (arrayLength - 1));
            childScope.$middle = !(childScope.$first || childScope.$last);

            if (!block.startNode) {
              linker(childScope, function(clone) {
                animate.enter(clone, null, jqLite(previousNode));
                previousNode = clone;
                block.scope = childScope;
                block.startNode = clone[0];
                block.elements = clone;
                block.endNode = clone[clone.length - 1];
                nextBlockMap[block.id] = block;
              });
            }
          }
          lastBlockMap = nextBlockMap;
        });
      };
    }
  };
}];

<commit_msg>docs(ngRepeat): add example for filters in conjunction with `track by`<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name ng.directive:ngRepeat
 *
 * @description
 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
 * instance gets its own scope, where the given loop variable is set to the current collection item,
 * and `$index` is set to the item index or key.
 *
 * Special properties are exposed on the local scope of each template instance, including:
 *
 * | Variable  | Type            | Details                                                                     |
 * |===========|=================|=============================================================================|
 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
 *
 * Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**,
 * **leave** and **move** effects.
 *
 *
 * # Special repeat start and end points
 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
 * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
 *
 * The example below makes use of this feature:
 *

 *
 *     Header {{ item }}
 *
 *

 *     Body {{ item }}
 *

 *
 *     Footer {{ item }}
 *
 *

 *
 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
 *

 *
 *     Header A
 *
 *

 *     Body A
 *

 *
 *     Footer A
 *
 *
 *     Header B
 *
 *

 *     Body B
 *

 *
 *     Footer B
 *
 *

 *
 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
 *
 * @animations
 * enter - when a new item is added to the list or when an item is revealed after a filter
 * leave - when an item is removed from the list or when an item is filtered out
 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
 *
 * @element ANY
 * @scope
 * @priority 1000
 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
 *   formats are currently supported:
 *
 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
 *     is a scope expression giving the collection to enumerate.
 *
 *     For example: `album in artist.albums`.
 *
 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
 *     and `expression` is the scope expression giving the collection to enumerate.
 *
 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
 *
 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
 *     before specifying a tracking expression.
 *
 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
 *     will be associated by item identity in the array.
 *
 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
 *     element in the same way ian the DOM.
 *
 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
 *     property is same.
 *
 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
 *     to items in conjunction with a tracking expression.
 *
 * @example
 * This example initializes the scope to a list of names and
 * then uses `ngRepeat` to display every person:
  <example animations="true">
    <file name="index.html">
      <div ng-init="friends = [
        {name:'John', age:25, gender:'boy'},
        {name:'Jessie', age:30, gender:'girl'},
        {name:'Johanna', age:28, gender:'girl'},
        {name:'Joy', age:15, gender:'girl'},
        {name:'Mary', age:28, gender:'girl'},
        {name:'Peter', age:95, gender:'boy'},
        {name:'Sebastian', age:50, gender:'boy'},
        {name:'Erika', age:27, gender:'girl'},
        {name:'Patrick', age:40, gender:'boy'},
        {name:'Samantha', age:60, gender:'girl'}
      ]">
        I have {{friends.length}} friends. They are:
        <input type="search" ng-model="q" placeholder="filter friends..." />

            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.

    </file>
    <file name="animations.css">
      .example-repeat-enter,
      .example-repeat-leave,
      .example-repeat-move {
        -webkit-transition:all linear 0.5s;
        -moz-transition:all linear 0.5s;
        -ms-transition:all linear 0.5s;
        -o-transition:all linear 0.5s;
        transition:all linear 0.5s;
      }

      .example-repeat-enter {
        line-height:0;
        opacity:0;
      }
      .example-repeat-enter.example-repeat-enter-active {
        line-height:20px;
        opacity:1;
      }

      .example-repeat-leave {
        opacity:1;
        line-height:20px;
      }
      .example-repeat-leave.example-repeat-leave-active {
        opacity:0;
        line-height:0;
      }

      .example-repeat-move { }
      .example-repeat-move.example-repeat-move-active { }
    </file>
    <file name="scenario.js">
       it('should render initial data set', function() {
         var r = using('.doc-example-live').repeater('ul li');
         expect(r.count()).toBe(10);
         expect(r.row(0)).toEqual(["1","John","25"]);
         expect(r.row(1)).toEqual(["2","Jessie","30"]);
         expect(r.row(9)).toEqual(["10","Samantha","60"]);
         expect(binding('friends.length')).toBe("10");
       });

       it('should update repeater when filter predicate changes', function() {
         var r = using('.doc-example-live').repeater('ul li');
         expect(r.count()).toBe(10);

         input('q').enter('ma');

         expect(r.count()).toBe(2);
         expect(r.row(0)).toEqual(["1","Mary","28"]);
         expect(r.row(1)).toEqual(["2","Samantha","60"]);
       });
      </file>
    </example>
 */
var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
  var NG_REMOVED = '$$NG_REMOVED';
  var ngRepeatMinErr = minErr('ngRepeat');
  return {
    transclude: 'element',
    priority: 1000,
    terminal: true,
    compile: function(element, attr, linker) {
      return function($scope, $element, $attr){
        var animate = $animator($scope, $attr);
        var expression = $attr.ngRepeat;
        var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
          trackByExp, trackByExpGetter, trackByIdFn, lhs, rhs, valueIdentifier, keyIdentifier,
          hashFnLocals = {$id: hashKey};

        if (!match) {
          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
            expression);
        }

        lhs = match[1];
        rhs = match[2];
        trackByExp = match[4];

        if (trackByExp) {
          trackByExpGetter = $parse(trackByExp);
          trackByIdFn = function(key, value, index) {
            // assign key, value, and $index to the locals so that they can be used in hash functions
            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
            hashFnLocals[valueIdentifier] = value;
            hashFnLocals.$index = index;
            return trackByExpGetter($scope, hashFnLocals);
          };
        } else {
          trackByIdFn = function(key, value) {
            return hashKey(value);
          }
        }

        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
        if (!match) {
          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
                                                                    lhs);
        }
        valueIdentifier = match[3] || match[1];
        keyIdentifier = match[2];

        // Store a list of elements from previous run. This is a hash where key is the item from the
        // iterator, and the value is objects with following properties.
        //   - scope: bound scope
        //   - element: previous element.
        //   - index: position
        var lastBlockMap = {};

        //watch props
        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
          var index, length,
              previousNode = $element[0],     // current position of the node
              nextNode,
              // Same as lastBlockMap but it has the current state. It will become the
              // lastBlockMap on the next iteration.
              nextBlockMap = {},
              arrayLength,
              childScope,
              key, value, // key/value of iteration
              trackById,
              collectionKeys,
              block,       // last object information {scope, element, id}
              nextBlockOrder = [];

          if (isArrayLike(collection)) {
            collectionKeys = collection;
          } else {
            // if object, extract keys, sort them and use to determine order of iteration over obj props
            collectionKeys = [];
            for (key in collection) {
              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
                collectionKeys.push(key);
              }
            }
            collectionKeys.sort();
          }

          arrayLength = collectionKeys.length;

          // locate existing items
          length = nextBlockOrder.length = collectionKeys.length;
          for(index = 0; index < length; index++) {
           key = (collection === collectionKeys) ? index : collectionKeys[index];
           value = collection[key];
           trackById = trackByIdFn(key, value, index);
           if(lastBlockMap.hasOwnProperty(trackById)) {
             block = lastBlockMap[trackById]
             delete lastBlockMap[trackById];
             nextBlockMap[trackById] = block;
             nextBlockOrder[index] = block;
           } else if (nextBlockMap.hasOwnProperty(trackById)) {
             // restore lastBlockMap
             forEach(nextBlockOrder, function(block) {
               if (block && block.startNode) lastBlockMap[block.id] = block;
             });
             // This is a duplicate and we need to throw an error
             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
                                                                                expression,       trackById);
           } else {
             // new never before seen block
             nextBlockOrder[index] = { id: trackById };
             nextBlockMap[trackById] = false;
           }
         }

          // remove existing items
          for (key in lastBlockMap) {
            if (lastBlockMap.hasOwnProperty(key)) {
              block = lastBlockMap[key];
              animate.leave(block.elements);
              forEach(block.elements, function(element) { element[NG_REMOVED] = true});
              block.scope.$destroy();
            }
          }

          // we are not using forEach for perf reasons (trying to avoid #call)
          for (index = 0, length = collectionKeys.length; index < length; index++) {
            key = (collection === collectionKeys) ? index : collectionKeys[index];
            value = collection[key];
            block = nextBlockOrder[index];

            if (block.startNode) {
              // if we have already seen this object, then we need to reuse the
              // associated scope/element
              childScope = block.scope;

              nextNode = previousNode;
              do {
                nextNode = nextNode.nextSibling;
              } while(nextNode && nextNode[NG_REMOVED]);

              if (block.startNode == nextNode) {
                // do nothing
              } else {
                // existing item which got moved
                animate.move(block.elements, null, jqLite(previousNode));
              }
              previousNode = block.endNode;
            } else {
              // new item which we don't know about
              childScope = $scope.$new();
            }

            childScope[valueIdentifier] = value;
            if (keyIdentifier) childScope[keyIdentifier] = key;
            childScope.$index = index;
            childScope.$first = (index === 0);
            childScope.$last = (index === (arrayLength - 1));
            childScope.$middle = !(childScope.$first || childScope.$last);

            if (!block.startNode) {
              linker(childScope, function(clone) {
                animate.enter(clone, null, jqLite(previousNode));
                previousNode = clone;
                block.scope = childScope;
                block.startNode = clone[0];
                block.elements = clone;
                block.endNode = clone[clone.length - 1];
                nextBlockMap[block.id] = block;
              });
            }
          }
          lastBlockMap = nextBlockMap;
        });
      };
    }
  };
}];

<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name ng.directive:ngSwitch
 * @restrict EA
 *
 * @description
 * Conditionally change the DOM structure. Elements within ngSwitch but without
 * ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
 * as specified in the template
 *
 * @usageContent
 * <ANY ng-switch-when="matchValue1">...</ANY>
 *   <ANY ng-switch-when="matchValue2">...</ANY>
 *   ...
 *   <ANY ng-switch-default>...</ANY>
 *   <ANY>...</ANY>
 *
 * @scope
 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
 * @paramDescription
 * On child elements add:
 *
 * * `ngSwitchWhen`: the case statement to match against. If match then this
 *   case will be displayed. If the same match appears multiple times, all the
 *   elements will be displayed.
 * * `ngSwitchDefault`: the default case when no other case match. If there
 *   are multiple default cases, all of them will be displayed when no other
 *   case match.
 *
 *
 * @example
    <doc:example>
      <doc:source>

          <select ng-model="selection" ng-options="item for item in items">
          </select>
          <tt>selection={{selection}}</tt>

Settings Div

            Home Span
            default

      </doc:source>
      <doc:scenario>
        it('should start in settings', function() {
         expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
        });
        it('should change to home', function() {
         select('selection').option('home');
         expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
        });
        it('should select default', function() {
         select('selection').option('other');
         expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
        });
      </doc:scenario>
    </doc:example>
 */
var NG_SWITCH = 'ng-switch';
var ngSwitchDirective = valueFn({
  restrict: 'EA',
  require: 'ngSwitch',
  // asks for $scope to fool the BC controller module
  controller: ['$scope', function ngSwitchController() {
    this.cases = {};
  }],
  link: function(scope, element, attr, ctrl) {
    var watchExpr = attr.ngSwitch || attr.on,
        selectedTranscludes,
        selectedElements,
        selectedScopes = [];

    scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
      for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
        selectedScopes[i].$destroy();
        selectedElements[i].remove();
      }

      selectedElements = [];
      selectedScopes = [];

      if ((selectedTranscludes = ctrl.cases['!' + value] || ctrl.cases['?'])) {
        scope.$eval(attr.change);
        forEach(selectedTranscludes, function(selectedTransclude) {
          var selectedScope = scope.$new();
          selectedScopes.push(selectedScope);
          selectedTransclude.transclude(selectedScope, function(caseElement) {
            selectedElements.push(caseElement);
            selectedTransclude.element.after(caseElement);
          });
        });
      }
    });
  }
});

var ngSwitchWhenDirective = ngDirective({
  transclude: 'element',
  priority: 500,
  require: '^ngSwitch',
  compile: function(element, attrs, transclude) {
    return function(scope, element, attr, ctrl) {
      ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
      ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
    };
  }
});

var ngSwitchDefaultDirective = ngDirective({
  transclude: 'element',
  priority: 500,
  require: '^ngSwitch',
  compile: function(element, attrs, transclude) {
    return function(scope, element, attr, ctrl) {
      ctrl.cases['?'] = (ctrl.cases['?'] || []);
      ctrl.cases['?'].push({ transclude: transclude, element: element });
    };
  }
});
<commit_msg>docs(ngSwitch): improve the @usage example<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name ng.directive:ngSwitch
 * @restrict EA
 *
 * @description
 * Conditionally change the DOM structure. Elements within ngSwitch but without
 * ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
 * as specified in the template
 *
 * @usage
 * <ANY ng-switch="expression">
 *   <ANY ng-switch-when="matchValue1">...</ANY>
 *   <ANY ng-switch-when="matchValue2">...</ANY>
 *   ...
 *   <ANY ng-switch-default>...</ANY>
 * </ANY>
 *
 * @scope
 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
 * @paramDescription
 * On child elements add:
 *
 * * `ngSwitchWhen`: the case statement to match against. If match then this
 *   case will be displayed. If the same match appears multiple times, all the
 *   elements will be displayed.
 * * `ngSwitchDefault`: the default case when no other case match. If there
 *   are multiple default cases, all of them will be displayed when no other
 *   case match.
 *
 *
 * @example
    <doc:example>
      <doc:source>

          <select ng-model="selection" ng-options="item for item in items">
          </select>
          <tt>selection={{selection}}</tt>

Settings Div

            Home Span
            default

      </doc:source>
      <doc:scenario>
        it('should start in settings', function() {
         expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
        });
        it('should change to home', function() {
         select('selection').option('home');
         expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
        });
        it('should select default', function() {
         select('selection').option('other');
         expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
        });
      </doc:scenario>
    </doc:example>
 */
var NG_SWITCH = 'ng-switch';
var ngSwitchDirective = valueFn({
  restrict: 'EA',
  require: 'ngSwitch',
  // asks for $scope to fool the BC controller module
  controller: ['$scope', function ngSwitchController() {
    this.cases = {};
  }],
  link: function(scope, element, attr, ctrl) {
    var watchExpr = attr.ngSwitch || attr.on,
        selectedTranscludes,
        selectedElements,
        selectedScopes = [];

    scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
      for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
        selectedScopes[i].$destroy();
        selectedElements[i].remove();
      }

      selectedElements = [];
      selectedScopes = [];

      if ((selectedTranscludes = ctrl.cases['!' + value] || ctrl.cases['?'])) {
        scope.$eval(attr.change);
        forEach(selectedTranscludes, function(selectedTransclude) {
          var selectedScope = scope.$new();
          selectedScopes.push(selectedScope);
          selectedTransclude.transclude(selectedScope, function(caseElement) {
            selectedElements.push(caseElement);
            selectedTransclude.element.after(caseElement);
          });
        });
      }
    });
  }
});

var ngSwitchWhenDirective = ngDirective({
  transclude: 'element',
  priority: 500,
  require: '^ngSwitch',
  compile: function(element, attrs, transclude) {
    return function(scope, element, attr, ctrl) {
      ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
      ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
    };
  }
});

var ngSwitchDefaultDirective = ngDirective({
  transclude: 'element',
  priority: 500,
  require: '^ngSwitch',
  compile: function(element, attrs, transclude) {
    return function(scope, element, attr, ctrl) {
      ctrl.cases['?'] = (ctrl.cases['?'] || []);
      ctrl.cases['?'].push({ transclude: transclude, element: element });
    };
  }
});
<|endoftext|>


<commit_before>import { Context } from './context';
import { PreparedContext } from './prepared-context';

import {
  setPassword,
  getPassword,
  setProperty,
  removeSensibleValues
} from './util';
import { version } from '../package.json';
import { GithubProvider } from 'github-repository-provider';
import { BitbucketProvider } from 'bitbucket-repository-provider';
import { LocalProvider } from 'local-repository-provider';
import { AggregationProvider } from 'aggregation-repository-provider';

const program = require('caporal'),
  prompt = require('prompt');

process.on('uncaughtException', err => console.error(err));
process.on('unhandledRejection', reason => console.error(reason));

const properties = {};

program
  .description('Keep npm package in sync with its template')
  .version(version)
  .option('--dry', 'do not create branch/pull request', program.BOOL, false)
  .option(
    '-k, --keystore <account/service>',
    'keystore',
    /^[\w\-]+\/.*/,
    'arlac77/GitHub for Mac SSH key passphrase — github.com'
  )
  .option('-s, --save', 'save keystore')
  .option('-d --define <key=value>', 'set provider option', values => {
    if (!Array.isArray(values)) {
      values = [values];
    }

    values.forEach(value => {
      const [k, v] = value.split(/=/);
      setProperty(properties, k, v);
    });
  })
  .option(
    '--list-providers',
    'list providers with options and exit',
    program.BOOL,
    false
  )
  .option(
    '--list-properties',
    'list all properties (if given of the first repo) and exit',
    program.BOOL,
    false
  )
  .option(
    '-t, --template <identifier>',
    'template repository',
    /^([\w\-]+\/[\w\-]+)|((git|ssh|https?):\/\/.*)$/
  )
  .option(
    '--usage',
    'track packages using template in package.json',
    program.BOOL,
    false
  )
  .argument('[repos...]', 'repos to merge')
  .action(async (args, options, logger) => {
    if (options.save) {
      prompt.start();
      const schema = {
        properties: {
          password: {
            required: true,
            hidden: true
          }
        }
      };
      prompt.get(schema, async (err, result) => {
        if (err) {
          logger.error(err);
          return;
        }

        try {
          await setPassword(result.password, options);
        } catch (e) {
          logger.error(err);
          return;
        }
        logger.info('password set');
      });
    }

    try {
      const pass = await getPassword(options);
      const aggregationProvider = new AggregationProvider();

      if (pass !== null && pass !== undefined) {
        if (properties.GithubProvider === undefined) {
          properties.GithubProvider = {};
        }
        properties.GithubProvider.auth = pass;
      }

      [BitbucketProvider, GithubProvider, LocalProvider].forEach(provider => {
        let options = provider.optionsFromEnvironment(process.env);

        if (options !== undefined || properties[provider.name] !== undefined) {
          options = Object.assign({}, options, properties[provider.name]);
          aggregationProvider.providers.push(new provider(options));
        }
      });

      if (options.listProviders) {
        logger.info(
          Array.from(
            aggregationProvider.providers.map(
              p =>
                `${p.name}: ${JSON.stringify(removeSensibleValues(p.config))}`
            )
          ).join('\n')
        );

        return;
      }

      const context = new Context(aggregationProvider, {
        templateBranchName: options.template,
        dry: options.dry,
        trackUsedByModule: options.usage,
        logger,
        properties
      });

      if (args.repos.length === 0 && options.listProperties) {
        logger.info(JSON.stringify(removeSensibleValues(context.properties)));
        return;
      }

      for (const repo of args.repos) {
        const pc = new PreparedContext(context, repo);
        await pc.initialize();

        if (options.listProperties) {
          logger.info(JSON.stringify(removeSensibleValues(pc.properties)));
          return;
        }

        await pc.execute();
      }
    } catch (err) {
      logger.error(err);
    }
  });

program.parse(process.argv);
<commit_msg>feat(cli): check node version and fail if none matching version is found<commit_after>import { Context } from "./context";
import { PreparedContext } from "./prepared-context";

import {
  setPassword,
  getPassword,
  setProperty,
  removeSensibleValues
} from "./util";
import { version, engines } from "../package.json";
import { GithubProvider } from "github-repository-provider";
import { BitbucketProvider } from "bitbucket-repository-provider";
import { LocalProvider } from "local-repository-provider";
import { AggregationProvider } from "aggregation-repository-provider";

const program = require("caporal"),
  prompt = require("prompt");

process.on("uncaughtException", err => console.error(err));
process.on("unhandledRejection", reason => console.error(reason));

const properties = {};

program
  .description("Keep npm package in sync with its template")
  .version(version)
  .option("--dry", "do not create branch/pull request", program.BOOL, false)
  .option(
    "-k, --keystore <account/service>",
    "keystore",
    /^[\w\-]+\/.*/,
    "arlac77/GitHub for Mac SSH key passphrase — github.com"
  )
  .option("-s, --save", "save keystore")
  .option("-d --define <key=value>", "set provider option", values => {
    if (!Array.isArray(values)) {
      values = [values];
    }

    values.forEach(value => {
      const [k, v] = value.split(/=/);
      setProperty(properties, k, v);
    });
  })
  .option(
    "--list-providers",
    "list providers with options and exit",
    program.BOOL,
    false
  )
  .option(
    "--list-properties",
    "list all properties (if given of the first repo) and exit",
    program.BOOL,
    false
  )
  .option(
    "-t, --template <identifier>",
    "template repository",
    /^([\w\-]+\/[\w\-]+)|((git|ssh|https?):\/\/.*)$/
  )
  .option(
    "--usage",
    "track packages using template in package.json",
    program.BOOL,
    false
  )
  .argument("[repos...]", "repos to merge")
  .action(async (args, options, logger) => {
    if (options.save) {
      prompt.start();
      const schema = {
        properties: {
          password: {
            required: true,
            hidden: true
          }
        }
      };
      prompt.get(schema, async (err, result) => {
        if (err) {
          logger.error(err);
          return;
        }

        try {
          await setPassword(result.password, options);
        } catch (e) {
          logger.error(err);
          return;
        }
        logger.info("password set");
      });
    }

    try {
      const pass = await getPassword(options);
      const aggregationProvider = new AggregationProvider();

      if (pass !== null && pass !== undefined) {
        if (properties.GithubProvider === undefined) {
          properties.GithubProvider = {};
        }
        properties.GithubProvider.auth = pass;
      }

      [BitbucketProvider, GithubProvider, LocalProvider].forEach(provider => {
        let options = provider.optionsFromEnvironment(process.env);

        if (options !== undefined || properties[provider.name] !== undefined) {
          options = Object.assign({}, options, properties[provider.name]);
          aggregationProvider.providers.push(new provider(options));
        }
      });

      if (options.listProviders) {
        logger.info(
          Array.from(
            aggregationProvider.providers.map(
              p =>
                `${p.name}: ${JSON.stringify(removeSensibleValues(p.config))}`
            )
          ).join("\n")
        );

        return;
      }

      const context = new Context(aggregationProvider, {
        templateBranchName: options.template,
        dry: options.dry,
        trackUsedByModule: options.usage,
        logger,
        properties
      });

      if (args.repos.length === 0 && options.listProperties) {
        logger.info(JSON.stringify(removeSensibleValues(context.properties)));
        return;
      }

      for (const repo of args.repos) {
        const pc = new PreparedContext(context, repo);
        await pc.initialize();

        if (options.listProperties) {
          logger.info(JSON.stringify(removeSensibleValues(pc.properties)));
          return;
        }

        await pc.execute();
      }
    } catch (err) {
      logger.error(err);
    }
  });

const requiredEngine = parseInt(engines.node.replace(/^[=><]?/, ""));

if (parseInt(process.versions.node.split(/\./)[0], 10) < requiredEngine) {
  console.error(`require node ${engines.node} (not ${process.versions.node})`);
  process.exit(-1);
}

program.parse(process.argv);
<|endoftext|>


<commit_before>/* eslint comma-dangle: "off" */

$(document).ready(() => {
  let query = '';

  function exportCSV() {
    const token = window.sessionStorage.getItem('userInfo-token');
    $.ajax({
      url: `http://localhost:3000/export${query}`,
      type: 'GET',
      headers: {
        'x-access-token': token
      }
    }).done((response) => {
      const data = response.data;
      const filename = response.filename;
      const link = document.createElement('a');
      link.setAttribute('href', data);
      link.setAttribute('download', filename);
      link.click();
    });
  }
  $('#export-button').click(exportCSV);

  $('#query2Checkbox').change(() => {
    const enabled = $('#query2Checkbox').prop('checked');
    $('#query2Attribute').attr('disabled', !enabled);
    $('#query2Comparator').attr('disabled', !enabled);
    $('#query2Value').attr('disabled', !enabled);
  });
  $('#query3Checkbox').change(() => {
    const enabled = $('#query3Checkbox').prop('checked');
    $('#query3Attribute').attr('disabled', !enabled);
    $('#query3Comparator').attr('disabled', !enabled);
    $('#query3Value').attr('disabled', !enabled);
  });
  $('#query4Checkbox').change(() => {
    const enabled = $('#query4Checkbox').prop('checked');
    $('#query4Attribute').attr('disabled', !enabled);
    $('#query4Comparator').attr('disabled', !enabled);
    $('#query4Value').attr('disabled', !enabled);
  });
  $('#query5Checkbox').change(() => {
    const enabled = $('#query5Checkbox').prop('checked');
    $('#query5Attribute').attr('disabled', !enabled);
    $('#query5Comparator').attr('disabled', !enabled);
    $('#query5Value').attr('disabled', !enabled);
  });

  function loadDataTable() {
    const uri = `http://localhost:3000/cases${query}`;
    // console.log(uri);
    const token = window.sessionStorage.getItem('userInfo-token');
    $('#example').DataTable({
      destroy: true,
      ajax: {
        type: 'GET',
        url: uri,
        headers: {
          'x-access-token': token,
        },
        dataSrc: json => json,
      },
      columnDefs: [
        {
          targets: [4, 5, 8, 12],
          render: $.fn.dataTable.render.moment('x', 'Do MMM YY'),
        },
        {
          targets: [0, 1],
          width: '20px',
        },
      ],
      columns: [
        { data: 'drNumber' },
        { data: 'masterDrNumber' },
        { data: 'division' },
        { data: 'bureau' },
        { data: 'dateOccured' },
        { data: 'dateReported' },
        { data: 'weaponUsed[, ]' },
        { data: 'caseStatus' },
        { data: 'caseStatusDate' },
        { data: 'solvabilityFactor' },
        { data: 'reportingDistrict' },
        { data: 'motive[, ]' },
        { data: 'lastModifiedDate' },
        { data: 'lastModifiedBy.email' },
        { data: 'victim.victName.first' },
        { data: 'address' },
        { data: 'suspects[0].suspName.first' },
        {
          targets: -1,
          data: null,
          defaultContent: '<button>Click!</button>'
        }
      ],
    });

    // https://datatables.net/examples/ajax/null_data_source.html
    $('#example tbody').on('click', 'button', () => {
      alert('Hello');
    });
  }
  // default data table loads with no query
  loadDataTable();

  $('#submit-query').on('click', () => {
    // /cases?drNumber={"lt": 100, "gt": 30}&bureau=OSB
    const a = $('#query1Attribute').val();
    const c = $('#query1Comparator').val();
    const v = $('#query1Value').val();
    if (c === '=') {
      query = `${query}/?${a}${c}${v}`;
    } else {
      query = `${query}${a}={"${c}":${+v}}`;
    }

    if ($('#query2Checkbox').prop('checked')) {
      const A = $('#query2Attribute').val();
      const C = $('#query2Comparator').val();
      const V = $('#query2Value').val();
      if (C === '=') {
        query = query + '&' + A + C + V;
      } else {
        query = `${query}&${A}={"${C}":${+V}}`;
      }
    }

    if ($('#query3Checkbox').prop('checked')) {
      if ($('#query3Comparator').val() === '=') {
        query = query + '&' + $('#query3Attribute').val() + $('#query3Comparator').val() + $('#query3Value').val();
      } else {
        query = `${query}&${$('#query3Attribute').val()}={"${$('#query3Comparator').val()}":${+$('#query3Value').val()}}`;
      }
    }

    if ($('#query4Checkbox').prop('checked')) {
      if ($('#query4Comparator').val() === '=') {
        query = query + '&' + $('#query4Attribute').val() + $('#query4Comparator').val() + $('#query4Value').val();
      } else {
        query = `${query}&${$('#query4Attribute').val()}={"${$('#query4Comparator').val()}":${+$('#query4Value').val()}}`;
      }
    }
    // console.log(query);
    loadDataTable();
  });
});
<commit_msg>Explorer links to case page with cookied id<commit_after>/* eslint comma-dangle: "off" */

$(document).ready(() => {
  let query = '';

  function exportCSV() {
    const token = window.sessionStorage.getItem('userInfo-token');
    $.ajax({
      url: `http://localhost:3000/export${query}`,
      type: 'GET',
      headers: {
        'x-access-token': token
      }
    }).done((response) => {
      const data = response.data;
      const filename = response.filename;
      const link = document.createElement('a');
      link.setAttribute('href', data);
      link.setAttribute('download', filename);
      link.click();
    });
  }
  $('#export-button').click(exportCSV);

  $('#query2Checkbox').change(() => {
    const enabled = $('#query2Checkbox').prop('checked');
    $('#query2Attribute').attr('disabled', !enabled);
    $('#query2Comparator').attr('disabled', !enabled);
    $('#query2Value').attr('disabled', !enabled);
  });
  $('#query3Checkbox').change(() => {
    const enabled = $('#query3Checkbox').prop('checked');
    $('#query3Attribute').attr('disabled', !enabled);
    $('#query3Comparator').attr('disabled', !enabled);
    $('#query3Value').attr('disabled', !enabled);
  });
  $('#query4Checkbox').change(() => {
    const enabled = $('#query4Checkbox').prop('checked');
    $('#query4Attribute').attr('disabled', !enabled);
    $('#query4Comparator').attr('disabled', !enabled);
    $('#query4Value').attr('disabled', !enabled);
  });
  $('#query5Checkbox').change(() => {
    const enabled = $('#query5Checkbox').prop('checked');
    $('#query5Attribute').attr('disabled', !enabled);
    $('#query5Comparator').attr('disabled', !enabled);
    $('#query5Value').attr('disabled', !enabled);
  });

  function loadDataTable() {
    const uri = `http://localhost:3000/cases${query}`;
    // console.log(uri);
    const token = window.sessionStorage.getItem('userInfo-token');
    const table = $('#example').DataTable({
      destroy: true,
      ajax: {
        type: 'GET',
        url: uri,
        headers: {
          'x-access-token': token,
        },
        dataSrc: json => json,
      },
      columnDefs: [
        {
          targets: [4, 5, 8, 12],
          render: $.fn.dataTable.render.moment('x', 'Do MMM YY'),
        },
        {
          targets: [0, 1],
          width: '20px',
        },
      ],
      columns: [
        { data: 'drNumber' },
        { data: 'masterDrNumber' },
        { data: 'division' },
        { data: 'bureau' },
        { data: 'dateOccured' },
        { data: 'dateReported' },
        { data: 'weaponUsed[, ]' },
        { data: 'caseStatus' },
        { data: 'caseStatusDate' },
        { data: 'solvabilityFactor' },
        { data: 'reportingDistrict' },
        { data: 'motive[, ]' },
        { data: 'lastModifiedDate' },
        { data: 'lastModifiedBy.email' },
        { data: 'victim.victName.first' },
        { data: 'address' },
        { data: 'suspects[0].suspName.first' },
        {
          targets: -1,
          data: null,
          defaultContent: '<button id=link-to-case>Click!</button>'
        }
      ],
    });

    // https://datatables.net/examples/ajax/null_data_source.html
    $('#example tbody').on('click', 'button', () => {
      const data = table.row().data();
      document.cookie = `id=${data['_id']}`;
      window.location = '/case';
    });
  }

  // default data table loads with no query
  loadDataTable();

  $('#submit-query').on('click', () => {
    // /cases?drNumber={"lt": 100, "gt": 30}&bureau=OSB
    const a = $('#query1Attribute').val();
    const c = $('#query1Comparator').val();
    const v = $('#query1Value').val();
    if (c === '=') {
      query = `${query}/?${a}${c}${v}`;
    } else {
      query = `${query}${a}={"${c}":${+v}}`;
    }

    if ($('#query2Checkbox').prop('checked')) {
      const A = $('#query2Attribute').val();
      const C = $('#query2Comparator').val();
      const V = $('#query2Value').val();
      if (C === '=') {
        query = query + '&' + A + C + V;
      } else {
        query = `${query}&${A}={"${C}":${+V}}`;
      }
    }

    if ($('#query3Checkbox').prop('checked')) {
      if ($('#query3Comparator').val() === '=') {
        query = query + '&' + $('#query3Attribute').val() + $('#query3Comparator').val() + $('#query3Value').val();
      } else {
        query = `${query}&${$('#query3Attribute').val()}={"${$('#query3Comparator').val()}":${+$('#query3Value').val()}}`;
      }
    }

    if ($('#query4Checkbox').prop('checked')) {
      if ($('#query4Comparator').val() === '=') {
        query = query + '&' + $('#query4Attribute').val() + $('#query4Comparator').val() + $('#query4Value').val();
      } else {
        query = `${query}&${$('#query4Attribute').val()}={"${$('#query4Comparator').val()}":${+$('#query4Value').val()}}`;
      }
    }
    // console.log(query);
    loadDataTable();
  });
});
<|endoftext|>


<commit_before>define(["dojo/_base/declare",
        "dojox/mvc/Output",
        "../xml"],
  function(declare, DojoxMvcOutput, xml) {

    return declare([DojoxMvcOutput], {
      // summary:
      //   Widget based on dojox/mvc/Output. The only difference
      //   is that the shown text is xml-escaped before it is put
      //   in the HTML.

      // missing: string
      //   This string is used when there is no value to show.
      missing: "?value?",
      // TODO re-render when missing changes

      postCreate: function() {
        this._output();
      },

      _output: function(){
        // summary:
        //		Produce the data-bound output, xml-escaped.
        // tags:
        //		protected
        var outputNode = this.srcNodeRef || this.domNode;
        var output = this.templateString ? this._exprRepl(this.templateString) : this.value;
        outputNode.innerHTML = xml.escape(output, false, this.missing);
      }

    });
  }
);
<commit_msg>Output now independent of dojox/mvc, and better escapeXml<commit_after>define(["dojo/_base/declare", "dijit/_WidgetBase",
        "dojo/dom", "../xml", "dojo/_base/lang", "dojo/regexp"],
  function(declare, _WidgetBase,
           dom, xml, lang, regexp) {

    return declare([_WidgetBase], {
      // summary:
      //   Widget based on dojox/mvc/Output. The only difference
      //   is that the shown text is xml-escaped by default before it is put
      //   in the HTML.

      // exprChar: String
      //   "$" cannot be used, because it conflicts
      //   with templated widgets, where ${} is already used.
      exprChar: "@",

      // missing: string
      //   This string is used when there is no value to show.
      missing: "?value?",

      // escapeXml: Boolean
      //   Default is true.
      escapeXml: true,

      // templateString: [private] String
      //		The template or data-bound output content.
      templateString : "",

      postscript: function(params, srcNodeRef){
        // summary:
        //		Override and save template from body.

        this.srcNodeRef = dom.byId(srcNodeRef);
        if(this.srcNodeRef){
          this.templateString = this.srcNodeRef.innerHTML;
          this.srcNodeRef.innerHTML = "";
        }
        this.inherited(arguments);
      },

      postCreate: function() {
        this._output();
      },

      _setValueAttr: function(value) {
        this._set("value", value);
        this._output();
      },

      _setExprCharAttr: function(value) {
        this._set("exprChar", value);
        this._output();
      },

      _setMissingAttr: function(value) {
        this._set("missing", value);
        this._output();
      },

      _setEscapeXmlAttr: function(value) {
        this._set("escapeXml", value);
        this._output();
      },

      _setTemplateStringAttr: function(value) {
        this._set("templateString", value);
        this._output();
      },

      _output: function(){
        // summary:
        //		Produce the data-bound output, xml-escaped.
        // tags:
        //		protected

        var self = this;

        function transform(value){
          if(!value) {
            return "";
          }
          var exp = value.substr(2);
          exp = exp.substr(0, exp.length - 1);
          var val;
          with (self) {
            val = eval(exp);
          }
          val = self.escapeXml ? xml.escapeXml(val) : val;
          return (val || val == 0 ? val : self.missing);
        }

        var outputNode = this.srcNodeRef || this.domNode;
        if (this.templateString) {
          var result = self.templateString.replace(
            new RegExp(regexp.escapeString(self.exprChar)+"(\{.*?\})","g"),
            transform
          );
          outputNode.innerHTML = result;
        }
        else {
          var cleanValue = self.escapeXml ? xml.escape(self.value, false) : self.value;
          outputNode.innerHTML = (cleanValue || cleanValue == 0) ? cleanValue : self.missing;
        }
      }

    });
  }
);
<|endoftext|>


<commit_before>import React from 'react'
import styled from 'styled-components'
import {
  BackgroundImage,
  Box,
  Flex,
  Container,
  Text,
  theme
} from '@hackclub/design-system'
import { Section, SectionTitle, Cols } from './Content'
import { Headline, Subhline, Featline, Title, Lead } from 'components/Content'
import Photo from 'components/Photo'
import Schedule from './Schedule'

const FullBleed = styled(BackgroundImage)`
  position: relative;
  width: 100%;
  min-height: 24rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75);
`
const FullBleedCaption = styled(Flex).attrs({
  fontSize: 1,
  py: 1,
  px: 3,
  m: [3, 4],
  align: 'center',
  color: 'dark'
})`
  position: absolute;
  right: 0;
  bottom: 0;
  border-radius: ${theme.pill};
  background: rgba(255, 255, 255, 0.875);
  text-shadow: none;
  line-height: 1.75;
  @supports (-webkit-backdrop-filter: none) or (backdrop-filter: none) {
    background: rgba(255, 255, 255, 0.75) !important;
    -webkit-backdrop-filter: saturate(180%) blur(2px);
  }
  ${theme.mediaQueries.reduceTransparency} {
    background: ${theme.colors.muted} !important;
  }
`

const Gallery = styled(Container).attrs({ maxWidth: 84, px: [3, 4] })`
  display: grid;
  grid-gap: ${theme.space[3]}px;
  ${theme.mediaQueries.md} {
    grid-template-columns: repeat(8, 1fr);
    > div {
      grid-column: span 4;
      min-height: 32rem;
      &[data-vertical] {
        grid-column: span 2;
      }
    }
  }
`

export default () => (

    <Container maxWidth={61.25} px={3}>
      <SectionTitle>Activities</SectionTitle>
      <Headline mb={2}>Schedule</Headline>
      <Cols cols="4fr 1fr" mt={4} mb={[5, 6]}>
        <Schedule
          events={[
            { start: '7:30am', color: 'white', name: 'Wake up' },
            {
              start: '8:30am',
              length: 0.5,
              color: 'yellow',
              name: 'Travel to HQ'
            },
            { start: '9:00am', color: 'teal', name: 'Breakfast at HQ' },
            { start: '10:00am', length: 2, name: 'Hacker Workshop' },
            { start: '12:00pm', length: 0.5, name: 'Project Demos' },
            { start: '12:30pm', color: 'teal', name: 'Lunch' },
            { start: '1:30pm', length: 1, name: 'Speaker' },
            { start: '2:30pm', length: 2, name: 'Challenge' },
            {
              start: '5:00pm',
              length: 0.5,
              color: 'yellow',
              name: 'Travel to Home Base'
            },
            { start: '5:30pm', length: 1.5, color: 'teal', name: 'Cooking' },
            { start: '7:00pm', color: 'teal', name: 'Dinner' },
            { start: '8:00pm', length: 0.5, color: 'yellow', name: 'Cleanup' },
            { start: '9:00pm', color: 'white', name: 'Free Time' },
            { start: '11:00pm', length: 0.5, color: 'white', name: 'Bedtime' }
          ]}
        />
        <Text fontSize={2}>
          We’ll change it up every day! But here’s what you can expect.
        </Text>
      </Cols>
      <Cols cols="1fr 2fr">
        <Headline>Better every day. Literally.</Headline>
        <Lead>
          Every night, we’ll poll for feedback on all activities. We’ll build
          the next day’s program around that feedback. So your Camp experience
          will only improve.
        </Lead>
      </Cols>
    </Container>
    <Gallery my={[5, 6]}>
      <Photo
        src="/camp/street.jpg"
        alt="Natoma St, HQ on the left"
        dark
        data-vertical
      />
      <Photo
        src="/camp/neighborhood.jpg"
        alt="Neighborhood, two blocks from HQ"
        dark
      />
      <Photo
        src="/camp/classroom.jpg"
        alt="HQ’s classroom space"
        dark
        data-vertical
      />
      <Photo src="/camp/conference.jpg" alt="HQ’s conference room" dark />
      <Photo src="/camp/library.jpg" alt="HQ’s library" dark />
    </Gallery>

)
<commit_msg>Describe Hack Club<commit_after>import React from 'react'
import styled from 'styled-components'
import {
  BackgroundImage,
  Box,
  Flex,
  Container,
  Text,
  theme
} from '@hackclub/design-system'
import { Link } from 'gatsby'
import { Section, SectionTitle, Cols } from './Content'
import { Headline, Subhline, Featline, Title, Lead } from 'components/Content'
import Photo from 'components/Photo'
import Schedule from './Schedule'

const FullBleed = styled(BackgroundImage)`
  position: relative;
  width: 100%;
  min-height: 24rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75);
`
const FullBleedCaption = styled(Flex).attrs({
  fontSize: 1,
  py: 1,
  px: 3,
  m: [3, 4],
  align: 'center',
  color: 'dark'
})`
  position: absolute;
  right: 0;
  bottom: 0;
  border-radius: ${theme.pill};
  background: rgba(255, 255, 255, 0.875);
  text-shadow: none;
  line-height: 1.75;
  @supports (-webkit-backdrop-filter: none) or (backdrop-filter: none) {
    background: rgba(255, 255, 255, 0.75) !important;
    -webkit-backdrop-filter: saturate(180%) blur(2px);
  }
  ${theme.mediaQueries.reduceTransparency} {
    background: ${theme.colors.muted} !important;
  }
`

const Gallery = styled(Container).attrs({ maxWidth: 84, px: [3, 4] })`
  display: grid;
  grid-gap: ${theme.space[3]}px;
  ${theme.mediaQueries.md} {
    grid-template-columns: repeat(8, 1fr);
    > div {
      grid-column: span 4;
      min-height: 32rem;
      &[data-vertical] {
        grid-column: span 2;
      }
    }
  }
`

export default () => (

    <Container maxWidth={61.25} px={3}>
      <SectionTitle>Activities</SectionTitle>
      <Headline mb={4}>Schedule</Headline>
      <Schedule
        events={[
          { start: '7:30am', color: 'white', name: 'Wake up' },
          {
            start: '8:30am',
            length: 0.5,
            color: 'yellow',
            name: 'Travel to HQ'
          },
          { start: '9:00am', color: 'teal', name: 'Breakfast at HQ' },
          { start: '10:00am', length: 2, name: 'Hacker Workshop' },
          { start: '12:00pm', length: 0.5, name: 'Project Demos' },
          { start: '12:30pm', color: 'teal', name: 'Lunch' },
          { start: '1:30pm', length: 1, name: 'Speaker' },
          { start: '2:30pm', length: 2, name: 'Challenge' },
          {
            start: '5:00pm',
            length: 0.5,
            color: 'yellow',
            name: 'Travel to Home Base'
          },
          { start: '5:30pm', length: 1.5, color: 'teal', name: 'Cooking' },
          { start: '7:00pm', color: 'teal', name: 'Dinner' },
          { start: '8:00pm', length: 0.5, color: 'yellow', name: 'Cleanup' },
          { start: '9:00pm', color: 'white', name: 'Free Time' },
          { start: '11:00pm', length: 0.5, color: 'white', name: 'Bedtime' }
        ]}
      />
      <Cols mt={[5, 6]}>

          <Featline>Coding? Just a starting point.</Featline>
          <Lead color="muted">
            Hack Camp is so much more than just “learn to code.” You’ll build a
            radio with a pencil, go on field trips, design games. There’s
            something for everyone.
          </Lead>

          <Featline>Better every day. Literally.</Featline>
          <Lead color="muted">
            To end each day, we’ll ask for honest feedback on all activities.
            We’ll update the next day’s program accordingly—so Camp
            continually improves.
          </Lead>

      </Cols>
    </Container>
    <Container align="center" maxWidth={48} px={3}>
      <Headline color="white" mt={[6, 7]} mb={2}>
        Welcome to Hack Club HQ.
      </Headline>
      <Lead color="muted">
        We’re{' '}
        <Link style={{ color: theme.colors.primary }} to="/">
          Hack Club
        </Link>
        , a global nonprofit network of high school hackers with coding clubs at
        2% of US high schools. We’re running Hack Camp right at our
        office in San Francisco (576 Natoma St) so we can X, Y, Z. Here’s the
        space.
      </Lead>
    </Container>
    <Gallery my={5}>
      <Photo
        src="/camp/street.jpg"
        alt="Natoma St, HQ on the left"
        dark
        data-vertical
      />
      <Photo
        src="/camp/neighborhood.jpg"
        alt="Neighborhood, two blocks from HQ"
        dark
      />
      <Photo
        src="/camp/classroom.jpg"
        alt="HQ’s classroom space"
        dark
        data-vertical
      />
      <Photo src="/camp/conference.jpg" alt="HQ’s conference room" dark />
      <Photo src="/camp/library.jpg" alt="HQ’s library" dark />
    </Gallery>

)
<|endoftext|>


<commit_before>$.jCanvas.defaults.fromCenter = false;
var $comicCanvas = $('#comic-canvas'); // <canvas id="comic-canvas" height="590" width="767">
var $savedComicCanvas = $('#saved-comic-canvas'); //<canvas id="saved-comic-canvas" width="767" height="129">
var hasBackground = false;
var selectedIndex;

$(document).on('dragstart', function(e) {
	var target = e.target;
	if (target.className.includes('draggable') == false) {return};
	e.dataTransfer = e.originalEvent.dataTransfer;
	e.dataTransfer.setData('text/plain', target.src);
	// e.name = "Image";
	if (target.src.includes("backgrounds")) {return};
	var img = new Image();
	img.src = target.src;
	e.dataTransfer.setDragImage(img, img.width/2, img.height/2);
});

$comicCanvas.on('dragover', function(e) {
	e.preventDefault();
	e.dataTransfer = e.originalEvent.dataTransfer;
	e.dataTransfer.dropEffect = 'move';
});

$comicCanvas.on('drop', function(e) {
	e.preventDefault();
	e.dataTransfer = e.originalEvent.dataTransfer;
	var src = e.dataTransfer.getData('text');

	// Find image size
	var img = new Image();
	img.src = src;

	// Use image size to draw on canvas right where you drop it.
	var x = e.pageX - $comicCanvas.offset().left - img.width/2;
	var y = e.pageY - $comicCanvas.offset().top - img.height/2;
	addLayer(src, x, y);
});

function addLayer(src, x, y) {
	var index, draggable;
	if (src.includes('backgrounds')) {
		// Backgrounds are centered in canvas...
		x = 0;
		y = 0;
		// Undraggable...
		draggable = false;
		// And replace the previous background if already drawn
		if (hasBackground) {
			$comicCanvas.removeLayer(0);
			index = 0;
		}
		hasBackground = true;
	} else {
		draggable = true
		index = 1 + $comicCanvas.getLayers().length;
	};

	$comicCanvas.addLayer({
		type: 'image',
		source: src,
		x: x, y: y,
		draggable: draggable,
		index: index,
		sel: true,
		// When selected, move to .6 opaque
		dblclick: function(layer){
			var layers = $comicCanvas.getLayers();
			for (var i=0; i<layers.length; i++) {
				var l = layers[i];
				l.sel = false;
				l.opacity = 1;
			}
			layer.sel = true;
			layer.opacity = 0.6;
			selectedIndex = layer.index;
			console.log(selectedIndex);
		}
	}).drawLayers();
}

$('#images').on('click', 'img', function() {
	if(hasBackground){
		var x = ($comicCanvas.getLayers().length - 1) * 100;
	}else{
		var x = $comicCanvas.getLayers().length * 100;
	}
	addLayer(this.src, x, 0);
})

<commit_msg>Select layer automatically when added<commit_after>$.jCanvas.defaults.fromCenter = false;
var $comicCanvas = $('#comic-canvas'); // <canvas id="comic-canvas" height="590" width="767">
var $savedComicCanvas = $('#saved-comic-canvas'); //<canvas id="saved-comic-canvas" width="767" height="129">
var hasBackground = false;
var selectedIndex;

$(document).on('dragstart', function(e) {
	var target = e.target;
	if (target.className.includes('draggable') == false) {return};
	e.dataTransfer = e.originalEvent.dataTransfer;
	e.dataTransfer.setData('text/plain', target.src);
	// e.name = "Image";
	if (target.src.includes("backgrounds")) {return};
	var img = new Image();
	img.src = target.src;
	e.dataTransfer.setDragImage(img, img.width/2, img.height/2);
});

$comicCanvas.on('dragover', function(e) {
	e.preventDefault();
	e.dataTransfer = e.originalEvent.dataTransfer;
	e.dataTransfer.dropEffect = 'move';
});

$comicCanvas.on('drop', function(e) {
	e.preventDefault();
	e.dataTransfer = e.originalEvent.dataTransfer;
	var src = e.dataTransfer.getData('text');

	// Find image size
	var img = new Image();
	img.src = src;

	// Use image size to draw on canvas right where you drop it.
	var x = e.pageX - $comicCanvas.offset().left - img.width/2;
	var y = e.pageY - $comicCanvas.offset().top - img.height/2;
	addLayer(src, x, y);
});

$('#images').on('click', 'img', function() {
	if(hasBackground){
		var x = ($comicCanvas.getLayers().length - 1) * 100;
	}else{
		var x = $comicCanvas.getLayers().length * 100;
	}
	addLayer(this.src, x, 0);
});

function addLayer(src, x, y) {
	var index, draggable;
	if (src.includes('backgrounds')) {
		// Backgrounds are centered in canvas...
		x = 0;
		y = 0;
		// Undraggable...
		draggable = false;
		// And replace the previous background if already drawn
		if (hasBackground) {
			$comicCanvas.removeLayer(0);
			index = 0;
		}
		hasBackground = true;
	} else {
		draggable = true
		index = 1 + $comicCanvas.getLayers().length;
	};

	$comicCanvas.addLayer({
		type: 'image',
		source: src,
		x: x, y: y,
		draggable: draggable,
		index: index,
		sel: true,
		// When sedlected, move to .6 opaque
		dblclick: function(layer){
			selectLayer(layer);
		}
	});

	// Get layer we just added and select it
	var length = $comicCanvas.getLayers().length;
	var layer = $comicCanvas.getLayers()[length - 1];
	selectLayer(layer);

	$comicCanvas.drawLayers();
};

function selectLayer(layer) {
	var layers = $comicCanvas.getLayers();
	for (var i=0; i<layers.length; i++) {
		var l = layers[i];
		l.sel = false;
		l.opacity = 1;
	}
	layer.sel = true;
	layer.opacity = 0.6;
	selectedIndex = layer.index;
	console.log(selectedIndex);
}<|endoftext|>


<commit_before>"use strict";
const config = require("../config");
const customConfig = require('../configEdit');
const utils = require("../src/utils");
const qutils = require('../src/queueUtils');

function addApproval (bot, channelID, userTag, userID, command, msg, db, key, ADcontent, reportInfo, trello) {
  db.all("SELECT stance FROM reportQueueInfo WHERE id = ? AND userID = ? AND (stance = 'approve' OR stance = 'deny')", [key, userID] , function(error, checkQueueReport) {
    bot.getMessage(config.channels.queueChannel, reportInfo.reportMsgID).then((msgContent) => {
      if(!!msgContent && !!checkQueueReport) {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, checkQueueReport[0], reportInfo, msgContent, trello);
      } else if(!!msgContent && !checkQueueReport) {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, null, reportInfo, msgContent, trello);
      } else if(!msgContent && !!checkQueueReport) {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, checkQueueReport[0], reportInfo, null, trello);
      } else {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, null, reportInfo, null, trello);
      }

    }).catch((error) => {console.log("L14 appDeny\n" + error)});
  });
}

let approveDeny = {
  pattern: /!approve|!deny/i,
  execute: function(bot, channelID, userTag, userID, command, msg, trello, db) {
    let messageSplit = msg.content.split(' ');
    messageSplit.shift();
    let recievedMessage = messageSplit.join(' ');
    let contentMessage = recievedMessage.match(/(\d*)\s*\|\s*([\s\S]*)/i);

    if(!contentMessage) {
      utils.botReply(bot, userID, channelID, "please format your input correctly. `" + command + " <report ID> | system info`. See <#312262075361787905> for full syntax", command, msg.id, false);
      return;
    }

    let key = contentMessage[1];

    db.get("SELECT header, reportStatus, canRepro, cantRepro, reportMsgID, header, reportString, userID FROM reports WHERE id = ?", [key], function(error, reportInfo) {
      if(!!error) {
        console.log("appDeny\n" + error);
      }

      if(!reportInfo) { // check if report exists
        utils.botReply(bot, userID, channelID, "I can't find that report ID. Make sure you use a valid report ID.", command, msg.id, false);
        return;
      }
      if(command.toLowerCase() === "!approve" && reportInfo.userID === userID) { // check if user is trying to approve their own report
        utils.botReply(bot, userID, channelID, "You can't approve your own report.", command, msg.id, false);
        return;
      }
      if(reportInfo.reportStatus !== "queue") { // check if the report is in the queue, closed or sent to trello
        utils.botReply(bot, userID, channelID, "this report has already been moved", command, msg.id, false);
        return;
      }

      let cleanContent = utils.preCleanInputText(contentMessage[2], false);
      let whichClient = cleanContent.match(/(?:\B)(-l|-m|-w|-a|-i)(?:\b)/i);
      let ADcontent = cleanContent;
      //Check if ADcontent exists or not, reply "missing reason/user settings" if it's missing
      if(!cleanContent) {
        utils.botReply(bot, userID, channelID, "you're missing a reason or system settings. Refer to #Bot-Help for more info", command, msg.id, false);
        return;
      } else if(!!whichClient) {
        whichClient[1] = whichClient[1].toLowerCase();
        let system;
        if(whichClient[1] === "-w") {
          system = "windows";
        } else if(whichClient[1] === "-i") {
          system = "ios";
        } else if(whichClient[1] === "-l") {
          system = "linux";
        } else if(whichClient[1] === "-m") {
          system = "macOS";
        } else if(whichClient[1] === "-a") {
          system = "android";
        }
        db.get("SELECT " + system + " FROM users WHERE userid = ?", [userID], function(error, usrSys) {
          if(!!error) {
            console.log("getSystem\n" + error);
          }
          if(!!usrSys){
            let info = cleanContent;
            ADcontent = info.replace(/(?:\B)(-l|-m|-w|-a|-i)(?:\b)/i, " " + usrSys[system]);
            addApproval (bot, channelID, userTag, userID, command, msg, db, key, ADcontent, reportInfo, trello);
          } else {
            utils.botReply(bot, userID, channelID, "doesn't seem like you have that client in our database. You can add it with `!storeinfo " + whichClient[1] + " | system info`", command, msg.id, false);
            return;
          }
        });
      } else {
        addApproval (bot, channelID, userTag, userID, command, msg, db, key, ADcontent, reportInfo, trello);
      }
    });
  },
  roles: [
    config.roles.adminRole,
    config.roles.trelloModRole,
    config.roles.devRole,
    config.roles.hunterRole
    ],
  channels: [
    config.channels.queueChannel
  ],
  acceptFromDM: false
}
module.exports = approveDeny;
<commit_msg>Removed extra space<commit_after>"use strict";
const config = require("../config");
const customConfig = require('../configEdit');
const utils = require("../src/utils");
const qutils = require('../src/queueUtils');

function addApproval (bot, channelID, userTag, userID, command, msg, db, key, ADcontent, reportInfo, trello) {
  db.all("SELECT stance FROM reportQueueInfo WHERE id = ? AND userID = ? AND (stance = 'approve' OR stance = 'deny')", [key, userID] , function(error, checkQueueReport) {
    bot.getMessage(config.channels.queueChannel, reportInfo.reportMsgID).then((msgContent) => {
      if(!!msgContent && !!checkQueueReport) {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, checkQueueReport[0], reportInfo, msgContent, trello);
      } else if(!!msgContent && !checkQueueReport) {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, null, reportInfo, msgContent, trello);
      } else if(!msgContent && !!checkQueueReport) {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, checkQueueReport[0], reportInfo, null, trello);
      } else {
        qutils.addAD(bot, channelID, userTag, userID, command, msg, db, key, ADcontent, null, reportInfo, null, trello);
      }

    }).catch((error) => {console.log("L14 appDeny\n" + error)});
  });
}

let approveDeny = {
  pattern: /!approve|!deny/i,
  execute: function(bot, channelID, userTag, userID, command, msg, trello, db) {
    let messageSplit = msg.content.split(' ');
    messageSplit.shift();
    let recievedMessage = messageSplit.join(' ');
    let contentMessage = recievedMessage.match(/(\d*)\s*\|\s*([\s\S]*)/i);

    if(!contentMessage) {
      utils.botReply(bot, userID, channelID, "please format your input correctly. `" + command + " <report ID> | system info`. See <#312262075361787905> for full syntax", command, msg.id, false);
      return;
    }

    let key = contentMessage[1];

    db.get("SELECT header, reportStatus, canRepro, cantRepro, reportMsgID, header, reportString, userID FROM reports WHERE id = ?", [key], function(error, reportInfo) {
      if(!!error) {
        console.log("appDeny\n" + error);
      }

      if(!reportInfo) { // check if report exists
        utils.botReply(bot, userID, channelID, "I can't find that report ID. Make sure you use a valid report ID.", command, msg.id, false);
        return;
      }
      if(command.toLowerCase() === "!approve" && reportInfo.userID === userID) { // check if user is trying to approve their own report
        utils.botReply(bot, userID, channelID, "You can't approve your own report.", command, msg.id, false);
        return;
      }
      if(reportInfo.reportStatus !== "queue") { // check if the report is in the queue, closed or sent to trello
        utils.botReply(bot, userID, channelID, "this report has already been moved", command, msg.id, false);
        return;
      }

      let cleanContent = utils.preCleanInputText(contentMessage[2], false);
      let whichClient = cleanContent.match(/(?:\B)(-l|-m|-w|-a|-i)(?:\b)/i);
      let ADcontent = cleanContent;
      //Check if ADcontent exists or not, reply "missing reason/user settings" if it's missing
      if(!cleanContent) {
        utils.botReply(bot, userID, channelID, "you're missing a reason or system settings. Refer to #Bot-Help for more info", command, msg.id, false);
        return;
      } else if(!!whichClient) {
        whichClient[1] = whichClient[1].toLowerCase();
        let system;
        if(whichClient[1] === "-w") {
          system = "windows";
        } else if(whichClient[1] === "-i") {
          system = "ios";
        } else if(whichClient[1] === "-l") {
          system = "linux";
        } else if(whichClient[1] === "-m") {
          system = "macOS";
        } else if(whichClient[1] === "-a") {
          system = "android";
        }
        db.get("SELECT " + system + " FROM users WHERE userid = ?", [userID], function(error, usrSys) {
          if(!!error) {
            console.log("getSystem\n" + error);
          }
          if(!!usrSys){
            let info = cleanContent;
            ADcontent = info.replace(/(?:\B)(-l|-m|-w|-a|-i)(?:\b)/i, usrSys[system]);
            addApproval (bot, channelID, userTag, userID, command, msg, db, key, ADcontent, reportInfo, trello);
          } else {
            utils.botReply(bot, userID, channelID, "doesn't seem like you have that client in our database. You can add it with `!storeinfo " + whichClient[1] + " | system info`", command, msg.id, false);
            return;
          }
        });
      } else {
        addApproval (bot, channelID, userTag, userID, command, msg, db, key, ADcontent, reportInfo, trello);
      }
    });
  },
  roles: [
    config.roles.adminRole,
    config.roles.trelloModRole,
    config.roles.devRole,
    config.roles.hunterRole
    ],
  channels: [
    config.channels.queueChannel
  ],
  acceptFromDM: false
}
module.exports = approveDeny;
<|endoftext|>


<commit_before>module.exports = (client, message, args) => {

    { let numArray = args.map(n=> parseFloat(n));  let total = numArray.reduce( (p,c) => (p/c|0)); message.channel.sendMessage(total); }

  };<commit_msg><commit_after>module.exports = (client, message, args) => {

    { let numArray = args.map(n=> parseFloat(n)).then(msg => {msg.delete(10000)});;  let total = numArray.reduce( (p,c) => (p/c|0)); message.channel.sendMessage(total); }

  };<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIPlugin = require('../../base/ui_plugin');
var Styler = require('../../base/styler');
var JST = require('../../base/jst');
var Environment = require('../../components/environment');
var $ = require('jquery');

var PosterPlugin = UIPlugin.extend({
  name: 'poster',
  tagName: 'img',
  attributes: {
    'data-poster': ''
  },
  events: {
    'click': 'clicked'
  },
  initialize: function(options) {
    PosterPlugin.super('initialize').call(this, options);
    this.options = options;
    if (this.options.disableControlsOnPoster)
      this.container.disableMediaControl();
    this.el.src = options.poster || 'assets/default.png';
    this.render();
  },
  bindEvents: function() {
    this.listenTo(this.container, 'container:state:buffering', this.onBuffering);
    this.listenTo(this.container, 'container:play', this.onPlay);
    this.listenTo(this.container, 'container:stop', this.onStop);
    this.listenTo(this.container, 'container:ended', this.onStop);
  },
  onBuffering: function() {
    this.hidePlayButton();
  },
  onPlay: function() {
    this.$el.hide();
    if (this.options.disableControlsOnPoster) {
      this.container.enableMediaControl();
    }
  },
  onStop: function() {
    this.$el.show();
    if (this.options.disableControlsOnPoster) {
      this.container.disableMediaControl();
    }
    if (!this.options.hidePlayButton) {
      this.showPlayButton();
    }
  },
  onPipStateChanged: function(isPip) {
    if (isPip) {
      this.hidePlayButton();
    } else if (!this.options.hidePlayButton) {
      this.showPlayButton();
    }
  },
  hidePlayButton: function() {
    this.$playButton.hide();
  },
  showPlayButton: function() {
    this.$playButton.show();
  },
  render: function() {
    var style = Styler.getStyleFor(this.name);
    this.container.$el.append(style);
    this.container.$el.append(this.el);
    return this;
  },
  clicked: function() {
    this.container.play();
  }
});

module.exports = PosterPlugin;
<commit_msg>poster: remove envs dependency<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIPlugin = require('../../base/ui_plugin');
var Styler = require('../../base/styler');
var JST = require('../../base/jst');
var $ = require('jquery');

var PosterPlugin = UIPlugin.extend({
  name: 'poster',
  tagName: 'img',
  attributes: {
    'data-poster': ''
  },
  events: {
    'click': 'clicked'
  },
  initialize: function(options) {
    PosterPlugin.super('initialize').call(this, options);
    this.options = options;
    if (this.options.disableControlsOnPoster)
      this.container.disableMediaControl();
    this.el.src = options.poster || 'assets/default.png';
    this.render();
  },
  bindEvents: function() {
    this.listenTo(this.container, 'container:state:buffering', this.onBuffering);
    this.listenTo(this.container, 'container:play', this.onPlay);
    this.listenTo(this.container, 'container:stop', this.onStop);
    this.listenTo(this.container, 'container:ended', this.onStop);
  },
  onBuffering: function() {
    this.hidePlayButton();
  },
  onPlay: function() {
    this.$el.hide();
    if (this.options.disableControlsOnPoster) {
      this.container.enableMediaControl();
    }
  },
  onStop: function() {
    this.$el.show();
    if (this.options.disableControlsOnPoster) {
      this.container.disableMediaControl();
    }
    if (!this.options.hidePlayButton) {
      this.showPlayButton();
    }
  },
  onPipStateChanged: function(isPip) {
    if (isPip) {
      this.hidePlayButton();
    } else if (!this.options.hidePlayButton) {
      this.showPlayButton();
    }
  },
  hidePlayButton: function() {
    this.$playButton.hide();
  },
  showPlayButton: function() {
    this.$playButton.show();
  },
  render: function() {
    var style = Styler.getStyleFor(this.name);
    this.container.$el.append(style);
    this.container.$el.append(this.el);
    return this;
  },
  clicked: function() {
    this.container.play();
  }
});

module.exports = PosterPlugin;
<|endoftext|>