<commit_before>/*
The MIT License (MIT) Copyright © 2014

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

var expressionParser = (function _expressionParser() {
    var dateTimeRegex = '^(((?:(?:(?:(?:(?:(?:(?:(0?[13578]|1[02])(\\/|-|\\.)(31))\\4|(?:(0?[1,3-9]|1[0-2])(\\/|-|\\.)(29|30)\\7))|(?:(?:(?:(?:(31)(\\/|-|\\.)(0?[13578]|1[02])\\10)|(?:(29|30)(\\/|-|\\.)' +
        '(0?[1,3-9]|1[0-2])\\13)))))((?:1[6-9]|[2-9]\\d)?\\d{2})|(?:(?:(?:(0?2)(\\/|-|\\.)(29)\\17)|(?:(29)(\\/|-|\\.)(0?2))\\20)((?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])' +
        '|(?:(?:16|[2468][048]|[3579][26])00))))|(?:(?:((?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.)(0?[1-9]|1\\d|2[0-8]))\\24|(0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)((?:0?[1-9])|(?:1[0-2]))\\27)' +
        '((?:1[6-9]|[2-9]\\d)?\\d{2}))))|(?:(?:((?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\\/|-|\\.)(?:(?:(?:(0?2)(?:\\31)(29))))' +
        '|((?:1[6-9]|[2-9]\\d)?\\d{2})(\\/|-|\\.)(?:(?:(?:(0?[13578]|1[02])\\35(31))|(?:(0?[1,3-9]|1[0-2])\\35(29|30)))|((?:0?[1-9])|(?:1[0-2]))\\35(0?[1-9]|1\\d|2[0-8])))))' +
        '(?: |T)((0?[1-9]|1[012])(?:(?:(:|\\.)([0-5]\\d))(?:\\44([0-5]\\d))?)?(?:(\\ [AP]M))$|([01]?\\d|2[0-3])(?:(?:(:|\\.)([0-5]\\d))(?:\\49([0-5]\\d))?)$))';

    var booleanExpressionTree = {
        init: function _init() {
            this.tree = null;
            this.context = null;
            this.rootNode = null;
            return this;
        }
    };

    booleanExpressionTree.setTree = function _setTree(tree) {
        this.queue = tree;
        this.rootNode = tree[this.queue.length - 1];
        return this;
    };
    booleanExpressionTree.createTree = function _createTree() {
        this.queue.pop;
        if (this.queue.length)
            this.rootNode.addChildren(this.queue);
    };
    booleanExpressionTree.filterCollection = function _filterCollection(collection) {
        return collection.filter(function collectionMap(curr) {
            this.context = curr;
            return this.rootNode.evaluate(curr);
        }, this);
    };
    booleanExpressionTree.internalGetContext = function _internalGetContext() {
        return this.context;
    };
    booleanExpressionTree.getContext = function _getContext() {
        return this.internalGetContext.bind(this);
    };
    booleanExpressionTree.isTrue = function _isTrue(item) {
        this.context = item;
        return this.rootNode.value;
    };

    var astNode = {
        createNode: function _createNode(node) {
            var operatorCharacteristics = getOperatorPrecedence(node);
            if (operatorCharacteristics) {
                this.operator = node;
                this.numberOfOperands = getNumberOfOperands(this.operator);
                this.precedence = operatorCharacteristics.precedence;
                this.associativity = operatorCharacteristics.associativity;
                this.children = [];
            }
            else {
                this.field = node.field;
                this.standard = node.value;
                this.operation = node.operation;
                this.dataType = node.dataType;
                this.context = null;
            }
            this._value = null;
            this.getContext = null;
            this.queue = null;
        }
    };

    astNode.createTree = function _createTree(queue) {
        this.queue = queue.reverse();
        this.tree = this.queue;
        this.addChildren(this.queue);
    };

    astNode.addChildren = function _addChildren(tree) {
        if (this.children && this.children.length < this.numberOfOperands) {
            var child = tree.pop;
            child.addChildren(tree);
            this.children.push(child);
            child = tree.pop;
            child.addChildren(tree);
            this.children.push(child);
        }
        return this;
    };

    astNode.addChild = function _addChild(child) {
        if (this.children && this.children.length < this.numberOfOperands)
            this.children.push(child);
        return this;
    };

    astNode.evaluate = function _evaluate() {
        if (this.children && this.children.length) {
            switch (this.operator) {
                case 'or':
                    return this.children[1].evaluate() || this.children[0].evaluate();
                case 'and':
                    return this.children[1].evaluate() && this.children[0].evaluate();
                case 'xor':
                    return !!(this.children[1].evaluate() ^ this.children[0].evaluate());
                case 'nor':
                    return !(this.children[1].evaluate() || this.children[0].evaluate());
                case 'nand':
                    return !(this.children[1].evaluate() && this.children[0].evaluate());
                case 'xnor':
                    return !(this.children[1].evaluate() ^ this.children[0].evaluate());
            }
        }
        else {
            var baseVal,
                curVal,
                initialVal = this.getContext()[this.field];

            switch(this.dataType == null ? typeof this.getContext()[this.field] : this.dataType) {
                case 'time':
                    curVal = getNumbersFromTime(initialVal);
                    baseVal = getNumbersFromTime(this.standard);

                    if (initialVal.indexOf('PM') > -1) curVal[0] += 12;
                    if (this.standard.indexOf('PM') > -1) baseVal[0] += 12;

                    curVal = convertTimeArrayToSeconds(curVal);
                    baseVal = convertTimeArrayToSeconds(baseVal);
                    break;
                case 'datetime':
                    var re = new RegExp(dateTimeRegex),
                        execVal1, execVal2;
                    if (re.test(initialVal) && re.test(this.standard)) {
                        execVal1 = re.exec(initialVal);
                        execVal2 = re.exec(this.standard);

                        var dateComp1 = execVal1[2],
                            dateComp2 = execVal2[2],
                            timeComp1 = execVal1[42],
                            timeComp2 = execVal2[42];

                        timeComp1 = getNumbersFromTime(timeComp1);
                        timeComp2 = getNumbersFromTime(timeComp2);
                        if (timeComp1[3] && timeComp1[3] === 'PM')
                            timeComp1[0] += 12;
                        if (timeComp2[3] && timeComp2[3] === 'PM')
                            timeComp2[0] += 12;

                        dateComp1 = new Date(dateComp1);
                        dateComp2 = new Date(dateComp2);
                        curVal = dateComp1.getTime() + convertTimeArrayToSeconds(timeComp1);
                        baseVal = dateComp2.getTime() + convertTimeArrayToSeconds(timeComp2);
                    }
                    else {
                        curVal = 0;
                        baseVal = 0;
                    }
                    break;
                case 'number':
                    curVal = parseFloat(initialVal);
                    baseVal = parseFloat(this.standard);
                    break;
                case 'date':
                    curVal = new Date(initialVal);
                    baseVal = new Date(this.standard);
                    break;
                case 'boolean':
                    curVal = initialVal.toString();
                    baseVal = this.standard.toString();
                    break;
                default:
                    curVal = initialVal.toString();
                    baseVal = this.standard.toString();
                    break;
            }

            this._value = comparator(curVal, baseVal, this.operation);
            return this._value;
        }
    };

    astNode.getValue = function _getValue() {
        if (this._value == null)
            this._value = this.evaluate();
        return this._value;
    };

    Object.defineProperty(astNode, 'value', {
        get: function _getValue() {
            if (!this._value) {
                this._value = this.evaluate();
            }
            return this._value;
        }
    });

    function getNodeContext(bet) {
        return bet.internalGetContext.bind(bet);
    }

    function createFilterTreeFromFilterObject(filterObject) {
        var ret = Object.create(booleanExpressionTree);
        ret.init();
        var operandStack = Object.create(stack);
        operandStack.init();
        var queue = [],
            topOfStack;

        iterateFilterGroup(filterObject, operandStack, queue, getNodeContext(ret));

        while (operandStack.length) {
            topOfStack = operandStack.peek;
            if (topOfStack.operator !== '(')
                queue.push(operandStack.pop);
            else operandStack.pop;
        }

        ret.setTree(queue);
        ret.createTree();
        return ret;
    }

    function iterateFilterGroup(filterObject, stack, queue, contextGetter) {
        var conjunction = filterObject.conjunct,
            idx = 0,
            topOfStack;

        while (idx < filterObject.filterGroup.length) {
            if (idx > 0) {
                var conjunctObj = Object.create(astNode);
                conjunctObj.createNode(conjunction);
                pushConjunctionOntoStack(conjunctObj, stack, queue);
            }
            if (filterObject.filterGroup[idx].conjunct) {
                var paren = Object.create(astNode);
                paren.createNode('(');
                stack.push(paren);
                iterateFilterGroup(filterObject.filterGroup[idx], stack, queue, contextGetter);
                while (stack.length) {
                    topOfStack = stack.peek;
                    if (topOfStack.operator !== '(')
                        queue.push(stack.pop);
                    else {
                        stack.pop;
                        break;
                    }
                }
            }
            else {
                var leafNode = Object.create(astNode);
                leafNode.createNode(filterObject.filterGroup[idx]);
                leafNode.getContext = contextGetter;
                queue.push(leafNode);
            }
            ++idx;
        }
    }

    function pushConjunctionOntoStack(conjunction, stack, queue) {
        while (stack.length) {
            var topOfStack = stack.peek;
            if ((conjunction.associativity === associativity.LTR && conjunction.precedence <= topOfStack.precedence)
                || (conjunction.associativity === associativity.RTL && conjunction.precedence < topOfStack.precedence))
                queue.push(stack.pop);
            else
                break;
        }
        stack.push(conjunction);
    }

    var stack = {
        init: function _init() {
            this.data = [];
            this.top = 0;
        },
        push: function _push(item) {
            this.data[this.top++] = item;
        },
        get pop() {
            return this.data[--this.top];
        },
        get peek() {
            return this.data[this.top - 1];
        },
        get clear() {
            this.top = 0;
        },
        get length() {
            return this.top;
        }
    };

    function comparator(val, base, type) {
        switch (type) {
            case 'eq':
            case '===':
                return val === base;
            case '==':
                return val == base;
            case 'neq':
            case '!==':
                return val !== base;
            case '!=':
                return val != base;
            case 'gte':
            case '>=':
                return val >= base;
            case 'gt':
            case '>':
                return val > base;
            case 'lte':
            case '<=':
                return val <= base;
            case 'lt':
            case '<':
                return val < base;
            case 'not':
            case '!':
            case 'falsey':
                return !val;
            case 'truthy':
                return !!val;
            case 'ct':
                return !!~val.toLowerCase().indexOf(base.toLowerCase());
            case 'nct':
                return !~val.toLowerCase().indexOf(base.toLowerCase());
        }
    }

    function getNumberOfOperands(operator) {
        switch (operator) {
            case '!':
                return 1;
            case '(':
            case ')':
                return 0;
            default:
                return 2;
        }
    }

    var associativity = { RTL: 1, LTR: 2 };

    function getOperatorPrecedence(operator) {
        switch (operator) {
            case '!':
                return {
                    precedence: 1,
                    associativity: associativity.LTR
                };
            case 'and':
                return {
                    precedence: 2,
                    associativity: associativity.RTL
                };
            case 'xor':
                return {
                    precedence: 3,
                    associativity: associativity.RTL
                };
            case 'or':
                return {
                    precedence: 4,
                    associativity: associativity.RTL
                };
            case '(':
            case ')':
                return {
                    precedence: null,
                    associativity: null
                };
            default:
                return null;
        }
    }

    function getNumbersFromTime(val) {
        var re = /^(0?[1-9]|1[012])(?:(?:(:|\.)([0-5]\d))(?:\2([0-5]\d))?)?(?:(\ [AP]M))$|^([01]?\d|2[0-3])(?:(?:(:|\.)([0-5]\d))(?:\7([0-5]\d))?)$/;
        if (!re.test(val)) return [];
        var timeGroups = re.exec(val);
        var hours = timeGroups[1] ? +timeGroups[1] : +timeGroups[6];
        var minutes, seconds, meridiem, retVal = [];
        if (timeGroups[2]) {
            minutes = timeGroups[3] || '00';
            seconds = timeGroups[4]  || '00';
            meridiem = timeGroups[5].replace(' ', '') || null;
        }
        else if (timeGroups[6]) {
            minutes = timeGroups[8] || '00';
            seconds = timeGroups[9] || '00';
        }
        else{
            minutes = '00';
            seconds = '00';
        }
        retVal.push(hours);
        retVal.push(minutes);
        retVal.push(seconds);
        if (meridiem) retVal.push(meridiem);
        return retVal;
    }

    function convertTimeArrayToSeconds(timeArray) {
        var hourVal = parseInt(timeArray[0].toString()) === 12 || parseInt(timeArray[0].toString()) === 24 ? parseInt(timeArray[0].toString()) - 12 : parseInt(timeArray[0]);
        return 3660 * hourVal + 60 * parseInt(timeArray[1]) + parseInt(timeArray[2]);
    }

    return {
        createFilterTreeFromFilterObject: createFilterTreeFromFilterObject
    };
})();
<commit_msg>master: added 'tokens' enum and replaced magic strings<commit_after>/*
The MIT License (MIT) Copyright © 2014

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

var expressionParser = (function _expressionParser() {
    var tokens = {
        rightParens: ')',
        leftParens: '(',
        AND: 'and',
        OR: 'or',
        XOR: 'xor',
        XAND: 'xand',
        XNOR: 'xnor',
        NOR: 'nor',
        NAND: 'nand',
        NOT: '!'
    };

    var dateTimeRegex = '^(((?:(?:(?:(?:(?:(?:(?:(0?[13578]|1[02])(\\/|-|\\.)(31))\\4|(?:(0?[1,3-9]|1[0-2])(\\/|-|\\.)(29|30)\\7))|(?:(?:(?:(?:(31)(\\/|-|\\.)(0?[13578]|1[02])\\10)|(?:(29|30)(\\/|-|\\.)' +
        '(0?[1,3-9]|1[0-2])\\13)))))((?:1[6-9]|[2-9]\\d)?\\d{2})|(?:(?:(?:(0?2)(\\/|-|\\.)(29)\\17)|(?:(29)(\\/|-|\\.)(0?2))\\20)((?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])' +
        '|(?:(?:16|[2468][048]|[3579][26])00))))|(?:(?:((?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.)(0?[1-9]|1\\d|2[0-8]))\\24|(0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)((?:0?[1-9])|(?:1[0-2]))\\27)' +
        '((?:1[6-9]|[2-9]\\d)?\\d{2}))))|(?:(?:((?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\\/|-|\\.)(?:(?:(?:(0?2)(?:\\31)(29))))' +
        '|((?:1[6-9]|[2-9]\\d)?\\d{2})(\\/|-|\\.)(?:(?:(?:(0?[13578]|1[02])\\35(31))|(?:(0?[1,3-9]|1[0-2])\\35(29|30)))|((?:0?[1-9])|(?:1[0-2]))\\35(0?[1-9]|1\\d|2[0-8])))))' +
        '(?: |T)((0?[1-9]|1[012])(?:(?:(:|\\.)([0-5]\\d))(?:\\44([0-5]\\d))?)?(?:(\\ [AP]M))$|([01]?\\d|2[0-3])(?:(?:(:|\\.)([0-5]\\d))(?:\\49([0-5]\\d))?)$))';

    var booleanExpressionTree = {
        init: function _init() {
            this.tree = null;
            this.context = null;
            this.rootNode = null;
            return this;
        }
    };

    booleanExpressionTree.setTree = function _setTree(tree) {
        this.queue = tree;
        this.rootNode = tree[this.queue.length - 1];
        return this;
    };
    booleanExpressionTree.createTree = function _createTree() {
        this.queue.pop;
        if (this.queue.length)
            this.rootNode.addChildren(this.queue);
    };
    booleanExpressionTree.filterCollection = function _filterCollection(collection) {
        return collection.filter(function collectionMap(curr) {
            this.context = curr;
            return this.rootNode.evaluate(curr);
        }, this);
    };
    booleanExpressionTree.internalGetContext = function _internalGetContext() {
        return this.context;
    };
    booleanExpressionTree.getContext = function _getContext() {
        return this.internalGetContext.bind(this);
    };
    booleanExpressionTree.isTrue = function _isTrue(item) {
        this.context = item;
        return this.rootNode.value;
    };

    var astNode = {
        createNode: function _createNode(node) {
            var operatorCharacteristics = getOperatorPrecedence(node);
            if (operatorCharacteristics) {
                this.operator = node;
                this.numberOfOperands = getNumberOfOperands(this.operator);
                this.precedence = operatorCharacteristics.precedence;
                this.associativity = operatorCharacteristics.associativity;
                this.children = [];
            }
            else {
                this.field = node.field;
                this.standard = node.value;
                this.operation = node.operation;
                this.dataType = node.dataType;
                this.context = null;
            }
            this._value = null;
            this.getContext = null;
            this.queue = null;
        }
    };

    astNode.createTree = function _createTree(queue) {
        this.queue = queue.reverse();
        this.tree = this.queue;
        this.addChildren(this.queue);
    };

    astNode.addChildren = function _addChildren(tree) {
        if (this.children && this.children.length < this.numberOfOperands) {
            var child = tree.pop;
            child.addChildren(tree);
            this.children.push(child);
            child = tree.pop;
            child.addChildren(tree);
            this.children.push(child);
        }
        return this;
    };

    astNode.addChild = function _addChild(child) {
        if (this.children && this.children.length < this.numberOfOperands)
            this.children.push(child);
        return this;
    };

    astNode.evaluate = function _evaluate() {
        if (this.children && this.children.length) {
            switch (this.operator) {
                case tokens.OR:
                    return this.children[1].evaluate() || this.children[0].evaluate();
                case tokens.AND:
                    return this.children[1].evaluate() && this.children[0].evaluate();
                case tokens.XOR:
                    return !!(this.children[1].evaluate() ^ this.children[0].evaluate());
                case tokens.NOR:
                    return !(this.children[1].evaluate() || this.children[0].evaluate());
                case tokens.NAND:
                    return !(this.children[1].evaluate() && this.children[0].evaluate());
                case tokens.XNOR:
                    return !(this.children[1].evaluate() ^ this.children[0].evaluate());
            }
        }
        else {
            var baseVal,
                curVal,
                initialVal = this.getContext()[this.field];

            switch(this.dataType == null ? typeof this.getContext()[this.field] : this.dataType) {
                case 'time':
                    curVal = getNumbersFromTime(initialVal);
                    baseVal = getNumbersFromTime(this.standard);

                    if (initialVal.indexOf('PM') > -1) curVal[0] += 12;
                    if (this.standard.indexOf('PM') > -1) baseVal[0] += 12;

                    curVal = convertTimeArrayToSeconds(curVal);
                    baseVal = convertTimeArrayToSeconds(baseVal);
                    break;
                case 'datetime':
                    var re = new RegExp(dateTimeRegex),
                        execVal1, execVal2;
                    if (re.test(initialVal) && re.test(this.standard)) {
                        execVal1 = re.exec(initialVal);
                        execVal2 = re.exec(this.standard);

                        var dateComp1 = execVal1[2],
                            dateComp2 = execVal2[2],
                            timeComp1 = execVal1[42],
                            timeComp2 = execVal2[42];

                        timeComp1 = getNumbersFromTime(timeComp1);
                        timeComp2 = getNumbersFromTime(timeComp2);
                        if (timeComp1[3] && timeComp1[3] === 'PM')
                            timeComp1[0] += 12;
                        if (timeComp2[3] && timeComp2[3] === 'PM')
                            timeComp2[0] += 12;

                        dateComp1 = new Date(dateComp1);
                        dateComp2 = new Date(dateComp2);
                        curVal = dateComp1.getTime() + convertTimeArrayToSeconds(timeComp1);
                        baseVal = dateComp2.getTime() + convertTimeArrayToSeconds(timeComp2);
                    }
                    else {
                        curVal = 0;
                        baseVal = 0;
                    }
                    break;
                case 'number':
                    curVal = parseFloat(initialVal);
                    baseVal = parseFloat(this.standard);
                    break;
                case 'date':
                    curVal = new Date(initialVal);
                    baseVal = new Date(this.standard);
                    break;
                case 'boolean':
                    curVal = initialVal.toString();
                    baseVal = this.standard.toString();
                    break;
                default:
                    curVal = initialVal.toString();
                    baseVal = this.standard.toString();
                    break;
            }

            this._value = comparator(curVal, baseVal, this.operation);
            return this._value;
        }
    };

    astNode.getValue = function _getValue() {
        if (this._value == null)
            this._value = this.evaluate();
        return this._value;
    };

    Object.defineProperty(astNode, 'value', {
        get: function _getValue() {
            if (!this._value) {
                this._value = this.evaluate();
            }
            return this._value;
        }
    });

    function getNodeContext(bet) {
        return bet.internalGetContext.bind(bet);
    }

    function createFilterTreeFromFilterObject(filterObject) {
        var ret = Object.create(booleanExpressionTree);
        ret.init();
        var operandStack = Object.create(stack).init();
        var queue = [],
            topOfStack;

        iterateFilterGroup(filterObject, operandStack, queue, getNodeContext(ret));

        while (operandStack.length) {
            topOfStack = operandStack.peek;
            if (topOfStack.operator !== tokens.leftParens)
                queue.push(operandStack.pop);
            else operandStack.pop;
        }

        ret.setTree(queue);
        ret.createTree();
        return ret;
    }

    function iterateFilterGroup(filterObject, stack, queue, contextGetter) {
        var conjunction = filterObject.conjunct,
            idx = 0,
            topOfStack;

        while (idx < filterObject.filterGroup.length) {
            if (idx > 0) {
                var conjunctObj = Object.create(astNode);
                conjunctObj.createNode(conjunction);
                pushConjunctionOntoStack(conjunctObj, stack, queue);
            }
            if (filterObject.filterGroup[idx].conjunct) {
                var paren = Object.create(astNode);
                paren.createNode(tokens.leftParens);
                stack.push(paren);
                iterateFilterGroup(filterObject.filterGroup[idx], stack, queue, contextGetter);
                while (stack.length) {
                    topOfStack = stack.peek;
                    if (topOfStack.operator !== tokens.leftParens)
                        queue.push(stack.pop);
                    else {
                        stack.pop;
                        break;
                    }
                }
            }
            else {
                var leafNode = Object.create(astNode);
                leafNode.createNode(filterObject.filterGroup[idx]);
                leafNode.getContext = contextGetter;
                queue.push(leafNode);
            }
            ++idx;
        }
    }

    function pushConjunctionOntoStack(conjunction, stack, queue) {
        while (stack.length) {
            var topOfStack = stack.peek;
            if ((conjunction.associativity === associativity.LTR && conjunction.precedence <= topOfStack.precedence)
                || (conjunction.associativity === associativity.RTL && conjunction.precedence < topOfStack.precedence))
                queue.push(stack.pop);
            else
                break;
        }
        stack.push(conjunction);
    }

    var stack = {
        init: function _init() {
            this.data = [];
            this.top = 0;
            return this;
        },
        push: function _push(item) {
            this.data[this.top++] = item;
            return this;
        },
        get pop() {
            return this.data[--this.top];
        },
        get peek() {
            return this.data[this.top - 1];
        },
        get clear() {
            this.top = 0;
            return this;
        },
        get length() {
            return this.top;
        }
    };

    function comparator(val, base, type) {
        switch (type) {
            case 'eq':
            case '===':
                return val === base;
            case '==':
                return val == base;
            case 'neq':
            case '!==':
                return val !== base;
            case '!=':
                return val != base;
            case 'gte':
            case '>=':
                return val >= base;
            case 'gt':
            case '>':
                return val > base;
            case 'lte':
            case '<=':
                return val <= base;
            case 'lt':
            case '<':
                return val < base;
            case 'not':
            case '!':
            case 'falsey':
                return !val;
            case 'truthy':
                return !!val;
            case 'ct':
                return !!~val.toLowerCase().indexOf(base.toLowerCase());
            case 'nct':
                return !~val.toLowerCase().indexOf(base.toLowerCase());
        }
    }

    function getNumberOfOperands(operator) {
        switch (operator) {
            case tokens.NOT:
                return 1;
            case tokens.leftParens:
            case tokens.rightParens:
                return 0;
            default:
                return 2;
        }
    }

    var associativity = { RTL: 1, LTR: 2 };

    function getOperatorPrecedence(operator) {
        switch (operator) {
            case tokens.NOT:
                return {
                    precedence: 1,
                    associativity: associativity.LTR
                };
            case tokens.AND:
                return {
                    precedence: 2,
                    associativity: associativity.RTL
                };
            case tokens.XOR:
                return {
                    precedence: 3,
                    associativity: associativity.RTL
                };
            case tokens.OR:
                return {
                    precedence: 4,
                    associativity: associativity.RTL
                };
            case tokens.leftParens:
            case tokens.rightParens:
                return {
                    precedence: null,
                    associativity: null
                };
            default:
                return null;
        }
    }

    function getNumbersFromTime(val) {
        var re = /^(0?[1-9]|1[012])(?:(?:(:|\.)([0-5]\d))(?:\2([0-5]\d))?)?(?:(\ [AP]M))$|^([01]?\d|2[0-3])(?:(?:(:|\.)([0-5]\d))(?:\7([0-5]\d))?)$/;
        if (!re.test(val)) return [];
        var timeGroups = re.exec(val);
        var hours = timeGroups[1] ? +timeGroups[1] : +timeGroups[6];
        var minutes, seconds, meridiem, retVal = [];
        if (timeGroups[2]) {
            minutes = timeGroups[3] || '00';
            seconds = timeGroups[4]  || '00';
            meridiem = timeGroups[5].replace(' ', '') || null;
        }
        else if (timeGroups[6]) {
            minutes = timeGroups[8] || '00';
            seconds = timeGroups[9] || '00';
        }
        else{
            minutes = '00';
            seconds = '00';
        }
        retVal.push(hours);
        retVal.push(minutes);
        retVal.push(seconds);
        if (meridiem) retVal.push(meridiem);
        return retVal;
    }

    function convertTimeArrayToSeconds(timeArray) {
        var hourVal = parseInt(timeArray[0].toString()) === 12 || parseInt(timeArray[0].toString()) === 24 ? parseInt(timeArray[0].toString()) - 12 : parseInt(timeArray[0]);
        return 3660 * hourVal + 60 * parseInt(timeArray[1]) + parseInt(timeArray[2]);
    }

    return {
        createFilterTreeFromFilterObject: createFilterTreeFromFilterObject
    };
})();
<|endoftext|>


<commit_before>// Parse all kinds of data files
'use strict'
var fs = require('fs')
var xml2js = require('xml2js')

// Configure XML parser
// -- Avoid arrays for single elements
var xmlParser = new xml2js.Parser({explicitArray: false})

// -------------------------------------------------------------
// Module.
// -------------------------------------------------------------
var Parser = function () {
}

// Convert data.xml content into a JSON string
Parser.prototype.parseXML = function (xml, callback) {
  var presskit

  if (!xml) {
    callback(new Error('XML input was null or empty'), presskit)
    return
  }

  xmlParser.parseString(xml, function (err, result) {
    if (!err && result) {
      // Values are nested in the "game" or "company"node
      // So we need to detect and ignore this root element
      if (result.game) {
        presskit = result.game
        presskit.type = 'product'
      } else if (result.product) {
        presskit = result.product
        presskit.type = 'product'
      } else if (result.company) {
        presskit = result.company
        presskit.type = 'company'
      } else {
        console.error('Unrecognized XML file, expected <game> or <company> root tag')
      }
    }
    callback(err, presskit)
  })
}

// Convert an XML data file to a formatted JSON file
Parser.prototype.convertXMLFile = function (source, destination, format, callback) {
  fs.readFile(source, function (err, data) {
    Parser.parseXML(data, function (error, result) {
      if (!error) {
        var json = JSON.stringify(result.game, null, (format ? 2 : 0))
        fs.writeFile(destination, json, function (err) {
          callback(err)
        })
      } else {
        callback(err)
      }
    })
  })
}

// Parse a presskit.html data.json file
Parser.prototype.parseJSON = function (json, callback) {
  var presskit

  if (!json) {
    callback(new Error('JSON input was null or empty'), presskit)
    return
  }

  try {
    var o = JSON.parse(json)
  } catch (err) {
    callback(err, presskit)
    return
  }

  if (!o.product && !o.game && !o.company) callback(new Error('Missing company/game root node'), presskit)
  else {
    var err = null
    if (o.game) {
      presskit = o.game
      presskit.type = 'product'
    } else if (o.product) {
      presskit = o.product
      presskit.type = 'product'
    } else if (o.company) {
      presskit = o.company
      presskit.type = 'company'
    } else {
      err = new Error('Unrecognized JSON file, expected "game" or "company" root tag')
    }

    callback(err, presskit)
  }
}

// -------------------------------------------------------------
// Exports.
// -------------------------------------------------------------
module.exports = new Parser()
<commit_msg>Change console.error by a proper error creation<commit_after>// Parse all kinds of data files
'use strict'
var fs = require('fs')
var xml2js = require('xml2js')

// Configure XML parser
// -- Avoid arrays for single elements
var xmlParser = new xml2js.Parser({explicitArray: false})

// -------------------------------------------------------------
// Module.
// -------------------------------------------------------------
var Parser = function () {
}

// Convert data.xml content into a JSON string
Parser.prototype.parseXML = function (xml, callback) {
  var presskit

  if (!xml) {
    callback(new Error('XML input was null or empty'), presskit)
    return
  }

  xmlParser.parseString(xml, function (err, result) {
    if (!err && result) {
      // Values are nested in the "game" or "company"node
      // So we need to detect and ignore this root element
      if (result.game) {
        presskit = result.game
        presskit.type = 'product'
      } else if (result.product) {
        presskit = result.product
        presskit.type = 'product'
      } else if (result.company) {
        presskit = result.company
        presskit.type = 'company'
      } else {
        callback(new Error('Unrecognized XML file, expected <game> or <company> root tag'), presskit)
        return
      }
    }
    callback(err, presskit)
  })
}

// Convert an XML data file to a formatted JSON file
Parser.prototype.convertXMLFile = function (source, destination, format, callback) {
  fs.readFile(source, function (err, data) {
    Parser.parseXML(data, function (error, result) {
      if (!error) {
        var json = JSON.stringify(result.game, null, (format ? 2 : 0))
        fs.writeFile(destination, json, function (err) {
          callback(err)
        })
      } else {
        callback(err)
      }
    })
  })
}

// Parse a presskit.html data.json file
Parser.prototype.parseJSON = function (json, callback) {
  var presskit

  if (!json) {
    callback(new Error('JSON input was null or empty'), presskit)
    return
  }

  try {
    var o = JSON.parse(json)
  } catch (err) {
    callback(err, presskit)
    return
  }

  if (!o.product && !o.game && !o.company) callback(new Error('Missing company/game root node'), presskit)
  else {
    var err = null
    if (o.game) {
      presskit = o.game
      presskit.type = 'product'
    } else if (o.product) {
      presskit = o.product
      presskit.type = 'product'
    } else if (o.company) {
      presskit = o.company
      presskit.type = 'company'
    } else {
      err = new Error('Unrecognized JSON file, expected "game" or "company" root tag')
    }

    callback(err, presskit)
  }
}

// -------------------------------------------------------------
// Exports.
// -------------------------------------------------------------
module.exports = new Parser()
<|endoftext|>


<commit_before>import path from 'path';
import glob from 'glob';
import fs from 'fs';
import async from 'async';

import { MonicError } from './error';
import { FileStructure } from './file';
import { SourceMapConsumer } from 'source-map';

/**
 * Parser class
 */
