<commit_before>var less = exports || {};
//
// less.js - parser
//
//      A relatively straight-forward recursive-descent parser.
//      There is no tokenization/lexing stage, the input is parsed
//      in one sweep.
//
//      To make the parser fast enough to run in the browser, several
//      optimization had to be made:
//
//          - Instead of the more commonly used technique of slicing the
//          input string on every match, we use global regexps (/g),
//          and move the `lastIndex` pointer on match, foregoing `slice()`
//          completely. This gives us a 3x speed-up.
//
//          - Matching on a huge input is often cause of slowdowns,
//          especially with the /g flag. The solution to that is to
//          chunkify the input: we split it by /\n\n/, just to be on
//          the safe side. The chunks are stored in the `chunks` var,
//          `j` holds the current chunk index, and `current` holds
//          the index of the current chunk in relation to `input`.
//          This gives us an almost 4x speed-up.
//
//          - In many cases, we don't need to match individual tokens;
//          for example, if a value doesn't hold any variables, operations
//          or dynamic references, the parser can effectively 'skip' it,
//          treating it as a literal.
//          An example would be '1px solid #000' - which evaluates to itself,
//          we don't need to know what the individual components are.
//          The drawback, of course is that you don't get the benefits of
//          syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
//          and a smaller speed-up in the code-gen.
//
//
//      Token matching is done with the `$` function, which either takes
//      a terminal string or regexp, or a non-terminal function to call.
//      It also takes care of moving all the indices forwards.
//
//
var input,       // LeSS input string
    i = 0,       // current index in `input`
    j = 0,       // current chunk
    chunks = [], // chunkified input
    current = 0, // index of current chunk, in `input`
    inputLength;

function peek(regex) {
    var match;
    regex.lastIndex = i;

    if ((match = regex.exec(input)) &&
        (regex.lastIndex - match[0].length === i)) {
        return match;
    }
}

//
// Parse from a token, regexp or string, and move forward if match
//
function $(tok, root) {
    var match, args, length, c, index;

    //
    // Non-terminal
    //
    if (tok instanceof Function) {
        return tok.call(less.parser.parsers, root);
    //
    // Terminal
    //
    //     Either match a single character in the input,
    //     or match a regexp in the current chunk (chunk[j]).
    //
    } else if (typeof(tok) === 'string') {
        match = input[i] === tok ? tok : null;
        length = 1;

    //  1. We move to the next chunk, if necessary.
    //  2. Set the `lastIndex` to be relative
    //     to the current chunk, and try to match in it.
    //  3. Make sure we matched at `index`. Because we use
    //     the /g flag, the match could be anywhere in the
    //     chunk. We have to make sure it's at our previous
    //     index, which we stored in [2].
    //
    } else {
        if (i > current + chunks[j].length) { // 1.
            current += chunks[j++].length;
        }
        tok.lastIndex = index =  i - current; // 2.
        match = tok.exec(chunks[j]);

        if (match) {
            length = match[0].length;
            if (tok.lastIndex - length !== index) { return } // 3.
        }
    }

    // The match is confirmed, add the match length to `i`,
    // and consume any extra white-space characters (' ' || '\n')
    // which come after that. The reason for this is that LeSS's
    // grammar is mostly white-space insensitive.
    //
    if (match) {
        i += length;

        while (i < inputLength) {
            c = input.charCodeAt(i);
            if (! (c === 32 || c === 10)) { break }
            i++;
        }
        return match.length === 1 ? match[0] : match;
    }
}

