source: Dev/trunk/src/client/util/less/dist/less-1.3.3.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 147.9 KB
Line 
1//
2// LESS - Leaner CSS v1.3.3
3// http://lesscss.org
4//
5// Copyright (c) 2009-2011, Alexis Sellier
6// Licensed under the Apache 2.0 License.
7//
8(function (window, undefined) {
9//
10// Stub out `require` in the browser
11//
12function require(arg) {
13    return window.less[arg.split('/')[1]];
14};
15
16
17// ecma-5.js
18//
19// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
20// -- tlrobinson Tom Robinson
21// dantman Daniel Friesen
22
23//
24// Array
25//
26if (!Array.isArray) {
27    Array.isArray = function(obj) {
28        return Object.prototype.toString.call(obj) === "[object Array]" ||
29               (obj instanceof Array);
30    };
31}
32if (!Array.prototype.forEach) {
33    Array.prototype.forEach =  function(block, thisObject) {
34        var len = this.length >>> 0;
35        for (var i = 0; i < len; i++) {
36            if (i in this) {
37                block.call(thisObject, this[i], i, this);
38            }
39        }
40    };
41}
42if (!Array.prototype.map) {
43    Array.prototype.map = function(fun /*, thisp*/) {
44        var len = this.length >>> 0;
45        var res = new Array(len);
46        var thisp = arguments[1];
47
48        for (var i = 0; i < len; i++) {
49            if (i in this) {
50                res[i] = fun.call(thisp, this[i], i, this);
51            }
52        }
53        return res;
54    };
55}
56if (!Array.prototype.filter) {
57    Array.prototype.filter = function (block /*, thisp */) {
58        var values = [];
59        var thisp = arguments[1];
60        for (var i = 0; i < this.length; i++) {
61            if (block.call(thisp, this[i])) {
62                values.push(this[i]);
63            }
64        }
65        return values;
66    };
67}
68if (!Array.prototype.reduce) {
69    Array.prototype.reduce = function(fun /*, initial*/) {
70        var len = this.length >>> 0;
71        var i = 0;
72
73        // no value to return if no initial value and an empty array
74        if (len === 0 && arguments.length === 1) throw new TypeError();
75
76        if (arguments.length >= 2) {
77            var rv = arguments[1];
78        } else {
79            do {
80                if (i in this) {
81                    rv = this[i++];
82                    break;
83                }
84                // if array contains no values, no initial value to return
85                if (++i >= len) throw new TypeError();
86            } while (true);
87        }
88        for (; i < len; i++) {
89            if (i in this) {
90                rv = fun.call(null, rv, this[i], i, this);
91            }
92        }
93        return rv;
94    };
95}
96if (!Array.prototype.indexOf) {
97    Array.prototype.indexOf = function (value /*, fromIndex */ ) {
98        var length = this.length;
99        var i = arguments[1] || 0;
100
101        if (!length)     return -1;
102        if (i >= length) return -1;
103        if (i < 0)       i += length;
104
105        for (; i < length; i++) {
106            if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
107            if (value === this[i]) return i;
108        }
109        return -1;
110    };
111}
112
113//
114// Object
115//
116if (!Object.keys) {
117    Object.keys = function (object) {
118        var keys = [];
119        for (var name in object) {
120            if (Object.prototype.hasOwnProperty.call(object, name)) {
121                keys.push(name);
122            }
123        }
124        return keys;
125    };
126}
127
128//
129// String
130//
131if (!String.prototype.trim) {
132    String.prototype.trim = function () {
133        return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
134    };
135}
136var less, tree, charset;
137
138if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
139    // Rhino
140    // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
141    if (typeof(window) === 'undefined') { less = {} }
142    else                                { less = window.less = {} }
143    tree = less.tree = {};
144    less.mode = 'rhino';
145} else if (typeof(window) === 'undefined') {
146    // Node.js
147    less = exports,
148    tree = require('./tree');
149    less.mode = 'node';
150} else {
151    // Browser
152    if (typeof(window.less) === 'undefined') { window.less = {} }
153    less = window.less,
154    tree = window.less.tree = {};
155    less.mode = 'browser';
156}
157//
158// less.js - parser
159//
160//    A relatively straight-forward predictive parser.
161//    There is no tokenization/lexing stage, the input is parsed
162//    in one sweep.
163//
164//    To make the parser fast enough to run in the browser, several
165//    optimization had to be made:
166//
167//    - Matching and slicing on a huge input is often cause of slowdowns.
168//      The solution is to chunkify the input into smaller strings.
169//      The chunks are stored in the `chunks` var,
170//      `j` holds the current chunk index, and `current` holds
171//      the index of the current chunk in relation to `input`.
172//      This gives us an almost 4x speed-up.
173//
174//    - In many cases, we don't need to match individual tokens;
175//      for example, if a value doesn't hold any variables, operations
176//      or dynamic references, the parser can effectively 'skip' it,
177//      treating it as a literal.
178//      An example would be '1px solid #000' - which evaluates to itself,
179//      we don't need to know what the individual components are.
180//      The drawback, of course is that you don't get the benefits of
181//      syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
182//      and a smaller speed-up in the code-gen.
183//
184//
185//    Token matching is done with the `$` function, which either takes
186//    a terminal string or regexp, or a non-terminal function to call.
187//    It also takes care of moving all the indices forwards.
188//
189//
190less.Parser = function Parser(env) {
191    var input,       // LeSS input string
192        i,           // current index in `input`
193        j,           // current chunk
194        temp,        // temporarily holds a chunk's state, for backtracking
195        memo,        // temporarily holds `i`, when backtracking
196        furthest,    // furthest index the parser has gone to
197        chunks,      // chunkified input
198        current,     // index of current chunk, in `input`
199        parser;
200
201    var that = this;
202
203    // Top parser on an import tree must be sure there is one "env"
204    // which will then be passed arround by reference.
205    var env = env || { };
206    // env.contents and files must be passed arround with top env
207    if (!env.contents) { env.contents = {}; }
208    env.rootpath = env.rootpath || '';       // env.rootpath must be initialized to '' if not provided
209    if (!env.files) { env.files = {}; }
210
211    // This function is called after all files
212    // have been imported through `@import`.
213    var finish = function () {};
214
215    var imports = this.imports = {
216        paths: env.paths || [],  // Search paths, when importing
217        queue: [],               // Files which haven't been imported yet
218        files: env.files,        // Holds the imported parse trees
219        contents: env.contents,  // Holds the imported file contents
220        mime:  env.mime,         // MIME type of .less files
221        error: null,             // Error in parsing/evaluating an import
222        push: function (path, callback) {
223            var that = this;
224            this.queue.push(path);
225
226            //
227            // Import a file asynchronously
228            //
229            less.Parser.importer(path, this.paths, function (e, root, fullPath) {
230                that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
231
232                var imported = fullPath in that.files;
233
234                that.files[fullPath] = root;                        // Store the root
235
236                if (e && !that.error) { that.error = e }
237
238                callback(e, root, imported);
239
240                if (that.queue.length === 0) { finish(that.error) }       // Call `finish` if we're done importing
241            }, env);
242        }
243    };
244
245    function save()    { temp = chunks[j], memo = i, current = i }
246    function restore() { chunks[j] = temp, i = memo, current = i }
247
248    function sync() {
249        if (i > current) {
250            chunks[j] = chunks[j].slice(i - current);
251            current = i;
252        }
253    }
254    function isWhitespace(c) {
255        // Could change to \s?
256        var code = c.charCodeAt(0);
257        return code === 32 || code === 10 || code === 9;
258    }
259    //
260    // Parse from a token, regexp or string, and move forward if match
261    //
262    function $(tok) {
263        var match, args, length, index, k;
264
265        //
266        // Non-terminal
267        //
268        if (tok instanceof Function) {
269            return tok.call(parser.parsers);
270        //
271        // Terminal
272        //
273        //     Either match a single character in the input,
274        //     or match a regexp in the current chunk (chunk[j]).
275        //
276        } else if (typeof(tok) === 'string') {
277            match = input.charAt(i) === tok ? tok : null;
278            length = 1;
279            sync ();
280        } else {
281            sync ();
282
283            if (match = tok.exec(chunks[j])) {
284                length = match[0].length;
285            } else {
286                return null;
287            }
288        }
289
290        // The match is confirmed, add the match length to `i`,
291        // and consume any extra white-space characters (' ' || '\n')
292        // which come after that. The reason for this is that LeSS's
293        // grammar is mostly white-space insensitive.
294        //
295        if (match) {
296            skipWhitespace(length);
297
298            if(typeof(match) === 'string') {
299                return match;
300            } else {
301                return match.length === 1 ? match[0] : match;
302            }
303        }
304    }
305
306    function skipWhitespace(length) {
307        var oldi = i, oldj = j,
308            endIndex = i + chunks[j].length,
309            mem = i += length;
310
311        while (i < endIndex) {
312            if (! isWhitespace(input.charAt(i))) { break }
313            i++;
314        }
315        chunks[j] = chunks[j].slice(length + (i - mem));
316        current = i;
317
318        if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
319
320        return oldi !== i || oldj !== j;
321    }
322
323    function expect(arg, msg) {
324        var result = $(arg);
325        if (! result) {
326            error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
327                                                   : "unexpected token"));
328        } else {
329            return result;
330        }
331    }
332
333    function error(msg, type) {
334        var e = new Error(msg);
335        e.index = i;
336        e.type = type || 'Syntax';
337        throw e;
338    }
339
340    // Same as $(), but don't change the state of the parser,
341    // just return the match.
342    function peek(tok) {
343        if (typeof(tok) === 'string') {
344            return input.charAt(i) === tok;
345        } else {
346            if (tok.test(chunks[j])) {
347                return true;
348            } else {
349                return false;
350            }
351        }
352    }
353
354    function getInput(e, env) {
355        if (e.filename && env.filename && (e.filename !== env.filename)) {
356            return parser.imports.contents[e.filename];
357        } else {
358            return input;
359        }
360    }
361
362    function getLocation(index, input) {
363        for (var n = index, column = -1;
364                 n >= 0 && input.charAt(n) !== '\n';
365                 n--) { column++ }
366
367        return { line:   typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
368                 column: column };
369    }
370
371    function getFileName(e) {
372        if(less.mode === 'browser' || less.mode === 'rhino')
373            return e.filename;
374        else
375            return require('path').resolve(e.filename);
376    }
377
378    function getDebugInfo(index, inputStream, e) {
379        return {
380            lineNumber: getLocation(index, inputStream).line + 1,
381            fileName: getFileName(e)
382        };
383    }
384
385    function LessError(e, env) {
386        var input = getInput(e, env),
387            loc = getLocation(e.index, input),
388            line = loc.line,
389            col  = loc.column,
390            lines = input.split('\n');
391
392        this.type = e.type || 'Syntax';
393        this.message = e.message;
394        this.filename = e.filename || env.filename;
395        this.index = e.index;
396        this.line = typeof(line) === 'number' ? line + 1 : null;
397        this.callLine = e.call && (getLocation(e.call, input).line + 1);
398        this.callExtract = lines[getLocation(e.call, input).line];
399        this.stack = e.stack;
400        this.column = col;
401        this.extract = [
402            lines[line - 1],
403            lines[line],
404            lines[line + 1]
405        ];
406    }
407
408    this.env = env = env || {};
409
410    // The optimization level dictates the thoroughness of the parser,
411    // the lower the number, the less nodes it will create in the tree.
412    // This could matter for debugging, or if you want to access
413    // the individual nodes in the tree.
414    this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
415
416    this.env.filename = this.env.filename || null;
417
418    //
419    // The Parser
420    //
421    return parser = {
422
423        imports: imports,
424        //
425        // Parse an input string into an abstract syntax tree,
426        // call `callback` when done.
427        //
428        parse: function (str, callback) {
429            var root, start, end, zone, line, lines, buff = [], c, error = null;
430
431            i = j = current = furthest = 0;
432            input = str.replace(/\r\n/g, '\n');
433
434            // Remove potential UTF Byte Order Mark
435            input = input.replace(/^\uFEFF/, '');
436
437            // Split the input into chunks.
438            chunks = (function (chunks) {
439                var j = 0,
440                    skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
441                    comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
442                    string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
443                    level = 0,
444                    match,
445                    chunk = chunks[0],
446                    inParam;
447
448                for (var i = 0, c, cc; i < input.length;) {
449                    skip.lastIndex = i;
450                    if (match = skip.exec(input)) {
451                        if (match.index === i) {
452                            i += match[0].length;
453                            chunk.push(match[0]);
454                        }
455                    }
456                    c = input.charAt(i);
457                    comment.lastIndex = string.lastIndex = i;
458
459                    if (match = string.exec(input)) {
460                        if (match.index === i) {
461                            i += match[0].length;
462                            chunk.push(match[0]);
463                            continue;
464                        }
465                    }
466
467                    if (!inParam && c === '/') {
468                        cc = input.charAt(i + 1);
469                        if (cc === '/' || cc === '*') {
470                            if (match = comment.exec(input)) {
471                                if (match.index === i) {
472                                    i += match[0].length;
473                                    chunk.push(match[0]);
474                                    continue;
475                                }
476                            }
477                        }
478                    }
479                   
480                    switch (c) {
481                        case '{': if (! inParam) { level ++;        chunk.push(c);                           break }
482                        case '}': if (! inParam) { level --;        chunk.push(c); chunks[++j] = chunk = []; break }
483                        case '(': if (! inParam) { inParam = true;  chunk.push(c);                           break }
484                        case ')': if (  inParam) { inParam = false; chunk.push(c);                           break }
485                        default:                                    chunk.push(c);
486                    }
487                   
488                    i++;
489                }
490                if (level != 0) {
491                    error = new(LessError)({
492                        index: i-1,
493                        type: 'Parse',
494                        message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
495                        filename: env.filename
496                    }, env);
497                }
498
499                return chunks.map(function (c) { return c.join('') });;
500            })([[]]);
501
502            if (error) {
503                return callback(error, env);
504            }
505
506            // Start with the primary rule.
507            // The whole syntax tree is held under a Ruleset node,
508            // with the `root` property set to true, so no `{}` are
509            // output. The callback is called when the input is parsed.
510            try {
511                root = new(tree.Ruleset)([], $(this.parsers.primary));
512                root.root = true;
513            } catch (e) {
514                return callback(new(LessError)(e, env));
515            }
516
517            root.toCSS = (function (evaluate) {
518                var line, lines, column;
519
520                return function (options, variables) {
521                    var frames = [], importError;
522
523                    options = options || {};
524                    //
525                    // Allows setting variables with a hash, so:
526                    //
527                    //   `{ color: new(tree.Color)('#f01') }` will become:
528                    //
529                    //   new(tree.Rule)('@color',
530                    //     new(tree.Value)([
531                    //       new(tree.Expression)([
532                    //         new(tree.Color)('#f01')
533                    //       ])
534                    //     ])
535                    //   )
536                    //
537                    if (typeof(variables) === 'object' && !Array.isArray(variables)) {
538                        variables = Object.keys(variables).map(function (k) {
539                            var value = variables[k];
540
541                            if (! (value instanceof tree.Value)) {
542                                if (! (value instanceof tree.Expression)) {
543                                    value = new(tree.Expression)([value]);
544                                }
545                                value = new(tree.Value)([value]);
546                            }
547                            return new(tree.Rule)('@' + k, value, false, 0);
548                        });
549                        frames = [new(tree.Ruleset)(null, variables)];
550                    }
551
552                    try {
553                        var css = evaluate.call(this, { frames: frames })
554                                          .toCSS([], { compress: options.compress || false, dumpLineNumbers: env.dumpLineNumbers });
555                    } catch (e) {
556                        throw new(LessError)(e, env);
557                    }
558
559                    if ((importError = parser.imports.error)) { // Check if there was an error during importing
560                        if (importError instanceof LessError) throw importError;
561                        else                                  throw new(LessError)(importError, env);
562                    }
563
564                    if (options.yuicompress && less.mode === 'node') {
565                        return require('ycssmin').cssmin(css);
566                    } else if (options.compress) {
567                        return css.replace(/(\s)+/g, "$1");
568                    } else {
569                        return css;
570                    }
571                };
572            })(root.eval);
573
574            // If `i` is smaller than the `input.length - 1`,
575            // it means the parser wasn't able to parse the whole
576            // string, so we've got a parsing error.
577            //
578            // We try to extract a \n delimited string,
579            // showing the line where the parse error occured.
580            // We split it up into two parts (the part which parsed,
581            // and the part which didn't), so we can color them differently.
582            if (i < input.length - 1) {
583                i = furthest;
584                lines = input.split('\n');
585                line = (input.slice(0, i).match(/\n/g) || "").length + 1;
586
587                for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
588
589                error = {
590                    type: "Parse",
591                    message: "Syntax Error on line " + line,
592                    index: i,
593                    filename: env.filename,
594                    line: line,
595                    column: column,
596                    extract: [
597                        lines[line - 2],
598                        lines[line - 1],
599                        lines[line]
600                    ]
601                };
602            }
603
604            if (this.imports.queue.length > 0) {
605                finish = function (e) {
606                    e = error || e;
607                    if (e) callback(e);
608                    else callback(null, root);
609                };
610            } else {
611                callback(error, root);
612            }
613        },
614
615        //
616        // Here in, the parsing rules/functions
617        //
618        // The basic structure of the syntax tree generated is as follows:
619        //
620        //   Ruleset ->  Rule -> Value -> Expression -> Entity
621        //
622        // Here's some LESS code:
623        //
624        //    .class {
625        //      color: #fff;
626        //      border: 1px solid #000;
627        //      width: @w + 4px;
628        //      > .child {...}
629        //    }
630        //
631        // And here's what the parse tree might look like:
632        //
633        //     Ruleset (Selector '.class', [
634        //         Rule ("color",  Value ([Expression [Color #fff]]))
635        //         Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
636        //         Rule ("width",  Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
637        //         Ruleset (Selector [Element '>', '.child'], [...])
638        //     ])
639        //
640        //  In general, most rules will try to parse a token with the `$()` function, and if the return
641        //  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
642        //  first, before parsing, that's when we use `peek()`.
643        //
644        parsers: {
645            //
646            // The `primary` rule is the *entry* and *exit* point of the parser.
647            // The rules here can appear at any level of the parse tree.
648            //
649            // The recursive nature of the grammar is an interplay between the `block`
650            // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
651            // as represented by this simplified grammar:
652            //
653            //     primary  →  (ruleset | rule)+
654            //     ruleset  →  selector+ block
655            //     block    →  '{' primary '}'
656            //
657            // Only at one point is the primary rule not called from the
658            // block rule: at the root level.
659            //
660            primary: function () {
661                var node, root = [];
662
663                while ((node = $(this.mixin.definition) || $(this.rule)    ||  $(this.ruleset) ||
664                               $(this.mixin.call)       || $(this.comment) ||  $(this.directive))
665                               || $(/^[\s\n]+/) || $(/^;+/)) {
666                    node && root.push(node);
667                }
668                return root;
669            },
670
671            // We create a Comment node for CSS comments `/* */`,
672            // but keep the LeSS comments `//` silent, by just skipping
673            // over them.
674            comment: function () {
675                var comment;
676
677                if (input.charAt(i) !== '/') return;
678
679                if (input.charAt(i + 1) === '/') {
680                    return new(tree.Comment)($(/^\/\/.*/), true);
681                } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
682                    return new(tree.Comment)(comment);
683                }
684            },
685
686            //
687            // Entities are tokens which can be found inside an Expression
688            //
689            entities: {
690                //
691                // A string, which supports escaping " and '
692                //
693                //     "milky way" 'he\'s the one!'
694                //
695                quoted: function () {
696                    var str, j = i, e;
697
698                    if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
699                    if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
700
701                    e && $('~');
702
703                    if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
704                        return new(tree.Quoted)(str[0], str[1] || str[2], e);
705                    }
706                },
707
708                //
709                // A catch-all word, such as:
710                //
711                //     black border-collapse
712                //
713                keyword: function () {
714                    var k;
715
716                    if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
717                        if (tree.colors.hasOwnProperty(k)) {
718                            // detect named color
719                            return new(tree.Color)(tree.colors[k].slice(1));
720                        } else {
721                            return new(tree.Keyword)(k);
722                        }
723                    }
724                },
725
726                //
727                // A function call
728                //
729                //     rgb(255, 0, 255)
730                //
731                // We also try to catch IE's `alpha()`, but let the `alpha` parser
732                // deal with the details.
733                //
734                // The arguments are parsed with the `entities.arguments` parser.
735                //
736                call: function () {
737                    var name, nameLC, args, alpha_ret, index = i;
738
739                    if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
740
741                    name = name[1];
742                    nameLC = name.toLowerCase();
743
744                    if (nameLC === 'url') { return null }
745                    else                { i += name.length }
746
747                    if (nameLC === 'alpha') {
748                        alpha_ret = $(this.alpha);
749                        if(typeof alpha_ret !== 'undefined') {
750                            return alpha_ret;
751                        }
752                    }
753
754                    $('('); // Parse the '(' and consume whitespace.
755
756                    args = $(this.entities.arguments);
757
758                    if (! $(')')) return;
759
760                    if (name) { return new(tree.Call)(name, args, index, env.filename) }
761                },
762                arguments: function () {
763                    var args = [], arg;
764
765                    while (arg = $(this.entities.assignment) || $(this.expression)) {
766                        args.push(arg);
767                        if (! $(',')) { break }
768                    }
769                    return args;
770                },
771                literal: function () {
772                    return $(this.entities.ratio) ||
773                           $(this.entities.dimension) ||
774                           $(this.entities.color) ||
775                           $(this.entities.quoted) ||
776                           $(this.entities.unicodeDescriptor);
777                },
778
779                // Assignments are argument entities for calls.
780                // They are present in ie filter properties as shown below.
781                //
782                //     filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
783                //
784
785                assignment: function () {
786                    var key, value;
787                    if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
788                        return new(tree.Assignment)(key, value);
789                    }
790                },
791
792                //
793                // Parse url() tokens
794                //
795                // We use a specific rule for urls, because they don't really behave like
796                // standard function calls. The difference is that the argument doesn't have
797                // to be enclosed within a string, so it can't be parsed as an Expression.
798                //
799                url: function () {
800                    var value;
801
802                    if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
803                    value = $(this.entities.quoted)  || $(this.entities.variable) ||
804                            $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
805
806                    expect(')');
807
808                    return new(tree.URL)((value.value != null || value instanceof tree.Variable)
809                                        ? value : new(tree.Anonymous)(value), env.rootpath);
810                },
811
812                //
813                // A Variable entity, such as `@fink`, in
814                //
815                //     width: @fink + 2px
816                //
817                // We use a different parser for variable definitions,
818                // see `parsers.variable`.
819                //
820                variable: function () {
821                    var name, index = i;
822
823                    if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
824                        return new(tree.Variable)(name, index, env.filename);
825                    }
826                },
827
828                // A variable entity useing the protective {} e.g. @{var}
829                variableCurly: function () {
830                    var name, curly, index = i;
831
832                    if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
833                        return new(tree.Variable)("@" + curly[1], index, env.filename);
834                    }
835                },
836
837                //
838                // A Hexadecimal color
839                //
840                //     #4F3C2F
841                //
842                // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
843                //
844                color: function () {
845                    var rgb;
846
847                    if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
848                        return new(tree.Color)(rgb[1]);
849                    }
850                },
851
852                //
853                // A Dimension, that is, a number and a unit
854                //
855                //     0.5em 95%
856                //
857                dimension: function () {
858                    var value, c = input.charCodeAt(i);
859                    //Is the first char of the dimension 0-9, '.', '+' or '-'
860                    if ((c > 57 || c < 43) || c === 47 || c == 44) return;
861
862                    if (value = $(/^([+-]?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn|dpi|dpcm|dppx|rem|vw|vh|vmin|vm|ch)?/)) {
863                        return new(tree.Dimension)(value[1], value[2]);
864                    }
865                },
866
867                //
868                // A Ratio
869                //
870                //    16/9
871                //
872                ratio: function () {
873                  var value, c = input.charCodeAt(i);
874                  if (c > 57 || c < 48) return;
875
876                  if (value = $(/^(\d+\/\d+)/)) {
877                    return new(tree.Ratio)(value[1]);
878                  }
879                },
880               
881                //
882                // A unicode descriptor, as is used in unicode-range
883                //
884                // U+0??  or U+00A1-00A9
885                //
886                unicodeDescriptor: function () {
887                    var ud;
888                   
889                    if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) {
890                        return new(tree.UnicodeDescriptor)(ud[0]);
891                    }
892                },
893
894                //
895                // JavaScript code to be evaluated
896                //
897                //     `window.location.href`
898                //
899                javascript: function () {
900                    var str, j = i, e;
901
902                    if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
903                    if (input.charAt(j) !== '`') { return }
904
905                    e && $('~');
906
907                    if (str = $(/^`([^`]*)`/)) {
908                        return new(tree.JavaScript)(str[1], i, e);
909                    }
910                }
911            },
912
913            //
914            // The variable part of a variable definition. Used in the `rule` parser
915            //
916            //     @fink:
917            //
918            variable: function () {
919                var name;
920
921                if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
922            },
923
924            //
925            // A font size/line-height shorthand
926            //
927            //     small/12px
928            //
929            // We need to peek first, or we'll match on keywords and dimensions
930            //
931            shorthand: function () {
932                var a, b;
933
934                if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
935
936                save();
937
938                if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
939                    return new(tree.Shorthand)(a, b);
940                }
941
942                restore();
943            },
944
945            //
946            // Mixins
947            //
948            mixin: {
949                //
950                // A Mixin call, with an optional argument list
951                //
952                //     #mixins > .square(#fff);
953                //     .rounded(4px, black);
954                //     .button;
955                //
956                // The `while` loop is there because mixins can be
957                // namespaced, but we only support the child and descendant
958                // selector for now.
959                //
960                call: function () {
961                    var elements = [], e, c, argsSemiColon = [], argsComma = [], args, delim, arg, nameLoop, expressions, isSemiColonSeperated, expressionContainsNamed, index = i, s = input.charAt(i), name, value, important = false;
962
963                    if (s !== '.' && s !== '#') { return }
964                   
965                    save(); // stop us absorbing part of an invalid selector
966
967                    while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
968                        elements.push(new(tree.Element)(c, e, i));
969                        c = $('>');
970                    }
971                    if ($('(')) {
972                        expressions = [];
973                        while (arg = $(this.expression)) {
974                            nameLoop = null;
975                            value = arg;
976
977                            // Variable
978                            if (arg.value.length == 1) {
979                                var val = arg.value[0];
980                                if (val instanceof tree.Variable) {
981                                    if ($(':')) {
982                                        if (expressions.length > 0) {
983                                            if (isSemiColonSeperated) {
984                                                error("Cannot mix ; and , as delimiter types");
985                                            }
986                                            expressionContainsNamed = true;
987                                        }
988                                        value = expect(this.expression);
989                                        nameLoop = (name = val.name);
990                                    }
991                                }
992                            }
993                           
994                            expressions.push(value);
995                           
996                            argsComma.push({ name: nameLoop, value: value });
997                           
998                            if ($(',')) {
999                                continue;
1000                            }
1001                           
1002                            if ($(';') || isSemiColonSeperated) {
1003                           
1004                                if (expressionContainsNamed) {
1005                                    error("Cannot mix ; and , as delimiter types");
1006                                }
1007                           
1008                                isSemiColonSeperated = true;
1009                                                       
1010                                if (expressions.length > 1) {
1011                                    value = new(tree.Value)(expressions);
1012                                }
1013                                argsSemiColon.push({ name: name, value: value });
1014                           
1015                                name = null;
1016                                expressions = [];
1017                                expressionContainsNamed = false;
1018                            }
1019                        }
1020
1021                        expect(')');
1022                    }
1023
1024                    args = isSemiColonSeperated ? argsSemiColon : argsComma;
1025
1026                    if ($(this.important)) {
1027                        important = true;
1028                    }
1029
1030                    if (elements.length > 0 && ($(';') || peek('}'))) {
1031                        return new(tree.mixin.Call)(elements, args, index, env.filename, important);
1032                    }
1033                   
1034                    restore();
1035                },
1036
1037                //
1038                // A Mixin definition, with a list of parameters
1039                //
1040                //     .rounded (@radius: 2px, @color) {
1041                //        ...
1042                //     }
1043                //
1044                // Until we have a finer grained state-machine, we have to
1045                // do a look-ahead, to make sure we don't have a mixin call.
1046                // See the `rule` function for more information.
1047                //
1048                // We start by matching `.rounded (`, and then proceed on to
1049                // the argument list, which has optional default values.
1050                // We store the parameters in `params`, with a `value` key,
1051                // if there is a value, such as in the case of `@radius`.
1052                //
1053                // Once we've got our params list, and a closing `)`, we parse
1054                // the `{...}` block.
1055                //
1056                definition: function () {
1057                    var name, params = [], match, ruleset, param, value, cond, variadic = false;
1058                    if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
1059                        peek(/^[^{]*\}/)) return;
1060
1061                    save();
1062
1063                    if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
1064                        name = match[1];
1065
1066                        do {
1067                            $(this.comment);
1068                            if (input.charAt(i) === '.' && $(/^\.{3}/)) {
1069                                variadic = true;
1070                                params.push({ variadic: true });
1071                                break;
1072                            } else if (param = $(this.entities.variable) || $(this.entities.literal)
1073                                                                         || $(this.entities.keyword)) {
1074                                // Variable
1075                                if (param instanceof tree.Variable) {
1076                                    if ($(':')) {
1077                                        value = expect(this.expression, 'expected expression');
1078                                        params.push({ name: param.name, value: value });
1079                                    } else if ($(/^\.{3}/)) {
1080                                        params.push({ name: param.name, variadic: true });
1081                                        variadic = true;
1082                                        break;
1083                                    } else {
1084                                        params.push({ name: param.name });
1085                                    }
1086                                } else {
1087                                    params.push({ value: param });
1088                                }
1089                            } else {
1090                                break;
1091                            }
1092                        } while ($(',') || $(';'))
1093
1094                        // .mixincall("@{a}");
1095                        // looks a bit like a mixin definition.. so we have to be nice and restore
1096                        if (!$(')')) {
1097                            furthest = i;
1098                            restore();
1099                        }
1100                       
1101                        $(this.comment);
1102
1103                        if ($(/^when/)) { // Guard
1104                            cond = expect(this.conditions, 'expected condition');
1105                        }
1106
1107                        ruleset = $(this.block);
1108
1109                        if (ruleset) {
1110                            return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
1111                        } else {
1112                            restore();
1113                        }
1114                    }
1115                }
1116            },
1117
1118            //
1119            // Entities are the smallest recognized token,
1120            // and can be found inside a rule's value.
1121            //
1122            entity: function () {
1123                return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
1124                       $(this.entities.call)    || $(this.entities.keyword)  ||$(this.entities.javascript) ||
1125                       $(this.comment);
1126            },
1127
1128            //
1129            // A Rule terminator. Note that we use `peek()` to check for '}',
1130            // because the `block` rule will be expecting it, but we still need to make sure
1131            // it's there, if ';' was ommitted.
1132            //
1133            end: function () {
1134                return $(';') || peek('}');
1135            },
1136
1137            //
1138            // IE's alpha function
1139            //
1140            //     alpha(opacity=88)
1141            //
1142            alpha: function () {
1143                var value;
1144
1145                if (! $(/^\(opacity=/i)) return;
1146                if (value = $(/^\d+/) || $(this.entities.variable)) {
1147                    expect(')');
1148                    return new(tree.Alpha)(value);
1149                }
1150            },
1151
1152            //
1153            // A Selector Element
1154            //
1155            //     div
1156            //     + h1
1157            //     #socks
1158            //     input[type="text"]
1159            //
1160            // Elements are the building blocks for Selectors,
1161            // they are made out of a `Combinator` (see combinator rule),
1162            // and an element name, such as a tag a class, or `*`.
1163            //
1164            element: function () {
1165                var e, t, c, v;
1166
1167                c = $(this.combinator);
1168
1169                e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
1170                    $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly);
1171
1172                if (! e) {
1173                    if ($('(')) {
1174                        if ((v = ($(this.entities.variableCurly) ||
1175                                $(this.entities.variable) ||
1176                                $(this.selector))) &&
1177                                $(')')) {
1178                            e = new(tree.Paren)(v);
1179                        }
1180                    }
1181                }
1182
1183                if (e) { return new(tree.Element)(c, e, i) }
1184            },
1185
1186            //
1187            // Combinators combine elements together, in a Selector.
1188            //
1189            // Because our parser isn't white-space sensitive, special care
1190            // has to be taken, when parsing the descendant combinator, ` `,
1191            // as it's an empty space. We have to check the previous character
1192            // in the input, to see if it's a ` ` character. More info on how
1193            // we deal with this in *combinator.js*.
1194            //
1195            combinator: function () {
1196                var match, c = input.charAt(i);
1197
1198                if (c === '>' || c === '+' || c === '~' || c === '|') {
1199                    i++;
1200                    while (input.charAt(i).match(/\s/)) { i++ }
1201                    return new(tree.Combinator)(c);
1202                } else if (input.charAt(i - 1).match(/\s/)) {
1203                    return new(tree.Combinator)(" ");
1204                } else {
1205                    return new(tree.Combinator)(null);
1206                }
1207            },
1208
1209            //
1210            // A CSS Selector
1211            //
1212            //     .class > div + h1
1213            //     li a:hover
1214            //
1215            // Selectors are made out of one or more Elements, see above.
1216            //
1217            selector: function () {
1218                var sel, e, elements = [], c, match;
1219
1220                // depreciated, will be removed soon
1221                if ($('(')) {
1222                    sel = $(this.entity);
1223                    if (!$(')')) { return null; }
1224                    return new(tree.Selector)([new(tree.Element)('', sel, i)]);
1225                }
1226
1227                while (e = $(this.element)) {
1228                    c = input.charAt(i);
1229                    elements.push(e)
1230                    if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break }
1231                }
1232
1233                if (elements.length > 0) { return new(tree.Selector)(elements) }
1234            },
1235            attribute: function () {
1236                var attr = '', key, val, op;
1237
1238                if (! $('[')) return;
1239
1240                if (key = $(/^(?:[_A-Za-z0-9-]|\\.)+/) || $(this.entities.quoted)) {
1241                    if ((op = $(/^[|~*$^]?=/)) &&
1242                        (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
1243                        attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
1244                    } else { attr = key }
1245                }
1246
1247                if (! $(']')) return;
1248
1249                if (attr) { return "[" + attr + "]" }
1250            },
1251
1252            //
1253            // The `block` rule is used by `ruleset` and `mixin.definition`.
1254            // It's a wrapper around the `primary` rule, with added `{}`.
1255            //
1256            block: function () {
1257                var content;
1258                if ($('{') && (content = $(this.primary)) && $('}')) {
1259                    return content;
1260                }
1261            },
1262
1263            //
1264            // div, .class, body > p {...}
1265            //
1266            ruleset: function () {
1267                var selectors = [], s, rules, match, debugInfo;
1268               
1269                save();
1270
1271                if (env.dumpLineNumbers)
1272                    debugInfo = getDebugInfo(i, input, env);
1273
1274                while (s = $(this.selector)) {
1275                    selectors.push(s);
1276                    $(this.comment);
1277                    if (! $(',')) { break }
1278                    $(this.comment);
1279                }
1280
1281                if (selectors.length > 0 && (rules = $(this.block))) {
1282                    var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
1283                    if (env.dumpLineNumbers)
1284                        ruleset.debugInfo = debugInfo;
1285                    return ruleset;
1286                } else {
1287                    // Backtrack
1288                    furthest = i;
1289                    restore();
1290                }
1291            },
1292            rule: function () {
1293                var name, value, c = input.charAt(i), important, match;
1294                save();
1295
1296                if (c === '.' || c === '#' || c === '&') { return }
1297
1298                if (name = $(this.variable) || $(this.property)) {
1299                    if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) {
1300                        i += match[0].length - 1;
1301                        value = new(tree.Anonymous)(match[1]);
1302                    } else if (name === "font") {
1303                        value = $(this.font);
1304                    } else {
1305                        value = $(this.value);
1306                    }
1307                    important = $(this.important);
1308
1309                    if (value && $(this.end)) {
1310                        return new(tree.Rule)(name, value, important, memo);
1311                    } else {
1312                        furthest = i;
1313                        restore();
1314                    }
1315                }
1316            },
1317
1318            //
1319            // An @import directive
1320            //
1321            //     @import "lib";
1322            //
1323            // Depending on our environemnt, importing is done differently:
1324            // In the browser, it's an XHR request, in Node, it would be a
1325            // file-system operation. The function used for importing is
1326            // stored in `import`, which we pass to the Import constructor.
1327            //
1328            "import": function () {
1329                var path, features, index = i;
1330               
1331                save();
1332               
1333                var dir = $(/^@import(?:-(once))?\s+/);
1334
1335                if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
1336                    features = $(this.mediaFeatures);
1337                    if ($(';')) {
1338                        return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index, env.rootpath);
1339                    }
1340                }
1341               
1342                restore();
1343            },
1344
1345            mediaFeature: function () {
1346                var e, p, nodes = [];
1347
1348                do {
1349                    if (e = $(this.entities.keyword)) {
1350                        nodes.push(e);
1351                    } else if ($('(')) {
1352                        p = $(this.property);
1353                        e = $(this.entity);
1354                        if ($(')')) {
1355                            if (p && e) {
1356                                nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
1357                            } else if (e) {
1358                                nodes.push(new(tree.Paren)(e));
1359                            } else {
1360                                return null;
1361                            }
1362                        } else { return null }
1363                    }
1364                } while (e);
1365
1366                if (nodes.length > 0) {
1367                    return new(tree.Expression)(nodes);
1368                }
1369            },
1370
1371            mediaFeatures: function () {
1372                var e, features = [];
1373
1374                do {
1375                  if (e = $(this.mediaFeature)) {
1376                      features.push(e);
1377                      if (! $(',')) { break }
1378                  } else if (e = $(this.entities.variable)) {
1379                      features.push(e);
1380                      if (! $(',')) { break }
1381                  }
1382                } while (e);
1383
1384                return features.length > 0 ? features : null;
1385            },
1386
1387            media: function () {
1388                var features, rules, media, debugInfo;
1389
1390                if (env.dumpLineNumbers)
1391                    debugInfo = getDebugInfo(i, input, env);
1392
1393                if ($(/^@media/)) {
1394                    features = $(this.mediaFeatures);
1395
1396                    if (rules = $(this.block)) {
1397                        media = new(tree.Media)(rules, features);
1398                        if(env.dumpLineNumbers)
1399                            media.debugInfo = debugInfo;
1400                        return media;
1401                    }
1402                }
1403            },
1404
1405            //
1406            // A CSS Directive
1407            //
1408            //     @charset "utf-8";
1409            //
1410            directive: function () {
1411                var name, value, rules, identifier, e, nodes, nonVendorSpecificName,
1412                    hasBlock, hasIdentifier, hasExpression;
1413
1414                if (input.charAt(i) !== '@') return;
1415
1416                if (value = $(this['import']) || $(this.media)) {
1417                    return value;
1418                }
1419               
1420                save();
1421
1422                name = $(/^@[a-z-]+/);
1423               
1424                if (!name) return;
1425
1426                nonVendorSpecificName = name;
1427                if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
1428                    nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
1429                }
1430
1431                switch(nonVendorSpecificName) {
1432                    case "@font-face":
1433                        hasBlock = true;
1434                        break;
1435                    case "@viewport":
1436                    case "@top-left":
1437                    case "@top-left-corner":
1438                    case "@top-center":
1439                    case "@top-right":
1440                    case "@top-right-corner":
1441                    case "@bottom-left":
1442                    case "@bottom-left-corner":
1443                    case "@bottom-center":
1444                    case "@bottom-right":
1445                    case "@bottom-right-corner":
1446                    case "@left-top":
1447                    case "@left-middle":
1448                    case "@left-bottom":
1449                    case "@right-top":
1450                    case "@right-middle":
1451                    case "@right-bottom":
1452                        hasBlock = true;
1453                        break;
1454                    case "@page":
1455                    case "@document":
1456                    case "@supports":
1457                    case "@keyframes":
1458                        hasBlock = true;
1459                        hasIdentifier = true;
1460                        break;
1461                    case "@namespace":
1462                        hasExpression = true;
1463                        break;
1464                }
1465
1466                if (hasIdentifier) {
1467                    name += " " + ($(/^[^{]+/) || '').trim();
1468                }
1469
1470                if (hasBlock)
1471                {
1472                    if (rules = $(this.block)) {
1473                        return new(tree.Directive)(name, rules);
1474                    }
1475                } else {
1476                    if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
1477                        var directive = new(tree.Directive)(name, value);
1478                        if (env.dumpLineNumbers) {
1479                            directive.debugInfo = getDebugInfo(i, input, env);
1480                        }
1481                        return directive;
1482                    }
1483                }
1484               
1485                restore();
1486            },
1487            font: function () {
1488                var value = [], expression = [], weight, shorthand, font, e;
1489
1490                while (e = $(this.shorthand) || $(this.entity)) {
1491                    expression.push(e);
1492                }
1493                value.push(new(tree.Expression)(expression));
1494
1495                if ($(',')) {
1496                    while (e = $(this.expression)) {
1497                        value.push(e);
1498                        if (! $(',')) { break }
1499                    }
1500                }
1501                return new(tree.Value)(value);
1502            },
1503
1504            //
1505            // A Value is a comma-delimited list of Expressions
1506            //
1507            //     font-family: Baskerville, Georgia, serif;
1508            //
1509            // In a Rule, a Value represents everything after the `:`,
1510            // and before the `;`.
1511            //
1512            value: function () {
1513                var e, expressions = [], important;
1514
1515                while (e = $(this.expression)) {
1516                    expressions.push(e);
1517                    if (! $(',')) { break }
1518                }
1519
1520                if (expressions.length > 0) {
1521                    return new(tree.Value)(expressions);
1522                }
1523            },
1524            important: function () {
1525                if (input.charAt(i) === '!') {
1526                    return $(/^! *important/);
1527                }
1528            },
1529            sub: function () {
1530                var e;
1531
1532                if ($('(') && (e = $(this.expression)) && $(')')) {
1533                    return e;
1534                }
1535            },
1536            multiplication: function () {
1537                var m, a, op, operation;
1538                if (m = $(this.operand)) {
1539                    while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
1540                        operation = new(tree.Operation)(op, [operation || m, a]);
1541                    }
1542                    return operation || m;
1543                }
1544            },
1545            addition: function () {
1546                var m, a, op, operation;
1547                if (m = $(this.multiplication)) {
1548                    while ((op = $(/^[-+]\s+/) || (!isWhitespace(input.charAt(i - 1)) && ($('+') || $('-')))) &&
1549                           (a = $(this.multiplication))) {
1550                        operation = new(tree.Operation)(op, [operation || m, a]);
1551                    }
1552                    return operation || m;
1553                }
1554            },
1555            conditions: function () {
1556                var a, b, index = i, condition;
1557
1558                if (a = $(this.condition)) {
1559                    while ($(',') && (b = $(this.condition))) {
1560                        condition = new(tree.Condition)('or', condition || a, b, index);
1561                    }
1562                    return condition || a;
1563                }
1564            },
1565            condition: function () {
1566                var a, b, c, op, index = i, negate = false;
1567
1568                if ($(/^not/)) { negate = true }
1569                expect('(');
1570                if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
1571                    if (op = $(/^(?:>=|=<|[<=>])/)) {
1572                        if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
1573                            c = new(tree.Condition)(op, a, b, index, negate);
1574                        } else {
1575                            error('expected expression');
1576                        }
1577                    } else {
1578                        c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
1579                    }
1580                    expect(')');
1581                    return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
1582                }
1583            },
1584
1585            //
1586            // An operand is anything that can be part of an operation,
1587            // such as a Color, or a Variable
1588            //
1589            operand: function () {
1590                var negate, p = input.charAt(i + 1);
1591
1592                if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
1593                var o = $(this.sub) || $(this.entities.dimension) ||
1594                        $(this.entities.color) || $(this.entities.variable) ||
1595                        $(this.entities.call);
1596                return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o])
1597                              : o;
1598            },
1599
1600            //
1601            // Expressions either represent mathematical operations,
1602            // or white-space delimited Entities.
1603            //
1604            //     1px solid black
1605            //     @var * 2
1606            //
1607            expression: function () {
1608                var e, delim, entities = [], d;
1609
1610                while (e = $(this.addition) || $(this.entity)) {
1611                    entities.push(e);
1612                }
1613                if (entities.length > 0) {
1614                    return new(tree.Expression)(entities);
1615                }
1616            },
1617            property: function () {
1618                var name;
1619
1620                if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) {
1621                    return name[1];
1622                }
1623            }
1624        }
1625    };
1626};
1627
1628if (less.mode === 'browser' || less.mode === 'rhino') {
1629    //
1630    // Used by `@import` directives
1631    //
1632    less.Parser.importer = function (path, paths, callback, env) {
1633        if (!/^([a-z-]+:)?\//.test(path) && paths.length > 0) {
1634            path = paths[0] + path;
1635        }
1636        // We pass `true` as 3rd argument, to force the reload of the import.
1637        // This is so we can get the syntax tree as opposed to just the CSS output,
1638        // as we need this to evaluate the current stylesheet.
1639        loadStyleSheet({
1640            href: path,
1641            title: path,
1642            type: env.mime,
1643            contents: env.contents,
1644            files: env.files,
1645            rootpath: env.rootpath,
1646            entryPath: env.entryPath,
1647            relativeUrls: env.relativeUrls },
1648        function (e, root, data, sheet, _, path) {
1649            if (e && typeof(env.errback) === "function") {
1650                env.errback.call(null, path, paths, callback, env);
1651            } else {
1652                callback.call(null, e, root, path);
1653            }
1654        }, true);
1655    };
1656}
1657
1658(function (tree) {
1659
1660tree.functions = {
1661    rgb: function (r, g, b) {
1662        return this.rgba(r, g, b, 1.0);
1663    },
1664    rgba: function (r, g, b, a) {
1665        var rgb = [r, g, b].map(function (c) { return scaled(c, 256); });
1666        a = number(a);
1667        return new(tree.Color)(rgb, a);
1668    },
1669    hsl: function (h, s, l) {
1670        return this.hsla(h, s, l, 1.0);
1671    },
1672    hsla: function (h, s, l, a) {
1673        h = (number(h) % 360) / 360;
1674        s = number(s); l = number(l); a = number(a);
1675
1676        var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1677        var m1 = l * 2 - m2;
1678
1679        return this.rgba(hue(h + 1/3) * 255,
1680                         hue(h)       * 255,
1681                         hue(h - 1/3) * 255,
1682                         a);
1683
1684        function hue(h) {
1685            h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1686            if      (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
1687            else if (h * 2 < 1) return m2;
1688            else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
1689            else                return m1;
1690        }
1691    },
1692
1693    hsv: function(h, s, v) {
1694        return this.hsva(h, s, v, 1.0);
1695    },
1696
1697    hsva: function(h, s, v, a) {
1698        h = ((number(h) % 360) / 360) * 360;
1699        s = number(s); v = number(v); a = number(a);
1700
1701        var i, f;
1702        i = Math.floor((h / 60) % 6);
1703        f = (h / 60) - i;
1704
1705        var vs = [v,
1706                  v * (1 - s),
1707                  v * (1 - f * s),
1708                  v * (1 - (1 - f) * s)];
1709        var perm = [[0, 3, 1],
1710                    [2, 0, 1],
1711                    [1, 0, 3],
1712                    [1, 2, 0],
1713                    [3, 1, 0],
1714                    [0, 1, 2]];
1715
1716        return this.rgba(vs[perm[i][0]] * 255,
1717                         vs[perm[i][1]] * 255,
1718                         vs[perm[i][2]] * 255,
1719                         a);
1720    },
1721
1722    hue: function (color) {
1723        return new(tree.Dimension)(Math.round(color.toHSL().h));
1724    },
1725    saturation: function (color) {
1726        return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
1727    },
1728    lightness: function (color) {
1729        return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
1730    },
1731    red: function (color) {
1732        return new(tree.Dimension)(color.rgb[0]);
1733    },
1734    green: function (color) {
1735        return new(tree.Dimension)(color.rgb[1]);
1736    },
1737    blue: function (color) {
1738        return new(tree.Dimension)(color.rgb[2]);
1739    },
1740    alpha: function (color) {
1741        return new(tree.Dimension)(color.toHSL().a);
1742    },
1743    luma: function (color) {
1744        return new(tree.Dimension)(Math.round((0.2126 * (color.rgb[0]/255) +
1745            0.7152 * (color.rgb[1]/255) +
1746            0.0722 * (color.rgb[2]/255)) *
1747            color.alpha * 100), '%');
1748    },
1749    saturate: function (color, amount) {
1750        var hsl = color.toHSL();
1751
1752        hsl.s += amount.value / 100;
1753        hsl.s = clamp(hsl.s);
1754        return hsla(hsl);
1755    },
1756    desaturate: function (color, amount) {
1757        var hsl = color.toHSL();
1758
1759        hsl.s -= amount.value / 100;
1760        hsl.s = clamp(hsl.s);
1761        return hsla(hsl);
1762    },
1763    lighten: function (color, amount) {
1764        var hsl = color.toHSL();
1765
1766        hsl.l += amount.value / 100;
1767        hsl.l = clamp(hsl.l);
1768        return hsla(hsl);
1769    },
1770    darken: function (color, amount) {
1771        var hsl = color.toHSL();
1772
1773        hsl.l -= amount.value / 100;
1774        hsl.l = clamp(hsl.l);
1775        return hsla(hsl);
1776    },
1777    fadein: function (color, amount) {
1778        var hsl = color.toHSL();
1779
1780        hsl.a += amount.value / 100;
1781        hsl.a = clamp(hsl.a);
1782        return hsla(hsl);
1783    },
1784    fadeout: function (color, amount) {
1785        var hsl = color.toHSL();
1786
1787        hsl.a -= amount.value / 100;
1788        hsl.a = clamp(hsl.a);
1789        return hsla(hsl);
1790    },
1791    fade: function (color, amount) {
1792        var hsl = color.toHSL();
1793
1794        hsl.a = amount.value / 100;
1795        hsl.a = clamp(hsl.a);
1796        return hsla(hsl);
1797    },
1798    spin: function (color, amount) {
1799        var hsl = color.toHSL();
1800        var hue = (hsl.h + amount.value) % 360;
1801
1802        hsl.h = hue < 0 ? 360 + hue : hue;
1803
1804        return hsla(hsl);
1805    },
1806    //
1807    // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
1808    // http://sass-lang.com
1809    //
1810    mix: function (color1, color2, weight) {
1811        if (!weight) {
1812            weight = new(tree.Dimension)(50);
1813        }
1814        var p = weight.value / 100.0;
1815        var w = p * 2 - 1;
1816        var a = color1.toHSL().a - color2.toHSL().a;
1817
1818        var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1819        var w2 = 1 - w1;
1820
1821        var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1822                   color1.rgb[1] * w1 + color2.rgb[1] * w2,
1823                   color1.rgb[2] * w1 + color2.rgb[2] * w2];
1824
1825        var alpha = color1.alpha * p + color2.alpha * (1 - p);
1826
1827        return new(tree.Color)(rgb, alpha);
1828    },
1829    greyscale: function (color) {
1830        return this.desaturate(color, new(tree.Dimension)(100));
1831    },
1832    contrast: function (color, dark, light, threshold) {
1833        // filter: contrast(3.2);
1834        // should be kept as is, so check for color
1835        if (!color.rgb) {
1836            return null;
1837        }
1838        if (typeof light === 'undefined') {
1839            light = this.rgba(255, 255, 255, 1.0);
1840        }
1841        if (typeof dark === 'undefined') {
1842            dark = this.rgba(0, 0, 0, 1.0);
1843        }
1844        if (typeof threshold === 'undefined') {
1845            threshold = 0.43;
1846        } else {
1847            threshold = threshold.value;
1848        }
1849        if (((0.2126 * (color.rgb[0]/255) + 0.7152 * (color.rgb[1]/255) + 0.0722 * (color.rgb[2]/255)) * color.alpha) < threshold) {
1850            return light;
1851        } else {
1852            return dark;
1853        }
1854    },
1855    e: function (str) {
1856        return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
1857    },
1858    escape: function (str) {
1859        return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
1860    },
1861    '%': function (quoted /* arg, arg, ...*/) {
1862        var args = Array.prototype.slice.call(arguments, 1),
1863            str = quoted.value;
1864
1865        for (var i = 0; i < args.length; i++) {
1866            str = str.replace(/%[sda]/i, function(token) {
1867                var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
1868                return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
1869            });
1870        }
1871        str = str.replace(/%%/g, '%');
1872        return new(tree.Quoted)('"' + str + '"', str);
1873    },
1874    unit: function (val, unit) {
1875        return new(tree.Dimension)(val.value, unit ? unit.toCSS() : "");
1876    },
1877    round: function (n, f) {
1878        var fraction = typeof(f) === "undefined" ? 0 : f.value;
1879        return this._math(function(num) { return num.toFixed(fraction); }, n);
1880    },
1881    ceil: function (n) {
1882        return this._math(Math.ceil, n);
1883    },
1884    floor: function (n) {
1885        return this._math(Math.floor, n);
1886    },
1887    _math: function (fn, n) {
1888        if (n instanceof tree.Dimension) {
1889            return new(tree.Dimension)(fn(parseFloat(n.value)), n.unit);
1890        } else if (typeof(n) === 'number') {
1891            return fn(n);
1892        } else {
1893            throw { type: "Argument", message: "argument must be a number" };
1894        }
1895    },
1896    argb: function (color) {
1897        return new(tree.Anonymous)(color.toARGB());
1898
1899    },
1900    percentage: function (n) {
1901        return new(tree.Dimension)(n.value * 100, '%');
1902    },
1903    color: function (n) {
1904        if (n instanceof tree.Quoted) {
1905            return new(tree.Color)(n.value.slice(1));
1906        } else {
1907            throw { type: "Argument", message: "argument must be a string" };
1908        }
1909    },
1910    iscolor: function (n) {
1911        return this._isa(n, tree.Color);
1912    },
1913    isnumber: function (n) {
1914        return this._isa(n, tree.Dimension);
1915    },
1916    isstring: function (n) {
1917        return this._isa(n, tree.Quoted);
1918    },
1919    iskeyword: function (n) {
1920        return this._isa(n, tree.Keyword);
1921    },
1922    isurl: function (n) {
1923        return this._isa(n, tree.URL);
1924    },
1925    ispixel: function (n) {
1926        return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False;
1927    },
1928    ispercentage: function (n) {
1929        return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False;
1930    },
1931    isem: function (n) {
1932        return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False;
1933    },
1934    _isa: function (n, Type) {
1935        return (n instanceof Type) ? tree.True : tree.False;
1936    },
1937   
1938    /* Blending modes */
1939   
1940    multiply: function(color1, color2) {
1941        var r = color1.rgb[0] * color2.rgb[0] / 255;
1942        var g = color1.rgb[1] * color2.rgb[1] / 255;
1943        var b = color1.rgb[2] * color2.rgb[2] / 255;
1944        return this.rgb(r, g, b);
1945    },
1946    screen: function(color1, color2) {
1947        var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
1948        var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
1949        var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
1950        return this.rgb(r, g, b);
1951    },
1952    overlay: function(color1, color2) {
1953        var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
1954        var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
1955        var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
1956        return this.rgb(r, g, b);
1957    },
1958    softlight: function(color1, color2) {
1959        var t = color2.rgb[0] * color1.rgb[0] / 255;
1960        var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255;
1961        t = color2.rgb[1] * color1.rgb[1] / 255;
1962        var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255;
1963        t = color2.rgb[2] * color1.rgb[2] / 255;
1964        var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255;
1965        return this.rgb(r, g, b);
1966    },
1967    hardlight: function(color1, color2) {
1968        var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255;
1969        var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255;
1970        var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255;
1971        return this.rgb(r, g, b);
1972    },
1973    difference: function(color1, color2) {
1974        var r = Math.abs(color1.rgb[0] - color2.rgb[0]);
1975        var g = Math.abs(color1.rgb[1] - color2.rgb[1]);
1976        var b = Math.abs(color1.rgb[2] - color2.rgb[2]);
1977        return this.rgb(r, g, b);
1978    },
1979    exclusion: function(color1, color2) {
1980        var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255;
1981        var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255;
1982        var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255;
1983        return this.rgb(r, g, b);
1984    },
1985    average: function(color1, color2) {
1986        var r = (color1.rgb[0] + color2.rgb[0]) / 2;
1987        var g = (color1.rgb[1] + color2.rgb[1]) / 2;
1988        var b = (color1.rgb[2] + color2.rgb[2]) / 2;
1989        return this.rgb(r, g, b);
1990    },
1991    negation: function(color1, color2) {
1992        var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]);
1993        var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]);
1994        var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]);
1995        return this.rgb(r, g, b);
1996    },
1997    tint: function(color, amount) {
1998        return this.mix(this.rgb(255,255,255), color, amount);
1999    },
2000    shade: function(color, amount) {
2001        return this.mix(this.rgb(0, 0, 0), color, amount);
2002    }
2003};
2004
2005function hsla(color) {
2006    return tree.functions.hsla(color.h, color.s, color.l, color.a);
2007}
2008
2009function scaled(n, size) {
2010    if (n instanceof tree.Dimension && n.unit == '%') {
2011        return parseFloat(n.value * size / 100);
2012    } else {
2013        return number(n);
2014    }
2015}
2016
2017function number(n) {
2018    if (n instanceof tree.Dimension) {
2019        return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
2020    } else if (typeof(n) === 'number') {
2021        return n;
2022    } else {
2023        throw {
2024            error: "RuntimeError",
2025            message: "color functions take numbers as parameters"
2026        };
2027    }
2028}
2029
2030function clamp(val) {
2031    return Math.min(1, Math.max(0, val));
2032}
2033
2034})(require('./tree'));
2035(function (tree) {
2036    tree.colors = {
2037        'aliceblue':'#f0f8ff',
2038        'antiquewhite':'#faebd7',
2039        'aqua':'#00ffff',
2040        'aquamarine':'#7fffd4',
2041        'azure':'#f0ffff',
2042        'beige':'#f5f5dc',
2043        'bisque':'#ffe4c4',
2044        'black':'#000000',
2045        'blanchedalmond':'#ffebcd',
2046        'blue':'#0000ff',
2047        'blueviolet':'#8a2be2',
2048        'brown':'#a52a2a',
2049        'burlywood':'#deb887',
2050        'cadetblue':'#5f9ea0',
2051        'chartreuse':'#7fff00',
2052        'chocolate':'#d2691e',
2053        'coral':'#ff7f50',
2054        'cornflowerblue':'#6495ed',
2055        'cornsilk':'#fff8dc',
2056        'crimson':'#dc143c',
2057        'cyan':'#00ffff',
2058        'darkblue':'#00008b',
2059        'darkcyan':'#008b8b',
2060        'darkgoldenrod':'#b8860b',
2061        'darkgray':'#a9a9a9',
2062        'darkgrey':'#a9a9a9',
2063        'darkgreen':'#006400',
2064        'darkkhaki':'#bdb76b',
2065        'darkmagenta':'#8b008b',
2066        'darkolivegreen':'#556b2f',
2067        'darkorange':'#ff8c00',
2068        'darkorchid':'#9932cc',
2069        'darkred':'#8b0000',
2070        'darksalmon':'#e9967a',
2071        'darkseagreen':'#8fbc8f',
2072        'darkslateblue':'#483d8b',
2073        'darkslategray':'#2f4f4f',
2074        'darkslategrey':'#2f4f4f',
2075        'darkturquoise':'#00ced1',
2076        'darkviolet':'#9400d3',
2077        'deeppink':'#ff1493',
2078        'deepskyblue':'#00bfff',
2079        'dimgray':'#696969',
2080        'dimgrey':'#696969',
2081        'dodgerblue':'#1e90ff',
2082        'firebrick':'#b22222',
2083        'floralwhite':'#fffaf0',
2084        'forestgreen':'#228b22',
2085        'fuchsia':'#ff00ff',
2086        'gainsboro':'#dcdcdc',
2087        'ghostwhite':'#f8f8ff',
2088        'gold':'#ffd700',
2089        'goldenrod':'#daa520',
2090        'gray':'#808080',
2091        'grey':'#808080',
2092        'green':'#008000',
2093        'greenyellow':'#adff2f',
2094        'honeydew':'#f0fff0',
2095        'hotpink':'#ff69b4',
2096        'indianred':'#cd5c5c',
2097        'indigo':'#4b0082',
2098        'ivory':'#fffff0',
2099        'khaki':'#f0e68c',
2100        'lavender':'#e6e6fa',
2101        'lavenderblush':'#fff0f5',
2102        'lawngreen':'#7cfc00',
2103        'lemonchiffon':'#fffacd',
2104        'lightblue':'#add8e6',
2105        'lightcoral':'#f08080',
2106        'lightcyan':'#e0ffff',
2107        'lightgoldenrodyellow':'#fafad2',
2108        'lightgray':'#d3d3d3',
2109        'lightgrey':'#d3d3d3',
2110        'lightgreen':'#90ee90',
2111        'lightpink':'#ffb6c1',
2112        'lightsalmon':'#ffa07a',
2113        'lightseagreen':'#20b2aa',
2114        'lightskyblue':'#87cefa',
2115        'lightslategray':'#778899',
2116        'lightslategrey':'#778899',
2117        'lightsteelblue':'#b0c4de',
2118        'lightyellow':'#ffffe0',
2119        'lime':'#00ff00',
2120        'limegreen':'#32cd32',
2121        'linen':'#faf0e6',
2122        'magenta':'#ff00ff',
2123        'maroon':'#800000',
2124        'mediumaquamarine':'#66cdaa',
2125        'mediumblue':'#0000cd',
2126        'mediumorchid':'#ba55d3',
2127        'mediumpurple':'#9370d8',
2128        'mediumseagreen':'#3cb371',
2129        'mediumslateblue':'#7b68ee',
2130        'mediumspringgreen':'#00fa9a',
2131        'mediumturquoise':'#48d1cc',
2132        'mediumvioletred':'#c71585',
2133        'midnightblue':'#191970',
2134        'mintcream':'#f5fffa',
2135        'mistyrose':'#ffe4e1',
2136        'moccasin':'#ffe4b5',
2137        'navajowhite':'#ffdead',
2138        'navy':'#000080',
2139        'oldlace':'#fdf5e6',
2140        'olive':'#808000',
2141        'olivedrab':'#6b8e23',
2142        'orange':'#ffa500',
2143        'orangered':'#ff4500',
2144        'orchid':'#da70d6',
2145        'palegoldenrod':'#eee8aa',
2146        'palegreen':'#98fb98',
2147        'paleturquoise':'#afeeee',
2148        'palevioletred':'#d87093',
2149        'papayawhip':'#ffefd5',
2150        'peachpuff':'#ffdab9',
2151        'peru':'#cd853f',
2152        'pink':'#ffc0cb',
2153        'plum':'#dda0dd',
2154        'powderblue':'#b0e0e6',
2155        'purple':'#800080',
2156        'red':'#ff0000',
2157        'rosybrown':'#bc8f8f',
2158        'royalblue':'#4169e1',
2159        'saddlebrown':'#8b4513',
2160        'salmon':'#fa8072',
2161        'sandybrown':'#f4a460',
2162        'seagreen':'#2e8b57',
2163        'seashell':'#fff5ee',
2164        'sienna':'#a0522d',
2165        'silver':'#c0c0c0',
2166        'skyblue':'#87ceeb',
2167        'slateblue':'#6a5acd',
2168        'slategray':'#708090',
2169        'slategrey':'#708090',
2170        'snow':'#fffafa',
2171        'springgreen':'#00ff7f',
2172        'steelblue':'#4682b4',
2173        'tan':'#d2b48c',
2174        'teal':'#008080',
2175        'thistle':'#d8bfd8',
2176        'tomato':'#ff6347',
2177        // 'transparent':'rgba(0,0,0,0)',
2178        'turquoise':'#40e0d0',
2179        'violet':'#ee82ee',
2180        'wheat':'#f5deb3',
2181        'white':'#ffffff',
2182        'whitesmoke':'#f5f5f5',
2183        'yellow':'#ffff00',
2184        'yellowgreen':'#9acd32'
2185    };
2186})(require('./tree'));
2187(function (tree) {
2188
2189tree.Alpha = function (val) {
2190    this.value = val;
2191};
2192tree.Alpha.prototype = {
2193    toCSS: function () {
2194        return "alpha(opacity=" +
2195               (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
2196    },
2197    eval: function (env) {
2198        if (this.value.eval) { this.value = this.value.eval(env) }
2199        return this;
2200    }
2201};
2202
2203})(require('../tree'));
2204(function (tree) {
2205
2206tree.Anonymous = function (string) {
2207    this.value = string.value || string;
2208};
2209tree.Anonymous.prototype = {
2210    toCSS: function () {
2211        return this.value;
2212    },
2213    eval: function () { return this },
2214    compare: function (x) {
2215        if (!x.toCSS) {
2216            return -1;
2217        }
2218       
2219        var left = this.toCSS(),
2220            right = x.toCSS();
2221       
2222        if (left === right) {
2223            return 0;
2224        }
2225       
2226        return left < right ? -1 : 1;
2227    }
2228};
2229
2230})(require('../tree'));
2231(function (tree) {
2232
2233tree.Assignment = function (key, val) {
2234    this.key = key;
2235    this.value = val;
2236};
2237tree.Assignment.prototype = {
2238    toCSS: function () {
2239        return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
2240    },
2241    eval: function (env) {
2242        if (this.value.eval) {
2243            return new(tree.Assignment)(this.key, this.value.eval(env));
2244        }
2245        return this;
2246    }
2247};
2248
2249})(require('../tree'));(function (tree) {
2250
2251//
2252// A function call node.
2253//
2254tree.Call = function (name, args, index, filename) {
2255    this.name = name;
2256    this.args = args;
2257    this.index = index;
2258    this.filename = filename;
2259};
2260tree.Call.prototype = {
2261    //
2262    // When evaluating a function call,
2263    // we either find the function in `tree.functions` [1],
2264    // in which case we call it, passing the  evaluated arguments,
2265    // if this returns null or we cannot find the function, we
2266    // simply print it out as it appeared originally [2].
2267    //
2268    // The *functions.js* file contains the built-in functions.
2269    //
2270    // The reason why we evaluate the arguments, is in the case where
2271    // we try to pass a variable to a function, like: `saturate(@color)`.
2272    // The function should receive the value, not the variable.
2273    //
2274    eval: function (env) {
2275        var args = this.args.map(function (a) { return a.eval(env) }),
2276            result;
2277
2278        if (this.name in tree.functions) { // 1.
2279            try {
2280                result = tree.functions[this.name].apply(tree.functions, args);
2281                if (result != null) {
2282                    return result;
2283                }
2284            } catch (e) {
2285                throw { type: e.type || "Runtime",
2286                        message: "error evaluating function `" + this.name + "`" +
2287                                 (e.message ? ': ' + e.message : ''),
2288                        index: this.index, filename: this.filename };
2289            }
2290        }
2291       
2292        // 2.
2293        return new(tree.Anonymous)(this.name +
2294            "(" + args.map(function (a) { return a.toCSS(env) }).join(', ') + ")");
2295    },
2296
2297    toCSS: function (env) {
2298        return this.eval(env).toCSS();
2299    }
2300};
2301
2302})(require('../tree'));
2303(function (tree) {
2304//
2305// RGB Colors - #ff0014, #eee
2306//
2307tree.Color = function (rgb, a) {
2308    //
2309    // The end goal here, is to parse the arguments
2310    // into an integer triplet, such as `128, 255, 0`
2311    //
2312    // This facilitates operations and conversions.
2313    //
2314    if (Array.isArray(rgb)) {
2315        this.rgb = rgb;
2316    } else if (rgb.length == 6) {
2317        this.rgb = rgb.match(/.{2}/g).map(function (c) {
2318            return parseInt(c, 16);
2319        });
2320    } else {
2321        this.rgb = rgb.split('').map(function (c) {
2322            return parseInt(c + c, 16);
2323        });
2324    }
2325    this.alpha = typeof(a) === 'number' ? a : 1;
2326};
2327tree.Color.prototype = {
2328    eval: function () { return this },
2329
2330    //
2331    // If we have some transparency, the only way to represent it
2332    // is via `rgba`. Otherwise, we use the hex representation,
2333    // which has better compatibility with older browsers.
2334    // Values are capped between `0` and `255`, rounded and zero-padded.
2335    //
2336    toCSS: function () {
2337        if (this.alpha < 1.0) {
2338            return "rgba(" + this.rgb.map(function (c) {
2339                return Math.round(c);
2340            }).concat(this.alpha).join(', ') + ")";
2341        } else {
2342            return '#' + this.rgb.map(function (i) {
2343                i = Math.round(i);
2344                i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
2345                return i.length === 1 ? '0' + i : i;
2346            }).join('');
2347        }
2348    },
2349
2350    //
2351    // Operations have to be done per-channel, if not,
2352    // channels will spill onto each other. Once we have
2353    // our result, in the form of an integer triplet,
2354    // we create a new Color node to hold the result.
2355    //
2356    operate: function (op, other) {
2357        var result = [];
2358
2359        if (! (other instanceof tree.Color)) {
2360            other = other.toColor();
2361        }
2362
2363        for (var c = 0; c < 3; c++) {
2364            result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
2365        }
2366        return new(tree.Color)(result, this.alpha + other.alpha);
2367    },
2368
2369    toHSL: function () {
2370        var r = this.rgb[0] / 255,
2371            g = this.rgb[1] / 255,
2372            b = this.rgb[2] / 255,
2373            a = this.alpha;
2374
2375        var max = Math.max(r, g, b), min = Math.min(r, g, b);
2376        var h, s, l = (max + min) / 2, d = max - min;
2377
2378        if (max === min) {
2379            h = s = 0;
2380        } else {
2381            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
2382
2383            switch (max) {
2384                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
2385                case g: h = (b - r) / d + 2;               break;
2386                case b: h = (r - g) / d + 4;               break;
2387            }
2388            h /= 6;
2389        }
2390        return { h: h * 360, s: s, l: l, a: a };
2391    },
2392    toARGB: function () {
2393        var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
2394        return '#' + argb.map(function (i) {
2395            i = Math.round(i);
2396            i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
2397            return i.length === 1 ? '0' + i : i;
2398        }).join('');
2399    },
2400    compare: function (x) {
2401        if (!x.rgb) {
2402            return -1;
2403        }
2404       
2405        return (x.rgb[0] === this.rgb[0] &&
2406            x.rgb[1] === this.rgb[1] &&
2407            x.rgb[2] === this.rgb[2] &&
2408            x.alpha === this.alpha) ? 0 : -1;
2409    }
2410};
2411
2412
2413})(require('../tree'));
2414(function (tree) {
2415
2416tree.Comment = function (value, silent) {
2417    this.value = value;
2418    this.silent = !!silent;
2419};
2420tree.Comment.prototype = {
2421    toCSS: function (env) {
2422        return env.compress ? '' : this.value;
2423    },
2424    eval: function () { return this }
2425};
2426
2427})(require('../tree'));
2428(function (tree) {
2429
2430tree.Condition = function (op, l, r, i, negate) {
2431    this.op = op.trim();
2432    this.lvalue = l;
2433    this.rvalue = r;
2434    this.index = i;
2435    this.negate = negate;
2436};
2437tree.Condition.prototype.eval = function (env) {
2438    var a = this.lvalue.eval(env),
2439        b = this.rvalue.eval(env);
2440
2441    var i = this.index, result;
2442
2443    var result = (function (op) {
2444        switch (op) {
2445            case 'and':
2446                return a && b;
2447            case 'or':
2448                return a || b;
2449            default:
2450                if (a.compare) {
2451                    result = a.compare(b);
2452                } else if (b.compare) {
2453                    result = b.compare(a);
2454                } else {
2455                    throw { type: "Type",
2456                            message: "Unable to perform comparison",
2457                            index: i };
2458                }
2459                switch (result) {
2460                    case -1: return op === '<' || op === '=<';
2461                    case  0: return op === '=' || op === '>=' || op === '=<';
2462                    case  1: return op === '>' || op === '>=';
2463                }
2464        }
2465    })(this.op);
2466    return this.negate ? !result : result;
2467};
2468
2469})(require('../tree'));
2470(function (tree) {
2471
2472//
2473// A number with a unit
2474//
2475tree.Dimension = function (value, unit) {
2476    this.value = parseFloat(value);
2477    this.unit = unit || null;
2478};
2479
2480tree.Dimension.prototype = {
2481    eval: function () { return this },
2482    toColor: function () {
2483        return new(tree.Color)([this.value, this.value, this.value]);
2484    },
2485    toCSS: function () {
2486        var css = this.value + this.unit;
2487        return css;
2488    },
2489
2490    // In an operation between two Dimensions,
2491    // we default to the first Dimension's unit,
2492    // so `1px + 2em` will yield `3px`.
2493    // In the future, we could implement some unit
2494    // conversions such that `100cm + 10mm` would yield
2495    // `101cm`.
2496    operate: function (op, other) {
2497        return new(tree.Dimension)
2498                  (tree.operate(op, this.value, other.value),
2499                  this.unit || other.unit);
2500    },
2501
2502    compare: function (other) {
2503        if (other instanceof tree.Dimension) {
2504            if (other.value > this.value) {
2505                return -1;
2506            } else if (other.value < this.value) {
2507                return 1;
2508            } else {
2509                if (other.unit && this.unit !== other.unit) {
2510                    return -1;
2511                }
2512                return 0;
2513            }
2514        } else {
2515            return -1;
2516        }
2517    }
2518};
2519
2520})(require('../tree'));
2521(function (tree) {
2522
2523tree.Directive = function (name, value) {
2524    this.name = name;
2525
2526    if (Array.isArray(value)) {
2527        this.ruleset = new(tree.Ruleset)([], value);
2528        this.ruleset.allowImports = true;
2529    } else {
2530        this.value = value;
2531    }
2532};
2533tree.Directive.prototype = {
2534    toCSS: function (ctx, env) {
2535        if (this.ruleset) {
2536            this.ruleset.root = true;
2537            return this.name + (env.compress ? '{' : ' {\n  ') +
2538                   this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n  ') +
2539                               (env.compress ? '}': '\n}\n');
2540        } else {
2541            return this.name + ' ' + this.value.toCSS() + ';\n';
2542        }
2543    },
2544    eval: function (env) {
2545        var evaldDirective = this;
2546        if (this.ruleset) {
2547            env.frames.unshift(this);
2548            evaldDirective = new(tree.Directive)(this.name);
2549            evaldDirective.ruleset = this.ruleset.eval(env);
2550            env.frames.shift();
2551        }
2552        return evaldDirective;
2553    },
2554    variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
2555    find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
2556    rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
2557};
2558
2559})(require('../tree'));
2560(function (tree) {
2561
2562tree.Element = function (combinator, value, index) {
2563    this.combinator = combinator instanceof tree.Combinator ?
2564                      combinator : new(tree.Combinator)(combinator);
2565
2566    if (typeof(value) === 'string') {
2567        this.value = value.trim();
2568    } else if (value) {
2569        this.value = value;
2570    } else {
2571        this.value = "";
2572    }
2573    this.index = index;
2574};
2575tree.Element.prototype.eval = function (env) {
2576    return new(tree.Element)(this.combinator,
2577                             this.value.eval ? this.value.eval(env) : this.value,
2578                             this.index);
2579};
2580tree.Element.prototype.toCSS = function (env) {
2581        var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
2582        if (value == '' && this.combinator.value.charAt(0) == '&') {
2583                return '';
2584        } else {
2585                return this.combinator.toCSS(env || {}) + value;
2586        }
2587};
2588
2589tree.Combinator = function (value) {
2590    if (value === ' ') {
2591        this.value = ' ';
2592    } else {
2593        this.value = value ? value.trim() : "";
2594    }
2595};
2596tree.Combinator.prototype.toCSS = function (env) {
2597    return {
2598        ''  : '',
2599        ' ' : ' ',
2600        ':' : ' :',
2601        '+' : env.compress ? '+' : ' + ',
2602        '~' : env.compress ? '~' : ' ~ ',
2603        '>' : env.compress ? '>' : ' > ',
2604        '|' : env.compress ? '|' : ' | '
2605    }[this.value];
2606};
2607
2608})(require('../tree'));
2609(function (tree) {
2610
2611tree.Expression = function (value) { this.value = value };
2612tree.Expression.prototype = {
2613    eval: function (env) {
2614        if (this.value.length > 1) {
2615            return new(tree.Expression)(this.value.map(function (e) {
2616                return e.eval(env);
2617            }));
2618        } else if (this.value.length === 1) {
2619            return this.value[0].eval(env);
2620        } else {
2621            return this;
2622        }
2623    },
2624    toCSS: function (env) {
2625        return this.value.map(function (e) {
2626            return e.toCSS ? e.toCSS(env) : '';
2627        }).join(' ');
2628    }
2629};
2630
2631})(require('../tree'));
2632(function (tree) {
2633//
2634// CSS @import node
2635//
2636// The general strategy here is that we don't want to wait
2637// for the parsing to be completed, before we start importing
2638// the file. That's because in the context of a browser,
2639// most of the time will be spent waiting for the server to respond.
2640//
2641// On creation, we push the import path to our import queue, though
2642// `import,push`, we also pass it a callback, which it'll call once
2643// the file has been fetched, and parsed.
2644//
2645tree.Import = function (path, imports, features, once, index, rootpath) {
2646    var that = this;
2647
2648    this.once = once;
2649    this.index = index;
2650    this._path = path;
2651    this.features = features && new(tree.Value)(features);
2652    this.rootpath = rootpath;
2653               
2654    // The '.less' extension is optional
2655    if (path instanceof tree.Quoted) {
2656        this.path = /(\.[a-z]*$)|([\?;].*)$/.test(path.value) ? path.value : path.value + '.less';
2657    } else {
2658        this.path = path.value.value || path.value;
2659    }
2660
2661    this.css = /css([\?;].*)?$/.test(this.path);
2662
2663    // Only pre-compile .less files
2664    if (! this.css) {
2665        imports.push(this.path, function (e, root, imported) {
2666            if (e) { e.index = index }
2667            if (imported && that.once) that.skip = imported;
2668            that.root = root || new(tree.Ruleset)([], []);
2669        });
2670    }
2671};
2672
2673//
2674// The actual import node doesn't return anything, when converted to CSS.
2675// The reason is that it's used at the evaluation stage, so that the rules
2676// it imports can be treated like any other rules.
2677//
2678// In `eval`, we make sure all Import nodes get evaluated, recursively, so
2679// we end up with a flat structure, which can easily be imported in the parent
2680// ruleset.
2681//
2682tree.Import.prototype = {
2683    toCSS: function (env) {
2684        var features = this.features ? ' ' + this.features.toCSS(env) : '';
2685
2686        if (this.css) {
2687            // Add the base path if the import is relative
2688            if (typeof this._path.value === "string" && !/^(?:[a-z-]+:|\/)/.test(this._path.value)) {
2689                this._path.value = this.rootpath + this._path.value;
2690            }
2691            return "@import " + this._path.toCSS() + features + ';\n';
2692        } else {
2693            return "";
2694        }
2695    },
2696    eval: function (env) {
2697        var ruleset, features = this.features && this.features.eval(env);
2698
2699        if (this.skip) return [];
2700
2701        if (this.css) {
2702            return this;
2703        } else {
2704            ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
2705
2706            ruleset.evalImports(env);
2707
2708            return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
2709        }
2710    }
2711};
2712
2713})(require('../tree'));
2714(function (tree) {
2715
2716tree.JavaScript = function (string, index, escaped) {
2717    this.escaped = escaped;
2718    this.expression = string;
2719    this.index = index;
2720};
2721tree.JavaScript.prototype = {
2722    eval: function (env) {
2723        var result,
2724            that = this,
2725            context = {};
2726
2727        var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
2728            return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
2729        });
2730
2731        try {
2732            expression = new(Function)('return (' + expression + ')');
2733        } catch (e) {
2734            throw { message: "JavaScript evaluation error: `" + expression + "`" ,
2735                    index: this.index };
2736        }
2737
2738        for (var k in env.frames[0].variables()) {
2739            context[k.slice(1)] = {
2740                value: env.frames[0].variables()[k].value,
2741                toJS: function () {
2742                    return this.value.eval(env).toCSS();
2743                }
2744            };
2745        }
2746
2747        try {
2748            result = expression.call(context);
2749        } catch (e) {
2750            throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
2751                    index: this.index };
2752        }
2753        if (typeof(result) === 'string') {
2754            return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
2755        } else if (Array.isArray(result)) {
2756            return new(tree.Anonymous)(result.join(', '));
2757        } else {
2758            return new(tree.Anonymous)(result);
2759        }
2760    }
2761};
2762
2763})(require('../tree'));
2764
2765(function (tree) {
2766
2767tree.Keyword = function (value) { this.value = value };
2768tree.Keyword.prototype = {
2769    eval: function () { return this },
2770    toCSS: function () { return this.value },
2771    compare: function (other) {
2772        if (other instanceof tree.Keyword) {
2773            return other.value === this.value ? 0 : 1;
2774        } else {
2775            return -1;
2776        }
2777    }
2778};
2779
2780tree.True = new(tree.Keyword)('true');
2781tree.False = new(tree.Keyword)('false');
2782
2783})(require('../tree'));
2784(function (tree) {
2785
2786tree.Media = function (value, features) {
2787    var selectors = this.emptySelectors();
2788
2789    this.features = new(tree.Value)(features);
2790    this.ruleset = new(tree.Ruleset)(selectors, value);
2791    this.ruleset.allowImports = true;
2792};
2793tree.Media.prototype = {
2794    toCSS: function (ctx, env) {
2795        var features = this.features.toCSS(env);
2796
2797        this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
2798        return '@media ' + features + (env.compress ? '{' : ' {\n  ') +
2799               this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n  ') +
2800                           (env.compress ? '}': '\n}\n');
2801    },
2802    eval: function (env) {
2803        if (!env.mediaBlocks) {
2804            env.mediaBlocks = [];
2805            env.mediaPath = [];
2806        }
2807       
2808        var media = new(tree.Media)([], []);
2809        if(this.debugInfo) {
2810            this.ruleset.debugInfo = this.debugInfo;
2811            media.debugInfo = this.debugInfo;
2812        }
2813        media.features = this.features.eval(env);
2814       
2815        env.mediaPath.push(media);
2816        env.mediaBlocks.push(media);
2817       
2818        env.frames.unshift(this.ruleset);
2819        media.ruleset = this.ruleset.eval(env);
2820        env.frames.shift();
2821       
2822        env.mediaPath.pop();
2823
2824        return env.mediaPath.length === 0 ? media.evalTop(env) :
2825                    media.evalNested(env)
2826    },
2827    variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
2828    find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
2829    rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
2830    emptySelectors: function() {
2831        var el = new(tree.Element)('', '&', 0);
2832        return [new(tree.Selector)([el])];
2833    },
2834
2835    evalTop: function (env) {
2836        var result = this;
2837
2838        // Render all dependent Media blocks.
2839        if (env.mediaBlocks.length > 1) {
2840            var selectors = this.emptySelectors();
2841            result = new(tree.Ruleset)(selectors, env.mediaBlocks);
2842            result.multiMedia = true;
2843        }
2844
2845        delete env.mediaBlocks;
2846        delete env.mediaPath;
2847
2848        return result;
2849    },
2850    evalNested: function (env) {
2851        var i, value,
2852            path = env.mediaPath.concat([this]);
2853
2854        // Extract the media-query conditions separated with `,` (OR).
2855        for (i = 0; i < path.length; i++) {
2856            value = path[i].features instanceof tree.Value ?
2857                        path[i].features.value : path[i].features;
2858            path[i] = Array.isArray(value) ? value : [value];
2859        }
2860
2861        // Trace all permutations to generate the resulting media-query.
2862        //
2863        // (a, b and c) with nested (d, e) ->
2864        //    a and d
2865        //    a and e
2866        //    b and c and d
2867        //    b and c and e
2868        this.features = new(tree.Value)(this.permute(path).map(function (path) {
2869            path = path.map(function (fragment) {
2870                return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
2871            });
2872
2873            for(i = path.length - 1; i > 0; i--) {
2874                path.splice(i, 0, new(tree.Anonymous)("and"));
2875            }
2876
2877            return new(tree.Expression)(path);
2878        }));
2879
2880        // Fake a tree-node that doesn't output anything.
2881        return new(tree.Ruleset)([], []);
2882    },
2883    permute: function (arr) {
2884      if (arr.length === 0) {
2885          return [];
2886      } else if (arr.length === 1) {
2887          return arr[0];
2888      } else {
2889          var result = [];
2890          var rest = this.permute(arr.slice(1));
2891          for (var i = 0; i < rest.length; i++) {
2892              for (var j = 0; j < arr[0].length; j++) {
2893                  result.push([arr[0][j]].concat(rest[i]));
2894              }
2895          }
2896          return result;
2897      }
2898    },
2899    bubbleSelectors: function (selectors) {
2900      this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]);
2901    }
2902};
2903
2904})(require('../tree'));
2905(function (tree) {
2906
2907tree.mixin = {};
2908tree.mixin.Call = function (elements, args, index, filename, important) {
2909    this.selector = new(tree.Selector)(elements);
2910    this.arguments = args;
2911    this.index = index;
2912    this.filename = filename;
2913    this.important = important;
2914};
2915tree.mixin.Call.prototype = {
2916    eval: function (env) {
2917        var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound;
2918
2919        args = this.arguments && this.arguments.map(function (a) {
2920            return { name: a.name, value: a.value.eval(env) };
2921        });
2922
2923        for (i = 0; i < env.frames.length; i++) {
2924            if ((mixins = env.frames[i].find(this.selector)).length > 0) {
2925                isOneFound = true;
2926                for (m = 0; m < mixins.length; m++) {
2927                    mixin = mixins[m];
2928                    isRecursive = false;
2929                    for(f = 0; f < env.frames.length; f++) {
2930                        if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
2931                            isRecursive = true;
2932                            break;
2933                        }
2934                    }
2935                    if (isRecursive) {
2936                        continue;
2937                    }
2938                    if (mixin.matchArgs(args, env)) {
2939                        if (!mixin.matchCondition || mixin.matchCondition(args, env)) {
2940                            try {
2941                                Array.prototype.push.apply(
2942                                      rules, mixin.eval(env, args, this.important).rules);
2943                            } catch (e) {
2944                                throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
2945                            }
2946                        }
2947                        match = true;
2948                    }
2949                }
2950                if (match) {
2951                    return rules;
2952                }
2953            }
2954        }
2955        if (isOneFound) {
2956            throw { type:    'Runtime',
2957                    message: 'No matching definition was found for `' +
2958                              this.selector.toCSS().trim() + '('      +
2959                              (args ? args.map(function (a) {
2960                                  var argValue = "";
2961                                  if (a.name) {
2962                                      argValue += a.name + ":";
2963                                  }
2964                                  if (a.value.toCSS) {
2965                                      argValue += a.value.toCSS();
2966                                  } else {
2967                                      argValue += "???";
2968                                  }
2969                                  return argValue;
2970                              }).join(', ') : "") + ")`",
2971                    index:   this.index, filename: this.filename };
2972        } else {
2973            throw { type: 'Name',
2974                message: this.selector.toCSS().trim() + " is undefined",
2975                index: this.index, filename: this.filename };
2976        }
2977    }
2978};
2979
2980tree.mixin.Definition = function (name, params, rules, condition, variadic) {
2981    this.name = name;
2982    this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
2983    this.params = params;
2984    this.condition = condition;
2985    this.variadic = variadic;
2986    this.arity = params.length;
2987    this.rules = rules;
2988    this._lookups = {};
2989    this.required = params.reduce(function (count, p) {
2990        if (!p.name || (p.name && !p.value)) { return count + 1 }
2991        else                                 { return count }
2992    }, 0);
2993    this.parent = tree.Ruleset.prototype;
2994    this.frames = [];
2995};
2996tree.mixin.Definition.prototype = {
2997    toCSS:     function ()     { return "" },
2998    variable:  function (name) { return this.parent.variable.call(this, name) },
2999    variables: function ()     { return this.parent.variables.call(this) },
3000    find:      function ()     { return this.parent.find.apply(this, arguments) },
3001    rulesets:  function ()     { return this.parent.rulesets.apply(this) },
3002
3003    evalParams: function (env, mixinEnv, args, evaldArguments) {
3004        var frame = new(tree.Ruleset)(null, []), varargs, arg, params = this.params.slice(0), i, j, val, name, isNamedFound, argIndex;
3005       
3006        if (args) {
3007            args = args.slice(0);
3008
3009            for(i = 0; i < args.length; i++) {
3010                arg = args[i];
3011                if (name = (arg && arg.name)) {
3012                    isNamedFound = false;
3013                    for(j = 0; j < params.length; j++) {
3014                        if (!evaldArguments[j] && name === params[j].name) {
3015                            evaldArguments[j] = arg.value.eval(env);
3016                            frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env)));
3017                            isNamedFound = true;
3018                            break;
3019                        }
3020                    }
3021                    if (isNamedFound) {
3022                        args.splice(i, 1);
3023                        i--;
3024                        continue;
3025                    } else {
3026                        throw { type: 'Runtime', message: "Named argument for " + this.name +
3027                            ' ' + args[i].name + ' not found' };
3028                    }
3029                }
3030            }
3031        }
3032        argIndex = 0;
3033        for (i = 0; i < params.length; i++) {
3034            if (evaldArguments[i]) continue;
3035           
3036            arg = args && args[argIndex];
3037
3038            if (name = params[i].name) {
3039                if (params[i].variadic && args) {
3040                    varargs = [];
3041                    for (j = argIndex; j < args.length; j++) {
3042                        varargs.push(args[j].value.eval(env));
3043                    }
3044                    frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
3045                } else {
3046                    val = arg && arg.value;
3047                    if (val) {
3048                        val = val.eval(env);
3049                    } else if (params[i].value) {
3050                        val = params[i].value.eval(mixinEnv);
3051                    } else {
3052                        throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
3053                            ' (' + args.length + ' for ' + this.arity + ')' };
3054                    }
3055                   
3056                    frame.rules.unshift(new(tree.Rule)(name, val));
3057                    evaldArguments[i] = val;
3058                }
3059            }
3060           
3061            if (params[i].variadic && args) {
3062                for (j = argIndex; j < args.length; j++) {
3063                    evaldArguments[j] = args[j].value.eval(env);
3064                }
3065            }
3066            argIndex++;
3067        }
3068
3069        return frame;
3070    },
3071    eval: function (env, args, important) {
3072        var _arguments = [],
3073            mixinFrames = this.frames.concat(env.frames),
3074            frame = this.evalParams(env, {frames: mixinFrames}, args, _arguments),
3075            context, rules, start, ruleset;
3076
3077        frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
3078
3079        rules = important ?
3080            this.parent.makeImportant.apply(this).rules : this.rules.slice(0);
3081
3082        ruleset = new(tree.Ruleset)(null, rules).eval({
3083            frames: [this, frame].concat(mixinFrames)
3084        });
3085        ruleset.originalRuleset = this;
3086        return ruleset;
3087    },
3088    matchCondition: function (args, env) {
3089        if (this.condition && !this.condition.eval({
3090            frames: [this.evalParams(env, {frames: this.frames.concat(env.frames)}, args, [])].concat(env.frames)
3091        }))                                                           { return false }
3092        return true;
3093    },
3094    matchArgs: function (args, env) {
3095        var argsLength = (args && args.length) || 0, len, frame;
3096
3097        if (! this.variadic) {
3098            if (argsLength < this.required)                               { return false }
3099            if (argsLength > this.params.length)                          { return false }
3100            if ((this.required > 0) && (argsLength > this.params.length)) { return false }
3101        }
3102
3103        len = Math.min(argsLength, this.arity);
3104
3105        for (var i = 0; i < len; i++) {
3106            if (!this.params[i].name && !this.params[i].variadic) {
3107                if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
3108                    return false;
3109                }
3110            }
3111        }
3112        return true;
3113    }
3114};
3115
3116})(require('../tree'));
3117(function (tree) {
3118
3119tree.Operation = function (op, operands) {
3120    this.op = op.trim();
3121    this.operands = operands;
3122};
3123tree.Operation.prototype.eval = function (env) {
3124    var a = this.operands[0].eval(env),
3125        b = this.operands[1].eval(env),
3126        temp;
3127
3128    if (a instanceof tree.Dimension && b instanceof tree.Color) {
3129        if (this.op === '*' || this.op === '+') {
3130            temp = b, b = a, a = temp;
3131        } else {
3132            throw { name: "OperationError",
3133                    message: "Can't substract or divide a color from a number" };
3134        }
3135    }
3136    if (!a.operate) {
3137        throw { name: "OperationError",
3138                message: "Operation on an invalid type" };
3139    }
3140
3141    return a.operate(this.op, b);
3142};
3143
3144tree.operate = function (op, a, b) {
3145    switch (op) {
3146        case '+': return a + b;
3147        case '-': return a - b;
3148        case '*': return a * b;
3149        case '/': return a / b;
3150    }
3151};
3152
3153})(require('../tree'));
3154
3155(function (tree) {
3156
3157tree.Paren = function (node) {
3158    this.value = node;
3159};
3160tree.Paren.prototype = {
3161    toCSS: function (env) {
3162        return '(' + this.value.toCSS(env) + ')';
3163    },
3164    eval: function (env) {
3165        return new(tree.Paren)(this.value.eval(env));
3166    }
3167};
3168
3169})(require('../tree'));
3170(function (tree) {
3171
3172tree.Quoted = function (str, content, escaped, i) {
3173    this.escaped = escaped;
3174    this.value = content || '';
3175    this.quote = str.charAt(0);
3176    this.index = i;
3177};
3178tree.Quoted.prototype = {
3179    toCSS: function () {
3180        if (this.escaped) {
3181            return this.value;
3182        } else {
3183            return this.quote + this.value + this.quote;
3184        }
3185    },
3186    eval: function (env) {
3187        var that = this;
3188        var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
3189            return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
3190        }).replace(/@\{([\w-]+)\}/g, function (_, name) {
3191            var v = new(tree.Variable)('@' + name, that.index).eval(env);
3192            return (v instanceof tree.Quoted) ? v.value : v.toCSS();
3193        });
3194        return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
3195    },
3196    compare: function (x) {
3197        if (!x.toCSS) {
3198            return -1;
3199        }
3200       
3201        var left = this.toCSS(),
3202            right = x.toCSS();
3203       
3204        if (left === right) {
3205            return 0;
3206        }
3207       
3208        return left < right ? -1 : 1;
3209    }
3210};
3211
3212})(require('../tree'));
3213(function (tree) {
3214
3215tree.Ratio = function (value) {
3216    this.value = value;
3217};
3218tree.Ratio.prototype = {
3219    toCSS: function (env) {
3220        return this.value;
3221    },
3222    eval: function () { return this }
3223};
3224
3225})(require('../tree'));
3226(function (tree) {
3227
3228tree.Rule = function (name, value, important, index, inline) {
3229    this.name = name;
3230    this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
3231    this.important = important ? ' ' + important.trim() : '';
3232    this.index = index;
3233    this.inline = inline || false;
3234
3235    if (name.charAt(0) === '@') {
3236        this.variable = true;
3237    } else { this.variable = false }
3238};
3239tree.Rule.prototype.toCSS = function (env) {
3240    if (this.variable) { return "" }
3241    else {
3242        return this.name + (env.compress ? ':' : ': ') +
3243               this.value.toCSS(env) +
3244               this.important + (this.inline ? "" : ";");
3245    }
3246};
3247
3248tree.Rule.prototype.eval = function (context) {
3249    return new(tree.Rule)(this.name,
3250                          this.value.eval(context),
3251                          this.important,
3252                          this.index, this.inline);
3253};
3254
3255tree.Rule.prototype.makeImportant = function () {
3256    return new(tree.Rule)(this.name,
3257                          this.value,
3258                          "!important",
3259                          this.index, this.inline);
3260};
3261
3262tree.Shorthand = function (a, b) {
3263    this.a = a;
3264    this.b = b;
3265};
3266
3267tree.Shorthand.prototype = {
3268    toCSS: function (env) {
3269        return this.a.toCSS(env) + "/" + this.b.toCSS(env);
3270    },
3271    eval: function () { return this }
3272};
3273
3274})(require('../tree'));
3275(function (tree) {
3276
3277tree.Ruleset = function (selectors, rules, strictImports) {
3278    this.selectors = selectors;
3279    this.rules = rules;
3280    this._lookups = {};
3281    this.strictImports = strictImports;
3282};
3283tree.Ruleset.prototype = {
3284    eval: function (env) {
3285        var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
3286        var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
3287        var rules;
3288       
3289        ruleset.originalRuleset = this;
3290        ruleset.root = this.root;
3291        ruleset.allowImports = this.allowImports;
3292
3293        if(this.debugInfo) {
3294            ruleset.debugInfo = this.debugInfo;
3295        }
3296
3297        // push the current ruleset to the frames stack
3298        env.frames.unshift(ruleset);
3299
3300        // Evaluate imports
3301        if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
3302            ruleset.evalImports(env);
3303        }
3304
3305        // Store the frames around mixin definitions,
3306        // so they can be evaluated like closures when the time comes.
3307        for (var i = 0; i < ruleset.rules.length; i++) {
3308            if (ruleset.rules[i] instanceof tree.mixin.Definition) {
3309                ruleset.rules[i].frames = env.frames.slice(0);
3310            }
3311        }
3312       
3313        var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
3314
3315        // Evaluate mixin calls.
3316        for (var i = 0; i < ruleset.rules.length; i++) {
3317            if (ruleset.rules[i] instanceof tree.mixin.Call) {
3318                rules = ruleset.rules[i].eval(env);
3319                ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
3320                i += rules.length-1;
3321                ruleset.resetCache();
3322            }
3323        }
3324
3325        // Evaluate everything else
3326        for (var i = 0, rule; i < ruleset.rules.length; i++) {
3327            rule = ruleset.rules[i];
3328
3329            if (! (rule instanceof tree.mixin.Definition)) {
3330                ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
3331            }
3332        }
3333
3334        // Pop the stack
3335        env.frames.shift();
3336       
3337        if (env.mediaBlocks) {
3338            for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
3339                env.mediaBlocks[i].bubbleSelectors(selectors);
3340            }
3341        }
3342
3343        return ruleset;
3344    },
3345    evalImports: function(env) {
3346        var i, rules;
3347        for (i = 0; i < this.rules.length; i++) {
3348            if (this.rules[i] instanceof tree.Import) {
3349                rules = this.rules[i].eval(env);
3350                if (typeof rules.length === "number") {
3351                    this.rules.splice.apply(this.rules, [i, 1].concat(rules));
3352                    i+= rules.length-1;
3353                } else {
3354                    this.rules.splice(i, 1, rules);
3355                }
3356                this.resetCache();
3357            }
3358        }
3359    },
3360    makeImportant: function() {
3361        return new tree.Ruleset(this.selectors, this.rules.map(function (r) {
3362                    if (r.makeImportant) {
3363                        return r.makeImportant();
3364                    } else {
3365                        return r;
3366                    }
3367                }), this.strictImports);
3368    },
3369    matchArgs: function (args) {
3370        return !args || args.length === 0;
3371    },
3372    resetCache: function () {
3373        this._rulesets = null;
3374        this._variables = null;
3375        this._lookups = {};
3376    },
3377    variables: function () {
3378        if (this._variables) { return this._variables }
3379        else {
3380            return this._variables = this.rules.reduce(function (hash, r) {
3381                if (r instanceof tree.Rule && r.variable === true) {
3382                    hash[r.name] = r;
3383                }
3384                return hash;
3385            }, {});
3386        }
3387    },
3388    variable: function (name) {
3389        return this.variables()[name];
3390    },
3391    rulesets: function () {
3392        if (this._rulesets) { return this._rulesets }
3393        else {
3394            return this._rulesets = this.rules.filter(function (r) {
3395                return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
3396            });
3397        }
3398    },
3399    find: function (selector, self) {
3400        self = self || this;
3401        var rules = [], rule, match,
3402            key = selector.toCSS();
3403
3404        if (key in this._lookups) { return this._lookups[key] }
3405
3406        this.rulesets().forEach(function (rule) {
3407            if (rule !== self) {
3408                for (var j = 0; j < rule.selectors.length; j++) {
3409                    if (match = selector.match(rule.selectors[j])) {
3410                        if (selector.elements.length > rule.selectors[j].elements.length) {
3411                            Array.prototype.push.apply(rules, rule.find(
3412                                new(tree.Selector)(selector.elements.slice(1)), self));
3413                        } else {
3414                            rules.push(rule);
3415                        }
3416                        break;
3417                    }
3418                }
3419            }
3420        });
3421        return this._lookups[key] = rules;
3422    },
3423    //
3424    // Entry point for code generation
3425    //
3426    //     `context` holds an array of arrays.
3427    //
3428    toCSS: function (context, env) {
3429        var css = [],      // The CSS output
3430            rules = [],    // node.Rule instances
3431           _rules = [],    //
3432            rulesets = [], // node.Ruleset instances
3433            paths = [],    // Current selectors
3434            selector,      // The fully rendered selector
3435            debugInfo,     // Line number debugging
3436            rule;
3437
3438        if (! this.root) {
3439            this.joinSelectors(paths, context, this.selectors);
3440        }
3441
3442        // Compile rules and rulesets
3443        for (var i = 0; i < this.rules.length; i++) {
3444            rule = this.rules[i];
3445
3446            if (rule.rules || (rule instanceof tree.Media)) {
3447                rulesets.push(rule.toCSS(paths, env));
3448            } else if (rule instanceof tree.Directive) {
3449                var cssValue = rule.toCSS(paths, env);
3450                // Output only the first @charset definition as such - convert the others
3451                // to comments in case debug is enabled
3452                if (rule.name === "@charset") {
3453                    // Only output the debug info together with subsequent @charset definitions
3454                    // a comment (or @media statement) before the actual @charset directive would
3455                    // be considered illegal css as it has to be on the first line
3456                    if (env.charset) {
3457                        if (rule.debugInfo) {
3458                            rulesets.push(tree.debugInfo(env, rule));
3459                            rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env));
3460                        }
3461                        continue;
3462                    }
3463                    env.charset = true;
3464                }
3465                rulesets.push(cssValue);
3466            } else if (rule instanceof tree.Comment) {
3467                if (!rule.silent) {
3468                    if (this.root) {
3469                        rulesets.push(rule.toCSS(env));
3470                    } else {
3471                        rules.push(rule.toCSS(env));
3472                    }
3473                }
3474            } else {
3475                if (rule.toCSS && !rule.variable) {
3476                    rules.push(rule.toCSS(env));
3477                } else if (rule.value && !rule.variable) {
3478                    rules.push(rule.value.toString());
3479                }
3480            }
3481        }
3482
3483        rulesets = rulesets.join('');
3484
3485        // If this is the root node, we don't render
3486        // a selector, or {}.
3487        // Otherwise, only output if this ruleset has rules.
3488        if (this.root) {
3489            css.push(rules.join(env.compress ? '' : '\n'));
3490        } else {
3491            if (rules.length > 0) {
3492                debugInfo = tree.debugInfo(env, this);
3493                selector = paths.map(function (p) {
3494                    return p.map(function (s) {
3495                        return s.toCSS(env);
3496                    }).join('').trim();
3497                }).join(env.compress ? ',' : ',\n');
3498
3499                // Remove duplicates
3500                for (var i = rules.length - 1; i >= 0; i--) {
3501                    if (_rules.indexOf(rules[i]) === -1) {
3502                        _rules.unshift(rules[i]);
3503                    }
3504                }
3505                rules = _rules;
3506
3507                css.push(debugInfo + selector +
3508                        (env.compress ? '{' : ' {\n  ') +
3509                        rules.join(env.compress ? '' : '\n  ') +
3510                        (env.compress ? '}' : '\n}\n'));
3511            }
3512        }
3513        css.push(rulesets);
3514
3515        return css.join('')  + (env.compress ? '\n' : '');
3516    },
3517
3518    joinSelectors: function (paths, context, selectors) {
3519        for (var s = 0; s < selectors.length; s++) {
3520            this.joinSelector(paths, context, selectors[s]);
3521        }
3522    },
3523
3524    joinSelector: function (paths, context, selector) {
3525
3526        var i, j, k,
3527            hasParentSelector, newSelectors, el, sel, parentSel,
3528            newSelectorPath, afterParentJoin, newJoinedSelector,
3529            newJoinedSelectorEmpty, lastSelector, currentElements,
3530            selectorsMultiplied;
3531   
3532        for (i = 0; i < selector.elements.length; i++) {
3533            el = selector.elements[i];
3534            if (el.value === '&') {
3535                hasParentSelector = true;
3536            }
3537        }
3538   
3539        if (!hasParentSelector) {
3540            if (context.length > 0) {
3541                for(i = 0; i < context.length; i++) {
3542                    paths.push(context[i].concat(selector));
3543                }
3544            }
3545            else {
3546                paths.push([selector]);
3547            }
3548            return;
3549        }
3550
3551        // The paths are [[Selector]]
3552        // The first list is a list of comma seperated selectors
3553        // The inner list is a list of inheritance seperated selectors
3554        // e.g.
3555        // .a, .b {
3556        //   .c {
3557        //   }
3558        // }
3559        // == [[.a] [.c]] [[.b] [.c]]
3560        //
3561
3562        // the elements from the current selector so far
3563        currentElements = [];
3564        // the current list of new selectors to add to the path.
3565        // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
3566        // by the parents
3567        newSelectors = [[]];
3568
3569        for (i = 0; i < selector.elements.length; i++) {
3570            el = selector.elements[i];
3571            // non parent reference elements just get added
3572            if (el.value !== "&") {
3573                currentElements.push(el);
3574            } else {
3575                // the new list of selectors to add
3576                selectorsMultiplied = [];
3577
3578                // merge the current list of non parent selector elements
3579                // on to the current list of selectors to add
3580                if (currentElements.length > 0) {
3581                    this.mergeElementsOnToSelectors(currentElements, newSelectors);
3582                }
3583
3584                // loop through our current selectors
3585                for(j = 0; j < newSelectors.length; j++) {
3586                    sel = newSelectors[j];
3587                    // if we don't have any parent paths, the & might be in a mixin so that it can be used
3588                    // whether there are parents or not
3589                    if (context.length == 0) {
3590                        // the combinator used on el should now be applied to the next element instead so that
3591                        // it is not lost
3592                        if (sel.length > 0) {
3593                            sel[0].elements = sel[0].elements.slice(0);
3594                            sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator,  ""));
3595                        }
3596                        selectorsMultiplied.push(sel);
3597                    }
3598                    else {
3599                        // and the parent selectors
3600                        for(k = 0; k < context.length; k++) {
3601                            parentSel = context[k];
3602                            // We need to put the current selectors
3603                            // then join the last selector's elements on to the parents selectors
3604
3605                            // our new selector path
3606                            newSelectorPath = [];
3607                            // selectors from the parent after the join
3608                            afterParentJoin = [];
3609                            newJoinedSelectorEmpty = true;
3610
3611                            //construct the joined selector - if & is the first thing this will be empty,
3612                            // if not newJoinedSelector will be the last set of elements in the selector
3613                            if (sel.length > 0) {
3614                                newSelectorPath = sel.slice(0);
3615                                lastSelector = newSelectorPath.pop();
3616                                newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0));
3617                                newJoinedSelectorEmpty = false;
3618                            }
3619                            else {
3620                                newJoinedSelector = new(tree.Selector)([]);
3621                            }
3622
3623                            //put together the parent selectors after the join
3624                            if (parentSel.length > 1) {
3625                                afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
3626                            }
3627
3628                            if (parentSel.length > 0) {
3629                                newJoinedSelectorEmpty = false;
3630
3631                                // join the elements so far with the first part of the parent
3632                                newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0));
3633                                newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
3634                            }
3635
3636                            if (!newJoinedSelectorEmpty) {
3637                                // now add the joined selector
3638                                newSelectorPath.push(newJoinedSelector);
3639                            }
3640
3641                            // and the rest of the parent
3642                            newSelectorPath = newSelectorPath.concat(afterParentJoin);
3643
3644                            // add that to our new set of selectors
3645                            selectorsMultiplied.push(newSelectorPath);
3646                        }
3647                    }
3648                }
3649
3650                // our new selectors has been multiplied, so reset the state
3651                newSelectors = selectorsMultiplied;
3652                currentElements = [];
3653            }
3654        }
3655
3656        // if we have any elements left over (e.g. .a& .b == .b)
3657        // add them on to all the current selectors
3658        if (currentElements.length > 0) {
3659            this.mergeElementsOnToSelectors(currentElements, newSelectors);
3660        }
3661
3662        for(i = 0; i < newSelectors.length; i++) {
3663            paths.push(newSelectors[i]);
3664        }
3665    },
3666   
3667    mergeElementsOnToSelectors: function(elements, selectors) {
3668        var i, sel;
3669
3670        if (selectors.length == 0) {
3671            selectors.push([ new(tree.Selector)(elements) ]);
3672            return;
3673        }
3674
3675        for(i = 0; i < selectors.length; i++) {
3676            sel = selectors[i];
3677
3678            // if the previous thing in sel is a parent this needs to join on to it
3679            if (sel.length > 0) {
3680                sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements));
3681            }
3682            else {
3683                sel.push(new(tree.Selector)(elements));
3684            }
3685        }
3686    }
3687};
3688})(require('../tree'));
3689(function (tree) {
3690
3691tree.Selector = function (elements) {
3692    this.elements = elements;
3693};
3694tree.Selector.prototype.match = function (other) {
3695    var elements = this.elements,
3696        len = elements.length,
3697        oelements, olen, max, i;
3698
3699    oelements = other.elements.slice(
3700        (other.elements.length && other.elements[0].value === "&") ? 1 : 0);
3701    olen = oelements.length;
3702    max = Math.min(len, olen)
3703
3704    if (olen === 0 || len < olen) {
3705        return false;
3706    } else {
3707        for (i = 0; i < max; i++) {
3708            if (elements[i].value !== oelements[i].value) {
3709                return false;
3710            }
3711        }
3712    }
3713    return true;
3714};
3715tree.Selector.prototype.eval = function (env) {
3716    return new(tree.Selector)(this.elements.map(function (e) {
3717        return e.eval(env);
3718    }));
3719};
3720tree.Selector.prototype.toCSS = function (env) {
3721    if (this._css) { return this._css }
3722   
3723    if (this.elements[0].combinator.value === "") {
3724        this._css = ' ';
3725    } else {
3726        this._css = '';
3727    }
3728   
3729    this._css += this.elements.map(function (e) {
3730        if (typeof(e) === 'string') {
3731            return ' ' + e.trim();
3732        } else {
3733            return e.toCSS(env);
3734        }
3735    }).join('');
3736   
3737    return this._css;
3738};
3739
3740})(require('../tree'));
3741(function (tree) {
3742
3743tree.UnicodeDescriptor = function (value) {
3744    this.value = value;
3745};
3746tree.UnicodeDescriptor.prototype = {
3747    toCSS: function (env) {
3748        return this.value;
3749    },
3750    eval: function () { return this }
3751};
3752
3753})(require('../tree'));
3754(function (tree) {
3755
3756tree.URL = function (val, rootpath) {
3757    this.value = val;
3758    this.rootpath = rootpath;
3759};
3760tree.URL.prototype = {
3761    toCSS: function () {
3762        return "url(" + this.value.toCSS() + ")";
3763    },
3764    eval: function (ctx) {
3765        var val = this.value.eval(ctx), rootpath;
3766
3767        // Add the base path if the URL is relative
3768        if (typeof val.value === "string" && !/^(?:[a-z-]+:|\/)/.test(val.value)) {
3769            rootpath = this.rootpath;
3770            if (!val.quote) {
3771                rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
3772            }
3773            val.value = rootpath + val.value;
3774        }
3775
3776        return new(tree.URL)(val, this.rootpath);
3777    }
3778};
3779
3780})(require('../tree'));
3781(function (tree) {
3782
3783tree.Value = function (value) {
3784    this.value = value;
3785    this.is = 'value';
3786};
3787tree.Value.prototype = {
3788    eval: function (env) {
3789        if (this.value.length === 1) {
3790            return this.value[0].eval(env);
3791        } else {
3792            return new(tree.Value)(this.value.map(function (v) {
3793                return v.eval(env);
3794            }));
3795        }
3796    },
3797    toCSS: function (env) {
3798        return this.value.map(function (e) {
3799            return e.toCSS(env);
3800        }).join(env.compress ? ',' : ', ');
3801    }
3802};
3803
3804})(require('../tree'));
3805(function (tree) {
3806
3807tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file };
3808tree.Variable.prototype = {
3809    eval: function (env) {
3810        var variable, v, name = this.name;
3811
3812        if (name.indexOf('@@') == 0) {
3813            name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
3814        }
3815       
3816        if (this.evaluating) {
3817            throw { type: 'Name',
3818                    message: "Recursive variable definition for " + name,
3819                    filename: this.file,
3820                    index: this.index };
3821        }
3822       
3823        this.evaluating = true;
3824
3825        if (variable = tree.find(env.frames, function (frame) {
3826            if (v = frame.variable(name)) {
3827                return v.value.eval(env);
3828            }
3829        })) {
3830            this.evaluating = false;
3831            return variable;
3832        }
3833        else {
3834            throw { type: 'Name',
3835                    message: "variable " + name + " is undefined",
3836                    filename: this.file,
3837                    index: this.index };
3838        }
3839    }
3840};
3841
3842})(require('../tree'));
3843(function (tree) {
3844
3845tree.debugInfo = function(env, ctx) {
3846    var result="";
3847    if (env.dumpLineNumbers && !env.compress) {
3848        switch(env.dumpLineNumbers) {
3849            case 'comments':
3850                result = tree.debugInfo.asComment(ctx);
3851                break;
3852            case 'mediaquery':
3853                result = tree.debugInfo.asMediaQuery(ctx);
3854                break;
3855            case 'all':
3856                result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx);
3857                break;
3858        }
3859    }
3860    return result;
3861};
3862
3863tree.debugInfo.asComment = function(ctx) {
3864    return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
3865};
3866
3867tree.debugInfo.asMediaQuery = function(ctx) {
3868    return '@media -sass-debug-info{filename{font-family:' +
3869        ('file://' + ctx.debugInfo.fileName).replace(/[\/:.]/g, '\\$&') +
3870        '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
3871};
3872
3873tree.find = function (obj, fun) {
3874    for (var i = 0, r; i < obj.length; i++) {
3875        if (r = fun.call(obj, obj[i])) { return r }
3876    }
3877    return null;
3878};
3879tree.jsify = function (obj) {
3880    if (Array.isArray(obj.value) && (obj.value.length > 1)) {
3881        return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
3882    } else {
3883        return obj.toCSS(false);
3884    }
3885};
3886
3887})(require('./tree'));
3888//
3889// browser.js - client-side engine
3890//
3891
3892var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);
3893
3894less.env = less.env || (location.hostname == '127.0.0.1' ||
3895                        location.hostname == '0.0.0.0'   ||
3896                        location.hostname == 'localhost' ||
3897                        location.port.length > 0         ||
3898                        isFileProtocol                   ? 'development'
3899                                                         : 'production');
3900
3901// Load styles asynchronously (default: false)
3902//
3903// This is set to `false` by default, so that the body
3904// doesn't start loading before the stylesheets are parsed.
3905// Setting this to `true` can result in flickering.
3906//
3907less.async = less.async || false;
3908less.fileAsync = less.fileAsync || false;
3909
3910// Interval between watch polls
3911less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
3912
3913//Setup user functions
3914if (less.functions) {
3915    for(var func in less.functions) {
3916        less.tree.functions[func] = less.functions[func];
3917   }
3918}
3919
3920var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);
3921if (dumpLineNumbers) {
3922    less.dumpLineNumbers = dumpLineNumbers[1];
3923}
3924
3925//
3926// Watch mode
3927//
3928less.watch   = function () {   
3929        if (!less.watchMode ){         
3930                less.env = 'development';
3931                initRunningMode();
3932        }
3933        return this.watchMode = true
3934};
3935
3936less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; };
3937
3938function initRunningMode(){
3939        if (less.env === 'development') {               
3940                less.optimization = 0;         
3941                less.watchTimer = setInterval(function () {                     
3942                        if (less.watchMode) {
3943                                loadStyleSheets(function (e, root, _, sheet, env) {
3944                                        if (root) {
3945                                                createCSS(root.toCSS(), sheet, env.lastModified);
3946                                        }
3947                                });
3948                        }
3949                }, less.poll);
3950        } else {
3951                less.optimization = 3;
3952        }
3953}
3954
3955if (/!watch/.test(location.hash)) {
3956        less.watch();
3957}
3958
3959var cache = null;
3960
3961if (less.env != 'development') {
3962    try {
3963        cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
3964    } catch (_) {}
3965}
3966
3967//
3968// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
3969//
3970var links = document.getElementsByTagName('link');
3971var typePattern = /^text\/(x-)?less$/;
3972
3973less.sheets = [];
3974
3975for (var i = 0; i < links.length; i++) {
3976    if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
3977       (links[i].type.match(typePattern)))) {
3978        less.sheets.push(links[i]);
3979    }
3980}
3981
3982//
3983// With this function, it's possible to alter variables and re-render
3984// CSS without reloading less-files
3985//
3986var session_cache = '';
3987less.modifyVars = function(record) {
3988        var str = session_cache;
3989    for (name in record) {
3990        str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+
3991                ((record[name].slice(-1) === ';')? record[name] : record[name] +';');
3992    }
3993    new(less.Parser)().parse(str, function (e, root) {
3994        createCSS(root.toCSS(), less.sheets[less.sheets.length - 1]);
3995    });
3996};
3997
3998less.refresh = function (reload) {
3999    var startTime, endTime;
4000    startTime = endTime = new(Date);
4001
4002    loadStyleSheets(function (e, root, _, sheet, env) {
4003        if (env.local) {
4004            log("loading " + sheet.href + " from cache.");
4005        } else {
4006            log("parsed " + sheet.href + " successfully.");
4007            createCSS(root.toCSS(), sheet, env.lastModified);
4008        }
4009        log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
4010        (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
4011        endTime = new(Date);
4012    }, reload);
4013
4014    loadStyles();
4015};
4016less.refreshStyles = loadStyles;
4017
4018less.refresh(less.env === 'development');
4019
4020function loadStyles() {
4021    var styles = document.getElementsByTagName('style');
4022    for (var i = 0; i < styles.length; i++) {
4023        if (styles[i].type.match(typePattern)) {
4024            new(less.Parser)({
4025                filename: document.location.href.replace(/#.*$/, ''),
4026                dumpLineNumbers: less.dumpLineNumbers
4027            }).parse(styles[i].innerHTML || '', function (e, tree) {
4028                var css = tree.toCSS();
4029                var style = styles[i];
4030                style.type = 'text/css';
4031                if (style.styleSheet) {
4032                    style.styleSheet.cssText = css;
4033                } else {
4034                    style.innerHTML = css;
4035                }
4036            });
4037        }
4038    }
4039}
4040
4041function loadStyleSheets(callback, reload) {
4042    for (var i = 0; i < less.sheets.length; i++) {
4043        loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
4044    }
4045}
4046
4047function pathDiff(url, baseUrl) {
4048    // diff between two paths to create a relative path
4049
4050    var urlParts = extractUrlParts(url),
4051        baseUrlParts = extractUrlParts(baseUrl),
4052        i, max, urlDirectories, baseUrlDirectories, diff = "";
4053    if (urlParts.hostPart !== baseUrlParts.hostPart) {
4054        return "";
4055    }
4056    max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
4057    for(i = 0; i < max; i++) {
4058        if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
4059    }
4060    baseUrlDirectories = baseUrlParts.directories.slice(i);
4061    urlDirectories = urlParts.directories.slice(i);
4062    for(i = 0; i < baseUrlDirectories.length-1; i++) {
4063        diff += "../";
4064    }
4065    for(i = 0; i < urlDirectories.length-1; i++) {
4066        diff += urlDirectories[i] + "/";
4067    }
4068    return diff;
4069}
4070
4071function extractUrlParts(url, baseUrl) {
4072    // urlParts[1] = protocol&hostname || /
4073    // urlParts[2] = / if path relative to host base
4074    // urlParts[3] = directories
4075    // urlParts[4] = filename
4076    // urlParts[5] = parameters
4077
4078    var urlPartsRegex = /^((?:[a-z-]+:)?\/\/(?:[^\/\?#]+\/)|([\/\\]))?((?:[^\/\\\?#]+[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/,
4079        urlParts = url.match(urlPartsRegex),
4080        returner = {}, directories = [], i, baseUrlParts;
4081
4082    if (!urlParts) {
4083        throw new Error("Could not parse sheet href - '"+url+"'");
4084    }
4085
4086    // Stylesheets in IE don't always return the full path   
4087    if (!urlParts[1] || urlParts[2]) {
4088        baseUrlParts = baseUrl.match(urlPartsRegex);
4089        if (!baseUrlParts) {
4090            throw new Error("Could not parse page url - '"+baseUrl+"'");
4091        }
4092        urlParts[1] = baseUrlParts[1];
4093        if (!urlParts[2]) {
4094            urlParts[3] = baseUrlParts[3] + urlParts[3];
4095        }
4096    }
4097   
4098    if (urlParts[3]) {
4099        directories = urlParts[3].replace("\\", "/").split("/");
4100
4101        for(i = 0; i < directories.length; i++) {
4102            if (directories[i] === ".." && i > 0) {
4103                directories.splice(i-1, 2);
4104                i -= 2;
4105            }
4106        }
4107    }
4108
4109    returner.hostPart = urlParts[1];
4110    returner.directories = directories;
4111    returner.path = urlParts[1] + directories.join("/");
4112    returner.fileUrl = returner.path + (urlParts[4] || "");
4113    returner.url = returner.fileUrl + (urlParts[5] || "");
4114    return returner;
4115}
4116
4117function loadStyleSheet(sheet, callback, reload, remaining) {
4118    // sheet may be set to the stylesheet for the initial load or a collection of properties including
4119    // some env variables for imports
4120    var contents  = sheet.contents || {};
4121    var files     = sheet.files || {};
4122    var hrefParts = extractUrlParts(sheet.href, window.location.href);
4123    var href      = hrefParts.url;
4124    var css       = cache && cache.getItem(href);
4125    var timestamp = cache && cache.getItem(href + ':timestamp');
4126    var styles    = { css: css, timestamp: timestamp };
4127    var rootpath;
4128
4129    if (less.relativeUrls) {
4130        if (less.rootpath) {
4131            if (sheet.entryPath) {
4132                rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, sheet.entryPath)).path;
4133            } else {
4134                rootpath = less.rootpath;
4135            }
4136        } else {
4137            rootpath = hrefParts.path;
4138        }
4139    } else  {
4140        if (less.rootpath) {
4141            rootpath = less.rootpath;
4142        } else {
4143            if (sheet.entryPath) {
4144                rootpath = sheet.entryPath;
4145            } else {
4146                rootpath = hrefParts.path;
4147            }
4148        }
4149    }
4150
4151    xhr(href, sheet.type, function (data, lastModified) {
4152        // Store data this session
4153        session_cache += data.replace(/@import .+?;/ig, '');
4154
4155        if (!reload && styles && lastModified &&
4156           (new(Date)(lastModified).valueOf() ===
4157            new(Date)(styles.timestamp).valueOf())) {
4158            // Use local copy
4159            createCSS(styles.css, sheet);
4160            callback(null, null, data, sheet, { local: true, remaining: remaining }, href);
4161        } else {
4162            // Use remote copy (re-parse)
4163            try {
4164                contents[href] = data;  // Updating top importing parser content cache
4165                new(less.Parser)({
4166                    optimization: less.optimization,
4167                    paths: [hrefParts.path],
4168                    entryPath: sheet.entryPath || hrefParts.path,
4169                    mime: sheet.type,
4170                    filename: href,
4171                    rootpath: rootpath,
4172                    relativeUrls: sheet.relativeUrls,
4173                    contents: contents,    // Passing top importing parser content cache ref down.
4174                    files: files,
4175                    dumpLineNumbers: less.dumpLineNumbers
4176                }).parse(data, function (e, root) {
4177                    if (e) { return error(e, href) }
4178                    try {
4179                        callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href);
4180                        removeNode(document.getElementById('less-error-message:' + extractId(href)));
4181                    } catch (e) {
4182                        error(e, href);
4183                    }
4184                });
4185            } catch (e) {
4186                error(e, href);
4187            }
4188        }
4189    }, function (status, url) {
4190        throw new(Error)("Couldn't load " + url + " (" + status + ")");
4191    });
4192}
4193
4194function extractId(href) {
4195    return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' )  // Remove protocol & domain
4196               .replace(/^\//,                 '' )  // Remove root /
4197               .replace(/\.[a-zA-Z]+$/,        '' )  // Remove simple extension
4198               .replace(/[^\.\w-]+/g,          '-')  // Replace illegal characters
4199               .replace(/\./g,                 ':'); // Replace dots with colons(for valid id)
4200}
4201
4202function createCSS(styles, sheet, lastModified) {
4203    var css;
4204
4205    // Strip the query-string
4206    var href = sheet.href || '';
4207
4208    // If there is no title set, use the filename, minus the extension
4209    var id = 'less:' + (sheet.title || extractId(href));
4210
4211    // If the stylesheet doesn't exist, create a new node
4212    if ((css = document.getElementById(id)) === null) {
4213        css = document.createElement('style');
4214        css.type = 'text/css';
4215        if( sheet.media ){ css.media = sheet.media; }
4216        css.id = id;
4217        var nextEl = sheet && sheet.nextSibling || null;
4218        (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl);
4219    }
4220
4221    if (css.styleSheet) { // IE
4222        try {
4223            css.styleSheet.cssText = styles;
4224        } catch (e) {
4225            throw new(Error)("Couldn't reassign styleSheet.cssText.");
4226        }
4227    } else {
4228        (function (node) {
4229            if (css.childNodes.length > 0) {
4230                if (css.firstChild.nodeValue !== node.nodeValue) {
4231                    css.replaceChild(node, css.firstChild);
4232                }
4233            } else {
4234                css.appendChild(node);
4235            }
4236        })(document.createTextNode(styles));
4237    }
4238
4239    // Don't update the local store if the file wasn't modified
4240    if (lastModified && cache) {
4241        log('saving ' + href + ' to cache.');
4242        try {
4243            cache.setItem(href, styles);
4244            cache.setItem(href + ':timestamp', lastModified);
4245        } catch(e) {
4246            //TODO - could do with adding more robust error handling
4247            log('failed to save');
4248        }
4249    }
4250}
4251
4252function xhr(url, type, callback, errback) {
4253    var xhr = getXMLHttpRequest();
4254    var async = isFileProtocol ? less.fileAsync : less.async;
4255
4256    if (typeof(xhr.overrideMimeType) === 'function') {
4257        xhr.overrideMimeType('text/css');
4258    }
4259    xhr.open('GET', url, async);
4260    xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
4261    xhr.send(null);
4262
4263    if (isFileProtocol && !less.fileAsync) {
4264        if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
4265            callback(xhr.responseText);
4266        } else {
4267            errback(xhr.status, url);
4268        }
4269    } else if (async) {
4270        xhr.onreadystatechange = function () {
4271            if (xhr.readyState == 4) {
4272                handleResponse(xhr, callback, errback);
4273            }
4274        };
4275    } else {
4276        handleResponse(xhr, callback, errback);
4277    }
4278
4279    function handleResponse(xhr, callback, errback) {
4280        if (xhr.status >= 200 && xhr.status < 300) {
4281            callback(xhr.responseText,
4282                     xhr.getResponseHeader("Last-Modified"));
4283        } else if (typeof(errback) === 'function') {
4284            errback(xhr.status, url);
4285        }
4286    }
4287}
4288
4289function getXMLHttpRequest() {
4290    if (window.XMLHttpRequest) {
4291        return new(XMLHttpRequest);
4292    } else {
4293        try {
4294            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
4295        } catch (e) {
4296            log("browser doesn't support AJAX.");
4297            return null;
4298        }
4299    }
4300}
4301
4302function removeNode(node) {
4303    return node && node.parentNode.removeChild(node);
4304}
4305
4306function log(str) {
4307    if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
4308}
4309
4310function error(e, href) {
4311    var id = 'less-error-message:' + extractId(href);
4312    var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
4313    var elem = document.createElement('div'), timer, content, error = [];
4314    var filename = e.filename || href;
4315    var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
4316
4317    elem.id        = id;
4318    elem.className = "less-error-message";
4319
4320    content = '<h3>'  + (e.message || 'There is an error in your .less file') +
4321              '</h3>' + '<p>in <a href="' + filename   + '">' + filenameNoPath + "</a> ";
4322
4323    var errorline = function (e, i, classname) {
4324        if (e.extract[i]) {
4325            error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1))
4326                               .replace(/\{class\}/, classname)
4327                               .replace(/\{content\}/, e.extract[i]));
4328        }
4329    };
4330
4331    if (e.stack) {
4332        content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
4333    } else if (e.extract) {
4334        errorline(e, 0, '');
4335        errorline(e, 1, 'line');
4336        errorline(e, 2, '');
4337        content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
4338                    '<ul>' + error.join('') + '</ul>';
4339    }
4340    elem.innerHTML = content;
4341
4342    // CSS for error messages
4343    createCSS([
4344        '.less-error-message ul, .less-error-message li {',
4345            'list-style-type: none;',
4346            'margin-right: 15px;',
4347            'padding: 4px 0;',
4348            'margin: 0;',
4349        '}',
4350        '.less-error-message label {',
4351            'font-size: 12px;',
4352            'margin-right: 15px;',
4353            'padding: 4px 0;',
4354            'color: #cc7777;',
4355        '}',
4356        '.less-error-message pre {',
4357            'color: #dd6666;',
4358            'padding: 4px 0;',
4359            'margin: 0;',
4360            'display: inline-block;',
4361        '}',
4362        '.less-error-message pre.line {',
4363            'color: #ff0000;',
4364        '}',
4365        '.less-error-message h3 {',
4366            'font-size: 20px;',
4367            'font-weight: bold;',
4368            'padding: 15px 0 5px 0;',
4369            'margin: 0;',
4370        '}',
4371        '.less-error-message a {',
4372            'color: #10a',
4373        '}',
4374        '.less-error-message .error {',
4375            'color: red;',
4376            'font-weight: bold;',
4377            'padding-bottom: 2px;',
4378            'border-bottom: 1px dashed red;',
4379        '}'
4380    ].join('\n'), { title: 'error-message' });
4381
4382    elem.style.cssText = [
4383        "font-family: Arial, sans-serif",
4384        "border: 1px solid #e00",
4385        "background-color: #eee",
4386        "border-radius: 5px",
4387        "-webkit-border-radius: 5px",
4388        "-moz-border-radius: 5px",
4389        "color: #e00",
4390        "padding: 15px",
4391        "margin-bottom: 15px"
4392    ].join(';');
4393
4394    if (less.env == 'development') {
4395        timer = setInterval(function () {
4396            if (document.body) {
4397                if (document.getElementById(id)) {
4398                    document.body.replaceChild(elem, document.getElementById(id));
4399                } else {
4400                    document.body.insertBefore(elem, document.body.firstChild);
4401                }
4402                clearInterval(timer);
4403            }
4404        }, 10);
4405    }
4406}
4407// amd.js
4408//
4409// Define Less as an AMD module.
4410if (typeof define === "function" && define.amd) {
4411    define("less", [], function () { return less; } );
4412}
4413})(window);
Note: See TracBrowser for help on using the repository browser.