export default class Parser {
	/**
	 * @param {{
	 *   lineSeparator: string,
	 *   replacers: !Array
	 * }} params - additional parameters:
	 *   *) params.lineSeparator - EOL symbol;
	 *   *) params.replacers - an array of transform functions.
	 */
	constructor(params) {
		this.nl = params.lineSeparator;
		this.replacers = params.replacers || [];
		this.realpathCache = {};
		this.cache = {};
	}

	/**
	 * Checks a file for existence
	 * and returns an absolute path to it
	 *
	 * @param {string} file - the file path
	 * @param {function(Error, string=)} callback - a callback function
	 */
	normalizePath(file, callback) {
		file = path.normalize(path.resolve(file));

		if (this.realpathCache[file]) {
			callback(null, file);

		} else {
			async.waterfall([
				(next) => fs.stat(file, next),
				(stat, next) => {
					if (!stat.isFile()) {
						return next(new Error(`"${file}" is not a file`));
					}

					this.realpathCache[file] = true;
					next(null, file);
				}

			], callback);
		}
	}

	/**
	 * Parses a file and returns it structure
	 *
	 * @param {string} file - the file path
	 * @param {function(Error, FileStructure=, string=)} callback - a callback function
	 */
	parseFile(file, callback) {
		async.waterfall([
			(next) => this.normalizePath(file, next),

			(src, next) => {
				if (this.cache[src]) {
					return next(null, src, this.cache[src]);
				}

				fs.readFile(src, (err, content) => {
					next(err, src, String(content));
				});
			},

			(src, content, next) => {
				if (typeof content !== 'string') {
					return next(null, content, src);
				}

				this.parse(src, content, next);
			}

		], callback);
	}