less.parser = {
    //
    // Parse an input string into an abstract syntax tree
    //
    parse: function (str) {
        var tree;

        input = str;
        inputLength = input.length;

        // Split the input into chunks,
        // delmited by /\n\n/ (see rationale above)
        // We use a lookahead, because we want to
        // preserve the '\n's in the input.
        chunks = input.split(/^(?=\n)/mg);

        // Start with the primary rule
        tree = new(node.Ruleset)([], $(this.parsers.primary, []));
        tree.root = true;

        if (i < input.length - 1) {
            throw new(Error)("Parse Error: " + input.slice(0, i));
        }
        return tree;
    },
    parsers: {
        entities: {
            string: function string() {
                var str;
                if (input[i] !== '"' && input[i] !== "'") return;

                if (str = $(/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/g)) {
                    return new(node.Quoted)(str);
                }
            },
            keyword: function keyword() {
                var k;
                if (k = $(/[a-z-]+/g)) { return new(node.Keyword)(k) }
            },
            call: function call() {
                var name, args;

                if (! (name = $(/([a-zA-Z0-9_-]+)\(/g))) return;

                args = $(this.entities.arguments);

                if (! $(')')) return;

                if (name) { return new(node.Call)(name[1], args) }
            },
            arguments: function arguments() {
                var args = [], arg;

                while (arg = $(this.expression)) {
                    args.push(arg);
                    if (! $(',')) { break }
                }
                return args;
            },
            accessor: function accessor() {
            },
            literal: function literal() {
                return $(this.entities.dimension) ||
                       $(this.entities.color) ||
                       $(this.entities.string);
            },
            url: function url() {
            },
            font: function font() {
            },
            variable: function variable(def) {
                var name;

                if (input[i] !== '@') return;

                if (def && (name = $(/(@[a-zA-Z0-9_-]+)\s*:/g))) { return name[1] }
                else if (!def && (name = $(/@[a-zA-Z0-9_-]+/g))) { return new(node.Variable)(name) }
            },
            color: function color() {
                var rgb;

                if (input[i] !== '#') return;
                if (rgb = $(/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/g)) {
                    return new(node.Color)(rgb[1]);
                }
            },
            dimension: function dimension() {
                var number, unit;

                number = $(/-?[0-9]*\.?[0-9]+/g);
                unit = $(/(?:px|%|em|pc|ex|in|deg|s|pt|cm|mm)/g);

                if (number) { return new(node.Dimension)(number, unit) }
            }
        },
        mixin: {
            call: function mixinCall() {
                var prefix, mixin;

                if (input[i] !== '.') return;
                i++;
                mixin = $(this.entities.call);

                if (mixin && $(';')) {
                    return ['MIXIN-CALL', mixin];
                }
            },
            definition: function mixinDefinition(root) {
                var name, params = [], match, ruleset, param, value;

                if (input[i] !== '.' || peek(/[^{]*(;|})/g)) return;

                if (match = $(/([#.][a-zA-Z0-9_-]+)\s*\(/g)) {
                    name = match[1];
                    while (param = $(this.entities.variable)) {
                        value = null;
                        if ($(':')) {
                            if (value = $(this.expression)) {
                                params.push([param, value]);
                            } else {
                                throw new(Error)("Expected value");
                            }
                        } else {
                            params.push([param, null]);
                        }
                        if (! $(',')) { break }
                    }
                    if (! $(')')) throw new(Error)("Expected )");

                    ruleset = $(this.block, root);

                    if (ruleset) {
                        return ['MIXIN-DEF', name, params, ruleset];
                    }
                }
            }
        },
        entity: function entity() {
            var entities = [
                "url", "variable", "call", "accessor",
                "keyword",  "literal", "font"
            ], e;

            for (var i = 0; i < entities.length; i++) {
                if (e = $(this.entities[entities[i]])) {
                    return e;
                }
            }
        },
        combinator: function combinator() {
            var match;
            if (match = $(/[+>~]/g) || $('&') || $(/::/g)) {
                return new(node.Combinator)(match);
            }
        },
        selector: function selector() {
            var sel, e, elements = [], match;

            while (e = $(this.element)) { elements.push(e) }

            if (elements.length > 0) { return new(node.Selector)(elements) }
        },
        element: function element() {
            var e, t;

            c = $(this.combinator);
            e = $(/[.#:]?[a-zA-Z0-9_-]+/g) || $('*') || /*$(this.attribute) ||*/ $(/\([a-z0-9+-]+\)/g);

            if (e) { return new(node.Element)(c, e) }
        },
        tag: function tag() {
            return $(/[a-zA-Z][a-zA-Z-]*[0-9]?/g) || $('*');
        },
        attribute: function attribute() {
            var attr = '', key, val, op;

            if (! $('[')) return;
            if ((key = $(this.tag)) &&
                (op = $(/[|~*$^]?=/g)) &&
                (val = $(this.entities.string) || $(/[a-zA-Z0-9_-]+/g))) {
                attr = [key, op, val];
            } else if (val = $(this.tag) || $(this.string)) {
                attr = val;
            }
            if (! $(']')) return;

            if (attr) { return ['ATTR', '[' + attr + ']'] }
        },
        block: function block(node) {
            var content;

            if ($('{') && (content = $(this.primary, node)) && $('}')) {
                return content;
            }
        },
        ruleset: function ruleset(root) {
            var selectors = [], s, rules, match;

            if (peek(/[^{]+[;}]/g)) return;

            if (match = peek(/([a-z.#: _-]+)[\s\n]*\{/g)) {
                i += match[0].length - 1;
                selectors = [new(node.Selector)([match[1]])];
            } else {
                while (s = $(this.selector)) {
                    selectors.push(s);
                    if (! $(',')) { break }
                }
            }

            rules = $(this.block, root);

            if (selectors.length > 0 && rules) {
                return new(node.Ruleset)(selectors, rules);
            }
        },
        rule: function rule() {
            var name, value, match;

            if (name = $(this.property) || $(this.entities.variable, true)) {
                if ((name[0] != '@') && (match =
                        peek(/((?:[\s\w."']|-[a-z])+|[^@+\/*(-;}]+)[;}][\s\n]*/g))) {
                    i += match[0].length;
                    return new(node.Rule)(name, match[1]);
                }

                if ((value = $(this.value)) && $(';')) {
                    return new(node.Rule)(name, value);
                }
            }
        },
        directive: function directive(root) {
            var name, value, rules;

            if (input[i] !== '@') return;

            if (name = $(/@[a-z]+/g)) {
                if (name === '@media' || name === '@font-face') {
                    if (rules = $(this.block, root)) {
                        return new(node.Directive)(name, rules);
                    }
                } else if ((value = $(this.entity)) && $(';')) {
                    return new(node.Directive)(name, value);
                }
            }
        },
        value: function value() {
            var e, expressions = [];

            while (e = $(this.expression)) {
                expressions.push(e);
                if (! $(',')) { break }
            }
            if (expressions.length > 0) {
                return new(node.Value)(expressions);
            }
        },
        sub: function sub() {
            var e;

            if ($('(') && (e = $(this.expression)) && $(')')) {
                return ["()", e];
            }
        },
        multiplication: function () {
            var m, a, op;
            if (m = $(this.operand)) {
                if ((op = $(/[\/*]/g)) && (a = $(this.multiplication))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        addition: function () {
            var m, a, op;
            if (m = $(this.multiplication)) {
                if ((op = $(/[-+]\s+/g)) && (a = $(this.addition))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        operand: function () {
            var o;
            if (o = $(this.sub) || $(this.entities.dimension) ||
                    $(this.entities.color) || $(this.entities.variable) ||
                    ($('-') && $(this.operand))) {
                return o;
            }
        },
        expression: function expression() {
            var e, delim, entities = [], d;

            while (e = $(this.addition) || $(this.entity)) {
                entities.push(e);
            }
            if (entities.length > 0) {
                return new(node.Expression)(entities);
            }
        },
        property: function property() {
            var name;

            if (name = $(/(-?[-a-z]+)\s*:/g)) {
                return name[1];
            }
        },
        primary: function primary(root) {
            var node;

            while (node = $(this.ruleset, []) || $(this.rule) || $(this.mixin.definition, []) ||
                          $(this.mixin.call)  || $(/\/\*([^*]|\*+[^\/*])*\*+\//g) || $(/[\n\s]+/g) || $(this.directive)) {
                root.push(node);
            }
            return root;
        }
    }
};
<commit_msg>moved primary rule to the top<commit_after>var less = exports || {};
//
// less.js - parser
//
//      A relatively straight-forward recursive-descent parser.
//      There is no tokenization/lexing stage, the input is parsed
//      in one sweep.
//
//      To make the parser fast enough to run in the browser, several
//      optimization had to be made:
//
//          - Instead of the more commonly used technique of slicing the
//          input string on every match, we use global regexps (/g),
//          and move the `lastIndex` pointer on match, foregoing `slice()`
//          completely. This gives us a 3x speed-up.
//
//          - Matching on a huge input is often cause of slowdowns,
//          especially with the /g flag. The solution to that is to
//          chunkify the input: we split it by /\n\n/, just to be on
//          the safe side. The chunks are stored in the `chunks` var,
//          `j` holds the current chunk index, and `current` holds
//          the index of the current chunk in relation to `input`.
//          This gives us an almost 4x speed-up.
//
//          - In many cases, we don't need to match individual tokens;
//          for example, if a value doesn't hold any variables, operations
//          or dynamic references, the parser can effectively 'skip' it,
//          treating it as a literal.
//          An example would be '1px solid #000' - which evaluates to itself,
//          we don't need to know what the individual components are.
//          The drawback, of course is that you don't get the benefits of
//          syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
//          and a smaller speed-up in the code-gen.
//
//
//      Token matching is done with the `$` function, which either takes
//      a terminal string or regexp, or a non-terminal function to call.
//      It also takes care of moving all the indices forwards.
//
//
var input,       // LeSS input string
    i = 0,       // current index in `input`
    j = 0,       // current chunk
    chunks = [], // chunkified input
    current = 0, // index of current chunk, in `input`
    inputLength;

function peek(regex) {
    var match;
    regex.lastIndex = i;

    if ((match = regex.exec(input)) &&
        (regex.lastIndex - match[0].length === i)) {
        return match;
    }
}

//
// Parse from a token, regexp or string, and move forward if match
//
function $(tok, root) {
    var match, args, length, c, index;

    //
    // Non-terminal
    //
    if (tok instanceof Function) {
        return tok.call(less.parser.parsers, root);
    //
    // Terminal
    //
    //     Either match a single character in the input,
    //     or match a regexp in the current chunk (chunk[j]).
    //
    } else if (typeof(tok) === 'string') {
        match = input[i] === tok ? tok : null;
        length = 1;

    //  1. We move to the next chunk, if necessary.
    //  2. Set the `lastIndex` to be relative
    //     to the current chunk, and try to match in it.
    //  3. Make sure we matched at `index`. Because we use
    //     the /g flag, the match could be anywhere in the
    //     chunk. We have to make sure it's at our previous
    //     index, which we stored in [2].
    //
    } else {
        if (i > current + chunks[j].length) { // 1.
            current += chunks[j++].length;
        }
        tok.lastIndex = index =  i - current; // 2.
        match = tok.exec(chunks[j]);

        if (match) {
            length = match[0].length;
            if (tok.lastIndex - length !== index) { return } // 3.
        }
    }

    // The match is confirmed, add the match length to `i`,
    // and consume any extra white-space characters (' ' || '\n')
    // which come after that. The reason for this is that LeSS's
    // grammar is mostly white-space insensitive.
    //
    if (match) {
        i += length;

        while (i < inputLength) {
            c = input.charCodeAt(i);
            if (! (c === 32 || c === 10)) { break }
            i++;
        }
        return match.length === 1 ? match[0] : match;
    }
}

less.parser = {
    //
    // Parse an input string into an abstract syntax tree
    //
    parse: function (str) {
        var tree;

        input = str;
        inputLength = input.length;

        // Split the input into chunks,
        // delmited by /\n\n/ (see rationale above)
        // We use a lookahead, because we want to
        // preserve the '\n's in the input.
        chunks = input.split(/^(?=\n)/mg);

        // Start with the primary rule
        tree = new(node.Ruleset)([], $(this.parsers.primary, []));
        tree.root = true;

        if (i < input.length - 1) {
            throw new(Error)("Parse Error: " + input.slice(0, i));
        }
        return tree;
    },
    parsers: {
        primary: function primary(root) {
            var node;

            while (node = $(this.ruleset, []) || $(this.rule) || $(this.mixin.definition, []) ||
                          $(this.mixin.call)  || $(/\/\*([^*]|\*+[^\/*])*\*+\//g) || $(/[\n\s]+/g) || $(this.directive)) {
                root.push(node);
            }
            return root;
        },
        entities: {
            string: function string() {
                var str;
                if (input[i] !== '"' && input[i] !== "'") return;

                if (str = $(/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/g)) {
                    return new(node.Quoted)(str);
                }
            },
            keyword: function keyword() {
                var k;
                if (k = $(/[a-z-]+/g)) { return new(node.Keyword)(k) }
            },
            call: function call() {
                var name, args;

                if (! (name = $(/([a-zA-Z0-9_-]+)\(/g))) return;

                args = $(this.entities.arguments);

                if (! $(')')) return;

                if (name) { return new(node.Call)(name[1], args) }
            },
            arguments: function arguments() {
                var args = [], arg;

                while (arg = $(this.expression)) {
                    args.push(arg);
                    if (! $(',')) { break }
                }
                return args;
            },
            accessor: function accessor() {
            },
            literal: function literal() {
                return $(this.entities.dimension) ||
                       $(this.entities.color) ||
                       $(this.entities.string);
            },
            url: function url() {
            },
            font: function font() {
            },
            variable: function variable(def) {
                var name;

                if (input[i] !== '@') return;

                if (def && (name = $(/(@[a-zA-Z0-9_-]+)\s*:/g))) { return name[1] }
                else if (!def && (name = $(/@[a-zA-Z0-9_-]+/g))) { return new(node.Variable)(name) }
            },
            color: function color() {
                var rgb;

                if (input[i] !== '#') return;
                if (rgb = $(/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/g)) {
                    return new(node.Color)(rgb[1]);
                }
            },
            dimension: function dimension() {
                var number, unit;

                number = $(/-?[0-9]*\.?[0-9]+/g);
                unit = $(/(?:px|%|em|pc|ex|in|deg|s|pt|cm|mm)/g);

                if (number) { return new(node.Dimension)(number, unit) }
            }
        },
        mixin: {
            call: function mixinCall() {
                var prefix, mixin;

                if (input[i] !== '.') return;
                i++;
                mixin = $(this.entities.call);

                if (mixin && $(';')) {
                    return ['MIXIN-CALL', mixin];
                }
            },
            definition: function mixinDefinition(root) {
                var name, params = [], match, ruleset, param, value;

                if (input[i] !== '.' || peek(/[^{]*(;|})/g)) return;

                if (match = $(/([#.][a-zA-Z0-9_-]+)\s*\(/g)) {
                    name = match[1];
                    while (param = $(this.entities.variable)) {
                        value = null;
                        if ($(':')) {
                            if (value = $(this.expression)) {
                                params.push([param, value]);
                            } else {
                                throw new(Error)("Expected value");
                            }
                        } else {
                            params.push([param, null]);
                        }
                        if (! $(',')) { break }
                    }
                    if (! $(')')) throw new(Error)("Expected )");

                    ruleset = $(this.block, root);

                    if (ruleset) {
                        return ['MIXIN-DEF', name, params, ruleset];
                    }
                }
            }
        },
        entity: function entity() {
            var entities = [
                "url", "variable", "call", "accessor",
                "keyword",  "literal", "font"
            ], e;

            for (var i = 0; i < entities.length; i++) {
                if (e = $(this.entities[entities[i]])) {
                    return e;
                }
            }
        },
        combinator: function combinator() {
            var match;
            if (match = $(/[+>~]/g) || $('&') || $(/::/g)) {
                return new(node.Combinator)(match);
            }
        },
        selector: function selector() {
            var sel, e, elements = [], match;

            while (e = $(this.element)) { elements.push(e) }

            if (elements.length > 0) { return new(node.Selector)(elements) }
        },
        element: function element() {
            var e, t;

            c = $(this.combinator);
            e = $(/[.#:]?[a-zA-Z0-9_-]+/g) || $('*') || /*$(this.attribute) ||*/ $(/\([a-z0-9+-]+\)/g);

            if (e) { return new(node.Element)(c, e) }
        },
        tag: function tag() {
            return $(/[a-zA-Z][a-zA-Z-]*[0-9]?/g) || $('*');
        },
        attribute: function attribute() {
            var attr = '', key, val, op;

            if (! $('[')) return;
            if ((key = $(this.tag)) &&
                (op = $(/[|~*$^]?=/g)) &&
                (val = $(this.entities.string) || $(/[a-zA-Z0-9_-]+/g))) {
                attr = [key, op, val];
            } else if (val = $(this.tag) || $(this.string)) {
                attr = val;
            }
            if (! $(']')) return;

            if (attr) { return ['ATTR', '[' + attr + ']'] }
        },
        block: function block(node) {
            var content;

            if ($('{') && (content = $(this.primary, node)) && $('}')) {
                return content;
            }
        },
        ruleset: function ruleset(root) {
            var selectors = [], s, rules, match;

            if (peek(/[^{]+[;}]/g)) return;

            if (match = peek(/([a-z.#: _-]+)[\s\n]*\{/g)) {
                i += match[0].length - 1;
                selectors = [new(node.Selector)([match[1]])];
            } else {
                while (s = $(this.selector)) {
                    selectors.push(s);
                    if (! $(',')) { break }
                }
            }

            rules = $(this.block, root);

            if (selectors.length > 0 && rules) {
                return new(node.Ruleset)(selectors, rules);
            }
        },
        rule: function rule() {
            var name, value, match;

            if (name = $(this.property) || $(this.entities.variable, true)) {
                if ((name[0] != '@') && (match =
                        peek(/((?:[\s\w."']|-[a-z])+|[^@+\/*(-;}]+)[;}][\s\n]*/g))) {
                    i += match[0].length;
                    return new(node.Rule)(name, match[1]);
                }

                if ((value = $(this.value)) && $(';')) {
                    return new(node.Rule)(name, value);
                }
            }
        },
        directive: function directive(root) {
            var name, value, rules;

            if (input[i] !== '@') return;

            if (name = $(/@[a-z]+/g)) {
                if (name === '@media' || name === '@font-face') {
                    if (rules = $(this.block, root)) {
                        return new(node.Directive)(name, rules);
                    }
                } else if ((value = $(this.entity)) && $(';')) {
                    return new(node.Directive)(name, value);
                }
            }
        },
        value: function value() {
            var e, expressions = [];

            while (e = $(this.expression)) {
                expressions.push(e);
                if (! $(',')) { break }
            }
            if (expressions.length > 0) {
                return new(node.Value)(expressions);
            }
        },
        sub: function sub() {
            var e;

            if ($('(') && (e = $(this.expression)) && $(')')) {
                return ["()", e];
            }
        },
        multiplication: function () {
            var m, a, op;
            if (m = $(this.operand)) {
                if ((op = $(/[\/*]/g)) && (a = $(this.multiplication))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        addition: function () {
            var m, a, op;
            if (m = $(this.multiplication)) {
                if ((op = $(/[-+]\s+/g)) && (a = $(this.addition))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        operand: function () {
            var o;
            if (o = $(this.sub) || $(this.entities.dimension) ||
                    $(this.entities.color) || $(this.entities.variable) ||
                    ($('-') && $(this.operand))) {
                return o;
            }
        },
        expression: function expression() {
            var e, delim, entities = [], d;

            while (e = $(this.addition) || $(this.entity)) {
                entities.push(e);
            }
            if (entities.length > 0) {
                return new(node.Expression)(entities);
            }
        },
        property: function property() {
            var name;

            if (name = $(/(-?[-a-z]+)\s*:/g)) {
                return name[1];
            }
        }
    }
};

<|endoftext|>


<commit_before>var less = exports || {};
//
// less.js - parser
//
//      A relatively straight-forward recursive-descent parser.
//      There is no tokenization/lexing stage, the input is parsed
//      in one sweep.
//
//      To make the parser fast enough to run in the browser, several
//      optimization had to be made:
//
//          - Instead of the more commonly used technique of slicing the
//          input string on every match, we use global regexps (/g),
//          and move the `lastIndex` pointer on match, foregoing `slice()`
//          completely. This gives us a 3x speed-up.
//
//          - Matching on a huge input is often cause of slowdowns,
//          especially with the /g flag. The solution to that is to
//          chunkify the input: we split it by /\n\n/, just to be on
//          the safe side. The chunks are stored in the `chunks` var,
//          `j` holds the current chunk index, and `current` holds
//          the index of the current chunk in relation to `input`.
//          This gives us an almost 4x speed-up.
//
//          - In many cases, we don't need to match individual tokens;
//          for example, if a value doesn't hold any variables, operations
//          or dynamic references, the parser can effectively 'skip' it,
//          treating it as a literal.
//          An example would be '1px solid #000' - which evaluates to itself,
//          we don't need to know what the individual components are.
//          The drawback, of course is that you don't get the benefits of
//          syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
//          and a smaller speed-up in the code-gen.
//
//
//      Token matching is done with the `$` function, which either takes
//      a terminal string or regexp, or a non-terminal function to call.
//      It also takes care of moving all the indices forwards.
//
//
var input,       // LeSS input string
    i,           // current index in `input`
    j,           // current chunk
    chunks = [], // chunkified input
    current,     // index of current chunk, in `input`
    inputLength;

function peek(regex) {
    var match;
    regex.lastIndex = i;

    if ((match = regex.exec(input)) &&
        (regex.lastIndex - match[0].length === i)) {
        return match;
    }
}

//
// Parse from a token, regexp or string, and move forward if match
//
function $(tok, root) {
    var match, args, length, c, index;

    //
    // Non-terminal
    //
    if (tok instanceof Function) {
        return tok.call(less.parser.parsers, root);
    //
    // Terminal
    //
    //     Either match a single character in the input,
    //     or match a regexp in the current chunk (chunk[j]).
    //
    } else if (typeof(tok) === 'string') {
        match = input[i] === tok ? tok : null;
        length = 1;

    //  1. We move to the next chunk, if necessary.
    //  2. Set the `lastIndex` to be relative
    //     to the current chunk, and try to match in it.
    //  3. Make sure we matched at `index`. Because we use
    //     the /g flag, the match could be anywhere in the
    //     chunk. We have to make sure it's at our previous
    //     index, which we stored in [2].
    //
    } else {
        if (i > current + chunks[j].length) { // 1.
            current += chunks[j++].length;
        }
        tok.lastIndex = index =  i - current; // 2.
        match = tok.exec(chunks[j]);

        if (match) {
            length = match[0].length;
            if (tok.lastIndex - length !== index) { return } // 3.
        }
    }

    // The match is confirmed, add the match length to `i`,
    // and consume any extra white-space characters (' ' || '\n')
    // which come after that. The reason for this is that LeSS's
    // grammar is mostly white-space insensitive.
    //
    if (match) {
        i += length;

        while (i < inputLength) {
            c = input.charCodeAt(i);
            if (! (c === 32 || c === 10)) { break }
            i++;
        }
        return match.length === 1 ? match[0] : match;
    }
}

less.parser = {
    //
    // Parse an input string into an abstract syntax tree
    //
    parse: function (str) {
        var tree, start, end, zone, line;

        i = j = current = 0;
        input = str;
        inputLength = input.length;

        // Split the input into chunks,
        // delmited by /\n\n/ (see rationale above)
        // We use a lookahead, because we want to
        // preserve the '\n's in the input.
        chunks = input.split(/^(?=\n)/mg);

        // Start with the primary rule
        tree = new(node.Ruleset)([], $(this.parsers.primary, []));
        tree.root = true;

        // If `i` is smaller than the input length - 1,
        // it means the parser wasn't able to parse the whole
        // string, so we've got a parsing error.
        if (i < input.length - 1) {
            start = (function () {
                for (var n = i; n > 0; n--) {
                    if (input[n] === '\n') { break }
                }
                return n;
            })() + 1;
            line = (input.slice(0, i).match(/\n/g) || "").length + 1;
            end = input.slice(i).indexOf('\n') + i;
            zone = stylize(input.slice(start, i), 'green') +
                   stylize(input.slice(i, end), 'yellow');

            throw new(Error)("Parse Error on line " + line + ":\n" + zone);
        }
        return tree;
    },
    parsers: {
        primary: function primary(root) {
            var node;

            while (node = $(this.ruleset, []) || $(this.rule) || $(this.mixin.definition, []) ||
                          $(this.mixin.call)  || $(/\/\*([^*]|\*+[^\/*])*\*+\//g) || $(/\/\/.*/g) ||
                          $(/[\n\s]+/g)       || $(this.directive)) {
                root.push(node);
            }
            return root;
        },
        entities: {
            string: function string() {
                var str;
                if (input[i] !== '"' && input[i] !== "'") return;

                if (str = $(/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/g)) {
                    return new(node.Quoted)(str);
                }
            },
            keyword: function keyword() {
                var k;
                if (k = $(/[A-Za-z-]+/g)) { return new(node.Keyword)(k) }
            },
            call: function call() {
                var name, args;

                if (! (name = $(/([a-zA-Z0-9_-]+)\(/g))) return;

                args = $(this.entities.arguments);

                if (! $(')')) return;

                if (name) { return new(node.Call)(name[1], args) }
            },
            arguments: function arguments() {
                var args = [], arg;

                while (arg = $(this.expression)) {
                    args.push(arg);
                    if (! $(',')) { break }
                }
                return args;
            },
            accessor: function accessor() {
            },
            literal: function literal() {
                return $(this.entities.dimension) ||
                       $(this.entities.color) ||
                       $(this.entities.string);
            },
            url: function url() {
                var value;

                if (! $(/url\(/g)) return;
                value = $(this.entities.string) || $(/[-a-zA-Z0-9_%@$\/.&=:;#+?]+/g);
                if (! $(')')) throw new(Error)("missing closing ) for url()");

                return new(node.URL)(value);
            },
            font: function font() {
            },
            variable: function variable(def) {
                var name;

                if (input[i] !== '@') return;

                if (def && (name = $(/(@[a-zA-Z0-9_-]+)\s*:/g))) { return name[1] }
                else if (!def && (name = $(/@[a-zA-Z0-9_-]+/g))) { return new(node.Variable)(name) }
            },
            color: function color() {
                var rgb;

                if (input[i] !== '#') return;
                if (rgb = $(/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/g)) {
                    return new(node.Color)(rgb[1]);
                }
            },
            dimension: function dimension() {
                var number, unit;

                number = $(/-?[0-9]*\.?[0-9]+/g);
                unit = $(/(?:px|%|em|pc|ex|in|deg|s|pt|cm|mm)/g);

                if (number) { return new(node.Dimension)(number, unit) }
            }
        },
        mixin: {
            call: function mixinCall() {
                var prefix, mixin;

                if (input[i] !== '.') return;
                i++;
                mixin = $(this.entities.call);

                if (mixin && $(';')) {
                    return ['MIXIN-CALL', mixin];
                }
            },
            definition: function mixinDefinition(root) {
                var name, params = [], match, ruleset, param, value;

                if (input[i] !== '.' || peek(/[^{]*(;|})/g)) return;

                if (match = $(/([#.][a-zA-Z0-9_-]+)\s*\(/g)) {
                    name = match[1];
                    while (param = $(this.entities.variable)) {
                        value = null;
                        if ($(':')) {
                            if (value = $(this.expression)) {
                                params.push([param, value]);
                            } else {
                                throw new(Error)("Expected value");
                            }
                        } else {
                            params.push([param, null]);
                        }
                        if (! $(',')) { break }
                    }
                    if (! $(')')) throw new(Error)("Expected )");

                    ruleset = $(this.block, root);

                    if (ruleset) {
                        return ['MIXIN-DEF', name, params, ruleset];
                    }
                }
            }
        },
        entity: function entity() {
            var entities = [
                "url", "variable", "call", "accessor",
                "keyword",  "literal", "font"
            ], e;

            for (var i = 0; i < entities.length; i++) {
                if (e = $(this.entities[entities[i]])) {
                    return e;
                }
            }
        },
        combinator: function combinator() {
            var match;
            if (match = $(/[+>~]/g) || $('&') || $(/::/g)) {
                return new(node.Combinator)(match);
            }
        },
        selector: function selector() {
            var sel, e, elements = [], match;

            while (e = $(this.element)) { elements.push(e) }

            if (elements.length > 0) { return new(node.Selector)(elements) }
        },
        element: function element() {
            var e, t;

            c = $(this.combinator);
            e = $(/[.#:]?[a-zA-Z0-9_-]+/g) || $('*') || /*$(this.attribute) ||*/ $(/\([a-z0-9+-]+\)/g);

            if (e) { return new(node.Element)(c, e) }
        },
        tag: function tag() {
            return $(/[a-zA-Z][a-zA-Z-]*[0-9]?/g) || $('*');
        },
        attribute: function attribute() {
            var attr = '', key, val, op;

            if (! $('[')) return;
            if ((key = $(this.tag)) &&
                (op = $(/[|~*$^]?=/g)) &&
                (val = $(this.entities.string) || $(/[a-zA-Z0-9_-]+/g))) {
                attr = [key, op, val];
            } else if (val = $(this.tag) || $(this.string)) {
                attr = val;
            }
            if (! $(']')) return;

            if (attr) { return ['ATTR', '[' + attr + ']'] }
        },
        block: function block(node) {
            var content;

            if ($('{') && (content = $(this.primary, node)) && $('}')) {
                return content;
            }
        },
        ruleset: function ruleset(root) {
            var selectors = [], s, rules, match;

            if (peek(/[^{]+[;}]/g)) return;

            if (match = peek(/([a-z.#: _-]+)[\s\n]*\{/g)) {
                i += match[0].length - 1;
                selectors = [new(node.Selector)([match[1]])];
            } else {
                while (s = $(this.selector)) {
                    selectors.push(s);
                    if (! $(',')) { break }
                }
            }

            rules = $(this.block, root);

            if (selectors.length > 0 && rules) {
                return new(node.Ruleset)(selectors, rules);
            }
        },
        rule: function rule() {
            var name, value, match;

            if (name = $(this.property) || $(this.entities.variable, true)) {
                if ((name[0] != '@') && (match =
                        peek(/((?:[\s\w."']|-[a-z])+|[^@+\/*(-;}]+)[;}][\s\n]*/g))) {
                    i += match[0].length;
                    return new(node.Rule)(name, match[1]);
                }

                if ((value = $(this.value)) && $(';')) {
                    return new(node.Rule)(name, value);
                }
            }
        },
        directive: function directive(root) {
            var name, value, rules;

            if (input[i] !== '@') return;

            if (name = $(/@[a-z]+/g)) {
                if (name === '@media' || name === '@font-face') {
                    if (rules = $(this.block, root)) {
                        return new(node.Directive)(name, rules);
                    }
                } else if ((value = $(this.entity)) && $(';')) {
                    return new(node.Directive)(name, value);
                }
            }
        },
        value: function value() {
            var e, expressions = [];

            while (e = $(this.expression)) {
                expressions.push(e);
                if (! $(',')) { break }
            }
            if (expressions.length > 0) {
                return new(node.Value)(expressions);
            }
        },
        sub: function sub() {
            var e;

            if ($('(') && (e = $(this.expression)) && $(')')) {
                return e;
            }
        },
        multiplication: function () {
            var m, a, op;
            if (m = $(this.operand)) {
                if ((op = $(/[\/*]/g)) && (a = $(this.multiplication))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        addition: function () {
            var m, a, op;
            if (m = $(this.multiplication)) {
                if ((op = $(/[-+]\s+/g)) && (a = $(this.addition))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        operand: function () {
            var o;
            if (o = $(this.sub) || $(this.entities.dimension) ||
                    $(this.entities.color) || $(this.entities.variable) ||
                    ($('-') && $(this.operand))) {
                return o;
            }
        },
        expression: function expression() {
            var e, delim, entities = [], d;

            while (e = $(this.addition) || $(this.entity)) {
                entities.push(e);
            }
            if (entities.length > 0) {
                return new(node.Expression)(entities);
            }
        },
        property: function property() {
            var name;

            if (name = $(/(-?[-a-z]+)\s*:/g)) {
                return name[1];
            }
        }
    }
};

// Stylize a string
function stylize(str, style) {
    var styles = {
        'bold'      : [1,  22],
        'underline' : [4,  24],
        'yellow'    : [33, 39],
        'green'     : [32, 39],
        'red'       : [31, 39]
    };
    return '\033[' + styles[style][0] + 'm' + str +
           '\033[' + styles[style][1] + 'm';
}

<commit_msg>pass a context to directive(), so it can parse a block<commit_after>var less = exports || {};
//
// less.js - parser
//
//      A relatively straight-forward recursive-descent parser.
//      There is no tokenization/lexing stage, the input is parsed
//      in one sweep.
//
//      To make the parser fast enough to run in the browser, several
//      optimization had to be made:
//
//          - Instead of the more commonly used technique of slicing the
//          input string on every match, we use global regexps (/g),
//          and move the `lastIndex` pointer on match, foregoing `slice()`
//          completely. This gives us a 3x speed-up.
//
//          - Matching on a huge input is often cause of slowdowns,
//          especially with the /g flag. The solution to that is to
//          chunkify the input: we split it by /\n\n/, just to be on
//          the safe side. The chunks are stored in the `chunks` var,
//          `j` holds the current chunk index, and `current` holds
//          the index of the current chunk in relation to `input`.
//          This gives us an almost 4x speed-up.
//
//          - In many cases, we don't need to match individual tokens;
//          for example, if a value doesn't hold any variables, operations
//          or dynamic references, the parser can effectively 'skip' it,
//          treating it as a literal.
//          An example would be '1px solid #000' - which evaluates to itself,
//          we don't need to know what the individual components are.
//          The drawback, of course is that you don't get the benefits of
//          syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
//          and a smaller speed-up in the code-gen.
//
//
//      Token matching is done with the `$` function, which either takes
//      a terminal string or regexp, or a non-terminal function to call.
//      It also takes care of moving all the indices forwards.
//
//
var input,       // LeSS input string
    i,           // current index in `input`
    j,           // current chunk
    chunks = [], // chunkified input
    current,     // index of current chunk, in `input`
    inputLength;

function peek(regex) {
    var match;
    regex.lastIndex = i;

    if ((match = regex.exec(input)) &&
        (regex.lastIndex - match[0].length === i)) {
        return match;
    }
}

//
// Parse from a token, regexp or string, and move forward if match
//
function $(tok, root) {
    var match, args, length, c, index;

    //
    // Non-terminal
    //
    if (tok instanceof Function) {
        return tok.call(less.parser.parsers, root);
    //
    // Terminal
    //
    //     Either match a single character in the input,
    //     or match a regexp in the current chunk (chunk[j]).
    //
    } else if (typeof(tok) === 'string') {
        match = input[i] === tok ? tok : null;
        length = 1;

    //  1. We move to the next chunk, if necessary.
    //  2. Set the `lastIndex` to be relative
    //     to the current chunk, and try to match in it.
    //  3. Make sure we matched at `index`. Because we use
    //     the /g flag, the match could be anywhere in the
    //     chunk. We have to make sure it's at our previous
    //     index, which we stored in [2].
    //
    } else {
        if (i > current + chunks[j].length) { // 1.
            current += chunks[j++].length;
        }
        tok.lastIndex = index =  i - current; // 2.
        match = tok.exec(chunks[j]);

        if (match) {
            length = match[0].length;
            if (tok.lastIndex - length !== index) { return } // 3.
        }
    }

    // The match is confirmed, add the match length to `i`,
    // and consume any extra white-space characters (' ' || '\n')
    // which come after that. The reason for this is that LeSS's
    // grammar is mostly white-space insensitive.
    //
    if (match) {
        i += length;

        while (i < inputLength) {
            c = input.charCodeAt(i);
            if (! (c === 32 || c === 10)) { break }
            i++;
        }
        return match.length === 1 ? match[0] : match;
    }
}

less.parser = {
    //
    // Parse an input string into an abstract syntax tree
    //
    parse: function (str) {
        var tree, start, end, zone, line;

        i = j = current = 0;
        input = str;
        inputLength = input.length;

        // Split the input into chunks,
        // delmited by /\n\n/ (see rationale above)
        // We use a lookahead, because we want to
        // preserve the '\n's in the input.
        chunks = input.split(/^(?=\n)/mg);

        // Start with the primary rule
        tree = new(node.Ruleset)([], $(this.parsers.primary, []));
        tree.root = true;

        // If `i` is smaller than the input length - 1,
        // it means the parser wasn't able to parse the whole
        // string, so we've got a parsing error.
        if (i < input.length - 1) {
            start = (function () {
                for (var n = i; n > 0; n--) {
                    if (input[n] === '\n') { break }
                }
                return n;
            })() + 1;
            line = (input.slice(0, i).match(/\n/g) || "").length + 1;
            end = input.slice(i).indexOf('\n') + i;
            zone = stylize(input.slice(start, i), 'green') +
                   stylize(input.slice(i, end), 'yellow');

            throw new(Error)("Parse Error on line " + line + ":\n" + zone);
        }
        return tree;
    },
    parsers: {
        primary: function primary(root) {
            var node;

            while (node = $(this.ruleset, []) || $(this.rule) || $(this.mixin.definition, []) ||
                          $(this.mixin.call)  || $(/\/\*(?:[^*]|\*+[^\/*])*\*+\//g) || $(/\/\/.*/g) ||
                          $(/[\n\s]+/g)       || $(this.directive, [])) {
                root.push(node);
            }
            return root;
        },
        entities: {
            string: function string() {
                var str;
                if (input[i] !== '"' && input[i] !== "'") return;

                if (str = $(/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/g)) {
                    return new(node.Quoted)(str);
                }
            },
            keyword: function keyword() {
                var k;
                if (k = $(/[A-Za-z-]+/g)) { return new(node.Keyword)(k) }
            },
            call: function call() {
                var name, args;

                if (! (name = $(/([a-zA-Z0-9_-]+)\(/g))) return;

                args = $(this.entities.arguments);

                if (! $(')')) return;

                if (name) { return new(node.Call)(name[1], args) }
            },
            arguments: function arguments() {
                var args = [], arg;

                while (arg = $(this.expression)) {
                    args.push(arg);
                    if (! $(',')) { break }
                }
                return args;
            },
            accessor: function accessor() {
            },
            literal: function literal() {
                return $(this.entities.dimension) ||
                       $(this.entities.color) ||
                       $(this.entities.string);
            },
            url: function url() {
                var value;

                if (! $(/url\(/g)) return;
                value = $(this.entities.string) || $(/[-a-zA-Z0-9_%@$\/.&=:;#+?]+/g);
                if (! $(')')) throw new(Error)("missing closing ) for url()");

                return new(node.URL)(value);
            },
            font: function font() {
            },
            variable: function variable(def) {
                var name;

                if (input[i] !== '@') return;

                if (def && (name = $(/(@[a-zA-Z0-9_-]+)\s*:/g))) { return name[1] }
                else if (!def && (name = $(/@[a-zA-Z0-9_-]+/g))) { return new(node.Variable)(name) }
            },
            color: function color() {
                var rgb;

                if (input[i] !== '#') return;
                if (rgb = $(/#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/g)) {
                    return new(node.Color)(rgb[1]);
                }
            },
            dimension: function dimension() {
                var number, unit;

                number = $(/-?[0-9]*\.?[0-9]+/g);
                unit = $(/(?:px|%|em|pc|ex|in|deg|s|pt|cm|mm)/g);

                if (number) { return new(node.Dimension)(number, unit) }
            }
        },
        mixin: {
            call: function mixinCall() {
                var prefix, mixin;

                if (input[i] !== '.') return;
                i++;
                mixin = $(this.entities.call);

                if (mixin && $(';')) {
                    return ['MIXIN-CALL', mixin];
                }
            },
            definition: function mixinDefinition(root) {
                var name, params = [], match, ruleset, param, value;

                if (input[i] !== '.' || peek(/[^{]*(;|})/g)) return;

                if (match = $(/([#.][a-zA-Z0-9_-]+)\s*\(/g)) {
                    name = match[1];
                    while (param = $(this.entities.variable)) {
                        value = null;
                        if ($(':')) {
                            if (value = $(this.expression)) {
                                params.push([param, value]);
                            } else {
                                throw new(Error)("Expected value");
                            }
                        } else {
                            params.push([param, null]);
                        }
                        if (! $(',')) { break }
                    }
                    if (! $(')')) throw new(Error)("Expected )");

                    ruleset = $(this.block, root);

                    if (ruleset) {
                        return ['MIXIN-DEF', name, params, ruleset];
                    }
                }
            }
        },
        entity: function entity() {
            var entities = [
                "url", "variable", "call", "accessor",
                "keyword",  "literal", "font"
            ], e;

            for (var i = 0; i < entities.length; i++) {
                if (e = $(this.entities[entities[i]])) {
                    return e;
                }
            }
        },
        combinator: function combinator() {
            var match;
            if (match = $(/[+>~]/g) || $('&') || $(/::/g)) {
                return new(node.Combinator)(match);
            }
        },
        selector: function selector() {
            var sel, e, elements = [], match;

            while (e = $(this.element)) { elements.push(e) }

            if (elements.length > 0) { return new(node.Selector)(elements) }
        },
        element: function element() {
            var e, t;

            c = $(this.combinator);
            e = $(/[.#:]?[a-zA-Z0-9_-]+/g) || $('*') || /*$(this.attribute) ||*/ $(/\([a-z0-9+-]+\)/g);

            if (e) { return new(node.Element)(c, e) }
        },
        tag: function tag() {
            return $(/[a-zA-Z][a-zA-Z-]*[0-9]?/g) || $('*');
        },
        attribute: function attribute() {
            var attr = '', key, val, op;

            if (! $('[')) return;
            if ((key = $(this.tag)) &&
                (op = $(/[|~*$^]?=/g)) &&
                (val = $(this.entities.string) || $(/[a-zA-Z0-9_-]+/g))) {
                attr = [key, op, val];
            } else if (val = $(this.tag) || $(this.string)) {
                attr = val;
            }
            if (! $(']')) return;

            if (attr) { return ['ATTR', '[' + attr + ']'] }
        },
        block: function block(node) {
            var content;

            if ($('{') && (content = $(this.primary, node)) && $('}')) {
                return content;
            }
        },
        ruleset: function ruleset(root) {
            var selectors = [], s, rules, match;

            if (peek(/[^{]+[;}]/g)) return;

            if (match = peek(/([a-z.#: _-]+)[\s\n]*\{/g)) {
                i += match[0].length - 1;
                selectors = [new(node.Selector)([match[1]])];
            } else {
                while (s = $(this.selector)) {
                    selectors.push(s);
                    if (! $(',')) { break }
                }
            }

            rules = $(this.block, root);

            if (selectors.length > 0 && rules) {
                return new(node.Ruleset)(selectors, rules);
            }
        },
        rule: function rule() {
            var name, value, match;

            if (name = $(this.property) || $(this.entities.variable, true)) {
                if ((name[0] != '@') && (match =
                        peek(/((?:[\s\w."']|-[a-z])+|[^@+\/*(-;}]+)[;}][\s\n]*/g))) {
                    i += match[0].length;
                    return new(node.Rule)(name, match[1]);
                }

                if ((value = $(this.value)) && $(';')) {
                    return new(node.Rule)(name, value);
                }
            }
        },
        directive: function directive(root) {
            var name, value, rules;

            if (input[i] !== '@') return;

            if (name = $(/@[a-z]+/g)) {
                if (name === '@media' || name === '@font-face') {
                    if (rules = $(this.block, root)) {
                        return new(node.Directive)(name, rules);
                    }
                } else if ((value = $(this.entity)) && $(';')) {
                    return new(node.Directive)(name, value);
                }
            }
        },
        value: function value() {
            var e, expressions = [];

            while (e = $(this.expression)) {
                expressions.push(e);
                if (! $(',')) { break }
            }
            if (expressions.length > 0) {
                return new(node.Value)(expressions);
            }
        },
        sub: function sub() {
            var e;

            if ($('(') && (e = $(this.expression)) && $(')')) {
                return e;
            }
        },
        multiplication: function () {
            var m, a, op;
            if (m = $(this.operand)) {
                if ((op = $(/[\/*]/g)) && (a = $(this.multiplication))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        addition: function () {
            var m, a, op;
            if (m = $(this.multiplication)) {
                if ((op = $(/[-+]\s+/g)) && (a = $(this.addition))) {
                    return new(node.Operation)(op, [m, a]);
                } else {
                    return m;
                }
            }
        },
        operand: function () {
            var o;
            if (o = $(this.sub) || $(this.entities.dimension) ||
                    $(this.entities.color) || $(this.entities.variable) ||
                    ($('-') && $(this.operand))) {
                return o;
            }
        },
        expression: function expression() {
            var e, delim, entities = [], d;

            while (e = $(this.addition) || $(this.entity)) {
                entities.push(e);
            }
            if (entities.length > 0) {
                return new(node.Expression)(entities);
            }
        },
        property: function property() {
            var name;

            if (name = $(/(-?[-a-z]+)\s*:/g)) {
                return name[1];
            }
        }
    }
};

// Stylize a string
function stylize(str, style) {
    var styles = {
        'bold'      : [1,  22],
        'underline' : [4,  24],
        'yellow'    : [33, 39],
        'green'     : [32, 39],
        'red'       : [31, 39]
    };
    return '\033[' + styles[style][0] + 'm' + str +
           '\033[' + styles[style][1] + 'm';
}

<|endoftext|>


<commit_before>const path = require('path');
const bre = require('@nomiclabs/buidler');

const { Compiler } = require('@nomiclabs/buidler/internal/solidity/compiler');

const compiler = new Compiler(
  bre.config.solc.version,
  path.join(bre.config.paths.cache, 'compilers'),
);

module.exports = Object.assign(compiler.getSolc(), { __esModule: true });
<commit_msg>Fix prepare-docs-solc.js for Hardhat<commit_after>const hre = require('hardhat');

const { getCompilersDir } = require('hardhat/internal/util/global-dir');
const { CompilerDownloader } = require('hardhat/internal/solidity/compiler/downloader');
const { Compiler } = require('hardhat/internal/solidity/compiler');

const [{ version }] = hre.config.solidity.compilers;

async function getSolc () {
  const downloader = new CompilerDownloader(await getCompilersDir(), { forceSolcJs: true });
  const { compilerPath } = await downloader.getDownloadedCompilerPath(version);
  const compiler = new Compiler(compilerPath);
  return compiler.getSolc();
}

module.exports = Object.assign(getSolc(), { __esModule: true });
<|endoftext|>


<commit_before>var doc = document.getElementById('doc');
var menu = document.createElement('div');
var menucontainer = document.createElement('div');
var logoA = document.createElement('a');
var logo = document.createElement('img');
var hovermenu = document.createElement('div');
var mobile = false;

hovermenu.id = 'hovermenu';
hovermenu.textContent = 'Menu';
hovermenu.style.display = 'none';

hovermenu.onclick = function (e) {
  var targetMenuItem;
  for (var i = 0; i < headers.length; i++) {
    if (headers[i].getBoundingClientRect().top >= 0) {
      targetMenuItem = menuitems[i];
      break;
    }
  }

  document.body.style.overflow = 'hidden';
  menu.style.display = '';
  hovermenu.style.display = 'none';
  menu.scrollTop = targetMenuItem.offsetTop - window.innerHeight / 2;
  document.body.classList.add('pushout');
  menu.classList.remove('fadeout');
  menu.classList.add('slidein');
  doc.classList.remove('pushin');
  doc.classList.add('pushout');
  menu.onclick = doc.onclick = function (e) {
    menu.onclick = doc.onclick = null;
    menu.classList.add('fadeout');
    menu.classList.remove('slidein');
    menu.style.overflow = 'hidden';
    doc.classList.add('pushin');
    doc.classList.remove('pushout');
    hovermenu.style.display = '';
    window.onclick = null;
    document.body.style.overflow = '';
    setTimeout(function () {
      if (!mobile) {
        return;
      }
      menu.style.display = 'none';
      menu.style.overflow = '';
      menu.classList.remove('fadeout');
      doc.classList.remove('pushin');
    }, 500);
  };
};

menu.id = 'menu';
menucontainer.id = 'menucontainer';

logoA.href = 'https://redom.js.org';
logo.id = 'logo';
logo.src = '../img/logo.svg';

logoA.appendChild(logo);
menucontainer.appendChild(logoA);

document.body.appendChild(hovermenu);

var headers = [];
var menuitems = [];

for (var i = 0; i < doc.children.length; i++) {
  var child = doc.children[i];

  if (~'H2 H3 H4'.split(' ').indexOf(child.tagName)) {
    headers.push(child);
    addItem(menu, child);
  } else if (child.tagName === 'PRE') {
    var code = child.querySelector('code');

    if (code.className === 'lang-html') {
      code.className = 'language-markup';
    } else if (code.className === 'lang-js') {
      code.className = 'language-javascript';
    }
  }
}

function addItem (menu, child) {
  var item = document.createElement('p');
  var link = document.createElement('a');
  var indentation = parseInt(child.tagName.slice(1), 10) - 2;

  if (indentation) {
    item.className = 'menu-item menu-sub-item';
  } else {
    item.className = 'menu-item';
  }
  item.style.paddingLeft = indentation + 'rem';

  link.textContent = child.textContent;

  link.href = '#' + child.id;
  item.appendChild(link);
  menucontainer.appendChild(item);
  menuitems.push(item);
}
menu.appendChild(menucontainer);
document.body.appendChild(menu);

window.addEventListener('resize', resize);

resize();

function resize () {
  if (window.innerWidth <= 640) {
    if (mobile) {
      return;
    }
    mobile = true;
    menu.style.display = 'none';
    menu.style.width = '100%';
    menu.style.textAlign = 'center';
    menu.style.fontSize = 'calc(1.5rem + 1px)';
    menucontainer.style.textAlign = 'left';
    menucontainer.style.display = 'inline-block';
    hovermenu.style.display = '';
    doc.style.left = 0;
  } else {
    if (!mobile) {
      return;
    }
    mobile = false;
    menu.style.display = '';
    menu.style.width = '';
    menu.style.textAlign = '';
    menu.style.fontSize = '';
    menucontainer.style.textAlign = '';
    menucontainer.style.display = '';
    hovermenu.style.display = 'none';
    doc.style.left = '';
    doc.classList.remove('pushin');
    doc.classList.remove('pushout');
    menu.classList.remove('slidein');
    menu.classList.remove('fadeout');
    menu.onclick = doc.onclick = null;
    document.body.style.overflow = '';
  }
}
<commit_msg>Use autoscroll to 25 % instead of 50 %<commit_after>var doc = document.getElementById('doc');
var menu = document.createElement('div');
var menucontainer = document.createElement('div');
var logoA = document.createElement('a');
var logo = document.createElement('img');
var hovermenu = document.createElement('div');
var mobile = false;

hovermenu.id = 'hovermenu';
hovermenu.textContent = 'Menu';
hovermenu.style.display = 'none';

hovermenu.onclick = function (e) {
  var targetMenuItem;
  for (var i = 0; i < headers.length; i++) {
    if (headers[i].getBoundingClientRect().top >= 0) {
      targetMenuItem = menuitems[i];
      break;
    }
  }

  document.body.style.overflow = 'hidden';
  menu.style.display = '';
  hovermenu.style.display = 'none';
  menu.scrollTop = targetMenuItem.offsetTop - window.innerHeight / 4;
  document.body.classList.add('pushout');
  menu.classList.remove('fadeout');
  menu.classList.add('slidein');
  doc.classList.remove('pushin');
  doc.classList.add('pushout');
  menu.onclick = doc.onclick = function (e) {
    menu.onclick = doc.onclick = null;
    menu.classList.add('fadeout');
    menu.classList.remove('slidein');
    menu.style.overflow = 'hidden';
    doc.classList.add('pushin');
    doc.classList.remove('pushout');
    hovermenu.style.display = '';
    window.onclick = null;
    document.body.style.overflow = '';
    setTimeout(function () {
      if (!mobile) {
        return;
      }
      menu.style.display = 'none';
      menu.style.overflow = '';
      menu.classList.remove('fadeout');
      doc.classList.remove('pushin');
    }, 500);
  };
};

menu.id = 'menu';
menucontainer.id = 'menucontainer';

logoA.href = 'https://redom.js.org';
logo.id = 'logo';
logo.src = '../img/logo.svg';

logoA.appendChild(logo);
menucontainer.appendChild(logoA);

document.body.appendChild(hovermenu);

var headers = [];
var menuitems = [];

for (var i = 0; i < doc.children.length; i++) {
  var child = doc.children[i];

  if (~'H2 H3 H4'.split(' ').indexOf(child.tagName)) {
    headers.push(child);
    addItem(menu, child);
  } else if (child.tagName === 'PRE') {
    var code = child.querySelector('code');

    if (code.className === 'lang-html') {
      code.className = 'language-markup';
    } else if (code.className === 'lang-js') {
      code.className = 'language-javascript';
    }
  }
}

function addItem (menu, child) {
  var item = document.createElement('p');
  var link = document.createElement('a');
  var indentation = parseInt(child.tagName.slice(1), 10) - 2;

  if (indentation) {
    item.className = 'menu-item menu-sub-item';
  } else {
    item.className = 'menu-item';
  }
  item.style.paddingLeft = indentation + 'rem';

  link.textContent = child.textContent;

  link.href = '#' + child.id;
  item.appendChild(link);
  menucontainer.appendChild(item);
  menuitems.push(item);
}
menu.appendChild(menucontainer);
document.body.appendChild(menu);

window.addEventListener('resize', resize);

resize();

function resize () {
  if (window.innerWidth <= 640) {
    if (mobile) {
      return;
    }
    mobile = true;
    menu.style.display = 'none';
    menu.style.width = '100%';
    menu.style.textAlign = 'center';
    menu.style.fontSize = 'calc(1.5rem + 1px)';
    menucontainer.style.textAlign = 'left';
    menucontainer.style.display = 'inline-block';
    hovermenu.style.display = '';
    doc.style.left = 0;
  } else {
    if (!mobile) {
      return;
    }
    mobile = false;
    menu.style.display = '';
    menu.style.width = '';
    menu.style.textAlign = '';
    menu.style.fontSize = '';
    menucontainer.style.textAlign = '';
    menucontainer.style.display = '';
    hovermenu.style.display = 'none';
    doc.style.left = '';
    doc.classList.remove('pushin');
    doc.classList.remove('pushout');
    menu.classList.remove('slidein');
    menu.classList.remove('fadeout');
    menu.onclick = doc.onclick = null;
    document.body.style.overflow = '';
  }
}
<|endoftext|>


<commit_before>(function () {
    var r = new RegExp("(^|(.*?\\/))(include-openlayers\.js)(\\?|$)"),
        s = document.getElementsByTagName('script'), targetScript;
    for (var i = 0; i < s.length; i++) {
        var src = s[i].getAttribute('src');
        if (src) {
            var m = src.match(r);
            if (m) {
                targetScript = s[i];
                break;
            }
        }
    }

    function inputScript(url) {
        var script = '<script type="text/javascript" src="' + url + '"><' + '/script>';
        document.writeln(script);
    }

    function inputCSS(url) {
        var css = '<link rel="stylesheet" href="' + url + '">';
        document.writeln(css);
    }

    function inArray(arr, item) {
        for (i in arr) {
            if (arr[i] == item) {
                return true;
            }
        }
        return false;
    }

    //加载类库资源文件
    function load() {
        var includes = (targetScript.getAttribute('include') || "").split(",");
        var excludes = (targetScript.getAttribute('exclude') || "").split(",");
        if (!inArray(excludes, 'ol')) {
            inputCSS("http://cdn.bootcss.com/openlayers/4.2.0/ol.css");
            inputScript("http://cdn.bootcss.com/openlayers/4.2.0/ol.js");
        }
        if (inArray(includes, 'mapv')) {
            inputScript("http://mapv.baidu.com/build/mapv.min.js");
        }
        if (inArray(includes, 'turf')) {
            inputScript("https://cdn.bootcss.com/Turf.js/4.6.1/turf.min.js");
        }
        if (!inArray(excludes, 'iclient9-openlayers')) {
            inputScript("../../dist/iclient9-openlayers.min.js");
        }
        if (!inArray(excludes, 'iclient9-openlayers-css')) {
            inputCSS("../../dist/iclient9-openlayers.min.css");
        }
        if (inArray(includes, 'echarts')) {
            inputScript("http://cdn.bootcss.com/echarts/3.6.2/echarts.min.js");
        }
        if (inArray(includes, 'osmbuildings')) {
            inputScript("http://iclient.supermapol.com/libs/osmbuildings/OSMBuildings-OL3.js");
        }
        if (inArray(includes, 'animatedclusterlayer')) {
            inputScript("http://viglino.github.io/OL3-AnimatedCluster/layer/animatedclusterlayer.js");
        }
        if (inArray(includes, 'datgui')) {
            inputScript("http://cdn.bootcss.com/dat-gui/0.6.5/dat.gui.js");
        }
    }

    load();
})();
<commit_msg>fix openlayers 聚合点图层三方库引用方式错误问题<commit_after>(function () {
    var r = new RegExp("(^|(.*?\\/))(include-openlayers\.js)(\\?|$)"),
        s = document.getElementsByTagName('script'), targetScript;
    for (var i = 0; i < s.length; i++) {
        var src = s[i].getAttribute('src');
        if (src) {
            var m = src.match(r);
            if (m) {
                targetScript = s[i];
                break;
            }
        }
    }

    function inputScript(url) {
        var script = '<script type="text/javascript" src="' + url + '"><' + '/script>';
        document.writeln(script);
    }

    function inputCSS(url) {
        var css = '<link rel="stylesheet" href="' + url + '">';
        document.writeln(css);
    }

    function inArray(arr, item) {
        for (i in arr) {
            if (arr[i] == item) {
                return true;
            }
        }
        return false;
    }

    //加载类库资源文件
    function load() {
        var includes = (targetScript.getAttribute('include') || "").split(",");
        var excludes = (targetScript.getAttribute('exclude') || "").split(",");
        if (!inArray(excludes, 'ol')) {
            inputCSS("http://cdn.bootcss.com/openlayers/4.2.0/ol.css");
            inputScript("http://cdn.bootcss.com/openlayers/4.2.0/ol.js");
        }
        if (inArray(includes, 'mapv')) {
            inputScript("http://mapv.baidu.com/build/mapv.min.js");
        }
        if (inArray(includes, 'turf')) {
            inputScript("https://cdn.bootcss.com/Turf.js/4.6.1/turf.min.js");
        }
        if (!inArray(excludes, 'iclient9-openlayers')) {
            inputScript("../../dist/iclient9-openlayers.min.js");
        }
        if (!inArray(excludes, 'iclient9-openlayers-css')) {
            inputCSS("../../dist/iclient9-openlayers.min.css");
        }
        if (inArray(includes, 'echarts')) {
            inputScript("http://cdn.bootcss.com/echarts/3.6.2/echarts.min.js");
        }
        if (inArray(includes, 'osmbuildings')) {
            inputScript("http://iclient.supermapol.com/libs/osmbuildings/OSMBuildings-OL3.js");
        }
        if (inArray(includes, 'animatedclusterlayer')) {
            inputScript("http://iclient.supermapol.com/libs/openlayers/plugins/animatedclusterlayer/animatedclusterlayer.js");
        }
        if (inArray(includes, 'datgui')) {
            inputScript("http://cdn.bootcss.com/dat-gui/0.6.5/dat.gui.js");
        }
    }

    load();
})();
<|endoftext|>


<commit_before>	function Typing(){
		this.className = "";
		this.stringName = "";
		this.typingSpeed = 50;
		this.cursorSpeed = 50;
	}

	Typing.prototype.init = function(className,typingSpeed,cursorSpeed,callback){
		this.className = className;
		this.typingSpeed = typingSpeed;
		this.cursorSpeed = cursorSpeed;
		this.callback = callback;
		$("."+this.className).append(""+"");
		$("."+this.className).append(""+"▍"+"");
	};

	Typing.prototype.add = function(stringName){
		this.stringName = stringName;
		var This = this;
		var count = 0;
		var show = true;
		var length = this.stringName.length;

		var charInterval = setInterval(function(){

	        $("."+This.className + " .typing-container").append(""+This.stringName.charAt(count)+"");
	        count++;
		        if (count == length) {
		        	clearInterval(charInterval);
		       		clearInterval(cursorInterval);
		        	return This;
		        }
			}, this.typingSpeed);

		var cursorInterval = setInterval(function(){
			if (show) {
				$("."+This.className + " .cursor").css("opacity",1);
				show = false;
			}
			else{
				$("."+This.className + " .cursor").css("opacity",0);
				show = true;
			}
		},this.cursorSpeed);
	}

	Typing.prototype.delete = function(charCount){

	}

<commit_msg>Delete typing-animate2.js<commit_after><|endoftext|>


<commit_before>lru = require('lru-cache');
/**
 * Given a function,
 * return a memoized version using an LRU cache
 *
 * n.b. functions that take functions as arguments, or rely
 * on "this" context, won't work properly
 *
 * The options parameter is simply the options for the LRU cache,
 * which may be expressed as a simple number for number of entries to cache.
 * The option property 'next' can specify a callback to pass results.
 * This parameter will not be passed on to the LRU cache.
 *
 * @param {Function} fn
 * @param {Object|Number} options
 * @return {Function}
 */
module.exports = function(fn, options) {

  var usesNext;
  if (typeof options === 'undefined') {
    options = 10000;
  } else if (typeof options === 'object' && options.next) {
    usesNext = options.next;
    delete options.next;
  }

  var cache = lru(options);

  if (usesNext) {
    /* asynchronous function, with callback as last argument */
    return function() {
      var args = Array.prototype.slice.call(arguments);
      var next = args.pop();
      var key = args.join('\x01');
      if (cache.has(key)) {
        return next(cache.get(key));
      } else {
        args.push(function(results) {
          cache.set(key, results);
          return next(results);
        });
        fn.apply(null, args);
      }
    };
  } else {
    /* synchronous function */
    return function() {
      var args = Array.prototype.slice.call(arguments);
      var key = args.join('\x01');
      var results;
      if (cache.has(key)) {
        results = cache.get(key);
      } else {
        results = fn.apply(null, args);
        cache.set(key, results);
      }
      return results;
    };
  }
};

<commit_msg>improved docs for next option<commit_after>lru = require('lru-cache');
/**
 * Given a function,
 * return a memoized version using an LRU cache
 *
 * n.b. functions that take functions as arguments, or rely
 * on "this" context, won't work properly
 *
 * The options parameter is simply the options for the LRU cache,
 * which may be expressed as a simple number for number of entries to cache.
 * A true value for the option property 'next' specifies that the
 * final argument for the function should be treated as a callback. This
 * is primarily useful for asynchronous functions.
 *
 * @param {Function} fn
 * @param {Object|Number} options
 * @return {Function}
 */
module.exports = function(fn, options) {

  var usesNext;
  if (typeof options === 'undefined') {
    options = 10000;
  } else if (typeof options === 'object' && options.next) {
    usesNext = options.next;
    delete options.next;
  }

  var cache = lru(options);

  if (usesNext) {
    /* asynchronous function, with callback as last argument */
    return function() {
      var args = Array.prototype.slice.call(arguments);
      var next = args.pop();
      var key = args.join('\x01');
      if (cache.has(key)) {
        return next(cache.get(key));
      } else {
        args.push(function(results) {
          cache.set(key, results);
          return next(results);
        });
        fn.apply(null, args);
      }
    };
  } else {
    /* synchronous function */
    return function() {
      var args = Array.prototype.slice.call(arguments);
      var key = args.join('\x01');
      var results;
      if (cache.has(key)) {
        results = cache.get(key);
      } else {
        results = fn.apply(null, args);
        cache.set(key, results);
      }
      return results;
    };
  }
};

<|endoftext|>


<commit_before>const buttonStart = document.getElementById('button_start')
const buttonStop = document.getElementById('button_stop')
const buttonResponse = document.getElementById('add_response')
let socket = io()
let modal
socket.emit('join', {'course_id': courseID})

function disableStart () {
  buttonStart.disabled = true
  buttonStop.disabled = false
}

function disableStop () {
  buttonStart.disabled = false
  buttonStop.disabled = true
}

if (sessionActive) {
  disableStart()
} else {
  disableStop()
}

buttonStart.onclick = function () {
  disableStart()

  console.log('SESSION START')
  let data = {'session_control': 'start', 'course_id': courseID}
  socket.emit('lecturer_send', data)
}

buttonStop.onclick = function () {
  disableStop()

  console.log('SESSION STOP')
  let data = {'session_control': 'stop', 'course_id': courseID}
  socket.emit('lecturer_send', data)
}

buttonResponse.onclick = function () {
  console.log('Entering response scope')
  let kField = $('#keywords')
  let rField = $('#response')
  if(kField.val() && rField.val() ) {
    console.log('Sending keyword/response')
    let data = {'keywords': kField.val(), 'response': rField.val(), 'course_id': courseID}
    console.log(data)
    socket.emit('lecturer_keyword_new', data);
    kField.val('')
    rField.val('')
  }
  return false
}

let actions = ['slow', 'fast', 'easy', 'hard']

socket.on('lecturer_recv', function (msg) {
  if (msg.hasOwnProperty('action')) {
    console.log(msg['action'])
    $('#text_' + msg['action'][0]).attr('data-badge', msg['action'][1])
    if ($.inArray(msg['action'][0], actions.slice(0, 2)) !== -1) {
      speed.data.datasets[0].data[actions.indexOf(msg['action'][0])] = parseInt($('#text_' + msg['action'][0]).attr('data-badge'))
      speed.update()
    } else {
      difficulty.data.datasets[0].data[actions.indexOf(msg['action'][0]) - 2] = parseInt($('#text_' + msg['action'][0]).attr('data-badge'))
      difficulty.update()
    }
  } else if (msg.hasOwnProperty('question')) {
    let question = msg['question'][0]
    let groupNum = msg['question'][1]
    let questionList = $('#questions-' + groupNum)
    if (!questionList.length) {
      questionList = $('
', {id: 'questions-' + groupNum, 'class': 'mdl-list'})
      let questionLog = $('.questions-log')
      questionLog.prepend('
')
      questionLog.prepend(questionList)
    }
    questionList.prepend('
person' + question + '
')
  } else if (msg.hasOwnProperty('active')) {
    console.log(msg['active'])
    if (msg['active']) {
      disableStart()
    } else {
      disableStop()
    }
  } else if (msg.hasOwnProperty('command')) {
    if (msg['command'] === 'deleteQuestions') {
      $('.questions-log').empty()
    }
  }
})

let ctxSpeed = $('#speed')

let speed = new Chart(ctxSpeed, {
  type: 'doughnut',
  data: {
    datasets: [{
      data: [
        parseInt($('#text_slow').attr('data-badge')),
        parseInt($('#text_fast').attr('data-badge'))
      ],
      backgroundColor: [
        'rgba(172, 236, 0, 0.75)',
        'rgba(0, 187, 214, 0.75)'
      ]
    }],
    labels: [
      'Slow',
      'Fast'
    ]
  },
  options: {
    responsive: false
  }
})

let ctxDifficulty = $('#difficulty')

let difficulty = new Chart(ctxDifficulty, {
  type: 'doughnut',
  data: {
    datasets: [{
      data: [
        parseInt($('#text_easy').attr('data-badge')),
        parseInt($('#text_hard').attr('data-badge'))
      ],
      backgroundColor: [
        'rgba(186, 101, 201, 0.75)',
        'rgba(239, 60, 121, 0.75)'
      ]
    }],
    labels: [
      'Easy',
      'Hard'
    ]
  },
  options: {
    responsive: false
  }
})

let dialog = document.querySelector('dialog')
let showDialogButton = document.querySelector('#show-dialog')
if (!dialog.showModal) {
    dialogPolyfill.registerDialog(dialog)
}
showDialogButton.addEventListener('click', function () {
    dialog.showModal()
    modal = true
})
dialog.querySelector('.close').addEventListener('click', function () {
    dialog.close()
    modal = false
})

socket.on('new_response', function (msg) {
  console.log('new response received')
  localStorage.setItem('modal_open', modal)
  if(msg.hasOwnProperty('reload')) {
    if(msg['reload']) {
      window.location.reload(true)
    }
  }
})

$('form').keydown(function (e) {
  if (e.keyCode === 13 && !e.shiftKey) {
    e.preventDefault()
    buttonResponse.click()
  }
})
<commit_msg>Documentation, kinda<commit_after>const buttonStart = document.getElementById('button_start')
const buttonStop = document.getElementById('button_stop')
const buttonResponse = document.getElementById('add_response')
let socket = io()
let modal
socket.emit('join', {'course_id': courseID})

function disableStart () {
  buttonStart.disabled = true
  buttonStop.disabled = false
}

function disableStop () {
  buttonStart.disabled = false
  buttonStop.disabled = true
}

if (sessionActive) {
  disableStart()
} else {
  disableStop()
}

buttonStart.onclick = function () {
  disableStart()

  console.log('SESSION START')
  let data = {'session_control': 'start', 'course_id': courseID}
  socket.emit('lecturer_send', data)
}

buttonStop.onclick = function () {
  disableStop()

  console.log('SESSION STOP')
  let data = {'session_control': 'stop', 'course_id': courseID}
  socket.emit('lecturer_send', data)
}

buttonResponse.onclick = function () {
  console.log('Entering response scope')
  let kField = $('#keywords')
  let rField = $('#response')
  if(kField.val() && rField.val() ) {
    console.log('Sending keyword/response')
    let data = {'keywords': kField.val(), 'response': rField.val(), 'course_id': courseID}
    console.log(data)
    socket.emit('lecturer_keyword_new', data);
    kField.val('')
    rField.val('')
  }
  return false
}

let actions = ['slow', 'fast', 'easy', 'hard']

socket.on('lecturer_recv', function (msg) {
  if (msg.hasOwnProperty('action')) {
    console.log(msg['action'])
    $('#text_' + msg['action'][0]).attr('data-badge', msg['action'][1])
    if ($.inArray(msg['action'][0], actions.slice(0, 2)) !== -1) {
      speed.data.datasets[0].data[actions.indexOf(msg['action'][0])] = parseInt($('#text_' + msg['action'][0]).attr('data-badge'))
      speed.update()
    } else {
      difficulty.data.datasets[0].data[actions.indexOf(msg['action'][0]) - 2] = parseInt($('#text_' + msg['action'][0]).attr('data-badge'))
      difficulty.update()
    }
  } else if (msg.hasOwnProperty('question')) {
    let question = msg['question'][0]
    let groupNum = msg['question'][1]
    let questionList = $('#questions-' + groupNum)
    if (!questionList.length) {
      questionList = $('
', {id: 'questions-' + groupNum, 'class': 'mdl-list'})
      let questionLog = $('.questions-log')
      questionLog.prepend('
')
      questionLog.prepend(questionList)
    }
    questionList.prepend('
person' + question + '
')
  } else if (msg.hasOwnProperty('active')) {
    console.log(msg['active'])
    if (msg['active']) {
      disableStart()
    } else {
      disableStop()
    }
  } else if (msg.hasOwnProperty('command')) {
    if (msg['command'] === 'deleteQuestions') {
      $('.questions-log').empty()
    }
  }
})

let ctxSpeed = $('#speed')

let speed = new Chart(ctxSpeed, {
  type: 'doughnut',
  data: {
    datasets: [{
      data: [
        parseInt($('#text_slow').attr('data-badge')),
        parseInt($('#text_fast').attr('data-badge'))
      ],
      backgroundColor: [
        'rgba(172, 236, 0, 0.75)',
        'rgba(0, 187, 214, 0.75)'
      ]
    }],
    labels: [
      'Slow',
      'Fast'
    ]
  },
  options: {
    responsive: false
  }
})

let ctxDifficulty = $('#difficulty')

let difficulty = new Chart(ctxDifficulty, {
  type: 'doughnut',
  data: {
    datasets: [{
      data: [
        parseInt($('#text_easy').attr('data-badge')),
        parseInt($('#text_hard').attr('data-badge'))
      ],
      backgroundColor: [
        'rgba(186, 101, 201, 0.75)',
        'rgba(239, 60, 121, 0.75)'
      ]
    }],
    labels: [
      'Easy',
      'Hard'
    ]
  },
  options: {
    responsive: false
  }
})

let dialog = document.querySelector('dialog')
let showDialogButton = document.querySelector('#show-dialog')
if (!dialog.showModal) {
    dialogPolyfill.registerDialog(dialog)
}
showDialogButton.addEventListener('click', function () {
    dialog.showModal()
    modal = true
})
dialog.querySelector('.close').addEventListener('click', function () {
    dialog.close()
    modal = false
})

socket.on('new_response', function (msg) {
  console.log('new response received')
  localStorage.setItem('modal_open', modal)
  if(msg.hasOwnProperty('reload')) {
    if(msg['reload']) {
      window.location.reload(true)
    }
  }
})

//Disables newline on enter, allows shift-enter
$('form').keydown(function (e) {
  if (e.keyCode === 13 && !e.shiftKey) {
    e.preventDefault()
    buttonResponse.click()
  }
})
<|endoftext|>


<commit_before>// component test
import jsdom from "mocha-jsdom";
import assert from "assert";
import React from "react";
import ReactTestUtils from "react-addons-test-utils";

import HelloWorld from "../src/components/HelloWorld.jsx";

describe("HelloWorld component", () => {

  jsdom();

  it("should exist", () => {
    assert.ok( !!HelloWorld );
  });

  it("should be react element", () => {
    assert.ok( ReactTestUtils.isElement(<HelloWorld />),
      "is not a react element" );
  });

});
<commit_msg>Add DOM test case<commit_after>// component test
import jsdom from "mocha-jsdom";
import assert from "assert";
import React from "react";
import ReactDOM from "react-dom";
import ReactTestUtils from "react-addons-test-utils";

import HelloWorld from "../src/components/HelloWorld.jsx";

describe("HelloWorld component", () => {

  jsdom();

  it("should exist", () => {
    assert.ok( !!HelloWorld );
  });

  it("should be react element", () => {
    assert.ok( ReactTestUtils.isElement(<HelloWorld />),
      "is not a react element" );
  });

  describe("rendering", () => {

    it("should display 'text' prop in DOM somehow", () => {
      const container = document.createElement("div");
      ReactDOM.render(<HelloWorld text="TEST" />, container);
      assert.ok( /TEST/.test(container.innerHTML), "It don't displays 'text' prop in DOM");
    });

  });

});
<|endoftext|>


<commit_before>import BaseControllerMixin from 'mixins/baseControllerMixin';
import PaginationSupport from 'mixins/paginationSupport';
import ProgressIndicator from 'progressIndicator';

export default Ember.ObjectController.extend(BaseControllerMixin, PaginationSupport, {
    totalBinding: Ember.Binding.oneWay('model.totalHits'),
    pageBinding: 'model.page',
    sort: 'score',

    isEmptyQuery: function() {
        return Ember.isEmpty(this.get('query'));
    }.property('query'),

    goTo: function(query) {
        if (Ember.isEmpty(query)) {
            this.transitionToRoute('packages.list');
            return;
        }

        var model = this._search(query);
        this.transitionToRoute('packages.search', model);
    },

    update: function(query, page) {
        var model = this._search(query, page);
        var self = this;

        model.then(function() {
            self.set('model', model);
        });
    },

    _search: function(query, page) {
        page = page || 0;
        var completed = false;

        setTimeout(function() {
            if (!completed) {
                ProgressIndicator.start();
            }
        }, 250);

        return App.packages.search(query, page, this.get('pageSize'), this.get('sort'))
            .then(function(model) {
                completed = true;
                ProgressIndicator.done();
                return model;
            });
    },

    actions: {
        'nextPage': function() {
            this.update(this.get('query'), this.get('page') + 1);
        },
        'previousPage': function () {
            this.update(this.get('query'), this.get('page') - 1);
        },
        'goTo': function () {
            this.goTo.apply(this, arguments);
        },
    },
});
<commit_msg>Don’t set new model until it is resolved.<commit_after>import BaseControllerMixin from 'mixins/baseControllerMixin';
import PaginationSupport from 'mixins/paginationSupport';
import ProgressIndicator from 'progressIndicator';

export default Ember.ObjectController.extend(BaseControllerMixin, PaginationSupport, {
    totalBinding: Ember.Binding.oneWay('model.totalHits'),
    pageBinding: 'model.page',
    sort: 'score',

    isEmptyQuery: function() {
        return Ember.isEmpty(this.get('query'));
    }.property('query'),

    goTo: function(query) {
        if (Ember.isEmpty(query)) {
            this.transitionToRoute('packages.list');
        } else {
            var model = this._search(query);
            this.transitionToRoute('packages.search', model);
        }
    },

    update: function(query, page) {
        var self = this;
        this._search(query, page).then(function(model) {
            self.set('model', model);
        });
    },

    _search: function(query, page) {
        page = page || 0;
        var completed = false;

        setTimeout(function() {
            if (!completed) {
                ProgressIndicator.start();
            }
        }, 250);

        return App.packages.search(query, page, this.get('pageSize'), this.get('sort'))
            .then(function(model) {
                completed = true;
                ProgressIndicator.done();
                return model;
            });
    },

    actions: {
        'nextPage': function() {
            this.update(this.get('query'), this.get('page') + 1);
        },
        'previousPage': function () {
            this.update(this.get('query'), this.get('page') - 1);
        },
        'goTo': function () {
            this.goTo.apply(this, arguments);
        },
    },
});
<|endoftext|>


<commit_before>var handler = function(compileStep) {
	console.log('compile step');
	console.log(compileStep);
}

Plugin.registerSourceHandler("js", handler);<commit_msg>pseudo log<commit_after>console.log('Running code-separator');

var handler = function(compileStep) {
	console.log('compile step');
	console.log(compileStep);
}

Plugin.registerSourceHandler("js", handler);<|endoftext|>


<commit_before><commit_msg>Added jsdoc<commit_after><|endoftext|>


<commit_before>define([
    "dojo/_base/declare",
], function(declare){
    return declare('test.data.serviceResponses.testService.ControllerTestMethod', null, {
        processRequest : function(params) {
            var status = params.status;
            if (status == 200) {
                return {payload : params, isOk : true};
            } else if (status == 400) {
                return {payload : params, isInvalid : true};
            } else if (status == 403) {
                return {payload : params, isUnauthorised : true};
            } else if (status == 409) {
                return {payload : params, isConflicted : true};
            } else if (status == 123) {
                return {};
            }
        }
    });
});
<commit_msg>Remove trailing comma, oops<commit_after>define([
    "dojo/_base/declare"
], function(declare){
    return declare('test.data.serviceResponses.testService.ControllerTestMethod', null, {
        processRequest : function(params) {
            var status = params.status;
            if (status == 200) {
                return {payload : params, isOk : true};
            } else if (status == 400) {
                return {payload : params, isInvalid : true};
            } else if (status == 403) {
                return {payload : params, isUnauthorised : true};
            } else if (status == 409) {
                return {payload : params, isConflicted : true};
            } else if (status == 123) {
                return {};
            }
        }
    });
});
<|endoftext|>