1 (function() {
  2 //
  3 // Stub out `require` in rhino
  4 //
  5 function require(arg) {
  6     return less[arg.split('/')[1]];
  7 };
  8 
  9 
 10 // ecma-5.js
 11 //
 12 // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
 13 // -- tlrobinson Tom Robinson
 14 // dantman Daniel Friesen
 15 
 16 //
 17 // Array
 18 //
 19 if (!Array.isArray) {
 20     Array.isArray = function(obj) {
 21         return Object.prototype.toString.call(obj) === "[object Array]" ||
 22                (obj instanceof Array);
 23     };
 24 }
 25 if (!Array.prototype.forEach) {
 26     Array.prototype.forEach =  function(block, thisObject) {
 27         var len = this.length >>> 0;
 28         for (var i = 0; i < len; i++) {
 29             if (i in this) {
 30                 block.call(thisObject, this[i], i, this);
 31             }
 32         }
 33     };
 34 }
 35 if (!Array.prototype.map) {
 36     Array.prototype.map = function(fun /*, thisp*/) {
 37         var len = this.length >>> 0;
 38         var res = new Array(len);
 39         var thisp = arguments[1];
 40 
 41         for (var i = 0; i < len; i++) {
 42             if (i in this) {
 43                 res[i] = fun.call(thisp, this[i], i, this);
 44             }
 45         }
 46         return res;
 47     };
 48 }
 49 if (!Array.prototype.filter) {
 50     Array.prototype.filter = function (block /*, thisp */) {
 51         var values = [];
 52         var thisp = arguments[1];
 53         for (var i = 0; i < this.length; i++) {
 54             if (block.call(thisp, this[i])) {
 55                 values.push(this[i]);
 56             }
 57         }
 58         return values;
 59     };
 60 }
 61 if (!Array.prototype.reduce) {
 62     Array.prototype.reduce = function(fun /*, initial*/) {
 63         var len = this.length >>> 0;
 64         var i = 0;
 65 
 66         // no value to return if no initial value and an empty array
 67         if (len === 0 && arguments.length === 1) throw new TypeError();
 68 
 69         if (arguments.length >= 2) {
 70             var rv = arguments[1];
 71         } else {
 72             do {
 73                 if (i in this) {
 74                     rv = this[i++];
 75                     break;
 76                 }
 77                 // if array contains no values, no initial value to return
 78                 if (++i >= len) throw new TypeError();
 79             } while (true);
 80         }
 81         for (; i < len; i++) {
 82             if (i in this) {
 83                 rv = fun.call(null, rv, this[i], i, this);
 84             }
 85         }
 86         return rv;
 87     };
 88 }
 89 if (!Array.prototype.indexOf) {
 90     Array.prototype.indexOf = function (value /*, fromIndex */ ) {
 91         var length = this.length;
 92         var i = arguments[1] || 0;
 93 
 94         if (!length)     return -1;
 95         if (i >= length) return -1;
 96         if (i < 0)       i += length;
 97 
 98         for (; i < length; i++) {
 99             if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
100             if (value === this[i]) return i;
101         }
102         return -1;
103     };
104 }
105 
106 //
107 // Object
108 //
109 if (!Object.keys) {
110     Object.keys = function (object) {
111         var keys = [];
112         for (var name in object) {
113             if (Object.prototype.hasOwnProperty.call(object, name)) {
114                 keys.push(name);
115             }
116         }
117         return keys;
118     };
119 }
120 
121 //
122 // String
123 //
124 if (!String.prototype.trim) {
125     String.prototype.trim = function () {
126         return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
127     };
128 }
129 var less, tree;
130 
131 if (typeof HopObject === 'function') {
132     // Helma
133     // Fully qualified condition would be helma.main.Server.getServer() === 'string'
134     less = global.less = {}
135     tree = less.tree = {}
136     less.mode = 'rhino';
137 } else if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
138     // Rhino
139     // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
140     if (typeof(window) === 'undefined') { less = {} }
141     else                                { less = window.less = {} }
142     tree = less.tree = {};
143     less.mode = 'rhino';
144 } else if (typeof(window) === 'undefined') {
145     // Node.js
146     less = exports,
147     tree = require('./tree');
148     less.mode = 'node';
149 } else {
150     // Browser
151     if (typeof(window.less) === 'undefined') { window.less = {} }
152     less = window.less,
153     tree = window.less.tree = {};
154     less.mode = 'browser';
155 }
156 //
157 // less.js - parser
158 //
159 //    A relatively straight-forward predictive parser.
160 //    There is no tokenization/lexing stage, the input is parsed
161 //    in one sweep.
162 //
163 //    To make the parser fast enough to run in the browser, several
164 //    optimization had to be made:
165 //
166 //    - Matching and slicing on a huge input is often cause of slowdowns.
167 //      The solution is to chunkify the input into smaller strings.
168 //      The chunks are stored in the `chunks` var,
169 //      `j` holds the current chunk index, and `current` holds
170 //      the index of the current chunk in relation to `input`.
171 //      This gives us an almost 4x speed-up.
172 //
173 //    - In many cases, we don't need to match individual tokens;
174 //      for example, if a value doesn't hold any variables, operations
175 //      or dynamic references, the parser can effectively 'skip' it,
176 //      treating it as a literal.
177 //      An example would be '1px solid #000' - which evaluates to itself,
178 //      we don't need to know what the individual components are.
179 //      The drawback, of course is that you don't get the benefits of
180 //      syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
181 //      and a smaller speed-up in the code-gen.
182 //
183 //
184 //    Token matching is done with the `$` function, which either takes
185 //    a terminal string or regexp, or a non-terminal function to call.
186 //    It also takes care of moving all the indices forwards.
187 //
188 //
189 less.Parser = function Parser(env) {
190     var input,       // LeSS input string
191         i,           // current index in `input`
192         j,           // current chunk
193         temp,        // temporarily holds a chunk's state, for backtracking
194         memo,        // temporarily holds `i`, when backtracking
195         furthest,    // furthest index the parser has gone to
196         chunks,      // chunkified input
197         current,     // index of current chunk, in `input`
198         parser;
199 
200     var that = this;
201 
202     // This function is called after all files
203     // have been imported through `@import`.
204     var finish = function () {};
205 
206     var imports = this.imports = {
207         paths: env && env.paths || [],  // Search paths, when importing
208         queue: [],                      // Files which haven't been imported yet
209         files: {},                      // Holds the imported parse trees
210         contents: {},                   // Holds the imported file contents
211         mime:  env && env.mime,         // MIME type of .less files
212         error: null,                    // Error in parsing/evaluating an import
213         push: function (path, callback) {
214             var that = this;
215             this.queue.push(path);
216 
217             //
218             // Import a file asynchronously
219             //
220             less.Parser.importer(path, this.paths, function (e, root, contents) {
221                 that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
222 
223                 var imported = path in that.files;
224 
225                 that.files[path] = root;                        // Store the root
226                 that.contents[path] = contents;
227 
228                 if (e && !that.error) { that.error = e }
229 
230                 callback(e, root, imported);
231 
232                 if (that.queue.length === 0) { finish() }       // Call `finish` if we're done importing
233             }, env);
234         }
235     };
236 
237     function save()    { temp = chunks[j], memo = i, current = i }
238     function restore() { chunks[j] = temp, i = memo, current = i }
239 
240     function sync() {
241         if (i > current) {
242             chunks[j] = chunks[j].slice(i - current);
243             current = i;
244         }
245     }
246     //
247     // Parse from a token, regexp or string, and move forward if match
248     //
249     function $(tok) {
250         var match, args, length, c, index, endIndex, k, mem;
251 
252         //
253         // Non-terminal
254         //
255         if (tok instanceof Function) {
256             return tok.call(parser.parsers);
257         //
258         // Terminal
259         //
260         //     Either match a single character in the input,
261         //     or match a regexp in the current chunk (chunk[j]).
262         //
263         } else if (typeof(tok) === 'string') {
264             match = input.charAt(i) === tok ? tok : null;
265             length = 1;
266             sync ();
267         } else {
268             sync ();
269 
270             if (match = tok.exec(chunks[j])) {
271                 length = match[0].length;
272             } else {
273                 return null;
274             }
275         }
276 
277         // The match is confirmed, add the match length to `i`,
278         // and consume any extra white-space characters (' ' || '\n')
279         // which come after that. The reason for this is that LeSS's
280         // grammar is mostly white-space insensitive.
281         //
282         if (match) {
283             mem = i += length;
284             endIndex = i + chunks[j].length - length;
285 
286             while (i < endIndex) {
287                 c = input.charCodeAt(i);
288                 if (! (c === 32 || c === 10 || c === 9)) { break }
289                 i++;
290             }
291             chunks[j] = chunks[j].slice(length + (i - mem));
292             current = i;
293 
294             if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
295 
296             if(typeof(match) === 'string') {
297                 return match;
298             } else {
299                 return match.length === 1 ? match[0] : match;
300             }
301         }
302     }
303 
304     function expect(arg, msg) {
305         var result = $(arg);
306         if (! result) {
307             error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
308                                                    : "unexpected token"));
309         } else {
310             return result;
311         }
312     }
313 
314     function error(msg, type) {
315         throw { index: i, type: type || 'Syntax', message: msg };
316     }
317 
318     // Same as $(), but don't change the state of the parser,
319     // just return the match.
320     function peek(tok) {
321         if (typeof(tok) === 'string') {
322             return input.charAt(i) === tok;
323         } else {
324             if (tok.test(chunks[j])) {
325                 return true;
326             } else {
327                 return false;
328             }
329         }
330     }
331 
332     function basename(pathname) {
333         if (less.mode === 'node') {
334             return require('path').basename(pathname);
335         } else {
336             return pathname.match(/[^\/]+$/)[0];
337         }
338     }
339 
340     function getInput(e, env) {
341         if (e.filename && env.filename && (e.filename !== env.filename)) {
342             return parser.imports.contents[basename(e.filename)];
343         } else {
344             return input;
345         }
346     }
347 
348     function getLocation(index, input) {
349         for (var n = index, column = -1;
350                  n >= 0 && input.charAt(n) !== '\n';
351                  n--) { column++ }
352 
353         return { line:   typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
354                  column: column };
355     }
356 
357     function LessError(e, env) {
358         var input = getInput(e, env),
359             loc = getLocation(e.index, input),
360             line = loc.line,
361             col  = loc.column,
362             lines = input.split('\n');
363 
364         this.type = e.type || 'Syntax';
365         this.message = e.message;
366         this.filename = e.filename || env.filename;
367         this.index = e.index;
368         this.line = typeof(line) === 'number' ? line + 1 : null;
369         this.callLine = e.call && (getLocation(e.call, input).line + 1);
370         this.callExtract = lines[getLocation(e.call, input).line];
371         this.stack = e.stack;
372         this.column = col;
373         this.extract = [
374             lines[line - 1],
375             lines[line],
376             lines[line + 1]
377         ];
378     }
379 
380     this.env = env = env || {};
381 
382     // The optimization level dictates the thoroughness of the parser,
383     // the lower the number, the less nodes it will create in the tree.
384     // This could matter for debugging, or if you want to access
385     // the individual nodes in the tree.
386     this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
387 
388     this.env.filename = this.env.filename || null;
389 
390     //
391     // The Parser
392     //
393     return parser = {
394 
395         imports: imports,
396         //
397         // Parse an input string into an abstract syntax tree,
398         // call `callback` when done.
399         //
400         parse: function (str, callback) {
401             var root, start, end, zone, line, lines, buff = [], c, error = null;
402 
403             i = j = current = furthest = 0;
404             input = str.replace(/\r\n/g, '\n');
405 
406             // Split the input into chunks.
407             chunks = (function (chunks) {
408                 var j = 0,
409                     skip = /[^"'`\{\}\/\(\)\\]+/g,
410                     comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
411                     string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,
412                     level = 0,
413                     match,
414                     chunk = chunks[0],
415                     inParam;
416 
417                 for (var i = 0, c, cc; i < input.length; i++) {
418                     skip.lastIndex = i;
419                     if (match = skip.exec(input)) {
420                         if (match.index === i) {
421                             i += match[0].length;
422                             chunk.push(match[0]);
423                         }
424                     }
425                     c = input.charAt(i);
426                     comment.lastIndex = string.lastIndex = i;
427 
428                     if (match = string.exec(input)) {
429                         if (match.index === i) {
430                             i += match[0].length;
431                             chunk.push(match[0]);
432                             c = input.charAt(i);
433                         }
434                     }
435 
436                     if (!inParam && c === '/') {
437                         cc = input.charAt(i + 1);
438                         if (cc === '/' || cc === '*') {
439                             if (match = comment.exec(input)) {
440                                 if (match.index === i) {
441                                     i += match[0].length;
442                                     chunk.push(match[0]);
443                                     c = input.charAt(i);
444                                 }
445                             }
446                         }
447                     }
448 
449                     switch (c) {
450                         case '{': if (! inParam) { level ++;        chunk.push(c);                           break }
451                         case '}': if (! inParam) { level --;        chunk.push(c); chunks[++j] = chunk = []; break }
452                         case '(': if (! inParam) { inParam = true;  chunk.push(c);                           break }
453                         case ')': if (  inParam) { inParam = false; chunk.push(c);                           break }
454                         default:                                    chunk.push(c);
455                     }
456                 }
457                 if (level > 0) {
458                     error = new(LessError)({
459                         index: i,
460                         type: 'Parse',
461                         message: "missing closing `}`",
462                         filename: env.filename
463                     }, env);
464                 }
465 
466                 return chunks.map(function (c) { return c.join('') });;
467             })([[]]);
468 
469             if (error) {
470                 return callback(error);
471             }
472 
473             // Start with the primary rule.
474             // The whole syntax tree is held under a Ruleset node,
475             // with the `root` property set to true, so no `{}` are
476             // output. The callback is called when the input is parsed.
477             try {
478                 root = new(tree.Ruleset)([], $(this.parsers.primary));
479                 root.root = true;
480             } catch (e) {
481                 return callback(new(LessError)(e, env));
482             }
483 
484             root.toCSS = (function (evaluate) {
485                 var line, lines, column;
486 
487                 return function (options, variables) {
488                     var frames = [], importError;
489 
490                     options = options || {};
491                     //
492                     // Allows setting variables with a hash, so:
493                     //
494                     //   `{ color: new(tree.Color)('#f01') }` will become:
495                     //
496                     //   new(tree.Rule)('@color',
497                     //     new(tree.Value)([
498                     //       new(tree.Expression)([
499                     //         new(tree.Color)('#f01')
500                     //       ])
501                     //     ])
502                     //   )
503                     //
504                     if (typeof(variables) === 'object' && !Array.isArray(variables)) {
505                         variables = Object.keys(variables).map(function (k) {
506                             var value = variables[k];
507 
508                             if (! (value instanceof tree.Value)) {
509                                 if (! (value instanceof tree.Expression)) {
510                                     value = new(tree.Expression)([value]);
511                                 }
512                                 value = new(tree.Value)([value]);
513                             }
514                             return new(tree.Rule)('@' + k, value, false, 0);
515                         });
516                         frames = [new(tree.Ruleset)(null, variables)];
517                     }
518 
519                     try {
520                         var css = evaluate.call(this, { frames: frames })
521                                           .toCSS([], { compress: options.compress || false });
522                     } catch (e) {
523                         throw new(LessError)(e, env);
524                     }
525 
526                     if ((importError = parser.imports.error)) { // Check if there was an error during importing
527                         if (importError instanceof LessError) throw importError;
528                         else                                  throw new(LessError)(importError, env);
529                     }
530 
531                     if (options.yuicompress && less.mode === 'node') {
532                         return require('./cssmin').compressor.cssmin(css);
533                     } else if (options.compress) {
534                         return css.replace(/(\s)+/g, "$1");
535                     } else {
536                         return css;
537                     }
538                 };
539             })(root.eval);
540 
541             // If `i` is smaller than the `input.length - 1`,
542             // it means the parser wasn't able to parse the whole
543             // string, so we've got a parsing error.
544             //
545             // We try to extract a \n delimited string,
546             // showing the line where the parse error occured.
547             // We split it up into two parts (the part which parsed,
548             // and the part which didn't), so we can color them differently.
549             if (i < input.length - 1) {
550                 i = furthest;
551                 lines = input.split('\n');
552                 line = (input.slice(0, i).match(/\n/g) || "").length + 1;
553 
554                 for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
555 
556                 error = {
557                     type: "Parse",
558                     message: "Syntax Error on line " + line,
559                     index: i,
560                     filename: env.filename,
561                     line: line,
562                     column: column,
563                     extract: [
564                         lines[line - 2],
565                         lines[line - 1],
566                         lines[line]
567                     ]
568                 };
569             }
570 
571             if (this.imports.queue.length > 0) {
572                 finish = function () { callback(error, root) };
573             } else {
574                 callback(error, root);
575             }
576         },
577 
578         //
579         // Here in, the parsing rules/functions
580         //
581         // The basic structure of the syntax tree generated is as follows:
582         //
583         //   Ruleset ->  Rule -> Value -> Expression -> Entity
584         //
585         // Here's some LESS code:
586         //
587         //    .class {
588         //      color: #fff;
589         //      border: 1px solid #000;
590         //      width: @w + 4px;
591         //      > .child {...}
592         //    }
593         //
594         // And here's what the parse tree might look like:
595         //
596         //     Ruleset (Selector '.class', [
597         //         Rule ("color",  Value ([Expression [Color #fff]]))
598         //         Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
599         //         Rule ("width",  Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
600         //         Ruleset (Selector [Element '>', '.child'], [...])
601         //     ])
602         //
603         //  In general, most rules will try to parse a token with the `$()` function, and if the return
604         //  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
605         //  first, before parsing, that's when we use `peek()`.
606         //
607         parsers: {
608             //
609             // The `primary` rule is the *entry* and *exit* point of the parser.
610             // The rules here can appear at any level of the parse tree.
611             //
612             // The recursive nature of the grammar is an interplay between the `block`
613             // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
614             // as represented by this simplified grammar:
615             //
616             //     primary  →  (ruleset | rule)+
617             //     ruleset  →  selector+ block
618             //     block    →  '{' primary '}'
619             //
620             // Only at one point is the primary rule not called from the
621             // block rule: at the root level.
622             //
623             primary: function () {
624                 var node, root = [];
625 
626                 while ((node = $(this.mixin.definition) || $(this.rule)    ||  $(this.ruleset) ||
627                                $(this.mixin.call)       || $(this.comment) ||  $(this.directive))
628                                || $(/^[\s\n]+/)) {
629                     node && root.push(node);
630                 }
631                 return root;
632             },
633 
634             // We create a Comment node for CSS comments `/* */`,
635             // but keep the LeSS comments `//` silent, by just skipping
636             // over them.
637             comment: function () {
638                 var comment;
639 
640                 if (input.charAt(i) !== '/') return;
641 
642                 if (input.charAt(i + 1) === '/') {
643                     return new(tree.Comment)($(/^\/\/.*/), true);
644                 } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
645                     return new(tree.Comment)(comment);
646                 }
647             },
648 
649             //
650             // Entities are tokens which can be found inside an Expression
651             //
652             entities: {
653                 //
654                 // A string, which supports escaping " and '
655                 //
656                 //     "milky way" 'he\'s the one!'
657                 //
658                 quoted: function () {
659                     var str, j = i, e;
660 
661                     if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
662                     if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
663 
664                     e && $('~');
665 
666                     if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
667                         return new(tree.Quoted)(str[0], str[1] || str[2], e);
668                     }
669                 },
670 
671                 //
672                 // A catch-all word, such as:
673                 //
674                 //     black border-collapse
675                 //
676                 keyword: function () {
677                     var k;
678 
679                     if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { 
680                         if (tree.colors.hasOwnProperty(k)) {
681                             // detect named color
682                             return new(tree.Color)(tree.colors[k].slice(1));
683                         } else {
684                             return new(tree.Keyword)(k);
685                         }
686                     }
687                 },
688 
689                 //
690                 // A function call
691                 //
692                 //     rgb(255, 0, 255)
693                 //
694                 // We also try to catch IE's `alpha()`, but let the `alpha` parser
695                 // deal with the details.
696                 //
697                 // The arguments are parsed with the `entities.arguments` parser.
698                 //
699                 call: function () {
700                     var name, args, alpha_ret, index = i;
701 
702                     if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
703 
704                     name = name[1].toLowerCase();
705 
706                     if (name === 'url') { return null }
707                     else                { i += name.length }
708 
709                     if (name === 'alpha') {
710                         alpha_ret = $(this.alpha);
711                         if(typeof alpha_ret !== 'undefined') {
712                             return alpha_ret;
713                         }
714                     }
715 
716                     $('('); // Parse the '(' and consume whitespace.
717 
718                     args = $(this.entities.arguments);
719 
720                     if (! $(')')) return;
721 
722                     if (name) { return new(tree.Call)(name, args, index, env.filename) }
723                 },
724                 arguments: function () {
725                     var args = [], arg;
726 
727                     while (arg = $(this.entities.assignment) || $(this.expression)) {
728                         args.push(arg);
729                         if (! $(',')) { break }
730                     }
731                     return args;
732                 },
733                 literal: function () {
734                     return $(this.entities.dimension) ||
735                            $(this.entities.color) ||
736                            $(this.entities.quoted);
737                 },
738 
739                 // Assignments are argument entities for calls.
740                 // They are present in ie filter properties as shown below.
741                 //
742                 //     filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
743                 //
744 
745                 assignment: function () {
746                     var key, value;
747                     if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
748                         return new(tree.Assignment)(key, value);
749                     }
750                 },
751 
752                 //
753                 // Parse url() tokens
754                 //
755                 // We use a specific rule for urls, because they don't really behave like
756                 // standard function calls. The difference is that the argument doesn't have
757                 // to be enclosed within a string, so it can't be parsed as an Expression.
758                 //
759                 url: function () {
760                     var value;
761 
762                     if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
763                     value = $(this.entities.quoted)  || $(this.entities.variable) ||
764                             $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
765 
766                     expect(')');
767 
768                     return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
769                                         ? value : new(tree.Anonymous)(value), imports.paths);
770                 },
771 
772                 dataURI: function () {
773                     var obj;
774 
775                     if ($(/^data:/)) {
776                         obj         = {};
777                         obj.mime    = $(/^[^\/]+\/[^,;)]+/)     || '';
778                         obj.charset = $(/^;\s*charset=[^,;)]+/) || '';
779                         obj.base64  = $(/^;\s*base64/)          || '';
780                         obj.data    = $(/^,\s*[^)]+/);
781 
782                         if (obj.data) { return obj }
783                     }
784                 },
785 
786                 //
787                 // A Variable entity, such as `@fink`, in
788                 //
789                 //     width: @fink + 2px
790                 //
791                 // We use a different parser for variable definitions,
792                 // see `parsers.variable`.
793                 //
794                 variable: function () {
795                     var name, index = i;
796 
797                     if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
798                         return new(tree.Variable)(name, index, env.filename);
799                     }
800                 },
801 
802                 //
803                 // A Hexadecimal color
804                 //
805                 //     #4F3C2F
806                 //
807                 // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
808                 //
809                 color: function () {
810                     var rgb;
811 
812                     if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
813                         return new(tree.Color)(rgb[1]);
814                     }
815                 },
816 
817                 //
818                 // A Dimension, that is, a number and a unit
819                 //
820                 //     0.5em 95%
821                 //
822                 dimension: function () {
823                     var value, c = input.charCodeAt(i);
824                     if ((c > 57 || c < 45) || c === 47) return;
825 
826                     if (value = $(/^(-?\d*\.?\d+)(px|%|em|rem|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
827                         return new(tree.Dimension)(value[1], value[2]);
828                     }
829                 },
830 
831                 //
832                 // JavaScript code to be evaluated
833                 //
834                 //     `window.location.href`
835                 //
836                 javascript: function () {
837                     var str, j = i, e;
838 
839                     if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
840                     if (input.charAt(j) !== '`') { return }
841 
842                     e && $('~');
843 
844                     if (str = $(/^`([^`]*)`/)) {
845                         return new(tree.JavaScript)(str[1], i, e);
846                     }
847                 }
848             },
849 
850             //
851             // The variable part of a variable definition. Used in the `rule` parser
852             //
853             //     @fink:
854             //
855             variable: function () {
856                 var name;
857 
858                 if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
859             },
860 
861             //
862             // A font size/line-height shorthand
863             //
864             //     small/12px
865             //
866             // We need to peek first, or we'll match on keywords and dimensions
867             //
868             shorthand: function () {
869                 var a, b;
870 
871                 if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
872 
873                 if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
874                     return new(tree.Shorthand)(a, b);
875                 }
876             },
877 
878             //
879             // Mixins
880             //
881             mixin: {
882                 //
883                 // A Mixin call, with an optional argument list
884                 //
885                 //     #mixins > .square(#fff);
886                 //     .rounded(4px, black);
887                 //     .button;
888                 //
889                 // The `while` loop is there because mixins can be
890                 // namespaced, but we only support the child and descendant
891                 // selector for now.
892                 //
893                 call: function () {
894                     var elements = [], e, c, args = [], arg, index = i, s = input.charAt(i), name, value, important = false;
895 
896                     if (s !== '.' && s !== '#') { return }
897 
898                     while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
899                         elements.push(new(tree.Element)(c, e, i));
900                         c = $('>');
901                     }
902                     if ($('(')) {
903                         while (arg = $(this.expression)) {
904                             value = arg;
905                             name = null;
906 
907                             // Variable
908                             if (arg.value.length = 1) {
909                                 var val = arg.value[0];
910                                 if (val instanceof tree.Variable) {
911                                     if ($(':')) {
912                                         if (value = $(this.expression)) {
913                                             name = val.name;
914                                         } else {
915                                             throw new(Error)("Expected value");
916                                         }
917                                     }
918                                 }
919                             }
920 
921                             args.push({ name: name, value: value });
922 
923                             if (! $(',')) { break }
924                         }
925                         if (! $(')')) throw new(Error)("Expected )");
926                     }
927 
928                     if ($(this.important)) {
929                         important = true;
930                     }
931 
932                     if (elements.length > 0 && ($(';') || peek('}'))) {
933                         return new(tree.mixin.Call)(elements, args, index, env.filename, important);
934                     }
935                 },
936 
937                 //
938                 // A Mixin definition, with a list of parameters
939                 //
940                 //     .rounded (@radius: 2px, @color) {
941                 //        ...
942                 //     }
943                 //
944                 // Until we have a finer grained state-machine, we have to
945                 // do a look-ahead, to make sure we don't have a mixin call.
946                 // See the `rule` function for more information.
947                 //
948                 // We start by matching `.rounded (`, and then proceed on to
949                 // the argument list, which has optional default values.
950                 // We store the parameters in `params`, with a `value` key,
951                 // if there is a value, such as in the case of `@radius`.
952                 //
953                 // Once we've got our params list, and a closing `)`, we parse
954                 // the `{...}` block.
955                 //
956                 definition: function () {
957                     var name, params = [], match, ruleset, param, value, cond, variadic = false;
958                     if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
959                         peek(/^[^{]*(;|})/)) return;
960 
961                     save();
962 
963                     if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
964                         name = match[1];
965 
966                         do {
967                             if (input.charAt(i) === '.' && $(/^\.{3}/)) {
968                                 variadic = true;
969                                 break;
970                             } else if (param = $(this.entities.variable) || $(this.entities.literal)
971                                                                          || $(this.entities.keyword)) {
972                                 // Variable
973                                 if (param instanceof tree.Variable) {
974                                     if ($(':')) {
975                                         value = expect(this.expression, 'expected expression');
976                                         params.push({ name: param.name, value: value });
977                                     } else if ($(/^\.{3}/)) {
978                                         params.push({ name: param.name, variadic: true });
979                                         variadic = true;
980                                         break;
981                                     } else {
982                                         params.push({ name: param.name });
983                                     }
984                                 } else {
985                                     params.push({ value: param });
986                                 }
987                             } else {
988                                 break;
989                             }
990                         } while ($(','))
991 
992                         expect(')');
993 
994                         if ($(/^when/)) { // Guard
995                             cond = expect(this.conditions, 'expected condition');
996                         }
997 
998                         ruleset = $(this.block);
999 
1000                         if (ruleset) {
1001                             return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
1002                         } else {
1003                             restore();
1004                         }
1005                     }
1006                 }
1007             },
1008 
1009             //
1010             // Entities are the smallest recognized token,
1011             // and can be found inside a rule's value.
1012             //
1013             entity: function () {
1014                 return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
1015                        $(this.entities.call)    || $(this.entities.keyword)  || $(this.entities.javascript) ||
1016                        $(this.comment);
1017             },
1018 
1019             //
1020             // A Rule terminator. Note that we use `peek()` to check for '}',
1021             // because the `block` rule will be expecting it, but we still need to make sure
1022             // it's there, if ';' was ommitted.
1023             //
1024             end: function () {
1025                 return $(';') || peek('}');
1026             },
1027 
1028             //
1029             // IE's alpha function
1030             //
1031             //     alpha(opacity=88)
1032             //
1033             alpha: function () {
1034                 var value;
1035 
1036                 if (! $(/^\(opacity=/i)) return;
1037                 if (value = $(/^\d+/) || $(this.entities.variable)) {
1038                     expect(')');
1039                     return new(tree.Alpha)(value);
1040                 }
1041             },
1042 
1043             //
1044             // A Selector Element
1045             //
1046             //     div
1047             //     + h1
1048             //     #socks
1049             //     input[type="text"]
1050             //
1051             // Elements are the building blocks for Selectors,
1052             // they are made out of a `Combinator` (see combinator rule),
1053             // and an element name, such as a tag a class, or `*`.
1054             //
1055             element: function () {
1056                 var e, t, c, v;
1057 
1058                 c = $(this.combinator);
1059                 e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
1060                     $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
1061 
1062                 if (! e) {
1063                     $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
1064                 }
1065 
1066                 if (e) { return new(tree.Element)(c, e, i) }
1067 
1068                 if (c.value && c.value.charAt(0) === '&') {
1069                     return new(tree.Element)(c, null, i);
1070                 }
1071             },
1072 
1073             //
1074             // Combinators combine elements together, in a Selector.
1075             //
1076             // Because our parser isn't white-space sensitive, special care
1077             // has to be taken, when parsing the descendant combinator, ` `,
1078             // as it's an empty space. We have to check the previous character
1079             // in the input, to see if it's a ` ` character. More info on how
1080             // we deal with this in *combinator.js*.
1081             //
1082             combinator: function () {
1083                 var match, c = input.charAt(i);
1084 
1085                 if (c === '>' || c === '+' || c === '~') {
1086                     i++;
1087                     while (input.charAt(i) === ' ') { i++ }
1088                     return new(tree.Combinator)(c);
1089                 } else if (c === '&') {
1090                     match = '&';
1091                     i++;
1092                     if(input.charAt(i) === ' ') {
1093                         match = '& ';
1094                     }
1095                     while (input.charAt(i) === ' ') { i++ }
1096                     return new(tree.Combinator)(match);
1097                 } else if (input.charAt(i - 1) === ' ') {
1098                     return new(tree.Combinator)(" ");
1099                 } else {
1100                     return new(tree.Combinator)(null);
1101                 }
1102             },
1103 
1104             //
1105             // A CSS Selector
1106             //
1107             //     .class > div + h1
1108             //     li a:hover
1109             //
1110             // Selectors are made out of one or more Elements, see above.
1111             //
1112             selector: function () {
1113                 var sel, e, elements = [], c, match;
1114 
1115                 if ($('(')) {
1116                     sel = $(this.entity);
1117                     expect(')');
1118                     return new(tree.Selector)([new(tree.Element)('', sel, i)]);
1119                 }
1120 
1121                 while (e = $(this.element)) {
1122                     c = input.charAt(i);
1123                     elements.push(e)
1124                     if (c === '{' || c === '}' || c === ';' || c === ',') { break }
1125                 }
1126 
1127                 if (elements.length > 0) { return new(tree.Selector)(elements) }
1128             },
1129             tag: function () {
1130                 return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
1131             },
1132             attribute: function () {
1133                 var attr = '', key, val, op;
1134 
1135                 if (! $('[')) return;
1136 
1137                 if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) {
1138                     if ((op = $(/^[|~*$^]?=/)) &&
1139                         (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
1140                         attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
1141                     } else { attr = key }
1142                 }
1143 
1144                 if (! $(']')) return;
1145 
1146                 if (attr) { return "[" + attr + "]" }
1147             },
1148 
1149             //
1150             // The `block` rule is used by `ruleset` and `mixin.definition`.
1151             // It's a wrapper around the `primary` rule, with added `{}`.
1152             //
1153             block: function () {
1154                 var content;
1155 
1156                 if ($('{') && (content = $(this.primary)) && $('}')) {
1157                     return content;
1158                 }
1159             },
1160 
1161             //
1162             // div, .class, body > p {...}
1163             //
1164             ruleset: function () {
1165                 var selectors = [], s, rules, match;
1166                 save();
1167 
1168                 while (s = $(this.selector)) {
1169                     selectors.push(s);
1170                     $(this.comment);
1171                     if (! $(',')) { break }
1172                     $(this.comment);
1173                 }
1174 
1175                 if (selectors.length > 0 && (rules = $(this.block))) {
1176                     return new(tree.Ruleset)(selectors, rules, env.strictImports);
1177                 } else {
1178                     // Backtrack
1179                     furthest = i;
1180                     restore();
1181                 }
1182             },
1183             rule: function () {
1184                 var name, value, c = input.charAt(i), important, match;
1185                 save();
1186 
1187                 if (c === '.' || c === '#' || c === '&') { return }
1188 
1189                 if (name = $(this.variable) || $(this.property)) {
1190                     if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) {
1191                         i += match[0].length - 1;
1192                         value = new(tree.Anonymous)(match[1]);
1193                     } else if (name === "font") {
1194                         value = $(this.font);
1195                     } else {
1196                         value = $(this.value);
1197                     }
1198                     important = $(this.important);
1199 
1200                     if (value && $(this.end)) {
1201                         return new(tree.Rule)(name, value, important, memo);
1202                     } else {
1203                         furthest = i;
1204                         restore();
1205                     }
1206                 }
1207             },
1208 
1209             //
1210             // An @import directive
1211             //
1212             //     @import "lib";
1213             //
1214             // Depending on our environemnt, importing is done differently:
1215             // In the browser, it's an XHR request, in Node, it would be a
1216             // file-system operation. The function used for importing is
1217             // stored in `import`, which we pass to the Import constructor.
1218             //
1219             "import": function () {
1220                 var path, features, index = i;
1221                 var dir = $(/^@import(?:-(once))?\s+/);
1222 
1223                 if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
1224                     features = $(this.mediaFeatures);
1225                     if ($(';')) {
1226                         return new(tree.Import)(path, imports, features, (dir[1] === 'once'), index);
1227                     }
1228                 }
1229             },
1230 
1231             mediaFeature: function () {
1232                 var e, p, nodes = [];
1233 
1234                 do {
1235                     if (e = $(this.entities.keyword)) {
1236                         nodes.push(e);
1237                     } else if ($('(')) {
1238                         p = $(this.property);
1239                         e = $(this.entity);
1240                         if ($(')')) {
1241                             if (p && e) {
1242                                 nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
1243                             } else if (e) {
1244                                 nodes.push(new(tree.Paren)(e));
1245                             } else {
1246                                 return null;
1247                             }
1248                         } else { return null }
1249                     }
1250                 } while (e);
1251 
1252                 if (nodes.length > 0) {
1253                     return new(tree.Expression)(nodes);
1254                 }
1255             },
1256 
1257             mediaFeatures: function () {
1258                 var e, features = [];
1259                 
1260                 do {
1261                   if (e = $(this.mediaFeature)) {
1262                       features.push(e);
1263                       if (! $(',')) { break }
1264                   } else if (e = $(this.entities.variable)) {
1265                       features.push(e);
1266                       if (! $(',')) { break }
1267                   }
1268                 } while (e);
1269                 
1270                 return features.length > 0 ? features : null;
1271             },
1272 
1273             media: function () {
1274                 var features, rules;
1275 
1276                 if ($(/^@media/)) {
1277                     features = $(this.mediaFeatures);
1278 
1279                     if (rules = $(this.block)) {
1280                         return new(tree.Media)(rules, features);
1281                     }
1282                 }
1283             },
1284 
1285             //
1286             // A CSS Directive
1287             //
1288             //     @charset "utf-8";
1289             //
1290             directive: function () {
1291                 var name, value, rules, types, e, nodes;
1292 
1293                 if (input.charAt(i) !== '@') return;
1294 
1295                 if (value = $(this['import']) || $(this.media)) {
1296                     return value;
1297                 } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
1298                     types = ($(/^[^{]+/) || '').trim();
1299                     if (rules = $(this.block)) {
1300                         return new(tree.Directive)(name + " " + types, rules);
1301                     }
1302                 } else if (name = $(/^@[-a-z]+/)) {
1303                     if (name === '@font-face') {
1304                         if (rules = $(this.block)) {
1305                             return new(tree.Directive)(name, rules);
1306                         }
1307                     } else if ((value = $(this.entity)) && $(';')) {
1308                         return new(tree.Directive)(name, value);
1309                     }
1310                 }
1311             },
1312             font: function () {
1313                 var value = [], expression = [], weight, shorthand, font, e;
1314 
1315                 while (e = $(this.shorthand) || $(this.entity)) {
1316                     expression.push(e);
1317                 }
1318                 value.push(new(tree.Expression)(expression));
1319 
1320                 if ($(',')) {
1321                     while (e = $(this.expression)) {
1322                         value.push(e);
1323                         if (! $(',')) { break }
1324                     }
1325                 }
1326                 return new(tree.Value)(value);
1327             },
1328 
1329             //
1330             // A Value is a comma-delimited list of Expressions
1331             //
1332             //     font-family: Baskerville, Georgia, serif;
1333             //
1334             // In a Rule, a Value represents everything after the `:`,
1335             // and before the `;`.
1336             //
1337             value: function () {
1338                 var e, expressions = [], important;
1339 
1340                 while (e = $(this.expression)) {
1341                     expressions.push(e);
1342                     if (! $(',')) { break }
1343                 }
1344 
1345                 if (expressions.length > 0) {
1346                     return new(tree.Value)(expressions);
1347                 }
1348             },
1349             important: function () {
1350                 if (input.charAt(i) === '!') {
1351                     return $(/^! *important/);
1352                 }
1353             },
1354             sub: function () {
1355                 var e;
1356 
1357                 if ($('(') && (e = $(this.expression)) && $(')')) {
1358                     return e;
1359                 }
1360             },
1361             multiplication: function () {
1362                 var m, a, op, operation;
1363                 if (m = $(this.operand)) {
1364                     while (!peek(/^\/\*/) && (op = ($('/') || $('*'))) && (a = $(this.operand))) {
1365                         operation = new(tree.Operation)(op, [operation || m, a]);
1366                     }
1367                     return operation || m;
1368                 }
1369             },
1370             addition: function () {
1371                 var m, a, op, operation;
1372                 if (m = $(this.multiplication)) {
1373                     while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
1374                            (a = $(this.multiplication))) {
1375                         operation = new(tree.Operation)(op, [operation || m, a]);
1376                     }
1377                     return operation || m;
1378                 }
1379             },
1380             conditions: function () {
1381                 var a, b, index = i, condition;
1382 
1383                 if (a = $(this.condition)) {
1384                     while ($(',') && (b = $(this.condition))) {
1385                         condition = new(tree.Condition)('or', condition || a, b, index);
1386                     }
1387                     return condition || a;
1388                 }
1389             },
1390             condition: function () {
1391                 var a, b, c, op, index = i, negate = false;
1392 
1393                 if ($(/^not/)) { negate = true }
1394                 expect('(');
1395                 if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
1396                     if (op = $(/^(?:>=|=<|[<=>])/)) {
1397                         if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
1398                             c = new(tree.Condition)(op, a, b, index, negate);
1399                         } else {
1400                             error('expected expression');
1401                         }
1402                     } else {
1403                         c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
1404                     }
1405                     expect(')');
1406                     return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
1407                 }
1408             },
1409 
1410             //
1411             // An operand is anything that can be part of an operation,
1412             // such as a Color, or a Variable
1413             //
1414             operand: function () {
1415                 var negate, p = input.charAt(i + 1);
1416 
1417                 if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
1418                 var o = $(this.sub) || $(this.entities.dimension) ||
1419                         $(this.entities.color) || $(this.entities.variable) ||
1420                         $(this.entities.call);
1421                 return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o])
1422                               : o;
1423             },
1424 
1425             //
1426             // Expressions either represent mathematical operations,
1427             // or white-space delimited Entities.
1428             //
1429             //     1px solid black
1430             //     @var * 2
1431             //
1432             expression: function () {
1433                 var e, delim, entities = [], d;
1434 
1435                 while (e = $(this.addition) || $(this.entity)) {
1436                     entities.push(e);
1437                 }
1438                 if (entities.length > 0) {
1439                     return new(tree.Expression)(entities);
1440                 }
1441             },
1442             property: function () {
1443                 var name;
1444 
1445                 if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
1446                     return name[1];
1447                 }
1448             }
1449         }
1450     };
1451 };
1452 
1453 if (less.mode === 'browser' || less.mode === 'rhino') {
1454     //
1455     // Used by `@import` directives
1456     //
1457     less.Parser.importer = function (path, paths, callback, env) {
1458         if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) {
1459             path = paths[0] + path;
1460         }
1461         // We pass `true` as 3rd argument, to force the reload of the import.
1462         // This is so we can get the syntax tree as opposed to just the CSS output,
1463         // as we need this to evaluate the current stylesheet.
1464         loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) {
1465             if (e && typeof(env.errback) === "function") {
1466                 env.errback.call(null, path, paths, callback, env);
1467             } else {
1468                 callback.apply(null, arguments);
1469             }
1470         }, true);
1471     };
1472 }
1473 
1474 (function (tree) {
1475 
1476 tree.functions = {
1477     rgb: function (r, g, b) {
1478         return this.rgba(r, g, b, 1.0);
1479     },
1480     rgba: function (r, g, b, a) {
1481         var rgb = [r, g, b].map(function (c) { return number(c) }),
1482             a = number(a);
1483         return new(tree.Color)(rgb, a);
1484     },
1485     hsl: function (h, s, l) {
1486         return this.hsla(h, s, l, 1.0);
1487     },
1488     hsla: function (h, s, l, a) {
1489         h = (number(h) % 360) / 360;
1490         s = number(s); l = number(l); a = number(a);
1491 
1492         var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1493         var m1 = l * 2 - m2;
1494 
1495         return this.rgba(hue(h + 1/3) * 255,
1496                          hue(h)       * 255,
1497                          hue(h - 1/3) * 255,
1498                          a);
1499 
1500         function hue(h) {
1501             h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1502             if      (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
1503             else if (h * 2 < 1) return m2;
1504             else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
1505             else                return m1;
1506         }
1507     },
1508     hue: function (color) {
1509         return new(tree.Dimension)(Math.round(color.toHSL().h));
1510     },
1511     saturation: function (color) {
1512         return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
1513     },
1514     lightness: function (color) {
1515         return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
1516     },
1517     alpha: function (color) {
1518         return new(tree.Dimension)(color.toHSL().a);
1519     },
1520     saturate: function (color, amount) {
1521         var hsl = color.toHSL();
1522 
1523         hsl.s += amount.value / 100;
1524         hsl.s = clamp(hsl.s);
1525         return hsla(hsl);
1526     },
1527     desaturate: function (color, amount) {
1528         var hsl = color.toHSL();
1529 
1530         hsl.s -= amount.value / 100;
1531         hsl.s = clamp(hsl.s);
1532         return hsla(hsl);
1533     },
1534     lighten: function (color, amount) {
1535         var hsl = color.toHSL();
1536 
1537         hsl.l += amount.value / 100;
1538         hsl.l = clamp(hsl.l);
1539         return hsla(hsl);
1540     },
1541     darken: function (color, amount) {
1542         var hsl = color.toHSL();
1543 
1544         hsl.l -= amount.value / 100;
1545         hsl.l = clamp(hsl.l);
1546         return hsla(hsl);
1547     },
1548     fadein: function (color, amount) {
1549         var hsl = color.toHSL();
1550 
1551         hsl.a += amount.value / 100;
1552         hsl.a = clamp(hsl.a);
1553         return hsla(hsl);
1554     },
1555     fadeout: function (color, amount) {
1556         var hsl = color.toHSL();
1557 
1558         hsl.a -= amount.value / 100;
1559         hsl.a = clamp(hsl.a);
1560         return hsla(hsl);
1561     },
1562     fade: function (color, amount) {
1563         var hsl = color.toHSL();
1564 
1565         hsl.a = amount.value / 100;
1566         hsl.a = clamp(hsl.a);
1567         return hsla(hsl);
1568     },
1569     spin: function (color, amount) {
1570         var hsl = color.toHSL();
1571         var hue = (hsl.h + amount.value) % 360;
1572 
1573         hsl.h = hue < 0 ? 360 + hue : hue;
1574 
1575         return hsla(hsl);
1576     },
1577     //
1578     // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
1579     // http://sass-lang.com
1580     //
1581     mix: function (color1, color2, weight) {
1582         var p = weight.value / 100.0;
1583         var w = p * 2 - 1;
1584         var a = color1.toHSL().a - color2.toHSL().a;
1585 
1586         var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1587         var w2 = 1 - w1;
1588 
1589         var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1590                    color1.rgb[1] * w1 + color2.rgb[1] * w2,
1591                    color1.rgb[2] * w1 + color2.rgb[2] * w2];
1592 
1593         var alpha = color1.alpha * p + color2.alpha * (1 - p);
1594 
1595         return new(tree.Color)(rgb, alpha);
1596     },
1597     greyscale: function (color) {
1598         return this.desaturate(color, new(tree.Dimension)(100));
1599     },
1600     e: function (str) {
1601         return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
1602     },
1603     escape: function (str) {
1604         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"));
1605     },
1606     '%': function (quoted /* arg, arg, ...*/) {
1607         var args = Array.prototype.slice.call(arguments, 1),
1608             str = quoted.value;
1609 
1610         for (var i = 0; i < args.length; i++) {
1611             str = str.replace(/%[sda]/i, function(token) {
1612                 var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
1613                 return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
1614             });
1615         }
1616         str = str.replace(/%%/g, '%');
1617         return new(tree.Quoted)('"' + str + '"', str);
1618     },
1619     round: function (n) {
1620         return this._math('round', n);
1621     },
1622     ceil: function (n) {
1623         return this._math('ceil', n);
1624     },
1625     floor: function (n) {
1626         return this._math('floor', n);
1627     },
1628     _math: function (fn, n) {
1629         if (n instanceof tree.Dimension) {
1630             return new(tree.Dimension)(Math[fn](number(n)), n.unit);
1631         } else if (typeof(n) === 'number') {
1632             return Math[fn](n);
1633         } else {
1634             throw { type: "Argument", message: "argument must be a number" };
1635         }
1636     },
1637     argb: function (color) {
1638         return new(tree.Anonymous)(color.toARGB());
1639 
1640     },
1641     percentage: function (n) {
1642         return new(tree.Dimension)(n.value * 100, '%');
1643     },
1644     color: function (n) {
1645         if (n instanceof tree.Quoted) {
1646             return new(tree.Color)(n.value.slice(1));
1647         } else {
1648             throw { type: "Argument", message: "argument must be a string" };
1649         }
1650     },
1651     iscolor: function (n) {
1652         return this._isa(n, tree.Color);
1653     },
1654     isnumber: function (n) {
1655         return this._isa(n, tree.Dimension);
1656     },
1657     isstring: function (n) {
1658         return this._isa(n, tree.Quoted);
1659     },
1660     iskeyword: function (n) {
1661         return this._isa(n, tree.Keyword);
1662     },
1663     isurl: function (n) {
1664         return this._isa(n, tree.URL);
1665     },
1666     ispixel: function (n) {
1667         return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False;
1668     },
1669     ispercentage: function (n) {
1670         return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False;
1671     },
1672     isem: function (n) {
1673         return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False;
1674     },
1675     _isa: function (n, Type) {
1676         return (n instanceof Type) ? tree.True : tree.False;
1677     }
1678 };
1679 
1680 function hsla(hsla) {
1681     return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
1682 }
1683 
1684 function number(n) {
1685     if (n instanceof tree.Dimension) {
1686         return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
1687     } else if (typeof(n) === 'number') {
1688         return n;
1689     } else {
1690         throw {
1691             error: "RuntimeError",
1692             message: "color functions take numbers as parameters"
1693         };
1694     }
1695 }
1696 
1697 function clamp(val) {
1698     return Math.min(1, Math.max(0, val));
1699 }
1700 
1701 })(require('./tree'));
1702 (function (tree) {
1703 
1704 tree.Alpha = function (val) {
1705     this.value = val;
1706 };
1707 tree.Alpha.prototype = {
1708     toCSS: function () {
1709         return "alpha(opacity=" +
1710                (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
1711     },
1712     eval: function (env) {
1713         if (this.value.eval) { this.value = this.value.eval(env) }
1714         return this;
1715     }
1716 };
1717 
1718 })(require('../tree'));
1719 (function (tree) {
1720 
1721 tree.Anonymous = function (string) {
1722     this.value = string.value || string;
1723 };
1724 tree.Anonymous.prototype = {
1725     toCSS: function () {
1726         return this.value;
1727     },
1728     eval: function () { return this }
1729 };
1730 
1731 })(require('../tree'));
1732 (function (tree) {
1733 
1734 tree.Assignment = function (key, val) {
1735     this.key = key;
1736     this.value = val;
1737 };
1738 tree.Assignment.prototype = {
1739     toCSS: function () {
1740         return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
1741     },
1742     eval: function (env) {
1743         if (this.value.eval) { this.value = this.value.eval(env) }
1744         return this;
1745     }
1746 };
1747 
1748 })(require('../tree'));(function (tree) {
1749 
1750 //
1751 // A function call node.
1752 //
1753 tree.Call = function (name, args, index, filename) {
1754     this.name = name;
1755     this.args = args;
1756     this.index = index;
1757     this.filename = filename;
1758 };
1759 tree.Call.prototype = {
1760     //
1761     // When evaluating a function call,
1762     // we either find the function in `tree.functions` [1],
1763     // in which case we call it, passing the  evaluated arguments,
1764     // or we simply print it out as it appeared originally [2].
1765     //
1766     // The *functions.js* file contains the built-in functions.
1767     //
1768     // The reason why we evaluate the arguments, is in the case where
1769     // we try to pass a variable to a function, like: `saturate(@color)`.
1770     // The function should receive the value, not the variable.
1771     //
1772     eval: function (env) {
1773         var args = this.args.map(function (a) { return a.eval(env) });
1774 
1775         if (this.name in tree.functions) { // 1.
1776             try {
1777                 return tree.functions[this.name].apply(tree.functions, args);
1778             } catch (e) {
1779                 throw { type: e.type || "Runtime",
1780                         message: "error evaluating function `" + this.name + "`" +
1781                                  (e.message ? ': ' + e.message : ''),
1782                         index: this.index, filename: this.filename };
1783             }
1784         } else { // 2.
1785             return new(tree.Anonymous)(this.name +
1786                    "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
1787         }
1788     },
1789 
1790     toCSS: function (env) {
1791         return this.eval(env).toCSS();
1792     }
1793 };
1794 
1795 })(require('../tree'));
1796 (function (tree) {
1797 //
1798 // RGB Colors - #ff0014, #eee
1799 //
1800 tree.Color = function (rgb, a) {
1801     //
1802     // The end goal here, is to parse the arguments
1803     // into an integer triplet, such as `128, 255, 0`
1804     //
1805     // This facilitates operations and conversions.
1806     //
1807     if (Array.isArray(rgb)) {
1808         this.rgb = rgb;
1809     } else if (rgb.length == 6) {
1810         this.rgb = rgb.match(/.{2}/g).map(function (c) {
1811             return parseInt(c, 16);
1812         });
1813     } else {
1814         this.rgb = rgb.split('').map(function (c) {
1815             return parseInt(c + c, 16);
1816         });
1817     }
1818     this.alpha = typeof(a) === 'number' ? a : 1;
1819 };
1820 tree.Color.prototype = {
1821     eval: function () { return this },
1822 
1823     //
1824     // If we have some transparency, the only way to represent it
1825     // is via `rgba`. Otherwise, we use the hex representation,
1826     // which has better compatibility with older browsers.
1827     // Values are capped between `0` and `255`, rounded and zero-padded.
1828     //
1829     toCSS: function () {
1830         if (this.alpha < 1.0) {
1831             return "rgba(" + this.rgb.map(function (c) {
1832                 return Math.round(c);
1833             }).concat(this.alpha).join(', ') + ")";
1834         } else {
1835             return '#' + this.rgb.map(function (i) {
1836                 i = Math.round(i);
1837                 i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1838                 return i.length === 1 ? '0' + i : i;
1839             }).join('');
1840         }
1841     },
1842 
1843     //
1844     // Operations have to be done per-channel, if not,
1845     // channels will spill onto each other. Once we have
1846     // our result, in the form of an integer triplet,
1847     // we create a new Color node to hold the result.
1848     //
1849     operate: function (op, other) {
1850         var result = [];
1851 
1852         if (! (other instanceof tree.Color)) {
1853             other = other.toColor();
1854         }
1855 
1856         for (var c = 0; c < 3; c++) {
1857             result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
1858         }
1859         return new(tree.Color)(result, this.alpha + other.alpha);
1860     },
1861 
1862     toHSL: function () {
1863         var r = this.rgb[0] / 255,
1864             g = this.rgb[1] / 255,
1865             b = this.rgb[2] / 255,
1866             a = this.alpha;
1867 
1868         var max = Math.max(r, g, b), min = Math.min(r, g, b);
1869         var h, s, l = (max + min) / 2, d = max - min;
1870 
1871         if (max === min) {
1872             h = s = 0;
1873         } else {
1874             s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1875 
1876             switch (max) {
1877                 case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1878                 case g: h = (b - r) / d + 2;               break;
1879                 case b: h = (r - g) / d + 4;               break;
1880             }
1881             h /= 6;
1882         }
1883         return { h: h * 360, s: s, l: l, a: a };
1884     },
1885     toARGB: function () {
1886         var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
1887         return '#' + argb.map(function (i) {
1888             i = Math.round(i);
1889             i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1890             return i.length === 1 ? '0' + i : i;
1891         }).join('');
1892     }
1893 };
1894 
1895 
1896 })(require('../tree'));
1897 (function (tree) {
1898 
1899 tree.Comment = function (value, silent) {
1900     this.value = value;
1901     this.silent = !!silent;
1902 };
1903 tree.Comment.prototype = {
1904     toCSS: function (env) {
1905         return env.compress ? '' : this.value;
1906     },
1907     eval: function () { return this }
1908 };
1909 
1910 })(require('../tree'));
1911 (function (tree) {
1912 
1913 tree.Condition = function (op, l, r, i, negate) {
1914     this.op = op.trim();
1915     this.lvalue = l;
1916     this.rvalue = r;
1917     this.index = i;
1918     this.negate = negate;
1919 };
1920 tree.Condition.prototype.eval = function (env) {
1921     var a = this.lvalue.eval(env),
1922         b = this.rvalue.eval(env);
1923 
1924     var i = this.index, result;
1925 
1926     var result = (function (op) {
1927         switch (op) {
1928             case 'and':
1929                 return a && b;
1930             case 'or':
1931                 return a || b;
1932             default:
1933                 if (a.compare) {
1934                     result = a.compare(b);
1935                 } else if (b.compare) {
1936                     result = b.compare(a);
1937                 } else {
1938                     throw { type: "Type",
1939                             message: "Unable to perform comparison",
1940                             index: i };
1941                 }
1942                 switch (result) {
1943                     case -1: return op === '<' || op === '=<';
1944                     case  0: return op === '=' || op === '>=' || op === '=<';
1945                     case  1: return op === '>' || op === '>=';
1946                 }
1947         }
1948     })(this.op);
1949     return this.negate ? !result : result;
1950 };
1951 
1952 })(require('../tree'));
1953 (function (tree) {
1954 
1955 //
1956 // A number with a unit
1957 //
1958 tree.Dimension = function (value, unit) {
1959     this.value = parseFloat(value);
1960     this.unit = unit || null;
1961 };
1962 
1963 tree.Dimension.prototype = {
1964     eval: function () { return this },
1965     toColor: function () {
1966         return new(tree.Color)([this.value, this.value, this.value]);
1967     },
1968     toCSS: function () {
1969         var css = this.value + this.unit;
1970         return css;
1971     },
1972 
1973     // In an operation between two Dimensions,
1974     // we default to the first Dimension's unit,
1975     // so `1px + 2em` will yield `3px`.
1976     // In the future, we could implement some unit
1977     // conversions such that `100cm + 10mm` would yield
1978     // `101cm`.
1979     operate: function (op, other) {
1980         return new(tree.Dimension)
1981                   (tree.operate(op, this.value, other.value),
1982                   this.unit || other.unit);
1983     },
1984 
1985     // TODO: Perform unit conversion before comparing
1986     compare: function (other) {
1987         if (other instanceof tree.Dimension) {
1988             if (other.value > this.value) {
1989                 return -1;
1990             } else if (other.value < this.value) {
1991                 return 1;
1992             } else {
1993                 return 0;
1994             }
1995         } else {
1996             return -1;
1997         }
1998     }
1999 };
2000 
2001 })(require('../tree'));
2002 (function (tree) {
2003 
2004 tree.Directive = function (name, value, features) {
2005     this.name = name;
2006 
2007     if (Array.isArray(value)) {
2008         this.ruleset = new(tree.Ruleset)([], value);
2009         this.ruleset.allowImports = true;
2010     } else {
2011         this.value = value;
2012     }
2013 };
2014 tree.Directive.prototype = {
2015     toCSS: function (ctx, env) {
2016         if (this.ruleset) {
2017             this.ruleset.root = true;
2018             return this.name + (env.compress ? '{' : ' {\n  ') +
2019                    this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n  ') +
2020                                (env.compress ? '}': '\n}\n');
2021         } else {
2022             return this.name + ' ' + this.value.toCSS() + ';\n';
2023         }
2024     },
2025     eval: function (env) {
2026         env.frames.unshift(this);
2027         this.ruleset = this.ruleset && this.ruleset.eval(env);
2028         env.frames.shift();
2029         return this;
2030     },
2031     variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
2032     find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
2033     rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
2034 };
2035 
2036 })(require('../tree'));
2037 (function (tree) {
2038 
2039 tree.Element = function (combinator, value, index) {
2040     this.combinator = combinator instanceof tree.Combinator ?
2041                       combinator : new(tree.Combinator)(combinator);
2042 
2043     if (typeof(value) === 'string') {
2044         this.value = value.trim();
2045     } else if (value) {
2046         this.value = value;
2047     } else {
2048         this.value = "";
2049     }
2050     this.index = index;
2051 };
2052 tree.Element.prototype.eval = function (env) {
2053     return new(tree.Element)(this.combinator,
2054                              this.value.eval ? this.value.eval(env) : this.value,
2055                              this.index);
2056 };
2057 tree.Element.prototype.toCSS = function (env) {
2058 	var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
2059 	if (value == '' && this.combinator.value.charAt(0) == '&') {
2060 		return '';
2061 	} else {
2062 		return this.combinator.toCSS(env || {}) + value;
2063 	}
2064 };
2065 
2066 tree.Combinator = function (value) {
2067     if (value === ' ') {
2068         this.value = ' ';
2069     } else if (value === '& ') {
2070         this.value = '& ';
2071     } else {
2072         this.value = value ? value.trim() : "";
2073     }
2074 };
2075 tree.Combinator.prototype.toCSS = function (env) {
2076     return {
2077         ''  : '',
2078         ' ' : ' ',
2079         '&' : '',
2080         '& ' : ' ',
2081         ':' : ' :',
2082         '+' : env.compress ? '+' : ' + ',
2083         '~' : env.compress ? '~' : ' ~ ',
2084         '>' : env.compress ? '>' : ' > '
2085     }[this.value];
2086 };
2087 
2088 })(require('../tree'));
2089 (function (tree) {
2090 
2091 tree.Expression = function (value) { this.value = value };
2092 tree.Expression.prototype = {
2093     eval: function (env) {
2094         if (this.value.length > 1) {
2095             return new(tree.Expression)(this.value.map(function (e) {
2096                 return e.eval(env);
2097             }));
2098         } else if (this.value.length === 1) {
2099             return this.value[0].eval(env);
2100         } else {
2101             return this;
2102         }
2103     },
2104     toCSS: function (env) {
2105         return this.value.map(function (e) {
2106             return e.toCSS ? e.toCSS(env) : '';
2107         }).join(' ');
2108     }
2109 };
2110 
2111 })(require('../tree'));
2112 (function (tree) {
2113 //
2114 // CSS @import node
2115 //
2116 // The general strategy here is that we don't want to wait
2117 // for the parsing to be completed, before we start importing
2118 // the file. That's because in the context of a browser,
2119 // most of the time will be spent waiting for the server to respond.
2120 //
2121 // On creation, we push the import path to our import queue, though
2122 // `import,push`, we also pass it a callback, which it'll call once
2123 // the file has been fetched, and parsed.
2124 //
2125 tree.Import = function (path, imports, features, once, index) {
2126     var that = this;
2127 
2128     this.once = once;
2129     this.index = index;
2130     this._path = path;
2131     this.features = features && new(tree.Value)(features);
2132 
2133     // The '.less' extension is optional
2134     if (path instanceof tree.Quoted) {
2135         this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
2136     } else {
2137         this.path = path.value.value || path.value;
2138     }
2139 
2140     this.css = /css(\?.*)?$/.test(this.path);
2141 
2142     // Only pre-compile .less files
2143     if (! this.css) {
2144         imports.push(this.path, function (e, root, imported) {
2145             if (e) { e.index = index }
2146             if (imported && that.once) that.skip = imported;
2147             that.root = root || new(tree.Ruleset)([], []);
2148         });
2149     }
2150 };
2151 
2152 //
2153 // The actual import node doesn't return anything, when converted to CSS.
2154 // The reason is that it's used at the evaluation stage, so that the rules
2155 // it imports can be treated like any other rules.
2156 //
2157 // In `eval`, we make sure all Import nodes get evaluated, recursively, so
2158 // we end up with a flat structure, which can easily be imported in the parent
2159 // ruleset.
2160 //
2161 tree.Import.prototype = {
2162     toCSS: function (env) {
2163         var features = this.features ? ' ' + this.features.toCSS(env) : '';
2164 
2165         if (this.css) {
2166             return "@import " + this._path.toCSS() + features + ';\n';
2167         } else {
2168             return "";
2169         }
2170     },
2171     eval: function (env) {
2172         var ruleset, features = this.features && this.features.eval(env);
2173 
2174         if (this.skip) return [];
2175 
2176         if (this.css) {
2177             return this;
2178         } else {
2179             ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
2180 
2181             for (var i = 0; i < ruleset.rules.length; i++) {
2182                 if (ruleset.rules[i] instanceof tree.Import) {
2183                     Array.prototype
2184                          .splice
2185                          .apply(ruleset.rules,
2186                                 [i, 1].concat(ruleset.rules[i].eval(env)));
2187                 }
2188             }
2189             return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
2190         }
2191     }
2192 };
2193 
2194 })(require('../tree'));
2195 (function (tree) {
2196 
2197 tree.JavaScript = function (string, index, escaped) {
2198     this.escaped = escaped;
2199     this.expression = string;
2200     this.index = index;
2201 };
2202 tree.JavaScript.prototype = {
2203     eval: function (env) {
2204         var result,
2205             that = this,
2206             context = {};
2207 
2208         var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
2209             return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
2210         });
2211 
2212         try {
2213             expression = new(Function)('return (' + expression + ')');
2214         } catch (e) {
2215             throw { message: "JavaScript evaluation error: `" + expression + "`" ,
2216                     index: this.index };
2217         }
2218 
2219         for (var k in env.frames[0].variables()) {
2220             context[k.slice(1)] = {
2221                 value: env.frames[0].variables()[k].value,
2222                 toJS: function () {
2223                     return this.value.eval(env).toCSS();
2224                 }
2225             };
2226         }
2227 
2228         try {
2229             result = expression.call(context);
2230         } catch (e) {
2231             throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
2232                     index: this.index };
2233         }
2234         if (typeof(result) === 'string') {
2235             return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
2236         } else if (Array.isArray(result)) {
2237             return new(tree.Anonymous)(result.join(', '));
2238         } else {
2239             return new(tree.Anonymous)(result);
2240         }
2241     }
2242 };
2243 
2244 })(require('../tree'));
2245 
2246 (function (tree) {
2247 
2248 tree.Keyword = function (value) { this.value = value };
2249 tree.Keyword.prototype = {
2250     eval: function () { return this },
2251     toCSS: function () { return this.value },
2252     compare: function (other) {
2253         if (other instanceof tree.Keyword) {
2254             return other.value === this.value ? 0 : 1;
2255         } else {
2256             return -1;
2257         }
2258     }
2259 };
2260 
2261 tree.True = new(tree.Keyword)('true');
2262 tree.False = new(tree.Keyword)('false');
2263 
2264 })(require('../tree'));
2265 (function (tree) {
2266 
2267 tree.Media = function (value, features) {
2268     var el = new(tree.Element)('&', null, 0),
2269         selectors = [new(tree.Selector)([el])];
2270 
2271     this.features = new(tree.Value)(features);
2272     this.ruleset = new(tree.Ruleset)(selectors, value);
2273     this.ruleset.allowImports = true;
2274 };
2275 tree.Media.prototype = {
2276     toCSS: function (ctx, env) {
2277         var features = this.features.toCSS(env);
2278 
2279         this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
2280         return '@media ' + features + (env.compress ? '{' : ' {\n  ') +
2281                this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n  ') +
2282                            (env.compress ? '}': '\n}\n');
2283     },
2284     eval: function (env) {
2285         if (!env.mediaBlocks) {
2286             env.mediaBlocks = [];
2287             env.mediaPath = [];
2288         }
2289         
2290         var blockIndex = env.mediaBlocks.length;
2291         env.mediaPath.push(this);
2292         env.mediaBlocks.push(this);
2293 
2294         var media = new(tree.Media)([], []);
2295         media.features = this.features.eval(env);
2296         
2297         env.frames.unshift(this.ruleset);
2298         media.ruleset = this.ruleset.eval(env);
2299         env.frames.shift();
2300         
2301         env.mediaBlocks[blockIndex] = media;
2302         env.mediaPath.pop();
2303 
2304         return env.mediaPath.length === 0 ? media.evalTop(env) :
2305                     media.evalNested(env)
2306     },
2307     variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
2308     find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
2309     rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
2310 
2311     evalTop: function (env) {
2312         var result = this;
2313 
2314         // Render all dependent Media blocks.
2315         if (env.mediaBlocks.length > 1) {
2316             var el = new(tree.Element)('&', null, 0);
2317             var selectors = [new(tree.Selector)([el])];
2318             result = new(tree.Ruleset)(selectors, env.mediaBlocks);
2319             result.multiMedia = true;
2320         }
2321 
2322         delete env.mediaBlocks;
2323         delete env.mediaPath;
2324 
2325         return result;
2326     },
2327     evalNested: function (env) {
2328         var i, value,
2329             path = env.mediaPath.concat([this]);
2330 
2331         // Extract the media-query conditions separated with `,` (OR).
2332         for (i = 0; i < path.length; i++) {
2333             value = path[i].features instanceof tree.Value ?
2334                         path[i].features.value : path[i].features;
2335             path[i] = Array.isArray(value) ? value : [value];
2336         }
2337 
2338         // Trace all permutations to generate the resulting media-query.
2339         //
2340         // (a, b and c) with nested (d, e) ->
2341         //    a and d
2342         //    a and e
2343         //    b and c and d
2344         //    b and c and e
2345         this.features = new(tree.Value)(this.permute(path).map(function (path) {
2346             path = path.map(function (fragment) {
2347                 return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
2348             });
2349 
2350             for(i = path.length - 1; i > 0; i--) {
2351                 path.splice(i, 0, new(tree.Anonymous)("and"));
2352             }
2353 
2354             return new(tree.Expression)(path);
2355         }));
2356 
2357         // Fake a tree-node that doesn't output anything.
2358         return new(tree.Ruleset)([], []);
2359     },
2360     permute: function (arr) {
2361       if (arr.length === 0) {
2362           return [];
2363       } else if (arr.length === 1) {
2364           return arr[0];
2365       } else {
2366           var result = [];
2367           var rest = this.permute(arr.slice(1));
2368           for (var i = 0; i < rest.length; i++) {
2369               for (var j = 0; j < arr[0].length; j++) {
2370                   result.push([arr[0][j]].concat(rest[i]));
2371               }
2372           }
2373           return result;
2374       }
2375     }
2376 };
2377 
2378 })(require('../tree'));
2379 (function (tree) {
2380 
2381 tree.mixin = {};
2382 tree.mixin.Call = function (elements, args, index, filename, important) {
2383     this.selector = new(tree.Selector)(elements);
2384     this.arguments = args;
2385     this.index = index;
2386     this.filename = filename;
2387     this.important = important;
2388 };
2389 tree.mixin.Call.prototype = {
2390     eval: function (env) {
2391         var mixins, args, rules = [], match = false;
2392 
2393         for (var i = 0; i < env.frames.length; i++) {
2394             if ((mixins = env.frames[i].find(this.selector)).length > 0) {
2395                 args = this.arguments && this.arguments.map(function (a) {
2396                     return { name: a.name, value: a.value.eval(env) };
2397                 });
2398                 for (var m = 0; m < mixins.length; m++) {
2399                     if (mixins[m].match(args, env)) {
2400                         try {
2401                             Array.prototype.push.apply(
2402                                   rules, mixins[m].eval(env, this.arguments, this.important).rules);
2403                             match = true;
2404                         } catch (e) {
2405                             throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
2406                         }
2407                     }
2408                 }
2409                 if (match) {
2410                     return rules;
2411                 } else {
2412                     throw { type:    'Runtime',
2413                             message: 'No matching definition was found for `' +
2414                                       this.selector.toCSS().trim() + '('      +
2415                                       this.arguments.map(function (a) {
2416                                           return a.toCSS();
2417                                       }).join(', ') + ")`",
2418                             index:   this.index, filename: this.filename };
2419                 }
2420             }
2421         }
2422         throw { type: 'Name',
2423                 message: this.selector.toCSS().trim() + " is undefined",
2424                 index: this.index, filename: this.filename };
2425     }
2426 };
2427 
2428 tree.mixin.Definition = function (name, params, rules, condition, variadic) {
2429     this.name = name;
2430     this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
2431     this.params = params;
2432     this.condition = condition;
2433     this.variadic = variadic;
2434     this.arity = params.length;
2435     this.rules = rules;
2436     this._lookups = {};
2437     this.required = params.reduce(function (count, p) {
2438         if (!p.name || (p.name && !p.value)) { return count + 1 }
2439         else                                 { return count }
2440     }, 0);
2441     this.parent = tree.Ruleset.prototype;
2442     this.frames = [];
2443 };
2444 tree.mixin.Definition.prototype = {
2445     toCSS:     function ()     { return "" },
2446     variable:  function (name) { return this.parent.variable.call(this, name) },
2447     variables: function ()     { return this.parent.variables.call(this) },
2448     find:      function ()     { return this.parent.find.apply(this, arguments) },
2449     rulesets:  function ()     { return this.parent.rulesets.apply(this) },
2450 
2451     evalParams: function (env, args) {
2452         var frame = new(tree.Ruleset)(null, []), varargs, arg;
2453 
2454         for (var i = 0, val, name; i < this.params.length; i++) {
2455             arg = args && args[i]
2456 
2457             if (arg && arg.name) {
2458                 frame.rules.unshift(new(tree.Rule)(arg.name, arg.value.eval(env)));
2459                 args.splice(i, 1);
2460                 i--;
2461                 continue;
2462             }
2463 			
2464             if (name = this.params[i].name) {
2465                 if (this.params[i].variadic && args) {
2466                     varargs = [];
2467                     for (var j = i; j < args.length; j++) {
2468                         varargs.push(args[j].eval(env));
2469                     }
2470                     frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
2471                 } else if (val = (arg && arg.value) || this.params[i].value) {
2472                     frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
2473                 } else {
2474                     throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
2475                             ' (' + args.length + ' for ' + this.arity + ')' };
2476                 }
2477             }
2478         }
2479         return frame;
2480     },
2481     eval: function (env, args, important) {
2482         var frame = this.evalParams(env, args), context, _arguments = [], rules, start;
2483 
2484         for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
2485             _arguments.push((args[i] && args[i].value) || this.params[i].value);
2486         }
2487         frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
2488 
2489         rules = important ?
2490             this.rules.map(function (r) {
2491                 return new(tree.Rule)(r.name, r.value, '!important', r.index);
2492             }) : this.rules.slice(0);
2493 
2494         return new(tree.Ruleset)(null, rules).eval({
2495             frames: [this, frame].concat(this.frames, env.frames)
2496         });
2497     },
2498     match: function (args, env) {
2499         var argsLength = (args && args.length) || 0, len, frame;
2500 
2501         if (! this.variadic) {
2502             if (argsLength < this.required)                               { return false }
2503             if (argsLength > this.params.length)                          { return false }
2504             if ((this.required > 0) && (argsLength > this.params.length)) { return false }
2505         }
2506 
2507         if (this.condition && !this.condition.eval({
2508             frames: [this.evalParams(env, args)].concat(env.frames)
2509         }))                                                           { return false }
2510 
2511         len = Math.min(argsLength, this.arity);
2512 
2513         for (var i = 0; i < len; i++) {
2514             if (!this.params[i].name) {
2515                 if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
2516                     return false;
2517                 }
2518             }
2519         }
2520         return true;
2521     }
2522 };
2523 
2524 })(require('../tree'));
2525 (function (tree) {
2526 
2527 tree.Operation = function (op, operands) {
2528     this.op = op.trim();
2529     this.operands = operands;
2530 };
2531 tree.Operation.prototype.eval = function (env) {
2532     var a = this.operands[0].eval(env),
2533         b = this.operands[1].eval(env),
2534         temp;
2535 
2536     if (a instanceof tree.Dimension && b instanceof tree.Color) {
2537         if (this.op === '*' || this.op === '+') {
2538             temp = b, b = a, a = temp;
2539         } else {
2540             throw { name: "OperationError",
2541                     message: "Can't substract or divide a color from a number" };
2542         }
2543     }
2544     return a.operate(this.op, b);
2545 };
2546 
2547 tree.operate = function (op, a, b) {
2548     switch (op) {
2549         case '+': return a + b;
2550         case '-': return a - b;
2551         case '*': return a * b;
2552         case '/': return a / b;
2553     }
2554 };
2555 
2556 })(require('../tree'));
2557 
2558 (function (tree) {
2559 
2560 tree.Paren = function (node) {
2561     this.value = node;
2562 };
2563 tree.Paren.prototype = {
2564     toCSS: function (env) {
2565         return '(' + this.value.toCSS(env) + ')';
2566     },
2567     eval: function (env) {
2568         return new(tree.Paren)(this.value.eval(env));
2569     }
2570 };
2571 
2572 })(require('../tree'));
2573 (function (tree) {
2574 
2575 tree.Quoted = function (str, content, escaped, i) {
2576     this.escaped = escaped;
2577     this.value = content || '';
2578     this.quote = str.charAt(0);
2579     this.index = i;
2580 };
2581 tree.Quoted.prototype = {
2582     toCSS: function () {
2583         if (this.escaped) {
2584             return this.value;
2585         } else {
2586             return this.quote + this.value + this.quote;
2587         }
2588     },
2589     eval: function (env) {
2590         var that = this;
2591         var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
2592             return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
2593         }).replace(/@\{([\w-]+)\}/g, function (_, name) {
2594             var v = new(tree.Variable)('@' + name, that.index).eval(env);
2595             return ('value' in v) ? v.value : v.toCSS();
2596         });
2597         return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
2598     }
2599 };
2600 
2601 })(require('../tree'));
2602 (function (tree) {
2603 
2604 tree.Rule = function (name, value, important, index, inline) {
2605     this.name = name;
2606     this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
2607     this.important = important ? ' ' + important.trim() : '';
2608     this.index = index;
2609     this.inline = inline || false;
2610 
2611     if (name.charAt(0) === '@') {
2612         this.variable = true;
2613     } else { this.variable = false }
2614 };
2615 tree.Rule.prototype.toCSS = function (env) {
2616     if (this.variable) { return "" }
2617     else {
2618         return this.name + (env.compress ? ':' : ': ') +
2619                this.value.toCSS(env) +
2620                this.important + (this.inline ? "" : ";");
2621     }
2622 };
2623 
2624 tree.Rule.prototype.eval = function (context) {
2625     return new(tree.Rule)(this.name,
2626                           this.value.eval(context),
2627                           this.important,
2628                           this.index, this.inline);
2629 };
2630 
2631 tree.Shorthand = function (a, b) {
2632     this.a = a;
2633     this.b = b;
2634 };
2635 
2636 tree.Shorthand.prototype = {
2637     toCSS: function (env) {
2638         return this.a.toCSS(env) + "/" + this.b.toCSS(env);
2639     },
2640     eval: function () { return this }
2641 };
2642 
2643 })(require('../tree'));
2644 (function (tree) {
2645 
2646 tree.Ruleset = function (selectors, rules, strictImports) {
2647     this.selectors = selectors;
2648     this.rules = rules;
2649     this._lookups = {};
2650     this.strictImports = strictImports;
2651 };
2652 tree.Ruleset.prototype = {
2653     eval: function (env) {
2654         var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
2655         var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
2656 
2657         ruleset.root = this.root;
2658         ruleset.allowImports = this.allowImports;
2659 
2660         // push the current ruleset to the frames stack
2661         env.frames.unshift(ruleset);
2662 
2663         // Evaluate imports
2664         if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
2665             for (var i = 0; i < ruleset.rules.length; i++) {
2666                 if (ruleset.rules[i] instanceof tree.Import) {
2667                     Array.prototype.splice
2668                          .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2669                 }
2670             }
2671         }
2672 
2673         // Store the frames around mixin definitions,
2674         // so they can be evaluated like closures when the time comes.
2675         for (var i = 0; i < ruleset.rules.length; i++) {
2676             if (ruleset.rules[i] instanceof tree.mixin.Definition) {
2677                 ruleset.rules[i].frames = env.frames.slice(0);
2678             }
2679         }
2680 
2681         // Evaluate mixin calls.
2682         for (var i = 0; i < ruleset.rules.length; i++) {
2683             if (ruleset.rules[i] instanceof tree.mixin.Call) {
2684                 Array.prototype.splice
2685                      .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2686             }
2687         }
2688 
2689         // Evaluate everything else
2690         for (var i = 0, rule; i < ruleset.rules.length; i++) {
2691             rule = ruleset.rules[i];
2692 
2693             if (! (rule instanceof tree.mixin.Definition)) {
2694                 ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
2695             }
2696         }
2697 
2698         // Pop the stack
2699         env.frames.shift();
2700 
2701         return ruleset;
2702     },
2703     match: function (args) {
2704         return !args || args.length === 0;
2705     },
2706     variables: function () {
2707         if (this._variables) { return this._variables }
2708         else {
2709             return this._variables = this.rules.reduce(function (hash, r) {
2710                 if (r instanceof tree.Rule && r.variable === true) {
2711                     hash[r.name] = r;
2712                 }
2713                 return hash;
2714             }, {});
2715         }
2716     },
2717     variable: function (name) {
2718         return this.variables()[name];
2719     },
2720     rulesets: function () {
2721         if (this._rulesets) { return this._rulesets }
2722         else {
2723             return this._rulesets = this.rules.filter(function (r) {
2724                 return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
2725             });
2726         }
2727     },
2728     find: function (selector, self) {
2729         self = self || this;
2730         var rules = [], rule, match,
2731             key = selector.toCSS();
2732 
2733         if (key in this._lookups) { return this._lookups[key] }
2734 
2735         this.rulesets().forEach(function (rule) {
2736             if (rule !== self) {
2737                 for (var j = 0; j < rule.selectors.length; j++) {
2738                     if (match = selector.match(rule.selectors[j])) {
2739                         if (selector.elements.length > rule.selectors[j].elements.length) {
2740                             Array.prototype.push.apply(rules, rule.find(
2741                                 new(tree.Selector)(selector.elements.slice(1)), self));
2742                         } else {
2743                             rules.push(rule);
2744                         }
2745                         break;
2746                     }
2747                 }
2748             }
2749         });
2750         return this._lookups[key] = rules;
2751     },
2752     //
2753     // Entry point for code generation
2754     //
2755     //     `context` holds an array of arrays.
2756     //
2757     toCSS: function (context, env) {
2758         var css = [],      // The CSS output
2759             rules = [],    // node.Rule instances
2760            _rules = [],    //
2761             rulesets = [], // node.Ruleset instances
2762             paths = [],    // Current selectors
2763             selector,      // The fully rendered selector
2764             rule;
2765 
2766         if (! this.root) {
2767             if (context.length === 0) {
2768                 paths = this.selectors.map(function (s) { return [s] });
2769             } else {
2770                 this.joinSelectors(paths, context, this.selectors);
2771             }
2772         }
2773 
2774         // Compile rules and rulesets
2775         for (var i = 0; i < this.rules.length; i++) {
2776             rule = this.rules[i];
2777 
2778             if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) {
2779                 rulesets.push(rule.toCSS(paths, env));
2780             } else if (rule instanceof tree.Comment) {
2781                 if (!rule.silent) {
2782                     if (this.root) {
2783                         rulesets.push(rule.toCSS(env));
2784                     } else {
2785                         rules.push(rule.toCSS(env));
2786                     }
2787                 }
2788             } else {
2789                 if (rule.toCSS && !rule.variable) {
2790                     rules.push(rule.toCSS(env));
2791                 } else if (rule.value && !rule.variable) {
2792                     rules.push(rule.value.toString());
2793                 }
2794             }
2795         } 
2796 
2797         rulesets = rulesets.join('');
2798 
2799         // If this is the root node, we don't render
2800         // a selector, or {}.
2801         // Otherwise, only output if this ruleset has rules.
2802         if (this.root) {
2803             css.push(rules.join(env.compress ? '' : '\n'));
2804         } else {
2805             if (rules.length > 0) {
2806                 selector = paths.map(function (p) {
2807                     return p.map(function (s) {
2808                         return s.toCSS(env);
2809                     }).join('').trim();
2810                 }).join(env.compress ? ',' : ',\n');
2811 
2812                 // Remove duplicates
2813                 for (var i = rules.length - 1; i >= 0; i--) {
2814                     if (_rules.indexOf(rules[i]) === -1) {
2815                         _rules.unshift(rules[i]);
2816                     }
2817                 }
2818                 rules = _rules;
2819 
2820                 css.push(selector,
2821                         (env.compress ? '{' : ' {\n  ') +
2822                         rules.join(env.compress ? '' : '\n  ') +
2823                         (env.compress ? '}' : '\n}\n'));
2824             }
2825         }
2826         css.push(rulesets);
2827 
2828         return css.join('') + (env.compress ? '\n' : '');
2829     },
2830 
2831     joinSelectors: function (paths, context, selectors) {
2832         for (var s = 0; s < selectors.length; s++) {
2833             this.joinSelector(paths, context, selectors[s]);
2834         }
2835     },
2836 
2837     joinSelector: function (paths, context, selector) {
2838         var before = [], after = [], beforeElements = [],
2839             afterElements = [], hasParentSelector = false, el;
2840 
2841         for (var i = 0; i < selector.elements.length; i++) {
2842             el = selector.elements[i];
2843             if (el.combinator.value.charAt(0) === '&') {
2844                 hasParentSelector = true;
2845             }
2846             if (hasParentSelector) afterElements.push(el);
2847             else                   beforeElements.push(el);
2848         }
2849 
2850         if (! hasParentSelector) {
2851             afterElements = beforeElements;
2852             beforeElements = [];
2853         }
2854 
2855         if (beforeElements.length > 0) {
2856             before.push(new(tree.Selector)(beforeElements));
2857         }
2858 
2859         if (afterElements.length > 0) {
2860             after.push(new(tree.Selector)(afterElements));
2861         }
2862 
2863         for (var c = 0; c < context.length; c++) {
2864             paths.push(before.concat(context[c]).concat(after));
2865         }
2866     }
2867 };
2868 })(require('../tree'));
2869 (function (tree) {
2870 
2871 tree.Selector = function (elements) {
2872     this.elements = elements;
2873     if (this.elements[0].combinator.value === "") {
2874         this.elements[0].combinator.value = ' ';
2875     }
2876 };
2877 tree.Selector.prototype.match = function (other) {
2878     var len  = this.elements.length,
2879         olen = other.elements.length,
2880         max  = Math.min(len, olen);
2881 
2882     if (len < olen) {
2883         return false;
2884     } else {
2885         for (var i = 0; i < max; i++) {
2886             if (this.elements[i].value !== other.elements[i].value) {
2887                 return false;
2888             }
2889         }
2890     }
2891     return true;
2892 };
2893 tree.Selector.prototype.eval = function (env) {
2894     return new(tree.Selector)(this.elements.map(function (e) {
2895         return e.eval(env);
2896     }));
2897 };
2898 tree.Selector.prototype.toCSS = function (env) {
2899     if (this._css) { return this._css }
2900 
2901     return this._css = this.elements.map(function (e) {
2902         if (typeof(e) === 'string') {
2903             return ' ' + e.trim();
2904         } else {
2905             return e.toCSS(env);
2906         }
2907     }).join('');
2908 };
2909 
2910 })(require('../tree'));
2911 (function (tree) {
2912 
2913 tree.URL = function (val, paths) {
2914     if (val.data) {
2915         this.attrs = val;
2916     } else {
2917         // Add the base path if the URL is relative and we are in the browser
2918         if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
2919             val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
2920         }
2921         this.value = val;
2922         this.paths = paths;
2923     }
2924 };
2925 tree.URL.prototype = {
2926     toCSS: function () {
2927         return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data
2928                                     : this.value.toCSS()) + ")";
2929     },
2930     eval: function (ctx) {
2931         return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths);
2932     }
2933 };
2934 
2935 })(require('../tree'));
2936 (function (tree) {
2937 
2938 tree.Value = function (value) {
2939     this.value = value;
2940     this.is = 'value';
2941 };
2942 tree.Value.prototype = {
2943     eval: function (env) {
2944         if (this.value.length === 1) {
2945             return this.value[0].eval(env);
2946         } else {
2947             return new(tree.Value)(this.value.map(function (v) {
2948                 return v.eval(env);
2949             }));
2950         }
2951     },
2952     toCSS: function (env) {
2953         return this.value.map(function (e) {
2954             return e.toCSS(env);
2955         }).join(env.compress ? ',' : ', ');
2956     }
2957 };
2958 
2959 })(require('../tree'));
2960 (function (tree) {
2961 
2962 tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file };
2963 tree.Variable.prototype = {
2964     eval: function (env) {
2965         var variable, v, name = this.name;
2966 
2967         if (name.indexOf('@@') == 0) {
2968             name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
2969         }
2970 
2971         if (variable = tree.find(env.frames, function (frame) {
2972             if (v = frame.variable(name)) {
2973                 return v.value.eval(env);
2974             }
2975         })) { return variable }
2976         else {
2977             throw { type: 'Name',
2978                     message: "variable " + name + " is undefined",
2979                     filename: this.file,
2980                     index: this.index };
2981         }
2982     }
2983 };
2984 
2985 })(require('../tree'));
2986 (function (tree) {
2987 
2988 tree.find = function (obj, fun) {
2989     for (var i = 0, r; i < obj.length; i++) {
2990         if (r = fun.call(obj, obj[i])) { return r }
2991     }
2992     return null;
2993 };
2994 tree.jsify = function (obj) {
2995     if (Array.isArray(obj.value) && (obj.value.length > 1)) {
2996         return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
2997     } else {
2998         return obj.toCSS(false);
2999     }
3000 };
3001 
3002 })(require('./tree'));
3003 (function (tree) {
3004     tree.colors = {
3005         'aliceblue':'#f0f8ff',
3006         'antiquewhite':'#faebd7',
3007         'aqua':'#00ffff',
3008         'aquamarine':'#7fffd4',
3009         'azure':'#f0ffff',
3010         'beige':'#f5f5dc',
3011         'bisque':'#ffe4c4',
3012         'black':'#000000',
3013         'blanchedalmond':'#ffebcd',
3014         'blue':'#0000ff',
3015         'blueviolet':'#8a2be2',
3016         'brown':'#a52a2a',
3017         'burlywood':'#deb887',
3018         'cadetblue':'#5f9ea0',
3019         'chartreuse':'#7fff00',
3020         'chocolate':'#d2691e',
3021         'coral':'#ff7f50',
3022         'cornflowerblue':'#6495ed',
3023         'cornsilk':'#fff8dc',
3024         'crimson':'#dc143c',
3025         'cyan':'#00ffff',
3026         'darkblue':'#00008b',
3027         'darkcyan':'#008b8b',
3028         'darkgoldenrod':'#b8860b',
3029         'darkgray':'#a9a9a9',
3030         'darkgrey':'#a9a9a9',
3031         'darkgreen':'#006400',
3032         'darkkhaki':'#bdb76b',
3033         'darkmagenta':'#8b008b',
3034         'darkolivegreen':'#556b2f',
3035         'darkorange':'#ff8c00',
3036         'darkorchid':'#9932cc',
3037         'darkred':'#8b0000',
3038         'darksalmon':'#e9967a',
3039         'darkseagreen':'#8fbc8f',
3040         'darkslateblue':'#483d8b',
3041         'darkslategray':'#2f4f4f',
3042         'darkslategrey':'#2f4f4f',
3043         'darkturquoise':'#00ced1',
3044         'darkviolet':'#9400d3',
3045         'deeppink':'#ff1493',
3046         'deepskyblue':'#00bfff',
3047         'dimgray':'#696969',
3048         'dimgrey':'#696969',
3049         'dodgerblue':'#1e90ff',
3050         'firebrick':'#b22222',
3051         'floralwhite':'#fffaf0',
3052         'forestgreen':'#228b22',
3053         'fuchsia':'#ff00ff',
3054         'gainsboro':'#dcdcdc',
3055         'ghostwhite':'#f8f8ff',
3056         'gold':'#ffd700',
3057         'goldenrod':'#daa520',
3058         'gray':'#808080',
3059         'grey':'#808080',
3060         'green':'#008000',
3061         'greenyellow':'#adff2f',
3062         'honeydew':'#f0fff0',
3063         'hotpink':'#ff69b4',
3064         'indianred':'#cd5c5c',
3065         'indigo':'#4b0082',
3066         'ivory':'#fffff0',
3067         'khaki':'#f0e68c',
3068         'lavender':'#e6e6fa',
3069         'lavenderblush':'#fff0f5',
3070         'lawngreen':'#7cfc00',
3071         'lemonchiffon':'#fffacd',
3072         'lightblue':'#add8e6',
3073         'lightcoral':'#f08080',
3074         'lightcyan':'#e0ffff',
3075         'lightgoldenrodyellow':'#fafad2',
3076         'lightgray':'#d3d3d3',
3077         'lightgrey':'#d3d3d3',
3078         'lightgreen':'#90ee90',
3079         'lightpink':'#ffb6c1',
3080         'lightsalmon':'#ffa07a',
3081         'lightseagreen':'#20b2aa',
3082         'lightskyblue':'#87cefa',
3083         'lightslategray':'#778899',
3084         'lightslategrey':'#778899',
3085         'lightsteelblue':'#b0c4de',
3086         'lightyellow':'#ffffe0',
3087         'lime':'#00ff00',
3088         'limegreen':'#32cd32',
3089         'linen':'#faf0e6',
3090         'magenta':'#ff00ff',
3091         'maroon':'#800000',
3092         'mediumaquamarine':'#66cdaa',
3093         'mediumblue':'#0000cd',
3094         'mediumorchid':'#ba55d3',
3095         'mediumpurple':'#9370d8',
3096         'mediumseagreen':'#3cb371',
3097         'mediumslateblue':'#7b68ee',
3098         'mediumspringgreen':'#00fa9a',
3099         'mediumturquoise':'#48d1cc',
3100         'mediumvioletred':'#c71585',
3101         'midnightblue':'#191970',
3102         'mintcream':'#f5fffa',
3103         'mistyrose':'#ffe4e1',
3104         'moccasin':'#ffe4b5',
3105         'navajowhite':'#ffdead',
3106         'navy':'#000080',
3107         'oldlace':'#fdf5e6',
3108         'olive':'#808000',
3109         'olivedrab':'#6b8e23',
3110         'orange':'#ffa500',
3111         'orangered':'#ff4500',
3112         'orchid':'#da70d6',
3113         'palegoldenrod':'#eee8aa',
3114         'palegreen':'#98fb98',
3115         'paleturquoise':'#afeeee',
3116         'palevioletred':'#d87093',
3117         'papayawhip':'#ffefd5',
3118         'peachpuff':'#ffdab9',
3119         'peru':'#cd853f',
3120         'pink':'#ffc0cb',
3121         'plum':'#dda0dd',
3122         'powderblue':'#b0e0e6',
3123         'purple':'#800080',
3124         'red':'#ff0000',
3125         'rosybrown':'#bc8f8f',
3126         'royalblue':'#4169e1',
3127         'saddlebrown':'#8b4513',
3128         'salmon':'#fa8072',
3129         'sandybrown':'#f4a460',
3130         'seagreen':'#2e8b57',
3131         'seashell':'#fff5ee',
3132         'sienna':'#a0522d',
3133         'silver':'#c0c0c0',
3134         'skyblue':'#87ceeb',
3135         'slateblue':'#6a5acd',
3136         'slategray':'#708090',
3137         'slategrey':'#708090',
3138         'snow':'#fffafa',
3139         'springgreen':'#00ff7f',
3140         'steelblue':'#4682b4',
3141         'tan':'#d2b48c',
3142         'teal':'#008080',
3143         'thistle':'#d8bfd8',
3144         'tomato':'#ff6347',
3145         'turquoise':'#40e0d0',
3146         'violet':'#ee82ee',
3147         'wheat':'#f5deb3',
3148         'white':'#ffffff',
3149         'whitesmoke':'#f5f5f5',
3150         'yellow':'#ffff00',
3151         'yellowgreen':'#9acd32'
3152     };
3153 })(require('./tree'));
3154 var name;
3155 
3156 function loadStyleSheet(sheet, callback, reload, remaining) {
3157     var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href;
3158     var input = readFile(sheetName);
3159     var parser = new less.Parser({
3160         paths: [sheet.href.replace(/[\w\.-]+$/, '')]
3161     });
3162     parser.parse(input, function (e, root) {
3163         if (e) {
3164             print("Error: " + e);
3165             quit(1);
3166         }
3167         callback(root, sheet, { local: false, lastModified: 0, remaining: remaining });
3168     });
3169 
3170     // callback({}, sheet, { local: true, remaining: remaining });
3171 }
3172 
3173 function writeFile(filename, content) {
3174     var fstream = new java.io.FileWriter(filename);
3175     var out = new java.io.BufferedWriter(fstream);
3176     out.write(content);
3177     out.close();
3178 }
3179 
3180 // Prevent command line integration with Helma
3181 if (typeof HopObject === 'undefined') {
3182     // Command line integration via Rhino
3183     (function (args) {
3184         name = args[0];
3185         var output = args[1];
3186 
3187         if (!name) {
3188             print('No files present in the fileset; Check your pattern match in build.xml');
3189             quit(1);
3190         }
3191         path = name.split("/");path.pop();path=path.join("/")
3192 
3193         var input = readFile(name);
3194 
3195         if (!input) {
3196             print('lesscss: couldn\'t open file ' + name);
3197             quit(1);
3198         }
3199 
3200         var result;
3201         var parser = new less.Parser();
3202         parser.parse(input, function (e, root) {
3203             if (e) {
3204                 quit(1);
3205             } else {
3206                 result = root.toCSS();
3207                 if (output) {
3208                     writeFile(output, result);
3209                     print("Written to " + output);
3210                 } else {
3211                     print(result);
3212                 }
3213                 quit(0);
3214             }
3215         });
3216         print("done");
3217     }(arguments));
3218 }})();
3219