	/**
	 * Parses a text and returns it structure
	 *
	 * @param {string} file - a path to a file
	 * @param {string} content - the source text
	 * @param {function(Error, FileStructure=, string=)} callback - a callback function
	 */
	parse(file, content, callback) {
		if (this.cache[file]) {
			return callback(null, this.cache[file], file);
		}

		const
			actions = [],
			dirname = path.dirname(file);

		content = this.replacers.reduce((content, el) => {
			content = el(content, file);
			return content;

		}, content);

		// URL transformers
		content = content.replace(/^(\s*\/\/(?:#include|without)\s+)(.*)/gm, (sstr, decl, src) => {
			actions.push((cb) => {
				const parts = src.split('::');
				glob(path.join(dirname, parts[0]), null, (err, files) => {
					if (files) {
						content = content.replace(sstr, files.reduce((res, el) => {
							parts[0] = path.relative(dirname, el);
							res += decl + parts.join('::') + this.nl;
							return res;
						}, ''));
					}

					cb(err, files);
				});
			});

			return sstr;
		});

		let sourceMap;
		content = content.replace(/\/\/# sourceMappingURL=(.*?)\s*$/, (sstr, url) => {
			actions.push((cb) => {
				fs.readFile(path.normalize(path.resolve(path.dirname(file), url)), (err, str) => {
					try {
						sourceMap = new SourceMapConsumer(JSON.parse(str));

					} catch (ignore) {

					} finally {
						cb(null);
					}

					content = content.replace(sstr, this.nl);
				});
			});

			return sstr;
		});

		async.parallel(actions, (err) => {
			if (err) {
				return callback(err);
			}

			const
				fileStructure = new FileStructure(file, this.nl),
				lines = content.split(/\r?\n|\r/);

			this.cache[file] = fileStructure;
			const parseLines = (start) => {
				const
					errors = [];

				let
					info,
					i;

				function appendError(err) {
					const
						msg = err.message;

					errors.push(new MonicError(msg, file, i + 1));
					fileStructure.error(msg, info);
				}

				function asyncParseCallback(err) {
					if (err) {
						appendError(err);
					}

					parseLines(i + 1);
				}

				let original;
				if (sourceMap) {
					let
						originalMap = [];

					sourceMap.eachMapping((el) => {
						originalMap.push({
							generated: {
								line: el.generatedLine,
								column: el.generatedColumn
							},

							original: {
								line: el.originalLine,
								column: el.originalColumn
							},

							source: el.source,
							name: el.name
						});
					});

					if (sourceMap.sourcesContent) {
						sourceMap.sourcesContent.forEach((content, i) => {
							const
								src = sourceMap.sources[i];

							$C(originalMap).forEach((el) => {
								if (el.source === src) {
									el.sourcesContent = content;
								}
							});
						});
					}

					original = $C(originalMap).group('generated > line');
				}

				for (i = start; i < lines.length; i++) {
					const
						line = lines[i],
						val = line + (i < lines.length - 1 ? this.nl : '');

					if (original) {
						info = original[i] || {ignore: true};

					} else {
						info = {
							generated: {
								column: 0
							},

							original: {
								line: i + 1,
								column: 0
							},

							source: file,
							sourcesContent: content,
							line
						};
					}

					if (line.match(/^\s*\/\/#(.*)/)) {
						if (RegExp.$1) {
							const
								command = RegExp.$1.split(' '),
								dir = String(command.shift());

							const
								key = '_' + dir,
								params = command.join(' ');

							if (/^(?:include|without)$/.test(dir)) {
								return this[key](fileStructure, params, asyncParseCallback);

							} else if (/^(?:label|endlabel|if|endif|set|unset)$/.test(dir)) {
								try {
									this[key](fileStructure, params);

								} catch (err) {
									appendError(err);
								}

							} else {
								fileStructure.addCode(val, info);
							}
						}

					} else {
						fileStructure.addCode(val, info);
					}
				}

				callback(null, fileStructure, file);
			};

			parseLines(0);
		});
	}

	/**
	 * Directive #include
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 * @param {function(Error=)} callback - a callback function
	 */
	_include(file, value, callback) {
		let
			paramsParts = value.split('::'),
			includeFileName = paramsParts.shift();

		paramsParts = paramsParts.reduce((res, el) => {
			res[el] = true;
			return res;
		}, {});

		if (includeFileName) {
			this.parseFile(file.getRelativePathOf(includeFileName), (err, includeFile) => {
				if (err) {
					return callback(err);
				}

				file.addInclude(includeFile, paramsParts);
				callback();
			});

		} else {
			$C(paramsParts).forEach((el, key) => {
				file.root.labels[key] = true;
			});

			callback();
		}
	}

	/**
	 * Directive #without
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 * @param {function(Error=)} callback - a callback function
	 */
	_without(file, value, callback) {
		let
			paramsParts = value.split('::'),
			includeFname = file.getRelativePathOf(paramsParts.shift());

		paramsParts = paramsParts.reduce((res, el) => {
			res[el] = true;
			return res;
		}, {});

		this.parseFile(includeFname, (err, includeFile) => {
			if (err) {
				return callback(err);
			}

			file.addWithout(includeFile, paramsParts);
			callback();
		});
	}

	/**
	 * Directive #label
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_label(file, value) {
		file.beginLabel(value);
	}

	/**
	 * Directive #endlabel
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 */
	_endlabel(file) {
		file.endLabel();
	}

	/**
	 * Directive #if
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_if(file, value) {
		value = value.trim();

		if (!value) {
			throw new Error('Bad "if" directive');
		}

		const
			args = value.split(/\s+/);

		let res = true;
		if (args.length > 1 && args[0] === 'not') {
			res = false;
			args.shift();
		}

		file.beginIf(args[0], res);
	}

	/**
	 * Directive #endif
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 */
	_endif(file) {
		file.endIf();
	}

	/**
	 * Directive #set
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_set(file, value) {
		value = value.trim();

		if (!value) {
			throw new Error('Bad "set" directive');
		}

		file.addSet(value);
	}

	/**
	 * Directive #unset
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_unset(file, value) {
		value = value.trim();

		if (!value) {
			throw new Error('Bad "unset" directive');
		}

		file.addUnset(value);
	}
}
<commit_msg>Refactoring<commit_after>import path from 'path';
import glob from 'glob';
import fs from 'fs';
import async from 'async';

import { MonicError } from './error';
import { FileStructure } from './file';
import { SourceMapConsumer } from 'source-map';

/**
 * Parser class
 */
export default class Parser {
	/**
	 * @param {{
	 *   lineSeparator: string,
	 *   replacers: !Array
	 * }} params - additional parameters:
	 *   *) params.lineSeparator - EOL symbol;
	 *   *) params.replacers - an array of transform functions.
	 */
	constructor(params) {
		this.nl = params.lineSeparator;
		this.replacers = params.replacers || [];
		this.realpathCache = {};
		this.cache = {};
	}

	/**
	 * Checks a file for existence
	 * and returns an absolute path to it
	 *
	 * @param {string} file - the file path
	 * @param {function(Error, string=)} callback - a callback function
	 */
	normalizePath(file, callback) {
		file = path.normalize(path.resolve(file));

		if (this.realpathCache[file]) {
			callback(null, file);

		} else {
			async.waterfall([
				(next) => fs.stat(file, next),
				(stat, next) => {
					if (!stat.isFile()) {
						return next(new Error(`"${file}" is not a file`));
					}

					this.realpathCache[file] = true;
					next(null, file);
				}

			], callback);
		}
	}

	/**
	 * Parses a file and returns it structure
	 *
	 * @param {string} file - the file path
	 * @param {function(Error, FileStructure=, string=)} callback - a callback function
	 */
	parseFile(file, callback) {
		async.waterfall([
			(next) => this.normalizePath(file, next),

			(src, next) => {
				if (this.cache[src]) {
					return next(null, src, this.cache[src]);
				}

				fs.readFile(src, (err, content) => {
					next(err, src, String(content));
				});
			},

			(src, content, next) => {
				if (typeof content !== 'string') {
					return next(null, content, src);
				}

				this.parse(src, content, next);
			}

		], callback);
	}

	/**
	 * Parses a text and returns it structure
	 *
	 * @param {string} file - a path to a file
	 * @param {string} content - the source text
	 * @param {function(Error, FileStructure=, string=)} callback - a callback function
	 */
	parse(file, content, callback) {
		if (this.cache[file]) {
			return callback(null, this.cache[file], file);
		}

		const
			actions = [],
			dirname = path.dirname(file);

		content = $C(this.replacers).reduce((content, el) => {
			content = el(content, file);
			return content;

		}, content);

		// URL transformers
		content = content.replace(/^(\s*\/\/(?:#include|without)\s+)(.*)/gm, (sstr, decl, src) => {
			actions.push((cb) => {
				const parts = src.split('::');
				glob(path.join(dirname, parts[0]), null, (err, files) => {
					if (files) {
						content = content.replace(sstr, $C(files).reduce((res, el) => {
							parts[0] = path.relative(dirname, el);
							res += decl + parts.join('::') + (files.length ? this.nl : '');
							return res;
						}, ''));
					}

					cb(err, files);
				});
			});

			return sstr;
		});

		let sourceMap;
		content = content.replace(/\/\/# sourceMappingURL=(.*?)\s*$/, (sstr, url) => {
			actions.push((cb) => {
				fs.readFile(path.normalize(path.resolve(path.dirname(file), url)), (err, str) => {
					try {
						sourceMap = new SourceMapConsumer(JSON.parse(str));

					} catch (ignore) {

					} finally {
						cb(null);
					}

					content = content.replace(sstr, this.nl);
				});
			});

			return sstr;
		});

		async.parallel(actions, (err) => {
			if (err) {
				return callback(err);
			}

			const
				fileStructure = new FileStructure(file, this.nl),
				lines = content.split(/\r?\n|\r/);

			this.cache[file] = fileStructure;
			const parseLines = (start) => {
				const
					errors = [];

				let
					info,
					i;

				function appendError(err) {
					const
						msg = err.message;

					errors.push(new MonicError(msg, file, i + 1));
					fileStructure.error(msg, info);
				}

				function asyncParseCallback(err) {
					if (err) {
						appendError(err);
					}

					parseLines(i + 1);
				}

				let original;
				if (sourceMap) {
					let
						originalMap = [];

					sourceMap.eachMapping((el) => {
						originalMap.push({
							generated: {
								line: el.generatedLine,
								column: el.generatedColumn
							},

							original: {
								line: el.originalLine,
								column: el.originalColumn
							},

							source: el.source,
							name: el.name
						});
					});

					if (sourceMap.sourcesContent) {
						$C(sourceMap.sourcesContent).forEach((content, i) => {
							const
								src = sourceMap.sources[i];

							$C(originalMap).forEach((el) => {
								if (el.source === src) {
									el.sourcesContent = content;
								}
							});
						});
					}

					original = $C(originalMap).group('generated > line');
				}

				for (i = start; i < lines.length; i++) {
					const
						line = lines[i],
						val = line + (i < lines.length - 1 ? this.nl : '');

					if (original) {
						info = original[i] || {ignore: true};

					} else {
						info = {
							generated: {
								column: 0
							},

							original: {
								line: i + 1,
								column: 0
							},

							source: file,
							sourcesContent: content,
							line
						};
					}

					if (line.match(/^\s*\/\/#(.*)/)) {
						if (RegExp.$1) {
							const
								command = RegExp.$1.split(' '),
								dir = String(command.shift());

							const
								key = '_' + dir,
								params = command.join(' ');

							if (/^(?:include|without)$/.test(dir)) {
								return this[key](fileStructure, params, asyncParseCallback);

							} else if (/^(?:label|endlabel|if|endif|set|unset)$/.test(dir)) {
								try {
									this[key](fileStructure, params);

								} catch (err) {
									appendError(err);
								}

							} else {
								fileStructure.addCode(val, info);
							}
						}

					} else {
						fileStructure.addCode(val, info);
					}
				}

				callback(null, fileStructure, file);
			};

			parseLines(0);
		});
	}

	/**
	 * Directive #include
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 * @param {function(Error=)} callback - a callback function
	 */
	_include(file, value, callback) {
		let
			paramsParts = value.split('::'),
			includeFileName = paramsParts.shift();

		paramsParts = $C(paramsParts).reduce((res, el) => {
			res[el] = true;
			return res;
		}, {});

		if (includeFileName) {
			this.parseFile(file.getRelativePathOf(includeFileName), (err, includeFile) => {
				if (err) {
					return callback(err);
				}

				file.addInclude(includeFile, paramsParts);
				callback();
			});

		} else {
			$C(paramsParts).forEach((el, key) => {
				file.root.labels[key] = true;
			});

			callback();
		}
	}

	/**
	 * Directive #without
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 * @param {function(Error=)} callback - a callback function
	 */
	_without(file, value, callback) {
		let
			paramsParts = value.split('::'),
			includeFname = file.getRelativePathOf(paramsParts.shift());

		paramsParts = $C(paramsParts).reduce((res, el) => {
			res[el] = true;
			return res;
		}, {});

		this.parseFile(includeFname, (err, includeFile) => {
			if (err) {
				return callback(err);
			}

			file.addWithout(includeFile, paramsParts);
			callback();
		});
	}

	/**
	 * Directive #label
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_label(file, value) {
		file.beginLabel(value);
	}

	/**
	 * Directive #endlabel
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 */
	_endlabel(file) {
		file.endLabel();
	}

	/**
	 * Directive #if
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_if(file, value) {
		value = value.trim();

		if (!value) {
			throw new Error('Bad "if" directive');
		}

		const
			args = value.split(/\s+/);

		let res = true;
		if (args.length > 1 && args[0] === 'not') {
			res = false;
			args.shift();
		}

		file.beginIf(args[0], res);
	}

	/**
	 * Directive #endif
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 */
	_endif(file) {
		file.endIf();
	}

	/**
	 * Directive #set
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_set(file, value) {
		value = value.trim();

		if (!value) {
			throw new Error('Bad "set" directive');
		}

		file.addSet(value);
	}

	/**
	 * Directive #unset
	 *
	 * @private
	 * @param {!FileStructure} file - a file structure
	 * @param {string} value - a value of the directive
	 */
	_unset(file, value) {
		value = value.trim();

		if (!value) {
			throw new Error('Bad "unset" directive');
		}

		file.addUnset(value);
	}
}
<|endoftext|>


<commit_before>import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { all, map } from 'rsvp';

export default class CourseVisualizeSessionTypesRoute extends Route {
  @service session;
  @service store;
  @service dataLoader;

  titleToken = 'general.coursesAndSessions';

  async model(params) {
    return this.dataLoader.loadCourse(params.course_id);
  }

  async afterModel(course) {
    const sessions = (await course.sessions).toArray();
    return await all([
      map(sessions.toArray(), (s) => s.sessionType),
      map(sessions.toArray(), (s) => s.totalSumDuration),
    ]);
  }

  beforeModel(transition) {
    this.session.requireAuthentication(transition, 'login');
  }
}
<commit_msg>drops attempt to load and await Resources asynchronously, it does not work like that.<commit_after>import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { map } from 'rsvp';

export default class CourseVisualizeSessionTypesRoute extends Route {
  @service session;
  @service store;
  @service dataLoader;

  titleToken = 'general.coursesAndSessions';

  async model(params) {
    return this.dataLoader.loadCourse(params.course_id);
  }

  async afterModel(course) {
    const sessions = (await course.sessions).toArray();
    return await map(sessions.toArray(), (s) => s.sessionType);
  }

  beforeModel(transition) {
    this.session.requireAuthentication(transition, 'login');
  }
}
<|endoftext|>


<commit_before>
/*!
 * CSS - Parser
 * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Lexer = require('./lexer')
  , nodes = require('./nodes')
  , inspect = require('sys').inspect;

/**
 * Initialize a new `Parser` with the given `str` and `options`.
 *
 * @param {String} str
 * @param {Object} options
 * @api private
 */

var Parser = module.exports = function Parser(str, options) {
  options = options || {};
  this.str = str;
  this.filename = options.filename || 'stylus';
  this.lexer = new Lexer(str, options);
  this.lexer.isSelector = true;
};

/**
 * Parser prototype.
 */

Parser.prototype = {

  /**
   * Parse the input, then return the root node.
   *
   * @return {Node}
   * @api private
   */

  parse: function(){
    var block = this.root = this.parent = new nodes.Root;
    while ('eos' != this.peek.type) {
      if (this.accept('newline')) continue;
      var stmt = this.statement;
      if (!stmt) this.error('unexpected token {peek}, not allowed at the root level');
      block.push(stmt);
    }
    return block;
  },

  /**
   * Throw an `Error` with the given `msg`.
   *
   * @param {String} msg
   * @api private
   */

  error: function(msg){
    var type = this.peek.type
      , val = undefined == this.peek.val
        ? ''
        : ' ' + this.peek.toString();
    throw new Error(msg.replace('{peek}', type + val));
  },

  /**
   * Accept the given token `type`, and return it,
   * otherwise return `undefined`.
   *
   * @param {String} type
   * @return {Token}
   * @api private
   */

  accept: function(type){
    if (type == this.peek.type) {
      return this.next;
    }
  },

  /**
   * Expect token `type` and return it, throw otherwise.
   *
   * @param {String} type
   * @return {Token}
   * @api private
   */

  expect: function(type){
    if (type != this.peek.type) {
      throw new Error('expected ' + type + ', got ' + this.peek);
    }
    return this.next;
  },

  /**
   * Get the next token.
   *
   * @return {Token}
   * @api private
   */

  get next() {
    var tok = this.lexer.next;
    nodes.lineno = tok.lineno;
    return tok;
  },

  /**
   * Peek with lookahead(1).
   *
   * @return {Token}
   * @api private
   */

  get peek() {
    return this.lexer.peek;
  },

  /**
   * Lookahead `n` tokens.
   *
   * @param {Number} n
   * @return {Token}
   * @api private
   */

  lookahead: function(n){
    return this.lexer.lookahead(n);
  },

  /**
   *    variable
   *  | property
   *  | selector
   *  | literal
   *  | charset
   *  | import
   *  | expression
   */

  get statement() {
    var type = this.peek.type;
    switch (type) {
      case 'property':
      case 'selector':
      case 'literal':
      case 'charset':
      case 'import':
        return this[type];
      default:
        var expr = this.expression;
        if (expr.isEmpty) this.error('unexpected {peek} in expression');
        return expr;
    }
  },

  /**
   * indent (!outdent)+ outdent
   */

  get block() {
    var block = this.parent = new nodes.Block(this.parent);
    this.expect('indent');
    while ('outdent' != this.peek.type) {
      if (this.accept('newline')) continue;
      var stmt = this.statement;
      if (!stmt) this.error('unexpected token {peek} in block');
      block.push(stmt);
    }
    this.expect('outdent');
    this.parent = block.parent;
    return block;
  },

  /**
   * import string
   */

  get import() {
    this.expect('import');
    var path = this.expect('string');
    console.log(this.paths);
  },

  /**
   * property expression
   */

  get property() {
    var name = this.expect('property').val
      , prop = new nodes.Property(name);

    this.lexer.isSelector = false;
    prop.expr = this.list;
    if (prop.expr.isEmpty) this.error('property "' + name + '" expects an expression, got {peek}');
    this.lexer.isSelector = true;

    return prop;
  },

  /**
   * charset string
   */

  get charset() {
    this.expect('charset');
    var str = this.expect('string').val;
    return new nodes.Charset(str);
  },

  /**
   * literal
   */

  get literal() {
    return this.expect('literal').val;
  },

  /**
   *   selector ',' selector
   * | selector newline selector
   * | selector block
   */

  get selector() {
    var node
      , set = new nodes.RuleSet;

    do {
      node = new nodes.Selector(this.expect('selector').val);
      set.push(node);
    } while (this.accept(',') || this.accept('newline'));

    set.setBlock(this.block);

    return set;
  },

  /**
   *   variable ('=' | '?=') expression
   * | function
   */

  get variable() {
    var op
      , name = this._name = this.expect('variable').val.name;
    if (op = this.accept('=') || this.accept('?=')) {
      this.lexer.isSelector = false;
      var expr = this.list;
      if (expr.isEmpty) this.error('invalid right-hand side operand in assignment, got {peek}')
      var node = new nodes.Variable(name, expr);
      this.lexer.isSelector = true;

      // Conditional assignment
      if ('?=' == op) {
        var defined = new nodes.BinOp('is defined', node)
          , lookup = new nodes.Variable(name);
        node = new nodes.Ternary(defined, lookup, node);
      }

      return node;
    }
    return this.function;
  },

  /**
   *   variable '(' params ')' block
   * | variable '(' expression ')'
   * | variable
   */

  get function() {
    var name = this._name;
    if (this.accept('(')) {
      var tok
        , i = 1
        , parens = 1;

      this.lexer.isSelector = false;

      // Lookahead and determine if we are dealing
      // with a function call or definition. Here
      // we pair parens to prevent false negatives
      out:
      while (tok = this.lookahead(i++)) {
        switch (tok.type) {
          case '(': ++parens; break;
          case ')': if (!--parens) break out;
        }
      }

      this.lexer.isSelector = true;

      // Definition or call
      return 'indent' == this.lookahead(i).type
        ? this.functionDefinition
        : this.functionCall;
    }
    return new nodes.Variable(name);
  },

  /**
   * variable '(' expression ')'
   */

  get functionCall() {
    var name = this._name
      , args = this.list;
    this.expect(')');
    return new nodes.Call(name, args);
  },

  /**
   * variable '(' params ')' block
   */

  get functionDefinition() {
    var name = this._name
      , params = this.params;
    this.expect(')');
    var fn = new nodes.Function(name, params, this.block);
    return new nodes.Variable(name, fn);
  },

  /**
   * (variable (',' variable ('=' expression)?)*)?
   */

  get params() {
    var tok
      , params = new nodes.Params;
    while (tok = this.accept('variable')) {
      params.push(tok.val);
      if (this.accept('=')) {
        tok.val.val = this.expression;
      }
      this.accept(',');
    }
    return params;
  },

  /**
   * expression (',' expression)*
   */

  get list() {
    var node = this.expression;
    while (this.accept(',')) {
      if (node.isList) {
        list.push(this.expression);
      } else {
        var list = new nodes.Expression(true);
        list.push(node);
        list.push(this.expression);
        node = list;
      }
    }
    return node;
  },

  /**
   * defined+
   */

  get expression() {
    var node
      , expr = new nodes.Expression;
    while (node = this.ternary) {
      if (!node) this.error('unexpected token {peek} in expression');
      expr.push(node);
    }
    return expr;
  },

  /**
   * logical ('?' expression : expression)?
   */

  get ternary() {
    var node = this.logical;
    if (this.accept('?')) {
      var trueExpr = this.expression;
      this.expect(':');
      var falseExpr = this.expression;
      node = new nodes.Ternary(node, trueExpr, falseExpr);
    }
    return node;
  },

  /**
   * defined (('&&' | '||') defined)*
   */

  get logical() {
    var op
      , node = this.defined;
    while (op = this.accept('&&') || this.accept('||')) {
      node = new nodes.BinOp(op.type, node, this.defined);
    }
    return node;
  },

  /**
   *    equality 'is defined'
   *  | equality
   */

  get defined() {
    var node = this.equality;
    if (this.accept('is defined')) {
      node = new nodes.BinOp('is defined', node);
    }
    return node;
  },

  /**
   * typecheck (('==' | '>=' | '<=' | '>' | '<') typecheck)*
   */

  get equality() {
    var op
      , node = this.typecheck;
    while (op =
         this.accept('==')
      || this.accept('>=')
      || this.accept('<=')
      || this.accept('<')
      || this.accept('>')
      ) {
      node = new nodes.BinOp(op.type, node, this.typecheck);
    }
    return node;
  },

  /**
   * additive ('is a' additive)*
   */

  get typecheck() {
    var op
      , node = this.additive;
    while (op = this.accept('is a')) {
      node = new nodes.BinOp(op.type, node, this.additive);
    }
    return node;
  },

  /**
   * multiplicative (('+' | '-') multiplicative)*
   */

  get additive() {
    var op
      , node = this.multiplicative;
    while (op = this.accept('+') || this.accept('-')) {
      node = new nodes.BinOp(op.type, node, this.multiplicative);
    }
    return node;
  },

  /**
   * unary (('**' | '*' | '/' | '%') unary)*
   */

  get multiplicative() {
    var op
      , node = this.unary;
    while (op =
         this.accept('**')
      || this.accept('*')
      || this.accept('/')
      || this.accept('%')) {
      node = new nodes.BinOp(op.type, node, this.unary);
    }
    return node;
  },

  /**
   *   (('!' | '~' | '-' | '+') expression)+
   * | primary
   */

  get unary() {
    var op, node;
    while (op =
         this.accept('!')
      || this.accept('~')
      || this.accept('-')
      || this.accept('+')) {
      node = new nodes.UnaryOp(op.type, node || this.expression);
    }
    return node || this.primary;
  },

  /**
   *   unit
   * | color
   * | string
   * | variable
   * | ident
   * | boolean
   * | literal
   * | '(' expression ')'
   */

  get primary() {
    if (this.accept('(')) {
      var expr = this.expression;
      this.expect(')');
      return expr;
    }
    switch (this.peek.type) {
      case 'unit':
      case 'color':
      case 'string':
      case 'ident':
      case 'literal':
      case 'boolean':
        return this.next.val;
      case 'variable':
        return this.variable;
    }
  }
};
<commit_msg>@import lookup<commit_after>
/*!
 * CSS - Parser
 * Copyright(c) 2010 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var Lexer = require('./lexer')
  , nodes = require('./nodes')
  , fs = require('fs')
  , inspect = require('sys').inspect
  , dirname = require('path').dirname;

/**
 * Initialize a new `Parser` with the given `str` and `options`.
 *
 * @param {String} str
 * @param {Object} options
 * @api private
 */

var Parser = module.exports = function Parser(str, options) {
  options = options || {};
  this.str = str;
  this.filename = options.filename || 'stylus';
  this.lexer = new Lexer(str, options);
  this.lexer.isSelector = true;
  this.paths = options.paths || [dirname(this.filename)];
};

/**
 * Parser prototype.
 */

Parser.prototype = {

  /**
   * Parse the input, then return the root node.
   *
   * @return {Node}
   * @api private
   */

  parse: function(){
    var block = this.root = this.parent = new nodes.Root;
    while ('eos' != this.peek.type) {
      if (this.accept('newline')) continue;
      var stmt = this.statement;
      if (!stmt) this.error('unexpected token {peek}, not allowed at the root level');
      block.push(stmt);
    }
    return block;
  },

  /**
   * Throw an `Error` with the given `msg`.
   *
   * @param {String} msg
   * @api private
   */

  error: function(msg){
    var type = this.peek.type
      , val = undefined == this.peek.val
        ? ''
        : ' ' + this.peek.toString();
    throw new Error(msg.replace('{peek}', type + val));
  },

  /**
   * Accept the given token `type`, and return it,
   * otherwise return `undefined`.
   *
   * @param {String} type
   * @return {Token}
   * @api private
   */

  accept: function(type){
    if (type == this.peek.type) {
      return this.next;
    }
  },

  /**
   * Expect token `type` and return it, throw otherwise.
   *
   * @param {String} type
   * @return {Token}
   * @api private
   */

  expect: function(type){
    if (type != this.peek.type) {
      throw new Error('expected ' + type + ', got ' + this.peek);
    }
    return this.next;
  },

  /**
   * Get the next token.
   *
   * @return {Token}
   * @api private
   */

  get next() {
    var tok = this.lexer.next;
    nodes.lineno = tok.lineno;
    return tok;
  },

  /**
   * Peek with lookahead(1).
   *
   * @return {Token}
   * @api private
   */

  get peek() {
    return this.lexer.peek;
  },

  /**
   * Lookahead `n` tokens.
   *
   * @param {Number} n
   * @return {Token}
   * @api private
   */

  lookahead: function(n){
    return this.lexer.lookahead(n);
  },

  /**
   *    variable
   *  | property
   *  | selector
   *  | literal
   *  | charset
   *  | import
   *  | expression
   */

  get statement() {
    var type = this.peek.type;
    switch (type) {
      case 'property':
      case 'selector':
      case 'literal':
      case 'charset':
      case 'import':
        return this[type];
      default:
        var expr = this.expression;
        if (expr.isEmpty) this.error('unexpected {peek} in expression');
        return expr;
    }
  },

  /**
   * indent (!outdent)+ outdent
   */

  get block() {
    var block = this.parent = new nodes.Block(this.parent);
    this.expect('indent');
    while ('outdent' != this.peek.type) {
      if (this.accept('newline')) continue;
      var stmt = this.statement;
      if (!stmt) this.error('unexpected token {peek} in block');
      block.push(stmt);
    }
    this.expect('outdent');
    this.parent = block.parent;
    return block;
  },

  /**
   * import string
   */

  get import() {
    this.expect('import');
    var css
      , path = this.expect('string').val.val;

    // TODO: literal

    // Lookup
    // TODO: abstract
    for (var i = 0, len = this.paths.length; i < len; ++i) {
      var lookup = this.paths[i] + '/' + path;
      try {
        css = fs.readFileSync(lookup, 'utf8');
        path = lookup;
        break;
      } catch (err) {
        // Ignore
      }
    }

    // Throw if import failed
    if (!css) throw new Error('failed to import ' + path);

    return new nodes.String(css);
  },

  /**
   * property expression
   */

  get property() {
    var name = this.expect('property').val
      , prop = new nodes.Property(name);

    this.lexer.isSelector = false;
    prop.expr = this.list;
    if (prop.expr.isEmpty) this.error('property "' + name + '" expects an expression, got {peek}');
    this.lexer.isSelector = true;

    return prop;
  },

  /**
   * charset string
   */

  get charset() {
    this.expect('charset');
    var str = this.expect('string').val;
    return new nodes.Charset(str);
  },

  /**
   * literal
   */

  get literal() {
    return this.expect('literal').val;
  },

  /**
   *   selector ',' selector
   * | selector newline selector
   * | selector block
   */

  get selector() {
    var node
      , set = new nodes.RuleSet;

    do {
      node = new nodes.Selector(this.expect('selector').val);
      set.push(node);
    } while (this.accept(',') || this.accept('newline'));

    set.setBlock(this.block);

    return set;
  },

  /**
   *   variable ('=' | '?=') expression
   * | function
   */

  get variable() {
    var op
      , name = this._name = this.expect('variable').val.name;
    if (op = this.accept('=') || this.accept('?=')) {
      this.lexer.isSelector = false;
      var expr = this.list;
      if (expr.isEmpty) this.error('invalid right-hand side operand in assignment, got {peek}')
      var node = new nodes.Variable(name, expr);
      this.lexer.isSelector = true;

      // Conditional assignment
      if ('?=' == op) {
        var defined = new nodes.BinOp('is defined', node)
          , lookup = new nodes.Variable(name);
        node = new nodes.Ternary(defined, lookup, node);
      }

      return node;
    }
    return this.function;
  },

  /**
   *   variable '(' params ')' block
   * | variable '(' expression ')'
   * | variable
   */

  get function() {
    var name = this._name;
    if (this.accept('(')) {
      var tok
        , i = 1
        , parens = 1;

      this.lexer.isSelector = false;

      // Lookahead and determine if we are dealing
      // with a function call or definition. Here
      // we pair parens to prevent false negatives
      out:
      while (tok = this.lookahead(i++)) {
        switch (tok.type) {
          case '(': ++parens; break;
          case ')': if (!--parens) break out;
        }
      }

      this.lexer.isSelector = true;

      // Definition or call
      return 'indent' == this.lookahead(i).type
        ? this.functionDefinition
        : this.functionCall;
    }
    return new nodes.Variable(name);
  },

  /**
   * variable '(' expression ')'
   */

  get functionCall() {
    var name = this._name
      , args = this.list;
    this.expect(')');
    return new nodes.Call(name, args);
  },

  /**
   * variable '(' params ')' block
   */

  get functionDefinition() {
    var name = this._name
      , params = this.params;
    this.expect(')');
    var fn = new nodes.Function(name, params, this.block);
    return new nodes.Variable(name, fn);
  },

  /**
   * (variable (',' variable ('=' expression)?)*)?
   */

  get params() {
    var tok
      , params = new nodes.Params;
    while (tok = this.accept('variable')) {
      params.push(tok.val);
      if (this.accept('=')) {
        tok.val.val = this.expression;
      }
      this.accept(',');
    }
    return params;
  },

  /**
   * expression (',' expression)*
   */

  get list() {
    var node = this.expression;
    while (this.accept(',')) {
      if (node.isList) {
        list.push(this.expression);
      } else {
        var list = new nodes.Expression(true);
        list.push(node);
        list.push(this.expression);
        node = list;
      }
    }
    return node;
  },

  /**
   * defined+
   */

  get expression() {
    var node
      , expr = new nodes.Expression;
    while (node = this.ternary) {
      if (!node) this.error('unexpected token {peek} in expression');
      expr.push(node);
    }
    return expr;
  },

  /**
   * logical ('?' expression : expression)?
   */

  get ternary() {
    var node = this.logical;
    if (this.accept('?')) {
      var trueExpr = this.expression;
      this.expect(':');
      var falseExpr = this.expression;
      node = new nodes.Ternary(node, trueExpr, falseExpr);
    }
    return node;
  },

  /**
   * defined (('&&' | '||') defined)*
   */

  get logical() {
    var op
      , node = this.defined;
    while (op = this.accept('&&') || this.accept('||')) {
      node = new nodes.BinOp(op.type, node, this.defined);
    }
    return node;
  },

  /**
   *    equality 'is defined'
   *  | equality
   */

  get defined() {
    var node = this.equality;
    if (this.accept('is defined')) {
      node = new nodes.BinOp('is defined', node);
    }
    return node;
  },

  /**
   * typecheck (('==' | '>=' | '<=' | '>' | '<') typecheck)*
   */

  get equality() {
    var op
      , node = this.typecheck;
    while (op =
         this.accept('==')
      || this.accept('>=')
      || this.accept('<=')
      || this.accept('<')
      || this.accept('>')
      ) {
      node = new nodes.BinOp(op.type, node, this.typecheck);
    }
    return node;
  },

  /**
   * additive ('is a' additive)*
   */

  get typecheck() {
    var op
      , node = this.additive;
    while (op = this.accept('is a')) {
      node = new nodes.BinOp(op.type, node, this.additive);
    }
    return node;
  },

  /**
   * multiplicative (('+' | '-') multiplicative)*
   */

  get additive() {
    var op
      , node = this.multiplicative;
    while (op = this.accept('+') || this.accept('-')) {
      node = new nodes.BinOp(op.type, node, this.multiplicative);
    }
    return node;
  },

  /**
   * unary (('**' | '*' | '/' | '%') unary)*
   */

  get multiplicative() {
    var op
      , node = this.unary;
    while (op =
         this.accept('**')
      || this.accept('*')
      || this.accept('/')
      || this.accept('%')) {
      node = new nodes.BinOp(op.type, node, this.unary);
    }
    return node;
  },

  /**
   *   (('!' | '~' | '-' | '+') expression)+
   * | primary
   */

  get unary() {
    var op, node;
    while (op =
         this.accept('!')
      || this.accept('~')
      || this.accept('-')
      || this.accept('+')) {
      node = new nodes.UnaryOp(op.type, node || this.expression);
    }
    return node || this.primary;
  },

  /**
   *   unit
   * | color
   * | string
   * | variable
   * | ident
   * | boolean
   * | literal
   * | '(' expression ')'
   */

  get primary() {
    if (this.accept('(')) {
      var expr = this.expression;
      this.expect(')');
      return expr;
    }
    switch (this.peek.type) {
      case 'unit':
      case 'color':
      case 'string':
      case 'ident':
      case 'literal':
      case 'boolean':
        return this.next.val;
      case 'variable':
        return this.variable;
    }
  }
};
<|endoftext|>


<commit_before>function fix (template) {
  if (!template.content && window.HTMLTemplateElement && window.HTMLTemplateElement.decorate) {
    window.HTMLTemplateElement.decorate(template);
  }
  return template;
};

function needFixImportNode () {
  // console.log('needFixImportNode?');
  if (document.__importNode) {
    // already fixed
    return false;
  }
  let template = document.createElement('template');
  template.innerHTML = '<template>i</template>';
  let imported = document.importNode(template.content, true);
  return imported.firstChild.content.firstChild.textContent !== 'i';
}

if (needFixImportNode()) {
  // console.log('fixed importNode');
  document.__importNode = document.importNode;
  document.importNode = function (node, deep) {
    if (!deep) {
      return document.__importNode(node, deep);
    }

    let sourceTpls = [].slice.call(node.querySelectorAll('template'));
    let imported = document.__importNode(node, deep);
    [].forEach.call(imported.querySelectorAll('template'), (child, i) => {
      child.innerHTML = sourceTpls[i].innerHTML;
    });

    return imported;
  };
}

export { fix };
<commit_msg>Fix function needFixImportNode to work with kitkat<commit_after>function fix (template) {
  if (!template.content && window.HTMLTemplateElement && window.HTMLTemplateElement.decorate) {
    window.HTMLTemplateElement.decorate(template);
  }
  return template;
};

function needFixImportNode () {
  // console.log('needFixImportNode?');
  if (document.__importNode) {
    // already fixed
    return false;
  }
  let template = document.createElement('template');
  template.innerHTML = '<template>i</template>';
  let imported = document.importNode(template.content, true);
  return !imported.firstChild.content.firstChild || imported.firstChild.content.firstChild.textContent !== 'i';
}

if (needFixImportNode()) {
  // console.log('fixed importNode');
  document.__importNode = document.importNode;
  document.importNode = function (node, deep) {
    if (!deep) {
      return document.__importNode(node, deep);
    }

    let sourceTpls = [].slice.call(node.querySelectorAll('template'));
    let imported = document.__importNode(node, deep);
    [].forEach.call(imported.querySelectorAll('template'), (child, i) => {
      child.innerHTML = sourceTpls[i].innerHTML;
    });

    return imported;
  };
}

export { fix };
<|endoftext|>


<commit_before>(function () {

  var template = chrome.extension.getURL('bar.html');
  $.ajax({
    url: template,
    async: false,
    success: function (html) {
      var nimbleBar = $(html);
      $('body').append(nimbleBar);
      window.nimbleBar = nimbleBar;
      bindInputDropdown();
    }
  });

  var dropdownItems;
  var filteredItems;
  var selectedOptionIndex;
  var shown = false;
  var pipeline;

  function initialize () {
    dropdownItems = [];
    filteredItems = [];
    selectedOptionIndex = -1;
    pipeline = [];
    $('.nimble-pipeline').html('');
    $('.nimble-options').html('');
    console.log('initialize')
  }

  function populateDropdown (items) {
    $('.nimble-options').html('');
    selectedOptionIndex = -1;
    _.each(items, function (item) {
      var $nimbleOption = $('
');
      var content = item.extras.title;
      $nimbleOption.html('
' + content + '
');
      $('.nimble-options').append($nimbleOption);
    })
  }

  function showNimbleBar () {
    initialize();
    window.nimbleBar.addClass('visible animated bounceInUp');
    setTimeout(function (argument) {
      nimbleBar.removeClass('bounceInUp');
      $('.nimble-input').val('');
      this.nimble.getData(function (data) {
        $('.nimble-input').focus();
        dropdownItems = data;
        filteredItems = dropdownItems;
        populateDropdown(dropdownItems);
      });
    }, 750);
  }

  function hideNimbleBar () {
    $('.nimble-pipeline').empty();
    nimbleBar.addClass('bounceOutDown');
    setTimeout(function () {
      $('.nimble-input').blur();
      $('.nimble-input').val('');
      $('.nimble-options').html('');
      nimbleBar.removeClass('visible animated bounceOutDown');
    }, 750);
  }

  function bindInputDropdown () {
    $('.nimble-input').on('keyup', function (ev) {
      if (ev.keyCode == 38 || ev.keyCode == 40) {
        return;
      }
      var input = $('.nimble-input').val();
      filteredItems = _.filter(dropdownItems, function (text) {
        return text.queryPattern.test(input.toLowerCase())
        || text.extras.title.toLowerCase().indexOf(input) > -1;
      });
      if (filteredItems.length > 0) {
        populateDropdown(filteredItems);
      } else {
        populateDropdown([{
          extras: {
            title: 'No results found'
          }
        }]);
      }
      selectedOptionIndex = -1;
    });
  }

  Mousetrap.bind('n', function(e) {
    if (!shown) {
      e.preventDefault();
      showNimbleBar();
      shown = true;
    }
  });

  Mousetrap.bind('esc', function(e) {
    if (shown) {
      e.preventDefault();
      hideNimbleBar();
      shown = false;
    }
  });

  function highlightSelectedItem (index) {
    var options = document.querySelectorAll('.nimble-options li');
    $(options).removeClass('selected');
    $(options[index]).addClass('selected');
  }

  function updateInputQueryString () {
    var selectedItem = filteredItems[selectedOptionIndex];
    if (selectedItem && 'extras' in selectedItem && 'title' in selectedItem.extras) {
      $('.nimble-input').val(selectedItem.extras.title);
    }
  }

  Mousetrap.bind('down', function (e) {
    if (shown) {
      selectedOptionIndex++;
      highlightSelectedItem(selectedOptionIndex);
      updateInputQueryString();
    }
  });

  Mousetrap.bind('up', function (e) {
    if (shown) {
      selectedOptionIndex--;
      selectedOptionIndex = Math.max(selectedOptionIndex, 0);
      highlightSelectedItem(selectedOptionIndex);
      updateInputQueryString();
    }
  });

  Mousetrap.bind('tab', function (e) {
    e.preventDefault();
    $('.nimble-input').val('');
    var selectedObj = filteredItems[selectedOptionIndex];
    pipeline.push(selectedObj);
    var $nimblePipelineItem = $('
');
    var content = selectedObj.extras.title;
    if (content) {
      $nimblePipelineItem.html('' + content + '');
      $('.nimble-pipeline').append($nimblePipelineItem);
    }

    var filterCriteria = selectedObj.output !== undefined ?
      selectedObj.output : selectedObj;
    var matchResults = router.matchObject(filterCriteria);
    dropdownItems = matchResults;
    filteredItems = dropdownItems;
    populateDropdown(dropdownItems);
  });

  Mousetrap.bind('enter', function (e) {
    e.preventDefault();
    var obj = pipeline[0];
    obj.extras.telno = '+14255022351';
    this.nimble.chainPromise(pipeline.slice(1), obj);
    hideNimbleBar();
    shown = false;
  });

  initialize();

  var plugins = [
    'Googl',
    'PluginFacebook',
    'PluginDropbox',
    'Twilio'
  ];

  /* Creates instances of recipe workers for each entry in a recipe manifest.
   */
  var initPlugins = function (plugins) {
    var recipes = [];
    for (var i = 0; i < plugins.length; i++) {
      var construct = plugins[i] + '()';
      var pluginRef = eval(construct);
      var supportedRecipes = pluginRef.getRecipes();
      recipes = recipes.concat(supportedRecipes);
    }
    return recipes;
  };

  var recipes = initPlugins(plugins);
  var router = Router(recipes);
  console.log('Nimble finish loading');
})();
<commit_msg>Documented temp phone number injection.<commit_after>(function () {

  var template = chrome.extension.getURL('bar.html');
  $.ajax({
    url: template,
    async: false,
    success: function (html) {
      var nimbleBar = $(html);
      $('body').append(nimbleBar);
      window.nimbleBar = nimbleBar;
      bindInputDropdown();
    }
  });

  var dropdownItems;
  var filteredItems;
  var selectedOptionIndex;
  var shown = false;
  var pipeline;

  function initialize () {
    dropdownItems = [];
    filteredItems = [];
    selectedOptionIndex = -1;
    pipeline = [];
    $('.nimble-pipeline').html('');
    $('.nimble-options').html('');
    console.log('initialize')
  }

  function populateDropdown (items) {
    $('.nimble-options').html('');
    selectedOptionIndex = -1;
    _.each(items, function (item) {
      var $nimbleOption = $('
');
      var content = item.extras.title;
      $nimbleOption.html('
' + content + '
');
      $('.nimble-options').append($nimbleOption);
    })
  }

  function showNimbleBar () {
    initialize();
    window.nimbleBar.addClass('visible animated bounceInUp');
    setTimeout(function (argument) {
      nimbleBar.removeClass('bounceInUp');
      $('.nimble-input').val('');
      this.nimble.getData(function (data) {
        $('.nimble-input').focus();
        dropdownItems = data;
        filteredItems = dropdownItems;
        populateDropdown(dropdownItems);
      });
    }, 750);
  }

  function hideNimbleBar () {
    $('.nimble-pipeline').empty();
    nimbleBar.addClass('bounceOutDown');
    setTimeout(function () {
      $('.nimble-input').blur();
      $('.nimble-input').val('');
      $('.nimble-options').html('');
      nimbleBar.removeClass('visible animated bounceOutDown');
    }, 750);
  }

  function bindInputDropdown () {
    $('.nimble-input').on('keyup', function (ev) {
      if (ev.keyCode == 38 || ev.keyCode == 40) {
        return;
      }
      var input = $('.nimble-input').val();
      filteredItems = _.filter(dropdownItems, function (text) {
        return text.queryPattern.test(input.toLowerCase())
        || text.extras.title.toLowerCase().indexOf(input) > -1;
      });
      if (filteredItems.length > 0) {
        populateDropdown(filteredItems);
      } else {
        populateDropdown([{
          extras: {
            title: 'No results found'
          }
        }]);
      }
      selectedOptionIndex = -1;
    });
  }

  Mousetrap.bind('n', function(e) {
    if (!shown) {
      e.preventDefault();
      showNimbleBar();
      shown = true;
    }
  });

  Mousetrap.bind('esc', function(e) {
    if (shown) {
      e.preventDefault();
      hideNimbleBar();
      shown = false;
    }
  });

  function highlightSelectedItem (index) {
    var options = document.querySelectorAll('.nimble-options li');
    $(options).removeClass('selected');
    $(options[index]).addClass('selected');
  }

  function updateInputQueryString () {
    var selectedItem = filteredItems[selectedOptionIndex];
    if (selectedItem && 'extras' in selectedItem && 'title' in selectedItem.extras) {
      $('.nimble-input').val(selectedItem.extras.title);
    }
  }

  Mousetrap.bind('down', function (e) {
    if (shown) {
      selectedOptionIndex++;
      highlightSelectedItem(selectedOptionIndex);
      updateInputQueryString();
    }
  });

  Mousetrap.bind('up', function (e) {
    if (shown) {
      selectedOptionIndex--;
      selectedOptionIndex = Math.max(selectedOptionIndex, 0);
      highlightSelectedItem(selectedOptionIndex);
      updateInputQueryString();
    }
  });

  Mousetrap.bind('tab', function (e) {
    e.preventDefault();
    $('.nimble-input').val('');
    var selectedObj = filteredItems[selectedOptionIndex];
    pipeline.push(selectedObj);
    var $nimblePipelineItem = $('
');
    var content = selectedObj.extras.title;
    if (content) {
      $nimblePipelineItem.html('' + content + '');
      $('.nimble-pipeline').append($nimblePipelineItem);
    }

    var filterCriteria = selectedObj.output !== undefined ?
      selectedObj.output : selectedObj;
    var matchResults = router.matchObject(filterCriteria);
    dropdownItems = matchResults;
    filteredItems = dropdownItems;
    populateDropdown(dropdownItems);
  });

  Mousetrap.bind('enter', function (e) {
    e.preventDefault();

    // Temp. hack to test execution code.
    var obj = pipeline[0];
    obj.extras.telno = '+14255022351';

    this.nimble.chainPromise(pipeline.slice(1), obj);
    hideNimbleBar();
    shown = false;
  });

  initialize();

  var plugins = [
    'Googl',
    'PluginFacebook',
    'PluginDropbox',
    'Twilio'
  ];

  /* Creates instances of recipe workers for each entry in a recipe manifest.
   */
  var initPlugins = function (plugins) {
    var recipes = [];
    for (var i = 0; i < plugins.length; i++) {
      var construct = plugins[i] + '()';
      var pluginRef = eval(construct);
      var supportedRecipes = pluginRef.getRecipes();
      recipes = recipes.concat(supportedRecipes);
    }
    return recipes;
  };

  var recipes = initPlugins(plugins);
  var router = Router(recipes);
  console.log('Nimble finish loading');
})();
<|endoftext|>