source: Dev/trunk/src/client/util/less/dist/less-rhino-1.1.3.js @ 483

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

Added Dojo 1.9.3 release.

File size: 80.7 KB
Line 
1//
2// Stub out `require` in rhino
3//
4function require(arg) {
5    return less[arg.split('/')[1]];
6};
7
8
9// ecma-5.js
10//
11// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
12// -- tlrobinson Tom Robinson
13// dantman Daniel Friesen
14
15//
16// Array
17//
18if (!Array.isArray) {
19    Array.isArray = function(obj) {
20        return Object.prototype.toString.call(obj) === "[object Array]" ||
21               (obj instanceof Array);
22    };
23}
24if (!Array.prototype.forEach) {
25    Array.prototype.forEach =  function(block, thisObject) {
26        var len = this.length >>> 0;
27        for (var i = 0; i < len; i++) {
28            if (i in this) {
29                block.call(thisObject, this[i], i, this);
30            }
31        }
32    };
33}
34if (!Array.prototype.map) {
35    Array.prototype.map = function(fun /*, thisp*/) {
36        var len = this.length >>> 0;
37        var res = new Array(len);
38        var thisp = arguments[1];
39
40        for (var i = 0; i < len; i++) {
41            if (i in this) {
42                res[i] = fun.call(thisp, this[i], i, this);
43            }
44        }
45        return res;
46    };
47}
48if (!Array.prototype.filter) {
49    Array.prototype.filter = function (block /*, thisp */) {
50        var values = [];
51        var thisp = arguments[1];
52        for (var i = 0; i < this.length; i++) {
53            if (block.call(thisp, this[i])) {
54                values.push(this[i]);
55            }
56        }
57        return values;
58    };
59}
60if (!Array.prototype.reduce) {
61    Array.prototype.reduce = function(fun /*, initial*/) {
62        var len = this.length >>> 0;
63        var i = 0;
64
65        // no value to return if no initial value and an empty array
66        if (len === 0 && arguments.length === 1) throw new TypeError();
67
68        if (arguments.length >= 2) {
69            var rv = arguments[1];
70        } else {
71            do {
72                if (i in this) {
73                    rv = this[i++];
74                    break;
75                }
76                // if array contains no values, no initial value to return
77                if (++i >= len) throw new TypeError();
78            } while (true);
79        }
80        for (; i < len; i++) {
81            if (i in this) {
82                rv = fun.call(null, rv, this[i], i, this);
83            }
84        }
85        return rv;
86    };
87}
88if (!Array.prototype.indexOf) {
89    Array.prototype.indexOf = function (value /*, fromIndex */ ) {
90        var length = this.length;
91        var i = arguments[1] || 0;
92
93        if (!length)     return -1;
94        if (i >= length) return -1;
95        if (i < 0)       i += length;
96
97        for (; i < length; i++) {
98            if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
99            if (value === this[i]) return i;
100        }
101        return -1;
102    };
103}
104
105//
106// Object
107//
108if (!Object.keys) {
109    Object.keys = function (object) {
110        var keys = [];
111        for (var name in object) {
112            if (Object.prototype.hasOwnProperty.call(object, name)) {
113                keys.push(name);
114            }
115        }
116        return keys;
117    };
118}
119
120//
121// String
122//
123if (!String.prototype.trim) {
124    String.prototype.trim = function () {
125        return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
126    };
127}
128var less, tree;
129
130if (typeof(window) === 'undefined') {
131    if (typeof(exports) === 'undefined') {
132        // Rhino
133        less = {};
134        tree = less.tree = {};
135    } else {
136        // Node.js
137        less = exports,
138        tree = require('less/tree');
139    }
140} else {
141    // Browser
142    if (typeof(window.less) === 'undefined') { window.less = {} }
143    less = window.less,
144    tree = window.less.tree = {};
145}
146//
147// less.js - parser
148//
149//    A relatively straight-forward predictive parser.
150//    There is no tokenization/lexing stage, the input is parsed
151//    in one sweep.
152//
153//    To make the parser fast enough to run in the browser, several
154//    optimization had to be made:
155//
156//    - Matching and slicing on a huge input is often cause of slowdowns.
157//      The solution is to chunkify the input into smaller strings.
158//      The chunks are stored in the `chunks` var,
159//      `j` holds the current chunk index, and `current` holds
160//      the index of the current chunk in relation to `input`.
161//      This gives us an almost 4x speed-up.
162//
163//    - In many cases, we don't need to match individual tokens;
164//      for example, if a value doesn't hold any variables, operations
165//      or dynamic references, the parser can effectively 'skip' it,
166//      treating it as a literal.
167//      An example would be '1px solid #000' - which evaluates to itself,
168//      we don't need to know what the individual components are.
169//      The drawback, of course is that you don't get the benefits of
170//      syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
171//      and a smaller speed-up in the code-gen.
172//
173//
174//    Token matching is done with the `$` function, which either takes
175//    a terminal string or regexp, or a non-terminal function to call.
176//    It also takes care of moving all the indices forwards.
177//
178//
179less.Parser = function Parser(env) {
180    var input,       // LeSS input string
181        i,           // current index in `input`
182        j,           // current chunk
183        temp,        // temporarily holds a chunk's state, for backtracking
184        memo,        // temporarily holds `i`, when backtracking
185        furthest,    // furthest index the parser has gone to
186        chunks,      // chunkified input
187        current,     // index of current chunk, in `input`
188        parser;
189
190    var that = this;
191
192    // This function is called after all files
193    // have been imported through `@import`.
194    var finish = function () {};
195
196    var imports = this.imports = {
197        paths: env && env.paths || [],  // Search paths, when importing
198        queue: [],                      // Files which haven't been imported yet
199        files: {},                      // Holds the imported parse trees
200        mime:  env && env.mime,         // MIME type of .less files
201        push: function (path, callback) {
202            var that = this;
203            this.queue.push(path);
204
205            //
206            // Import a file asynchronously
207            //
208            less.Parser.importer(path, this.paths, function (root) {
209                that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
210                that.files[path] = root;                        // Store the root
211
212                callback(root);
213
214                if (that.queue.length === 0) { finish() }       // Call `finish` if we're done importing
215            }, env);
216        }
217    };
218
219    function save()    { temp = chunks[j], memo = i, current = i }
220    function restore() { chunks[j] = temp, i = memo, current = i }
221
222    function sync() {
223        if (i > current) {
224            chunks[j] = chunks[j].slice(i - current);
225            current = i;
226        }
227    }
228    //
229    // Parse from a token, regexp or string, and move forward if match
230    //
231    function $(tok) {
232        var match, args, length, c, index, endIndex, k, mem;
233
234        //
235        // Non-terminal
236        //
237        if (tok instanceof Function) {
238            return tok.call(parser.parsers);
239        //
240        // Terminal
241        //
242        //     Either match a single character in the input,
243        //     or match a regexp in the current chunk (chunk[j]).
244        //
245        } else if (typeof(tok) === 'string') {
246            match = input.charAt(i) === tok ? tok : null;
247            length = 1;
248            sync ();
249        } else {
250            sync ();
251
252            if (match = tok.exec(chunks[j])) {
253                length = match[0].length;
254            } else {
255                return null;
256            }
257        }
258
259        // The match is confirmed, add the match length to `i`,
260        // and consume any extra white-space characters (' ' || '\n')
261        // which come after that. The reason for this is that LeSS's
262        // grammar is mostly white-space insensitive.
263        //
264        if (match) {
265            mem = i += length;
266            endIndex = i + chunks[j].length - length;
267
268            while (i < endIndex) {
269                c = input.charCodeAt(i);
270                if (! (c === 32 || c === 10 || c === 9)) { break }
271                i++;
272            }
273            chunks[j] = chunks[j].slice(length + (i - mem));
274            current = i;
275
276            if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
277
278            if(typeof(match) === 'string') {
279                return match;
280            } else {
281                return match.length === 1 ? match[0] : match;
282            }
283        }
284    }
285
286    // Same as $(), but don't change the state of the parser,
287    // just return the match.
288    function peek(tok) {
289        if (typeof(tok) === 'string') {
290            return input.charAt(i) === tok;
291        } else {
292            if (tok.test(chunks[j])) {
293                return true;
294            } else {
295                return false;
296            }
297        }
298    }
299
300    this.env = env = env || {};
301
302    // The optimization level dictates the thoroughness of the parser,
303    // the lower the number, the less nodes it will create in the tree.
304    // This could matter for debugging, or if you want to access
305    // the individual nodes in the tree.
306    this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
307
308    this.env.filename = this.env.filename || null;
309
310    //
311    // The Parser
312    //
313    return parser = {
314
315        imports: imports,
316        //
317        // Parse an input string into an abstract syntax tree,
318        // call `callback` when done.
319        //
320        parse: function (str, callback) {
321            var root, start, end, zone, line, lines, buff = [], c, error = null;
322
323            i = j = current = furthest = 0;
324            chunks = [];
325            input = str.replace(/\r\n/g, '\n');
326
327            // Split the input into chunks.
328            chunks = (function (chunks) {
329                var j = 0,
330                    skip = /[^"'`\{\}\/\(\)]+/g,
331                    comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
332                    level = 0,
333                    match,
334                    chunk = chunks[0],
335                    inParam,
336                    inString;
337
338                for (var i = 0, c, cc; i < input.length; i++) {
339                    skip.lastIndex = i;
340                    if (match = skip.exec(input)) {
341                        if (match.index === i) {
342                            i += match[0].length;
343                            chunk.push(match[0]);
344                        }
345                    }
346                    c = input.charAt(i);
347                    comment.lastIndex = i;
348
349                    if (!inString && !inParam && c === '/') {
350                        cc = input.charAt(i + 1);
351                        if (cc === '/' || cc === '*') {
352                            if (match = comment.exec(input)) {
353                                if (match.index === i) {
354                                    i += match[0].length;
355                                    chunk.push(match[0]);
356                                    c = input.charAt(i);
357                                }
358                            }
359                        }
360                    }
361
362                    if        (c === '{' && !inString && !inParam) { level ++;
363                        chunk.push(c);
364                    } else if (c === '}' && !inString && !inParam) { level --;
365                        chunk.push(c);
366                        chunks[++j] = chunk = [];
367                    } else if (c === '(' && !inString && !inParam) {
368                        chunk.push(c);
369                        inParam = true;
370                    } else if (c === ')' && !inString && inParam) {
371                        chunk.push(c);
372                        inParam = false;
373                    } else {
374                        if (c === '"' || c === "'" || c === '`') {
375                            if (! inString) {
376                                inString = c;
377                            } else {
378                                inString = inString === c ? false : inString;
379                            }
380                        }
381                        chunk.push(c);
382                    }
383                }
384                if (level > 0) {
385                    throw {
386                        type: 'Syntax',
387                        message: "Missing closing `}`",
388                        filename: env.filename
389                    };
390                }
391
392                return chunks.map(function (c) { return c.join('') });;
393            })([[]]);
394
395            // Start with the primary rule.
396            // The whole syntax tree is held under a Ruleset node,
397            // with the `root` property set to true, so no `{}` are
398            // output. The callback is called when the input is parsed.
399            root = new(tree.Ruleset)([], $(this.parsers.primary));
400            root.root = true;
401
402            root.toCSS = (function (evaluate) {
403                var line, lines, column;
404
405                return function (options, variables) {
406                    var frames = [];
407
408                    options = options || {};
409                    //
410                    // Allows setting variables with a hash, so:
411                    //
412                    //   `{ color: new(tree.Color)('#f01') }` will become:
413                    //
414                    //   new(tree.Rule)('@color',
415                    //     new(tree.Value)([
416                    //       new(tree.Expression)([
417                    //         new(tree.Color)('#f01')
418                    //       ])
419                    //     ])
420                    //   )
421                    //
422                    if (typeof(variables) === 'object' && !Array.isArray(variables)) {
423                        variables = Object.keys(variables).map(function (k) {
424                            var value = variables[k];
425
426                            if (! (value instanceof tree.Value)) {
427                                if (! (value instanceof tree.Expression)) {
428                                    value = new(tree.Expression)([value]);
429                                }
430                                value = new(tree.Value)([value]);
431                            }
432                            return new(tree.Rule)('@' + k, value, false, 0);
433                        });
434                        frames = [new(tree.Ruleset)(null, variables)];
435                    }
436
437                    try {
438                        var css = evaluate.call(this, { frames: frames })
439                                          .toCSS([], { compress: options.compress || false });
440                    } catch (e) {
441                        lines = input.split('\n');
442                        line = getLine(e.index);
443
444                        for (var n = e.index, column = -1;
445                                 n >= 0 && input.charAt(n) !== '\n';
446                                 n--) { column++ }
447
448                        throw {
449                            type: e.type,
450                            message: e.message,
451                            filename: env.filename,
452                            index: e.index,
453                            line: typeof(line) === 'number' ? line + 1 : null,
454                            callLine: e.call && (getLine(e.call) + 1),
455                            callExtract: lines[getLine(e.call)],
456                            stack: e.stack,
457                            column: column,
458                            extract: [
459                                lines[line - 1],
460                                lines[line],
461                                lines[line + 1]
462                            ]
463                        };
464                    }
465                    if (options.compress) {
466                        return css.replace(/(\s)+/g, "$1");
467                    } else {
468                        return css;
469                    }
470
471                    function getLine(index) {
472                        return index ? (input.slice(0, index).match(/\n/g) || "").length : null;
473                    }
474                };
475            })(root.eval);
476
477            // If `i` is smaller than the `input.length - 1`,
478            // it means the parser wasn't able to parse the whole
479            // string, so we've got a parsing error.
480            //
481            // We try to extract a \n delimited string,
482            // showing the line where the parse error occured.
483            // We split it up into two parts (the part which parsed,
484            // and the part which didn't), so we can color them differently.
485            if (i < input.length - 1) {
486                i = furthest;
487                lines = input.split('\n');
488                line = (input.slice(0, i).match(/\n/g) || "").length + 1;
489
490                for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
491
492                error = {
493                    name: "ParseError",
494                    message: "Syntax Error on line " + line,
495                    index: i,
496                    filename: env.filename,
497                    line: line,
498                    column: column,
499                    extract: [
500                        lines[line - 2],
501                        lines[line - 1],
502                        lines[line]
503                    ]
504                };
505            }
506
507            if (this.imports.queue.length > 0) {
508                finish = function () { callback(error, root) };
509            } else {
510                callback(error, root);
511            }
512        },
513
514        //
515        // Here in, the parsing rules/functions
516        //
517        // The basic structure of the syntax tree generated is as follows:
518        //
519        //   Ruleset ->  Rule -> Value -> Expression -> Entity
520        //
521        // Here's some LESS code:
522        //
523        //    .class {
524        //      color: #fff;
525        //      border: 1px solid #000;
526        //      width: @w + 4px;
527        //      > .child {...}
528        //    }
529        //
530        // And here's what the parse tree might look like:
531        //
532        //     Ruleset (Selector '.class', [
533        //         Rule ("color",  Value ([Expression [Color #fff]]))
534        //         Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
535        //         Rule ("width",  Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
536        //         Ruleset (Selector [Element '>', '.child'], [...])
537        //     ])
538        //
539        //  In general, most rules will try to parse a token with the `$()` function, and if the return
540        //  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
541        //  first, before parsing, that's when we use `peek()`.
542        //
543        parsers: {
544            //
545            // The `primary` rule is the *entry* and *exit* point of the parser.
546            // The rules here can appear at any level of the parse tree.
547            //
548            // The recursive nature of the grammar is an interplay between the `block`
549            // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
550            // as represented by this simplified grammar:
551            //
552            //     primary  →  (ruleset | rule)+
553            //     ruleset  →  selector+ block
554            //     block    →  '{' primary '}'
555            //
556            // Only at one point is the primary rule not called from the
557            // block rule: at the root level.
558            //
559            primary: function () {
560                var node, root = [];
561
562                while ((node = $(this.mixin.definition) || $(this.rule)    ||  $(this.ruleset) ||
563                               $(this.mixin.call)       || $(this.comment) ||  $(this.directive))
564                               || $(/^[\s\n]+/)) {
565                    node && root.push(node);
566                }
567                return root;
568            },
569
570            // We create a Comment node for CSS comments `/* */`,
571            // but keep the LeSS comments `//` silent, by just skipping
572            // over them.
573            comment: function () {
574                var comment;
575
576                if (input.charAt(i) !== '/') return;
577
578                if (input.charAt(i + 1) === '/') {
579                    return new(tree.Comment)($(/^\/\/.*/), true);
580                } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
581                    return new(tree.Comment)(comment);
582                }
583            },
584
585            //
586            // Entities are tokens which can be found inside an Expression
587            //
588            entities: {
589                //
590                // A string, which supports escaping " and '
591                //
592                //     "milky way" 'he\'s the one!'
593                //
594                quoted: function () {
595                    var str, j = i, e;
596
597                    if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
598                    if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
599
600                    e && $('~');
601
602                    if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
603                        return new(tree.Quoted)(str[0], str[1] || str[2], e);
604                    }
605                },
606
607                //
608                // A catch-all word, such as:
609                //
610                //     black border-collapse
611                //
612                keyword: function () {
613                    var k;
614                    if (k = $(/^[A-Za-z-]+/)) { return new(tree.Keyword)(k) }
615                },
616
617                //
618                // A function call
619                //
620                //     rgb(255, 0, 255)
621                //
622                // We also try to catch IE's `alpha()`, but let the `alpha` parser
623                // deal with the details.
624                //
625                // The arguments are parsed with the `entities.arguments` parser.
626                //
627                call: function () {
628                    var name, args, index = i;
629
630                    if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return;
631
632                    name = name[1].toLowerCase();
633
634                    if (name === 'url') { return null }
635                    else                { i += name.length }
636
637                    if (name === 'alpha') { return $(this.alpha) }
638
639                    $('('); // Parse the '(' and consume whitespace.
640
641                    args = $(this.entities.arguments);
642
643                    if (! $(')')) return;
644
645                    if (name) { return new(tree.Call)(name, args, index) }
646                },
647                arguments: function () {
648                    var args = [], arg;
649
650                    while (arg = $(this.expression)) {
651                        args.push(arg);
652                        if (! $(',')) { break }
653                    }
654                    return args;
655                },
656                literal: function () {
657                    return $(this.entities.dimension) ||
658                           $(this.entities.color) ||
659                           $(this.entities.quoted);
660                },
661
662                //
663                // Parse url() tokens
664                //
665                // We use a specific rule for urls, because they don't really behave like
666                // standard function calls. The difference is that the argument doesn't have
667                // to be enclosed within a string, so it can't be parsed as an Expression.
668                //
669                url: function () {
670                    var value;
671
672                    if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
673                    value = $(this.entities.quoted)  || $(this.entities.variable) ||
674                            $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
675                    if (! $(')')) throw new(Error)("missing closing ) for url()");
676
677                    return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
678                                        ? value : new(tree.Anonymous)(value), imports.paths);
679                },
680
681                dataURI: function () {
682                    var obj;
683
684                    if ($(/^data:/)) {
685                        obj         = {};
686                        obj.mime    = $(/^[^\/]+\/[^,;)]+/)     || '';
687                        obj.charset = $(/^;\s*charset=[^,;)]+/) || '';
688                        obj.base64  = $(/^;\s*base64/)          || '';
689                        obj.data    = $(/^,\s*[^)]+/);
690
691                        if (obj.data) { return obj }
692                    }
693                },
694
695                //
696                // A Variable entity, such as `@fink`, in
697                //
698                //     width: @fink + 2px
699                //
700                // We use a different parser for variable definitions,
701                // see `parsers.variable`.
702                //
703                variable: function () {
704                    var name, index = i;
705
706                    if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
707                        return new(tree.Variable)(name, index);
708                    }
709                },
710
711                //
712                // A Hexadecimal color
713                //
714                //     #4F3C2F
715                //
716                // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
717                //
718                color: function () {
719                    var rgb;
720
721                    if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
722                        return new(tree.Color)(rgb[1]);
723                    }
724                },
725
726                //
727                // A Dimension, that is, a number and a unit
728                //
729                //     0.5em 95%
730                //
731                dimension: function () {
732                    var value, c = input.charCodeAt(i);
733                    if ((c > 57 || c < 45) || c === 47) return;
734
735                    if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
736                        return new(tree.Dimension)(value[1], value[2]);
737                    }
738                },
739
740                //
741                // JavaScript code to be evaluated
742                //
743                //     `window.location.href`
744                //
745                javascript: function () {
746                    var str, j = i, e;
747
748                    if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
749                    if (input.charAt(j) !== '`') { return }
750
751                    e && $('~');
752
753                    if (str = $(/^`([^`]*)`/)) {
754                        return new(tree.JavaScript)(str[1], i, e);
755                    }
756                }
757            },
758
759            //
760            // The variable part of a variable definition. Used in the `rule` parser
761            //
762            //     @fink:
763            //
764            variable: function () {
765                var name;
766
767                if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
768            },
769
770            //
771            // A font size/line-height shorthand
772            //
773            //     small/12px
774            //
775            // We need to peek first, or we'll match on keywords and dimensions
776            //
777            shorthand: function () {
778                var a, b;
779
780                if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
781
782                if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
783                    return new(tree.Shorthand)(a, b);
784                }
785            },
786
787            //
788            // Mixins
789            //
790            mixin: {
791                //
792                // A Mixin call, with an optional argument list
793                //
794                //     #mixins > .square(#fff);
795                //     .rounded(4px, black);
796                //     .button;
797                //
798                // The `while` loop is there because mixins can be
799                // namespaced, but we only support the child and descendant
800                // selector for now.
801                //
802                call: function () {
803                    var elements = [], e, c, args, index = i, s = input.charAt(i);
804
805                    if (s !== '.' && s !== '#') { return }
806
807                    while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
808                        elements.push(new(tree.Element)(c, e));
809                        c = $('>');
810                    }
811                    $('(') && (args = $(this.entities.arguments)) && $(')');
812
813                    if (elements.length > 0 && ($(';') || peek('}'))) {
814                        return new(tree.mixin.Call)(elements, args, index);
815                    }
816                },
817
818                //
819                // A Mixin definition, with a list of parameters
820                //
821                //     .rounded (@radius: 2px, @color) {
822                //        ...
823                //     }
824                //
825                // Until we have a finer grained state-machine, we have to
826                // do a look-ahead, to make sure we don't have a mixin call.
827                // See the `rule` function for more information.
828                //
829                // We start by matching `.rounded (`, and then proceed on to
830                // the argument list, which has optional default values.
831                // We store the parameters in `params`, with a `value` key,
832                // if there is a value, such as in the case of `@radius`.
833                //
834                // Once we've got our params list, and a closing `)`, we parse
835                // the `{...}` block.
836                //
837                definition: function () {
838                    var name, params = [], match, ruleset, param, value;
839
840                    if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
841                        peek(/^[^{]*(;|})/)) return;
842
843                    if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
844                        name = match[1];
845
846                        while (param = $(this.entities.variable) || $(this.entities.literal)
847                                                                 || $(this.entities.keyword)) {
848                            // Variable
849                            if (param instanceof tree.Variable) {
850                                if ($(':')) {
851                                    if (value = $(this.expression)) {
852                                        params.push({ name: param.name, value: value });
853                                    } else {
854                                        throw new(Error)("Expected value");
855                                    }
856                                } else {
857                                    params.push({ name: param.name });
858                                }
859                            } else {
860                                params.push({ value: param });
861                            }
862                            if (! $(',')) { break }
863                        }
864                        if (! $(')')) throw new(Error)("Expected )");
865
866                        ruleset = $(this.block);
867
868                        if (ruleset) {
869                            return new(tree.mixin.Definition)(name, params, ruleset);
870                        }
871                    }
872                }
873            },
874
875            //
876            // Entities are the smallest recognized token,
877            // and can be found inside a rule's value.
878            //
879            entity: function () {
880                return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
881                       $(this.entities.call)    || $(this.entities.keyword)  || $(this.entities.javascript) ||
882                       $(this.comment);
883            },
884
885            //
886            // A Rule terminator. Note that we use `peek()` to check for '}',
887            // because the `block` rule will be expecting it, but we still need to make sure
888            // it's there, if ';' was ommitted.
889            //
890            end: function () {
891                return $(';') || peek('}');
892            },
893
894            //
895            // IE's alpha function
896            //
897            //     alpha(opacity=88)
898            //
899            alpha: function () {
900                var value;
901
902                if (! $(/^\(opacity=/i)) return;
903                if (value = $(/^\d+/) || $(this.entities.variable)) {
904                    if (! $(')')) throw new(Error)("missing closing ) for alpha()");
905                    return new(tree.Alpha)(value);
906                }
907            },
908
909            //
910            // A Selector Element
911            //
912            //     div
913            //     + h1
914            //     #socks
915            //     input[type="text"]
916            //
917            // Elements are the building blocks for Selectors,
918            // they are made out of a `Combinator` (see combinator rule),
919            // and an element name, such as a tag a class, or `*`.
920            //
921            element: function () {
922                var e, t, c;
923
924                c = $(this.combinator);
925                e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
926
927                if (e) { return new(tree.Element)(c, e) }
928
929                if (c.value && c.value[0] === '&') {
930                  return new(tree.Element)(c, null);
931                }
932            },
933
934            //
935            // Combinators combine elements together, in a Selector.
936            //
937            // Because our parser isn't white-space sensitive, special care
938            // has to be taken, when parsing the descendant combinator, ` `,
939            // as it's an empty space. We have to check the previous character
940            // in the input, to see if it's a ` ` character. More info on how
941            // we deal with this in *combinator.js*.
942            //
943            combinator: function () {
944                var match, c = input.charAt(i);
945
946                if (c === '>' || c === '+' || c === '~') {
947                    i++;
948                    while (input.charAt(i) === ' ') { i++ }
949                    return new(tree.Combinator)(c);
950                } else if (c === '&') {
951                    match = '&';
952                    i++;
953                    if(input.charAt(i) === ' ') {
954                        match = '& ';
955                    }
956                    while (input.charAt(i) === ' ') { i++ }
957                    return new(tree.Combinator)(match);
958                } else if (c === ':' && input.charAt(i + 1) === ':') {
959                    i += 2;
960                    while (input.charAt(i) === ' ') { i++ }
961                    return new(tree.Combinator)('::');
962                } else if (input.charAt(i - 1) === ' ') {
963                    return new(tree.Combinator)(" ");
964                } else {
965                    return new(tree.Combinator)(null);
966                }
967            },
968
969            //
970            // A CSS Selector
971            //
972            //     .class > div + h1
973            //     li a:hover
974            //
975            // Selectors are made out of one or more Elements, see above.
976            //
977            selector: function () {
978                var sel, e, elements = [], c, match;
979
980                while (e = $(this.element)) {
981                    c = input.charAt(i);
982                    elements.push(e)
983                    if (c === '{' || c === '}' || c === ';' || c === ',') { break }
984                }
985
986                if (elements.length > 0) { return new(tree.Selector)(elements) }
987            },
988            tag: function () {
989                return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
990            },
991            attribute: function () {
992                var attr = '', key, val, op;
993
994                if (! $('[')) return;
995
996                if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) {
997                    if ((op = $(/^[|~*$^]?=/)) &&
998                        (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
999                        attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
1000                    } else { attr = key }
1001                }
1002
1003                if (! $(']')) return;
1004
1005                if (attr) { return "[" + attr + "]" }
1006            },
1007
1008            //
1009            // The `block` rule is used by `ruleset` and `mixin.definition`.
1010            // It's a wrapper around the `primary` rule, with added `{}`.
1011            //
1012            block: function () {
1013                var content;
1014
1015                if ($('{') && (content = $(this.primary)) && $('}')) {
1016                    return content;
1017                }
1018            },
1019
1020            //
1021            // div, .class, body > p {...}
1022            //
1023            ruleset: function () {
1024                var selectors = [], s, rules, match;
1025                save();
1026
1027                if (match = /^([.#: \w-]+)[\s\n]*\{/.exec(chunks[j])) {
1028                    i += match[0].length - 1;
1029                    selectors = [new(tree.Selector)([new(tree.Element)(null, match[1])])];
1030                } else {
1031                    while (s = $(this.selector)) {
1032                        selectors.push(s);
1033                        $(this.comment);
1034                        if (! $(',')) { break }
1035                        $(this.comment);
1036                    }
1037                }
1038
1039                if (selectors.length > 0 && (rules = $(this.block))) {
1040                    return new(tree.Ruleset)(selectors, rules);
1041                } else {
1042                    // Backtrack
1043                    furthest = i;
1044                    restore();
1045                }
1046            },
1047            rule: function () {
1048                var name, value, c = input.charAt(i), important, match;
1049                save();
1050
1051                if (c === '.' || c === '#' || c === '&') { return }
1052
1053                if (name = $(this.variable) || $(this.property)) {
1054                    if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) {
1055                        i += match[0].length - 1;
1056                        value = new(tree.Anonymous)(match[1]);
1057                    } else if (name === "font") {
1058                        value = $(this.font);
1059                    } else {
1060                        value = $(this.value);
1061                    }
1062                    important = $(this.important);
1063
1064                    if (value && $(this.end)) {
1065                        return new(tree.Rule)(name, value, important, memo);
1066                    } else {
1067                        furthest = i;
1068                        restore();
1069                    }
1070                }
1071            },
1072
1073            //
1074            // An @import directive
1075            //
1076            //     @import "lib";
1077            //
1078            // Depending on our environemnt, importing is done differently:
1079            // In the browser, it's an XHR request, in Node, it would be a
1080            // file-system operation. The function used for importing is
1081            // stored in `import`, which we pass to the Import constructor.
1082            //
1083            "import": function () {
1084                var path;
1085                if ($(/^@import\s+/) &&
1086                    (path = $(this.entities.quoted) || $(this.entities.url)) &&
1087                    $(';')) {
1088                    return new(tree.Import)(path, imports);
1089                }
1090            },
1091
1092            //
1093            // A CSS Directive
1094            //
1095            //     @charset "utf-8";
1096            //
1097            directive: function () {
1098                var name, value, rules, types;
1099
1100                if (input.charAt(i) !== '@') return;
1101
1102                if (value = $(this['import'])) {
1103                    return value;
1104                } else if (name = $(/^@media|@page|@-[-a-z]+/)) {
1105                    types = ($(/^[^{]+/) || '').trim();
1106                    if (rules = $(this.block)) {
1107                        return new(tree.Directive)(name + " " + types, rules);
1108                    }
1109                } else if (name = $(/^@[-a-z]+/)) {
1110                    if (name === '@font-face') {
1111                        if (rules = $(this.block)) {
1112                            return new(tree.Directive)(name, rules);
1113                        }
1114                    } else if ((value = $(this.entity)) && $(';')) {
1115                        return new(tree.Directive)(name, value);
1116                    }
1117                }
1118            },
1119            font: function () {
1120                var value = [], expression = [], weight, shorthand, font, e;
1121
1122                while (e = $(this.shorthand) || $(this.entity)) {
1123                    expression.push(e);
1124                }
1125                value.push(new(tree.Expression)(expression));
1126
1127                if ($(',')) {
1128                    while (e = $(this.expression)) {
1129                        value.push(e);
1130                        if (! $(',')) { break }
1131                    }
1132                }
1133                return new(tree.Value)(value);
1134            },
1135
1136            //
1137            // A Value is a comma-delimited list of Expressions
1138            //
1139            //     font-family: Baskerville, Georgia, serif;
1140            //
1141            // In a Rule, a Value represents everything after the `:`,
1142            // and before the `;`.
1143            //
1144            value: function () {
1145                var e, expressions = [], important;
1146
1147                while (e = $(this.expression)) {
1148                    expressions.push(e);
1149                    if (! $(',')) { break }
1150                }
1151
1152                if (expressions.length > 0) {
1153                    return new(tree.Value)(expressions);
1154                }
1155            },
1156            important: function () {
1157                if (input.charAt(i) === '!') {
1158                    return $(/^! *important/);
1159                }
1160            },
1161            sub: function () {
1162                var e;
1163
1164                if ($('(') && (e = $(this.expression)) && $(')')) {
1165                    return e;
1166                }
1167            },
1168            multiplication: function () {
1169                var m, a, op, operation;
1170                if (m = $(this.operand)) {
1171                    while ((op = ($('/') || $('*'))) && (a = $(this.operand))) {
1172                        operation = new(tree.Operation)(op, [operation || m, a]);
1173                    }
1174                    return operation || m;
1175                }
1176            },
1177            addition: function () {
1178                var m, a, op, operation;
1179                if (m = $(this.multiplication)) {
1180                    while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
1181                           (a = $(this.multiplication))) {
1182                        operation = new(tree.Operation)(op, [operation || m, a]);
1183                    }
1184                    return operation || m;
1185                }
1186            },
1187
1188            //
1189            // An operand is anything that can be part of an operation,
1190            // such as a Color, or a Variable
1191            //
1192            operand: function () {
1193                var negate, p = input.charAt(i + 1);
1194
1195                if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
1196                var o = $(this.sub) || $(this.entities.dimension) ||
1197                        $(this.entities.color) || $(this.entities.variable) ||
1198                        $(this.entities.call);
1199                return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o])
1200                              : o;
1201            },
1202
1203            //
1204            // Expressions either represent mathematical operations,
1205            // or white-space delimited Entities.
1206            //
1207            //     1px solid black
1208            //     @var * 2
1209            //
1210            expression: function () {
1211                var e, delim, entities = [], d;
1212
1213                while (e = $(this.addition) || $(this.entity)) {
1214                    entities.push(e);
1215                }
1216                if (entities.length > 0) {
1217                    return new(tree.Expression)(entities);
1218                }
1219            },
1220            property: function () {
1221                var name;
1222
1223                if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
1224                    return name[1];
1225                }
1226            }
1227        }
1228    };
1229};
1230
1231if (typeof(window) !== 'undefined' /* browser */ || typeof(exports) === 'undefined' /* rhino */) {
1232    //
1233    // Used by `@import` directives
1234    //
1235    less.Parser.importer = function (path, paths, callback, env) {
1236        if (path.charAt(0) !== '/' && paths.length > 0) {
1237            path = paths[0] + path;
1238        }
1239        // We pass `true` as 3rd argument, to force the reload of the import.
1240        // This is so we can get the syntax tree as opposed to just the CSS output,
1241        // as we need this to evaluate the current stylesheet.
1242        loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true);
1243    };
1244}
1245
1246(function (tree) {
1247
1248tree.functions = {
1249    rgb: function (r, g, b) {
1250        return this.rgba(r, g, b, 1.0);
1251    },
1252    rgba: function (r, g, b, a) {
1253        var rgb = [r, g, b].map(function (c) { return number(c) }),
1254            a = number(a);
1255        return new(tree.Color)(rgb, a);
1256    },
1257    hsl: function (h, s, l) {
1258        return this.hsla(h, s, l, 1.0);
1259    },
1260    hsla: function (h, s, l, a) {
1261        h = (number(h) % 360) / 360;
1262        s = number(s); l = number(l); a = number(a);
1263
1264        var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1265        var m1 = l * 2 - m2;
1266
1267        return this.rgba(hue(h + 1/3) * 255,
1268                         hue(h)       * 255,
1269                         hue(h - 1/3) * 255,
1270                         a);
1271
1272        function hue(h) {
1273            h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1274            if      (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
1275            else if (h * 2 < 1) return m2;
1276            else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
1277            else                return m1;
1278        }
1279    },
1280    hue: function (color) {
1281        return new(tree.Dimension)(Math.round(color.toHSL().h));
1282    },
1283    saturation: function (color) {
1284        return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
1285    },
1286    lightness: function (color) {
1287        return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
1288    },
1289    alpha: function (color) {
1290        return new(tree.Dimension)(color.toHSL().a);
1291    },
1292    saturate: function (color, amount) {
1293        var hsl = color.toHSL();
1294
1295        hsl.s += amount.value / 100;
1296        hsl.s = clamp(hsl.s);
1297        return hsla(hsl);
1298    },
1299    desaturate: function (color, amount) {
1300        var hsl = color.toHSL();
1301
1302        hsl.s -= amount.value / 100;
1303        hsl.s = clamp(hsl.s);
1304        return hsla(hsl);
1305    },
1306    lighten: function (color, amount) {
1307        var hsl = color.toHSL();
1308
1309        hsl.l += amount.value / 100;
1310        hsl.l = clamp(hsl.l);
1311        return hsla(hsl);
1312    },
1313    darken: function (color, amount) {
1314        var hsl = color.toHSL();
1315
1316        hsl.l -= amount.value / 100;
1317        hsl.l = clamp(hsl.l);
1318        return hsla(hsl);
1319    },
1320    fadein: function (color, amount) {
1321        var hsl = color.toHSL();
1322
1323        hsl.a += amount.value / 100;
1324        hsl.a = clamp(hsl.a);
1325        return hsla(hsl);
1326    },
1327    fadeout: function (color, amount) {
1328        var hsl = color.toHSL();
1329
1330        hsl.a -= amount.value / 100;
1331        hsl.a = clamp(hsl.a);
1332        return hsla(hsl);
1333    },
1334    spin: function (color, amount) {
1335        var hsl = color.toHSL();
1336        var hue = (hsl.h + amount.value) % 360;
1337
1338        hsl.h = hue < 0 ? 360 + hue : hue;
1339
1340        return hsla(hsl);
1341    },
1342    //
1343    // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
1344    // http://sass-lang.com
1345    //
1346    mix: function (color1, color2, weight) {
1347        var p = weight.value / 100.0;
1348        var w = p * 2 - 1;
1349        var a = color1.toHSL().a - color2.toHSL().a;
1350
1351        var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1352        var w2 = 1 - w1;
1353
1354        var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1355                   color1.rgb[1] * w1 + color2.rgb[1] * w2,
1356                   color1.rgb[2] * w1 + color2.rgb[2] * w2];
1357
1358        var alpha = color1.alpha * p + color2.alpha * (1 - p);
1359
1360        return new(tree.Color)(rgb, alpha);
1361    },
1362    greyscale: function (color) {
1363        return this.desaturate(color, new(tree.Dimension)(100));
1364    },
1365    e: function (str) {
1366        return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
1367    },
1368    escape: function (str) {
1369        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"));
1370    },
1371    '%': function (quoted /* arg, arg, ...*/) {
1372        var args = Array.prototype.slice.call(arguments, 1),
1373            str = quoted.value;
1374
1375        for (var i = 0; i < args.length; i++) {
1376            str = str.replace(/%[sda]/i, function(token) {
1377                var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
1378                return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
1379            });
1380        }
1381        str = str.replace(/%%/g, '%');
1382        return new(tree.Quoted)('"' + str + '"', str);
1383    },
1384    round: function (n) {
1385        if (n instanceof tree.Dimension) {
1386            return new(tree.Dimension)(Math.round(number(n)), n.unit);
1387        } else if (typeof(n) === 'number') {
1388            return Math.round(n);
1389        } else {
1390            throw {
1391                error: "RuntimeError",
1392                message: "math functions take numbers as parameters"
1393            };
1394        }
1395    }
1396};
1397
1398function hsla(hsla) {
1399    return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
1400}
1401
1402function number(n) {
1403    if (n instanceof tree.Dimension) {
1404        return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
1405    } else if (typeof(n) === 'number') {
1406        return n;
1407    } else {
1408        throw {
1409            error: "RuntimeError",
1410            message: "color functions take numbers as parameters"
1411        };
1412    }
1413}
1414
1415function clamp(val) {
1416    return Math.min(1, Math.max(0, val));
1417}
1418
1419})(require('less/tree'));
1420(function (tree) {
1421
1422tree.Alpha = function (val) {
1423    this.value = val;
1424};
1425tree.Alpha.prototype = {
1426    toCSS: function () {
1427        return "alpha(opacity=" +
1428               (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
1429    },
1430    eval: function (env) {
1431        if (this.value.eval) { this.value = this.value.eval(env) }
1432        return this;
1433    }
1434};
1435
1436})(require('less/tree'));
1437(function (tree) {
1438
1439tree.Anonymous = function (string) {
1440    this.value = string.value || string;
1441};
1442tree.Anonymous.prototype = {
1443    toCSS: function () {
1444        return this.value;
1445    },
1446    eval: function () { return this }
1447};
1448
1449})(require('less/tree'));
1450(function (tree) {
1451
1452//
1453// A function call node.
1454//
1455tree.Call = function (name, args, index) {
1456    this.name = name;
1457    this.args = args;
1458    this.index = index;
1459};
1460tree.Call.prototype = {
1461    //
1462    // When evaluating a function call,
1463    // we either find the function in `tree.functions` [1],
1464    // in which case we call it, passing the  evaluated arguments,
1465    // or we simply print it out as it appeared originally [2].
1466    //
1467    // The *functions.js* file contains the built-in functions.
1468    //
1469    // The reason why we evaluate the arguments, is in the case where
1470    // we try to pass a variable to a function, like: `saturate(@color)`.
1471    // The function should receive the value, not the variable.
1472    //
1473    eval: function (env) {
1474        var args = this.args.map(function (a) { return a.eval(env) });
1475
1476        if (this.name in tree.functions) { // 1.
1477            try {
1478                return tree.functions[this.name].apply(tree.functions, args);
1479            } catch (e) {
1480                throw { message: "error evaluating function `" + this.name + "`",
1481                        index: this.index };
1482            }
1483        } else { // 2.
1484            return new(tree.Anonymous)(this.name +
1485                   "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
1486        }
1487    },
1488
1489    toCSS: function (env) {
1490        return this.eval(env).toCSS();
1491    }
1492};
1493
1494})(require('less/tree'));
1495(function (tree) {
1496//
1497// RGB Colors - #ff0014, #eee
1498//
1499tree.Color = function (rgb, a) {
1500    //
1501    // The end goal here, is to parse the arguments
1502    // into an integer triplet, such as `128, 255, 0`
1503    //
1504    // This facilitates operations and conversions.
1505    //
1506    if (Array.isArray(rgb)) {
1507        this.rgb = rgb;
1508    } else if (rgb.length == 6) {
1509        this.rgb = rgb.match(/.{2}/g).map(function (c) {
1510            return parseInt(c, 16);
1511        });
1512    } else if (rgb.length == 8) {
1513        this.alpha = parseInt(rgb.substring(0,2), 16) / 255.0;
1514        this.rgb = rgb.substr(2).match(/.{2}/g).map(function (c) {
1515            return parseInt(c, 16);
1516        });
1517    } else {
1518        this.rgb = rgb.split('').map(function (c) {
1519            return parseInt(c + c, 16);
1520        });
1521    }
1522    this.alpha = typeof(a) === 'number' ? a : 1;
1523};
1524tree.Color.prototype = {
1525    eval: function () { return this },
1526
1527    //
1528    // If we have some transparency, the only way to represent it
1529    // is via `rgba`. Otherwise, we use the hex representation,
1530    // which has better compatibility with older browsers.
1531    // Values are capped between `0` and `255`, rounded and zero-padded.
1532    //
1533    toCSS: function () {
1534        if (this.alpha < 1.0) {
1535            return "rgba(" + this.rgb.map(function (c) {
1536                return Math.round(c);
1537            }).concat(this.alpha).join(', ') + ")";
1538        } else {
1539            return '#' + this.rgb.map(function (i) {
1540                i = Math.round(i);
1541                i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1542                return i.length === 1 ? '0' + i : i;
1543            }).join('');
1544        }
1545    },
1546
1547    //
1548    // Operations have to be done per-channel, if not,
1549    // channels will spill onto each other. Once we have
1550    // our result, in the form of an integer triplet,
1551    // we create a new Color node to hold the result.
1552    //
1553    operate: function (op, other) {
1554        var result = [];
1555
1556        if (! (other instanceof tree.Color)) {
1557            other = other.toColor();
1558        }
1559
1560        for (var c = 0; c < 3; c++) {
1561            result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
1562        }
1563        return new(tree.Color)(result, this.alpha + other.alpha);
1564    },
1565
1566    toHSL: function () {
1567        var r = this.rgb[0] / 255,
1568            g = this.rgb[1] / 255,
1569            b = this.rgb[2] / 255,
1570            a = this.alpha;
1571
1572        var max = Math.max(r, g, b), min = Math.min(r, g, b);
1573        var h, s, l = (max + min) / 2, d = max - min;
1574
1575        if (max === min) {
1576            h = s = 0;
1577        } else {
1578            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1579
1580            switch (max) {
1581                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1582                case g: h = (b - r) / d + 2;               break;
1583                case b: h = (r - g) / d + 4;               break;
1584            }
1585            h /= 6;
1586        }
1587        return { h: h * 360, s: s, l: l, a: a };
1588    }
1589};
1590
1591
1592})(require('less/tree'));
1593(function (tree) {
1594
1595tree.Comment = function (value, silent) {
1596    this.value = value;
1597    this.silent = !!silent;
1598};
1599tree.Comment.prototype = {
1600    toCSS: function (env) {
1601        return env.compress ? '' : this.value;
1602    },
1603    eval: function () { return this }
1604};
1605
1606})(require('less/tree'));
1607(function (tree) {
1608
1609//
1610// A number with a unit
1611//
1612tree.Dimension = function (value, unit) {
1613    this.value = parseFloat(value);
1614    this.unit = unit || null;
1615};
1616
1617tree.Dimension.prototype = {
1618    eval: function () { return this },
1619    toColor: function () {
1620        return new(tree.Color)([this.value, this.value, this.value]);
1621    },
1622    toCSS: function () {
1623        var css = this.value + this.unit;
1624        return css;
1625    },
1626
1627    // In an operation between two Dimensions,
1628    // we default to the first Dimension's unit,
1629    // so `1px + 2em` will yield `3px`.
1630    // In the future, we could implement some unit
1631    // conversions such that `100cm + 10mm` would yield
1632    // `101cm`.
1633    operate: function (op, other) {
1634        return new(tree.Dimension)
1635                  (tree.operate(op, this.value, other.value),
1636                  this.unit || other.unit);
1637    }
1638};
1639
1640})(require('less/tree'));
1641(function (tree) {
1642
1643tree.Directive = function (name, value) {
1644    this.name = name;
1645    if (Array.isArray(value)) {
1646        this.ruleset = new(tree.Ruleset)([], value);
1647    } else {
1648        this.value = value;
1649    }
1650};
1651tree.Directive.prototype = {
1652    toCSS: function (ctx, env) {
1653        if (this.ruleset) {
1654            this.ruleset.root = true;
1655            return this.name + (env.compress ? '{' : ' {\n  ') +
1656                   this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n  ') +
1657                               (env.compress ? '}': '\n}\n');
1658        } else {
1659            return this.name + ' ' + this.value.toCSS() + ';\n';
1660        }
1661    },
1662    eval: function (env) {
1663        env.frames.unshift(this);
1664        this.ruleset = this.ruleset && this.ruleset.eval(env);
1665        env.frames.shift();
1666        return this;
1667    },
1668    variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
1669    find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
1670    rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
1671};
1672
1673})(require('less/tree'));
1674(function (tree) {
1675
1676tree.Element = function (combinator, value) {
1677    this.combinator = combinator instanceof tree.Combinator ?
1678                      combinator : new(tree.Combinator)(combinator);
1679    this.value = value ? value.trim() : "";
1680};
1681tree.Element.prototype.toCSS = function (env) {
1682    return this.combinator.toCSS(env || {}) + this.value;
1683};
1684
1685tree.Combinator = function (value) {
1686    if (value === ' ') {
1687        this.value = ' ';
1688    } else if (value === '& ') {
1689        this.value = '& ';
1690    } else {
1691        this.value = value ? value.trim() : "";
1692    }
1693};
1694tree.Combinator.prototype.toCSS = function (env) {
1695    return {
1696        ''  : '',
1697        ' ' : ' ',
1698        '&' : '',
1699        '& ' : ' ',
1700        ':' : ' :',
1701        '::': '::',
1702        '+' : env.compress ? '+' : ' + ',
1703        '~' : env.compress ? '~' : ' ~ ',
1704        '>' : env.compress ? '>' : ' > '
1705    }[this.value];
1706};
1707
1708})(require('less/tree'));
1709(function (tree) {
1710
1711tree.Expression = function (value) { this.value = value };
1712tree.Expression.prototype = {
1713    eval: function (env) {
1714        if (this.value.length > 1) {
1715            return new(tree.Expression)(this.value.map(function (e) {
1716                return e.eval(env);
1717            }));
1718        } else if (this.value.length === 1) {
1719            return this.value[0].eval(env);
1720        } else {
1721            return this;
1722        }
1723    },
1724    toCSS: function (env) {
1725        return this.value.map(function (e) {
1726            return e.toCSS(env);
1727        }).join(' ');
1728    }
1729};
1730
1731})(require('less/tree'));
1732(function (tree) {
1733//
1734// CSS @import node
1735//
1736// The general strategy here is that we don't want to wait
1737// for the parsing to be completed, before we start importing
1738// the file. That's because in the context of a browser,
1739// most of the time will be spent waiting for the server to respond.
1740//
1741// On creation, we push the import path to our import queue, though
1742// `import,push`, we also pass it a callback, which it'll call once
1743// the file has been fetched, and parsed.
1744//
1745tree.Import = function (path, imports) {
1746    var that = this;
1747
1748    this._path = path;
1749
1750    // The '.less' extension is optional
1751    if (path instanceof tree.Quoted) {
1752        this.path = /\.(le?|c)ss$/.test(path.value) ? path.value : path.value + '.less';
1753    } else {
1754        this.path = path.value.value || path.value;
1755    }
1756
1757    this.css = /css$/.test(this.path);
1758
1759    // Only pre-compile .less files
1760    if (! this.css) {
1761        imports.push(this.path, function (root) {
1762            if (! root) {
1763                throw new(Error)("Error parsing " + that.path);
1764            }
1765            that.root = root;
1766        });
1767    }
1768};
1769
1770//
1771// The actual import node doesn't return anything, when converted to CSS.
1772// The reason is that it's used at the evaluation stage, so that the rules
1773// it imports can be treated like any other rules.
1774//
1775// In `eval`, we make sure all Import nodes get evaluated, recursively, so
1776// we end up with a flat structure, which can easily be imported in the parent
1777// ruleset.
1778//
1779tree.Import.prototype = {
1780    toCSS: function () {
1781        if (this.css) {
1782            return "@import " + this._path.toCSS() + ';\n';
1783        } else {
1784            return "";
1785        }
1786    },
1787    eval: function (env) {
1788        var ruleset;
1789
1790        if (this.css) {
1791            return this;
1792        } else {
1793            ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
1794
1795            for (var i = 0; i < ruleset.rules.length; i++) {
1796                if (ruleset.rules[i] instanceof tree.Import) {
1797                    Array.prototype
1798                         .splice
1799                         .apply(ruleset.rules,
1800                                [i, 1].concat(ruleset.rules[i].eval(env)));
1801                }
1802            }
1803            return ruleset.rules;
1804        }
1805    }
1806};
1807
1808})(require('less/tree'));
1809(function (tree) {
1810
1811tree.JavaScript = function (string, index, escaped) {
1812    this.escaped = escaped;
1813    this.expression = string;
1814    this.index = index;
1815};
1816tree.JavaScript.prototype = {
1817    eval: function (env) {
1818        var result,
1819            that = this,
1820            context = {};
1821
1822        var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
1823            return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
1824        });
1825
1826        try {
1827            expression = new(Function)('return (' + expression + ')');
1828        } catch (e) {
1829            throw { message: "JavaScript evaluation error: `" + expression + "`" ,
1830                    index: this.index };
1831        }
1832
1833        for (var k in env.frames[0].variables()) {
1834            context[k.slice(1)] = {
1835                value: env.frames[0].variables()[k].value,
1836                toJS: function () {
1837                    return this.value.eval(env).toCSS();
1838                }
1839            };
1840        }
1841
1842        try {
1843            result = expression.call(context);
1844        } catch (e) {
1845            throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
1846                    index: this.index };
1847        }
1848        if (typeof(result) === 'string') {
1849            return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
1850        } else if (Array.isArray(result)) {
1851            return new(tree.Anonymous)(result.join(', '));
1852        } else {
1853            return new(tree.Anonymous)(result);
1854        }
1855    }
1856};
1857
1858})(require('less/tree'));
1859
1860(function (tree) {
1861
1862tree.Keyword = function (value) { this.value = value };
1863tree.Keyword.prototype = {
1864    eval: function () { return this },
1865    toCSS: function () { return this.value }
1866};
1867
1868})(require('less/tree'));
1869(function (tree) {
1870
1871tree.mixin = {};
1872tree.mixin.Call = function (elements, args, index) {
1873    this.selector = new(tree.Selector)(elements);
1874    this.arguments = args;
1875    this.index = index;
1876};
1877tree.mixin.Call.prototype = {
1878    eval: function (env) {
1879        var mixins, args, rules = [], match = false;
1880
1881        for (var i = 0; i < env.frames.length; i++) {
1882            if ((mixins = env.frames[i].find(this.selector)).length > 0) {
1883                args = this.arguments && this.arguments.map(function (a) { return a.eval(env) });
1884                for (var m = 0; m < mixins.length; m++) {
1885                    if (mixins[m].match(args, env)) {
1886                        try {
1887                            Array.prototype.push.apply(
1888                                  rules, mixins[m].eval(env, this.arguments).rules);
1889                            match = true;
1890                        } catch (e) {
1891                            throw { message: e.message, index: e.index, stack: e.stack, call: this.index };
1892                        }
1893                    }
1894                }
1895                if (match) {
1896                    return rules;
1897                } else {
1898                    throw { message: 'No matching definition was found for `' +
1899                                      this.selector.toCSS().trim() + '('      +
1900                                      this.arguments.map(function (a) {
1901                                          return a.toCSS();
1902                                      }).join(', ') + ")`",
1903                            index:   this.index };
1904                }
1905            }
1906        }
1907        throw { message: this.selector.toCSS().trim() + " is undefined",
1908                index: this.index };
1909    }
1910};
1911
1912tree.mixin.Definition = function (name, params, rules) {
1913    this.name = name;
1914    this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
1915    this.params = params;
1916    this.arity = params.length;
1917    this.rules = rules;
1918    this._lookups = {};
1919    this.required = params.reduce(function (count, p) {
1920        if (!p.name || (p.name && !p.value)) { return count + 1 }
1921        else                                 { return count }
1922    }, 0);
1923    this.parent = tree.Ruleset.prototype;
1924    this.frames = [];
1925};
1926tree.mixin.Definition.prototype = {
1927    toCSS:     function ()     { return "" },
1928    variable:  function (name) { return this.parent.variable.call(this, name) },
1929    variables: function ()     { return this.parent.variables.call(this) },
1930    find:      function ()     { return this.parent.find.apply(this, arguments) },
1931    rulesets:  function ()     { return this.parent.rulesets.apply(this) },
1932
1933    eval: function (env, args) {
1934        var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
1935
1936        for (var i = 0, val; i < this.params.length; i++) {
1937            if (this.params[i].name) {
1938                if (val = (args && args[i]) || this.params[i].value) {
1939                    frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));
1940                } else {
1941                    throw { message: "wrong number of arguments for " + this.name +
1942                            ' (' + args.length + ' for ' + this.arity + ')' };
1943                }
1944            }
1945        }
1946        for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
1947            _arguments.push(args[i] || this.params[i].value);
1948        }
1949        frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
1950
1951        return new(tree.Ruleset)(null, this.rules.slice(0)).eval({
1952            frames: [this, frame].concat(this.frames, env.frames)
1953        });
1954    },
1955    match: function (args, env) {
1956        var argsLength = (args && args.length) || 0, len;
1957
1958        if (argsLength < this.required)                               { return false }
1959        if ((this.required > 0) && (argsLength > this.params.length)) { return false }
1960
1961        len = Math.min(argsLength, this.arity);
1962
1963        for (var i = 0; i < len; i++) {
1964            if (!this.params[i].name) {
1965                if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
1966                    return false;
1967                }
1968            }
1969        }
1970        return true;
1971    }
1972};
1973
1974})(require('less/tree'));
1975(function (tree) {
1976
1977tree.Operation = function (op, operands) {
1978    this.op = op.trim();
1979    this.operands = operands;
1980};
1981tree.Operation.prototype.eval = function (env) {
1982    var a = this.operands[0].eval(env),
1983        b = this.operands[1].eval(env),
1984        temp;
1985
1986    if (a instanceof tree.Dimension && b instanceof tree.Color) {
1987        if (this.op === '*' || this.op === '+') {
1988            temp = b, b = a, a = temp;
1989        } else {
1990            throw { name: "OperationError",
1991                    message: "Can't substract or divide a color from a number" };
1992        }
1993    }
1994    return a.operate(this.op, b);
1995};
1996
1997tree.operate = function (op, a, b) {
1998    switch (op) {
1999        case '+': return a + b;
2000        case '-': return a - b;
2001        case '*': return a * b;
2002        case '/': return a / b;
2003    }
2004};
2005
2006})(require('less/tree'));
2007(function (tree) {
2008
2009tree.Quoted = function (str, content, escaped, i) {
2010    this.escaped = escaped;
2011    this.value = content || '';
2012    this.quote = str.charAt(0);
2013    this.index = i;
2014};
2015tree.Quoted.prototype = {
2016    toCSS: function () {
2017        if (this.escaped) {
2018            return this.value;
2019        } else {
2020            return this.quote + this.value + this.quote;
2021        }
2022    },
2023    eval: function (env) {
2024        var that = this;
2025        var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
2026            return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
2027        }).replace(/@\{([\w-]+)\}/g, function (_, name) {
2028            var v = new(tree.Variable)('@' + name, that.index).eval(env);
2029            return v.value || v.toCSS();
2030        });
2031        return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
2032    }
2033};
2034
2035})(require('less/tree'));
2036(function (tree) {
2037
2038tree.Rule = function (name, value, important, index) {
2039    this.name = name;
2040    this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
2041    this.important = important ? ' ' + important.trim() : '';
2042    this.index = index;
2043
2044    if (name.charAt(0) === '@') {
2045        this.variable = true;
2046    } else { this.variable = false }
2047};
2048tree.Rule.prototype.toCSS = function (env) {
2049    if (this.variable) { return "" }
2050    else {
2051        return this.name + (env.compress ? ':' : ': ') +
2052               this.value.toCSS(env) +
2053               this.important + ";";
2054    }
2055};
2056
2057tree.Rule.prototype.eval = function (context) {
2058    return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index);
2059};
2060
2061tree.Shorthand = function (a, b) {
2062    this.a = a;
2063    this.b = b;
2064};
2065
2066tree.Shorthand.prototype = {
2067    toCSS: function (env) {
2068        return this.a.toCSS(env) + "/" + this.b.toCSS(env);
2069    },
2070    eval: function () { return this }
2071};
2072
2073})(require('less/tree'));
2074(function (tree) {
2075
2076tree.Ruleset = function (selectors, rules) {
2077    this.selectors = selectors;
2078    this.rules = rules;
2079    this._lookups = {};
2080};
2081tree.Ruleset.prototype = {
2082    eval: function (env) {
2083        var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));
2084
2085        ruleset.root = this.root;
2086
2087        // push the current ruleset to the frames stack
2088        env.frames.unshift(ruleset);
2089
2090        // Evaluate imports
2091        if (ruleset.root) {
2092            for (var i = 0; i < ruleset.rules.length; i++) {
2093                if (ruleset.rules[i] instanceof tree.Import) {
2094                    Array.prototype.splice
2095                         .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2096                }
2097            }
2098        }
2099
2100        // Store the frames around mixin definitions,
2101        // so they can be evaluated like closures when the time comes.
2102        for (var i = 0; i < ruleset.rules.length; i++) {
2103            if (ruleset.rules[i] instanceof tree.mixin.Definition) {
2104                ruleset.rules[i].frames = env.frames.slice(0);
2105            }
2106        }
2107
2108        // Evaluate mixin calls.
2109        for (var i = 0; i < ruleset.rules.length; i++) {
2110            if (ruleset.rules[i] instanceof tree.mixin.Call) {
2111                Array.prototype.splice
2112                     .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2113            }
2114        }
2115
2116        // Evaluate everything else
2117        for (var i = 0, rule; i < ruleset.rules.length; i++) {
2118            rule = ruleset.rules[i];
2119
2120            if (! (rule instanceof tree.mixin.Definition)) {
2121                ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
2122            }
2123        }
2124
2125        // Pop the stack
2126        env.frames.shift();
2127
2128        return ruleset;
2129    },
2130    match: function (args) {
2131        return !args || args.length === 0;
2132    },
2133    variables: function () {
2134        if (this._variables) { return this._variables }
2135        else {
2136            return this._variables = this.rules.reduce(function (hash, r) {
2137                if (r instanceof tree.Rule && r.variable === true) {
2138                    hash[r.name] = r;
2139                }
2140                return hash;
2141            }, {});
2142        }
2143    },
2144    variable: function (name) {
2145        return this.variables()[name];
2146    },
2147    rulesets: function () {
2148        if (this._rulesets) { return this._rulesets }
2149        else {
2150            return this._rulesets = this.rules.filter(function (r) {
2151                return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
2152            });
2153        }
2154    },
2155    find: function (selector, self) {
2156        self = self || this;
2157        var rules = [], rule, match,
2158            key = selector.toCSS();
2159
2160        if (key in this._lookups) { return this._lookups[key] }
2161
2162        this.rulesets().forEach(function (rule) {
2163            if (rule !== self) {
2164                for (var j = 0; j < rule.selectors.length; j++) {
2165                    if (match = selector.match(rule.selectors[j])) {
2166                        if (selector.elements.length > 1) {
2167                            Array.prototype.push.apply(rules, rule.find(
2168                                new(tree.Selector)(selector.elements.slice(1)), self));
2169                        } else {
2170                            rules.push(rule);
2171                        }
2172                        break;
2173                    }
2174                }
2175            }
2176        });
2177        return this._lookups[key] = rules;
2178    },
2179    //
2180    // Entry point for code generation
2181    //
2182    //     `context` holds an array of arrays.
2183    //
2184    toCSS: function (context, env) {
2185        var css = [],      // The CSS output
2186            rules = [],    // node.Rule instances
2187            rulesets = [], // node.Ruleset instances
2188            paths = [],    // Current selectors
2189            selector,      // The fully rendered selector
2190            rule;
2191
2192        if (! this.root) {
2193            if (context.length === 0) {
2194                paths = this.selectors.map(function (s) { return [s] });
2195            } else {
2196                this.joinSelectors( paths, context, this.selectors );
2197            }
2198        }
2199
2200        // Compile rules and rulesets
2201        for (var i = 0; i < this.rules.length; i++) {
2202            rule = this.rules[i];
2203
2204            if (rule.rules || (rule instanceof tree.Directive)) {
2205                rulesets.push(rule.toCSS(paths, env));
2206            } else if (rule instanceof tree.Comment) {
2207                if (!rule.silent) {
2208                    if (this.root) {
2209                        rulesets.push(rule.toCSS(env));
2210                    } else {
2211                        rules.push(rule.toCSS(env));
2212                    }
2213                }
2214            } else {
2215                if (rule.toCSS && !rule.variable) {
2216                    rules.push(rule.toCSS(env));
2217                } else if (rule.value && !rule.variable) {
2218                    rules.push(rule.value.toString());
2219                }
2220            }
2221        }
2222
2223        rulesets = rulesets.join('');
2224
2225        // If this is the root node, we don't render
2226        // a selector, or {}.
2227        // Otherwise, only output if this ruleset has rules.
2228        if (this.root) {
2229            css.push(rules.join(env.compress ? '' : '\n'));
2230        } else {
2231            if (rules.length > 0) {
2232                selector = paths.map(function (p) {
2233                    return p.map(function (s) {
2234                        return s.toCSS(env);
2235                    }).join('').trim();
2236                }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
2237                css.push(selector,
2238                        (env.compress ? '{' : ' {\n  ') +
2239                        rules.join(env.compress ? '' : '\n  ') +
2240                        (env.compress ? '}' : '\n}\n'));
2241            }
2242        }
2243        css.push(rulesets);
2244
2245        return css.join('') + (env.compress ? '\n' : '');
2246    },
2247
2248    joinSelectors: function( paths, context, selectors ) {
2249        for (var s = 0; s < selectors.length; s++) {
2250            this.joinSelector(paths, context, selectors[s]);
2251        }
2252    },
2253
2254    joinSelector: function( paths, context, selector ) {
2255        var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el;
2256
2257        for (var i = 0; i < selector.elements.length; i++) {
2258            el = selector.elements[i];
2259            if (el.combinator.value[0] === '&') {
2260                hasParentSelector = true;
2261            }
2262            if(!hasParentSelector) {
2263                beforeElements.push(el);
2264            } else {
2265                afterElements.push(el);
2266            }
2267        }
2268
2269        if(!hasParentSelector) {
2270            afterElements = beforeElements;
2271            beforeElements = [];
2272        }
2273
2274        if(beforeElements.length > 0) {
2275            before.push(new (tree.Selector)(beforeElements));
2276        }
2277        if(afterElements.length > 0) {
2278            after.push(new (tree.Selector)(afterElements));
2279        }
2280
2281        for (var c = 0; c < context.length; c++) {
2282            paths.push(before.concat(context[c]).concat(after));
2283        }
2284    }
2285};
2286})(require('less/tree'));
2287(function (tree) {
2288
2289tree.Selector = function (elements) {
2290    this.elements = elements;
2291    if (this.elements[0].combinator.value === "") {
2292        this.elements[0].combinator.value = ' ';
2293    }
2294};
2295tree.Selector.prototype.match = function (other) {
2296    if (this.elements[0].value === other.elements[0].value) {
2297        return true;
2298    } else {
2299        return false;
2300    }
2301};
2302tree.Selector.prototype.toCSS = function (env) {
2303    if (this._css) { return this._css }
2304
2305    return this._css = this.elements.map(function (e) {
2306        if (typeof(e) === 'string') {
2307            return ' ' + e.trim();
2308        } else {
2309            return e.toCSS(env);
2310        }
2311    }).join('');
2312};
2313
2314})(require('less/tree'));
2315(function (tree) {
2316
2317tree.URL = function (val, paths) {
2318    if (val.data) {
2319        this.attrs = val;
2320    } else {
2321        // Add the base path if the URL is relative and we are in the browser
2322        if (!/^(?:https?:\/|file:\/|data:\/)?\//.test(val.value) && paths.length > 0 && typeof(window) !== 'undefined') {
2323            val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
2324        }
2325        this.value = val;
2326        this.paths = paths;
2327    }
2328};
2329tree.URL.prototype = {
2330    toCSS: function () {
2331        return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data
2332                                    : this.value.toCSS()) + ")";
2333    },
2334    eval: function (ctx) {
2335        return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths);
2336    }
2337};
2338
2339})(require('less/tree'));
2340(function (tree) {
2341
2342tree.Value = function (value) {
2343    this.value = value;
2344    this.is = 'value';
2345};
2346tree.Value.prototype = {
2347    eval: function (env) {
2348        if (this.value.length === 1) {
2349            return this.value[0].eval(env);
2350        } else {
2351            return new(tree.Value)(this.value.map(function (v) {
2352                return v.eval(env);
2353            }));
2354        }
2355    },
2356    toCSS: function (env) {
2357        return this.value.map(function (e) {
2358            return e.toCSS(env);
2359        }).join(env.compress ? ',' : ', ');
2360    }
2361};
2362
2363})(require('less/tree'));
2364(function (tree) {
2365
2366tree.Variable = function (name, index) { this.name = name, this.index = index };
2367tree.Variable.prototype = {
2368    eval: function (env) {
2369        var variable, v, name = this.name;
2370
2371        if (name.indexOf('@@') == 0) {
2372            name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
2373        }
2374
2375        if (variable = tree.find(env.frames, function (frame) {
2376            if (v = frame.variable(name)) {
2377                return v.value.eval(env);
2378            }
2379        })) { return variable }
2380        else {
2381            throw { message: "variable " + name + " is undefined",
2382                    index: this.index };
2383        }
2384    }
2385};
2386
2387})(require('less/tree'));
2388require('less/tree').find = function (obj, fun) {
2389    for (var i = 0, r; i < obj.length; i++) {
2390        if (r = fun.call(obj, obj[i])) { return r }
2391    }
2392    return null;
2393};
2394require('less/tree').jsify = function (obj) {
2395    if (Array.isArray(obj.value) && (obj.value.length > 1)) {
2396        return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
2397    } else {
2398        return obj.toCSS(false);
2399    }
2400};
2401var name;
2402
2403function loadStyleSheet(sheet, callback, reload, remaining) {
2404    var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href;
2405    var input = readFile(sheetName);
2406    var parser = new less.Parser();
2407    parser.parse(input, function (e, root) {
2408        if (e) {
2409            print("Error: " + e);
2410            quit(1);
2411        }
2412        callback(root, sheet, { local: false, lastModified: 0, remaining: remaining });
2413    });
2414
2415    // callback({}, sheet, { local: true, remaining: remaining });
2416}
2417
2418function writeFile(filename, content) {
2419    var fstream = new java.io.FileWriter(filename);
2420    var out = new java.io.BufferedWriter(fstream);
2421    out.write(content);
2422    out.close();
2423}
2424
2425// Command line integration via Rhino
2426(function (args) {
2427    name = args[0];
2428    var output = args[1];
2429
2430    if (!name) {
2431        print('No files present in the fileset; Check your pattern match in build.xml');
2432        quit(1);
2433    }
2434    path = name.split("/");path.pop();path=path.join("/")
2435
2436    var input = readFile(name);
2437
2438    if (!input) {
2439        print('lesscss: couldn\'t open file ' + name);
2440        quit(1);
2441    }
2442
2443    var result;
2444    var parser = new less.Parser();
2445    parser.parse(input, function (e, root) {
2446        if (e) {
2447            quit(1);
2448        } else {
2449            result = root.toCSS();
2450            if (output) {
2451                writeFile(output, result);
2452                print("Written to " + output);
2453            } else {
2454                print(result);
2455            }
2456            quit(0);
2457        }
2458    });
2459    print("done");
2460}(arguments));
Note: See TracBrowser for help on using the repository browser.