~george-edison55/less/trunk

« back to all changes in this revision

Viewing changes to dist/less-1.4.0-beta.js

  • Committer: Nathan Osman
  • Date: 2013-04-16 22:43:51 UTC
  • Revision ID: admin@quickmediasolutions.com-20130416224351-5juqujuu4itkwpat
Initial commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * LESS - Leaner CSS v1.4.0
 
3
 * http://lesscss.org
 
4
 *
 
5
 * Copyright (c) 2009-2013, Alexis Sellier
 
6
 * Licensed under the Apache 2.0 License.
 
7
 *
 
8
 * @licence
 
9
 */
 
10
(function (window, undefined) {
 
11
//
 
12
// Stub out `require` in the browser
 
13
//
 
14
function require(arg) {
 
15
    return window.less[arg.split('/')[1]];
 
16
};
 
17
 
 
18
 
 
19
// ecma-5.js
 
20
//
 
21
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
 
22
// -- tlrobinson Tom Robinson
 
23
// dantman Daniel Friesen
 
24
 
 
25
//
 
26
// Array
 
27
//
 
28
if (!Array.isArray) {
 
29
    Array.isArray = function(obj) {
 
30
        return Object.prototype.toString.call(obj) === "[object Array]" ||
 
31
               (obj instanceof Array);
 
32
    };
 
33
}
 
34
if (!Array.prototype.forEach) {
 
35
    Array.prototype.forEach =  function(block, thisObject) {
 
36
        var len = this.length >>> 0;
 
37
        for (var i = 0; i < len; i++) {
 
38
            if (i in this) {
 
39
                block.call(thisObject, this[i], i, this);
 
40
            }
 
41
        }
 
42
    };
 
43
}
 
44
if (!Array.prototype.map) {
 
45
    Array.prototype.map = function(fun /*, thisp*/) {
 
46
        var len = this.length >>> 0;
 
47
        var res = new Array(len);
 
48
        var thisp = arguments[1];
 
49
 
 
50
        for (var i = 0; i < len; i++) {
 
51
            if (i in this) {
 
52
                res[i] = fun.call(thisp, this[i], i, this);
 
53
            }
 
54
        }
 
55
        return res;
 
56
    };
 
57
}
 
58
if (!Array.prototype.filter) {
 
59
    Array.prototype.filter = function (block /*, thisp */) {
 
60
        var values = [];
 
61
        var thisp = arguments[1];
 
62
        for (var i = 0; i < this.length; i++) {
 
63
            if (block.call(thisp, this[i])) {
 
64
                values.push(this[i]);
 
65
            }
 
66
        }
 
67
        return values;
 
68
    };
 
69
}
 
70
if (!Array.prototype.reduce) {
 
71
    Array.prototype.reduce = function(fun /*, initial*/) {
 
72
        var len = this.length >>> 0;
 
73
        var i = 0;
 
74
 
 
75
        // no value to return if no initial value and an empty array
 
76
        if (len === 0 && arguments.length === 1) throw new TypeError();
 
77
 
 
78
        if (arguments.length >= 2) {
 
79
            var rv = arguments[1];
 
80
        } else {
 
81
            do {
 
82
                if (i in this) {
 
83
                    rv = this[i++];
 
84
                    break;
 
85
                }
 
86
                // if array contains no values, no initial value to return
 
87
                if (++i >= len) throw new TypeError();
 
88
            } while (true);
 
89
        }
 
90
        for (; i < len; i++) {
 
91
            if (i in this) {
 
92
                rv = fun.call(null, rv, this[i], i, this);
 
93
            }
 
94
        }
 
95
        return rv;
 
96
    };
 
97
}
 
98
if (!Array.prototype.indexOf) {
 
99
    Array.prototype.indexOf = function (value /*, fromIndex */ ) {
 
100
        var length = this.length;
 
101
        var i = arguments[1] || 0;
 
102
 
 
103
        if (!length)     return -1;
 
104
        if (i >= length) return -1;
 
105
        if (i < 0)       i += length;
 
106
 
 
107
        for (; i < length; i++) {
 
108
            if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
 
109
            if (value === this[i]) return i;
 
110
        }
 
111
        return -1;
 
112
    };
 
113
}
 
114
 
 
115
//
 
116
// Object
 
117
//
 
118
if (!Object.keys) {
 
119
    Object.keys = function (object) {
 
120
        var keys = [];
 
121
        for (var name in object) {
 
122
            if (Object.prototype.hasOwnProperty.call(object, name)) {
 
123
                keys.push(name);
 
124
            }
 
125
        }
 
126
        return keys;
 
127
    };
 
128
}
 
129
 
 
130
//
 
131
// String
 
132
//
 
133
if (!String.prototype.trim) {
 
134
    String.prototype.trim = function () {
 
135
        return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
 
136
    };
 
137
}
 
138
var less, tree, charset;
 
139
 
 
140
if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
 
141
    // Rhino
 
142
    // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
 
143
    if (typeof(window) === 'undefined') { less = {} }
 
144
    else                                { less = window.less = {} }
 
145
    tree = less.tree = {};
 
146
    less.mode = 'rhino';
 
147
} else if (typeof(window) === 'undefined') {
 
148
    // Node.js
 
149
    less = exports,
 
150
    tree = require('./tree');
 
151
    less.mode = 'node';
 
152
} else {
 
153
    // Browser
 
154
    if (typeof(window.less) === 'undefined') { window.less = {} }
 
155
    less = window.less,
 
156
    tree = window.less.tree = {};
 
157
    less.mode = 'browser';
 
158
}
 
159
//
 
160
// less.js - parser
 
161
//
 
162
//    A relatively straight-forward predictive parser.
 
163
//    There is no tokenization/lexing stage, the input is parsed
 
164
//    in one sweep.
 
165
//
 
166
//    To make the parser fast enough to run in the browser, several
 
167
//    optimization had to be made:
 
168
//
 
169
//    - Matching and slicing on a huge input is often cause of slowdowns.
 
170
//      The solution is to chunkify the input into smaller strings.
 
171
//      The chunks are stored in the `chunks` var,
 
172
//      `j` holds the current chunk index, and `current` holds
 
173
//      the index of the current chunk in relation to `input`.
 
174
//      This gives us an almost 4x speed-up.
 
175
//
 
176
//    - In many cases, we don't need to match individual tokens;
 
177
//      for example, if a value doesn't hold any variables, operations
 
178
//      or dynamic references, the parser can effectively 'skip' it,
 
179
//      treating it as a literal.
 
180
//      An example would be '1px solid #000' - which evaluates to itself,
 
181
//      we don't need to know what the individual components are.
 
182
//      The drawback, of course is that you don't get the benefits of
 
183
//      syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
 
184
//      and a smaller speed-up in the code-gen.
 
185
//
 
186
//
 
187
//    Token matching is done with the `$` function, which either takes
 
188
//    a terminal string or regexp, or a non-terminal function to call.
 
189
//    It also takes care of moving all the indices forwards.
 
190
//
 
191
//
 
192
less.Parser = function Parser(env) {
 
193
    var input,       // LeSS input string
 
194
        i,           // current index in `input`
 
195
        j,           // current chunk
 
196
        temp,        // temporarily holds a chunk's state, for backtracking
 
197
        memo,        // temporarily holds `i`, when backtracking
 
198
        furthest,    // furthest index the parser has gone to
 
199
        chunks,      // chunkified input
 
200
        current,     // index of current chunk, in `input`
 
201
        parser;
 
202
 
 
203
    var that = this;
 
204
 
 
205
    // Top parser on an import tree must be sure there is one "env"
 
206
    // which will then be passed around by reference.
 
207
    if (!(env instanceof tree.parseEnv)) {
 
208
        env = new tree.parseEnv(env);
 
209
    }
 
210
 
 
211
    var imports = this.imports = {
 
212
        paths: env.paths || [],  // Search paths, when importing
 
213
        queue: [],               // Files which haven't been imported yet
 
214
        files: env.files,        // Holds the imported parse trees
 
215
        contents: env.contents,  // Holds the imported file contents
 
216
        mime:  env.mime,         // MIME type of .less files
 
217
        error: null,             // Error in parsing/evaluating an import
 
218
        push: function (path, currentFileInfo, callback) {
 
219
            var parserImporter = this;
 
220
            this.queue.push(path);
 
221
 
 
222
            //
 
223
            // Import a file asynchronously
 
224
            //
 
225
            less.Parser.importer(path, currentFileInfo, function (e, root, fullPath) {
 
226
                parserImporter.queue.splice(parserImporter.queue.indexOf(path), 1); // Remove the path from the queue
 
227
 
 
228
                var imported = fullPath in parserImporter.files;
 
229
 
 
230
                parserImporter.files[fullPath] = root;                        // Store the root
 
231
 
 
232
                if (e && !parserImporter.error) { parserImporter.error = e; }
 
233
                
 
234
                callback(e, root, imported);
 
235
            }, env);
 
236
        }
 
237
    };
 
238
 
 
239
    function save()    { temp = chunks[j], memo = i, current = i; }
 
240
    function restore() { chunks[j] = temp, i = memo, current = i; }
 
241
 
 
242
    function sync() {
 
243
        if (i > current) {
 
244
            chunks[j] = chunks[j].slice(i - current);
 
245
            current = i;
 
246
        }
 
247
    }
 
248
    function isWhitespace(c) {
 
249
        // Could change to \s?
 
250
        var code = c.charCodeAt(0);
 
251
        return code === 32 || code === 10 || code === 9;
 
252
    }
 
253
    //
 
254
    // Parse from a token, regexp or string, and move forward if match
 
255
    //
 
256
    function $(tok) {
 
257
        var match, args, length, index, k;
 
258
 
 
259
        //
 
260
        // Non-terminal
 
261
        //
 
262
        if (tok instanceof Function) {
 
263
            return tok.call(parser.parsers);
 
264
        //
 
265
        // Terminal
 
266
        //
 
267
        //     Either match a single character in the input,
 
268
        //     or match a regexp in the current chunk (chunk[j]).
 
269
        //
 
270
        } else if (typeof(tok) === 'string') {
 
271
            match = input.charAt(i) === tok ? tok : null;
 
272
            length = 1;
 
273
            sync ();
 
274
        } else {
 
275
            sync ();
 
276
 
 
277
            if (match = tok.exec(chunks[j])) {
 
278
                length = match[0].length;
 
279
            } else {
 
280
                return null;
 
281
            }
 
282
        }
 
283
 
 
284
        // The match is confirmed, add the match length to `i`,
 
285
        // and consume any extra white-space characters (' ' || '\n')
 
286
        // which come after that. The reason for this is that LeSS's
 
287
        // grammar is mostly white-space insensitive.
 
288
        //
 
289
        if (match) {
 
290
            skipWhitespace(length);
 
291
 
 
292
            if(typeof(match) === 'string') {
 
293
                return match;
 
294
            } else {
 
295
                return match.length === 1 ? match[0] : match;
 
296
            }
 
297
        }
 
298
    }
 
299
 
 
300
    function skipWhitespace(length) {
 
301
        var oldi = i, oldj = j,
 
302
            endIndex = i + chunks[j].length,
 
303
            mem = i += length;
 
304
 
 
305
        while (i < endIndex) {
 
306
            if (! isWhitespace(input.charAt(i))) { break }
 
307
            i++;
 
308
        }
 
309
        chunks[j] = chunks[j].slice(length + (i - mem));
 
310
        current = i;
 
311
 
 
312
        if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
 
313
 
 
314
        return oldi !== i || oldj !== j;
 
315
    }
 
316
 
 
317
    function expect(arg, msg) {
 
318
        var result = $(arg);
 
319
        if (! result) {
 
320
            error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
 
321
                                                   : "unexpected token"));
 
322
        } else {
 
323
            return result;
 
324
        }
 
325
    }
 
326
 
 
327
    function error(msg, type) {
 
328
        var e = new Error(msg);
 
329
        e.index = i;
 
330
        e.type = type || 'Syntax';
 
331
        throw e;
 
332
    }
 
333
 
 
334
    // Same as $(), but don't change the state of the parser,
 
335
    // just return the match.
 
336
    function peek(tok) {
 
337
        if (typeof(tok) === 'string') {
 
338
            return input.charAt(i) === tok;
 
339
        } else {
 
340
            if (tok.test(chunks[j])) {
 
341
                return true;
 
342
            } else {
 
343
                return false;
 
344
            }
 
345
        }
 
346
    }
 
347
 
 
348
    function getInput(e, env) {
 
349
        if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
 
350
            return parser.imports.contents[e.filename];
 
351
        } else {
 
352
            return input;
 
353
        }
 
354
    }
 
355
 
 
356
    function getLocation(index, input) {
 
357
        for (var n = index, column = -1;
 
358
                 n >= 0 && input.charAt(n) !== '\n';
 
359
                 n--) { column++ }
 
360
 
 
361
        return { line:   typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
 
362
                 column: column };
 
363
    }
 
364
 
 
365
    function getDebugInfo(index, inputStream, env) {
 
366
        var filename = env.currentFileInfo.filename;
 
367
        if(less.mode !== 'browser' && less.mode !== 'rhino') {
 
368
            filename = require('path').resolve(filename);
 
369
        }
 
370
 
 
371
        return {
 
372
            lineNumber: getLocation(index, inputStream).line + 1,
 
373
            fileName: filename
 
374
        };
 
375
    }
 
376
 
 
377
    function LessError(e, env) {
 
378
        var input = getInput(e, env),
 
379
            loc = getLocation(e.index, input),
 
380
            line = loc.line,
 
381
            col  = loc.column,
 
382
            lines = input.split('\n');
 
383
 
 
384
        this.type = e.type || 'Syntax';
 
385
        this.message = e.message;
 
386
        this.filename = e.filename || env.currentFileInfo.filename;
 
387
        this.index = e.index;
 
388
        this.line = typeof(line) === 'number' ? line + 1 : null;
 
389
        this.callLine = e.call && (getLocation(e.call, input).line + 1);
 
390
        this.callExtract = lines[getLocation(e.call, input).line];
 
391
        this.stack = e.stack;
 
392
        this.column = col;
 
393
        this.extract = [
 
394
            lines[line - 1],
 
395
            lines[line],
 
396
            lines[line + 1]
 
397
        ];
 
398
    }
 
399
 
 
400
    this.env = env = env || {};
 
401
 
 
402
    // The optimization level dictates the thoroughness of the parser,
 
403
    // the lower the number, the less nodes it will create in the tree.
 
404
    // This could matter for debugging, or if you want to access
 
405
    // the individual nodes in the tree.
 
406
    this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
 
407
 
 
408
    //
 
409
    // The Parser
 
410
    //
 
411
    return parser = {
 
412
 
 
413
        imports: imports,
 
414
        //
 
415
        // Parse an input string into an abstract syntax tree,
 
416
        // call `callback` when done.
 
417
        //
 
418
        parse: function (str, callback) {
 
419
            var root, start, end, zone, line, lines, buff = [], c, error = null;
 
420
 
 
421
            i = j = current = furthest = 0;
 
422
            input = str.replace(/\r\n/g, '\n');
 
423
 
 
424
            // Remove potential UTF Byte Order Mark
 
425
            input = input.replace(/^\uFEFF/, '');
 
426
 
 
427
            // Split the input into chunks.
 
428
            chunks = (function (chunks) {
 
429
                var j = 0,
 
430
                    skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
 
431
                    comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
 
432
                    string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
 
433
                    level = 0,
 
434
                    match,
 
435
                    chunk = chunks[0],
 
436
                    inParam;
 
437
 
 
438
                for (var i = 0, c, cc; i < input.length;) {
 
439
                    skip.lastIndex = i;
 
440
                    if (match = skip.exec(input)) {
 
441
                        if (match.index === i) {
 
442
                            i += match[0].length;
 
443
                            chunk.push(match[0]);
 
444
                        }
 
445
                    }
 
446
                    c = input.charAt(i);
 
447
                    comment.lastIndex = string.lastIndex = i;
 
448
 
 
449
                    if (match = string.exec(input)) {
 
450
                        if (match.index === i) {
 
451
                            i += match[0].length;
 
452
                            chunk.push(match[0]);
 
453
                            continue;
 
454
                        }
 
455
                    }
 
456
 
 
457
                    if (!inParam && c === '/') {
 
458
                        cc = input.charAt(i + 1);
 
459
                        if (cc === '/' || cc === '*') {
 
460
                            if (match = comment.exec(input)) {
 
461
                                if (match.index === i) {
 
462
                                    i += match[0].length;
 
463
                                    chunk.push(match[0]);
 
464
                                    continue;
 
465
                                }
 
466
                            }
 
467
                        }
 
468
                    }
 
469
                    
 
470
                    switch (c) {
 
471
                        case '{': if (! inParam) { level ++;        chunk.push(c);                           break }
 
472
                        case '}': if (! inParam) { level --;        chunk.push(c); chunks[++j] = chunk = []; break }
 
473
                        case '(': if (! inParam) { inParam = true;  chunk.push(c);                           break }
 
474
                        case ')': if (  inParam) { inParam = false; chunk.push(c);                           break }
 
475
                        default:                                    chunk.push(c);
 
476
                    }
 
477
                    
 
478
                    i++;
 
479
                }
 
480
                if (level != 0) {
 
481
                    error = new(LessError)({
 
482
                        index: i-1,
 
483
                        type: 'Parse',
 
484
                        message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
 
485
                        filename: env.currentFileInfo.filename
 
486
                    }, env);
 
487
                }
 
488
 
 
489
                return chunks.map(function (c) { return c.join('') });;
 
490
            })([[]]);
 
491
 
 
492
            if (error) {
 
493
                return callback(new(LessError)(error, env));
 
494
            }
 
495
 
 
496
            // Start with the primary rule.
 
497
            // The whole syntax tree is held under a Ruleset node,
 
498
            // with the `root` property set to true, so no `{}` are
 
499
            // output. The callback is called when the input is parsed.
 
500
            try {
 
501
                root = new(tree.Ruleset)([], $(this.parsers.primary));
 
502
                root.root = true;
 
503
                root.firstRoot = true;
 
504
            } catch (e) {
 
505
                return callback(new(LessError)(e, env));
 
506
            }
 
507
 
 
508
            root.toCSS = (function (evaluate) {
 
509
                var line, lines, column;
 
510
 
 
511
                return function (options, variables) {
 
512
                    options = options || {};
 
513
                    var importError,
 
514
                        evalEnv = new tree.evalEnv(options);
 
515
                        
 
516
                    //
 
517
                    // Allows setting variables with a hash, so:
 
518
                    //
 
519
                    //   `{ color: new(tree.Color)('#f01') }` will become:
 
520
                    //
 
521
                    //   new(tree.Rule)('@color',
 
522
                    //     new(tree.Value)([
 
523
                    //       new(tree.Expression)([
 
524
                    //         new(tree.Color)('#f01')
 
525
                    //       ])
 
526
                    //     ])
 
527
                    //   )
 
528
                    //
 
529
                    if (typeof(variables) === 'object' && !Array.isArray(variables)) {
 
530
                        variables = Object.keys(variables).map(function (k) {
 
531
                            var value = variables[k];
 
532
 
 
533
                            if (! (value instanceof tree.Value)) {
 
534
                                if (! (value instanceof tree.Expression)) {
 
535
                                    value = new(tree.Expression)([value]);
 
536
                                }
 
537
                                value = new(tree.Value)([value]);
 
538
                            }
 
539
                            return new(tree.Rule)('@' + k, value, false, 0);
 
540
                        });
 
541
                        evalEnv.frames = [new(tree.Ruleset)(null, variables)];
 
542
                    }
 
543
 
 
544
                    try {
 
545
                        var evaldRoot = evaluate.call(this, evalEnv);
 
546
 
 
547
                        new(tree.joinSelectorVisitor)()
 
548
                            .run(evaldRoot);
 
549
 
 
550
                        new(tree.processExtendsVisitor)()
 
551
                            .run(evaldRoot);
 
552
 
 
553
                        var css = evaldRoot.toCSS({
 
554
                                compress: options.compress || false,
 
555
                                dumpLineNumbers: env.dumpLineNumbers,
 
556
                                strictUnits: options.strictUnits === false ? false : true});
 
557
                    } catch (e) {
 
558
                        throw new(LessError)(e, env);
 
559
                    }
 
560
 
 
561
                    if (options.yuicompress && less.mode === 'node') {
 
562
                        return require('ycssmin').cssmin(css);
 
563
                    } else if (options.compress) {
 
564
                        return css.replace(/(\s)+/g, "$1");
 
565
                    } else {
 
566
                        return css;
 
567
                    }
 
568
                };
 
569
            })(root.eval);
 
570
 
 
571
            // If `i` is smaller than the `input.length - 1`,
 
572
            // it means the parser wasn't able to parse the whole
 
573
            // string, so we've got a parsing error.
 
574
            //
 
575
            // We try to extract a \n delimited string,
 
576
            // showing the line where the parse error occured.
 
577
            // We split it up into two parts (the part which parsed,
 
578
            // and the part which didn't), so we can color them differently.
 
579
            if (i < input.length - 1) {
 
580
                i = furthest;
 
581
                lines = input.split('\n');
 
582
                line = (input.slice(0, i).match(/\n/g) || "").length + 1;
 
583
 
 
584
                for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
 
585
 
 
586
                error = {
 
587
                    type: "Parse",
 
588
                    message: "Unrecognised input",
 
589
                    index: i,
 
590
                    filename: env.currentFileInfo.filename,
 
591
                    line: line,
 
592
                    column: column,
 
593
                    extract: [
 
594
                        lines[line - 2],
 
595
                        lines[line - 1],
 
596
                        lines[line]
 
597
                    ]
 
598
                };
 
599
            }
 
600
 
 
601
            var finish = function (e) {
 
602
                e = error || e || parser.imports.error;
 
603
 
 
604
                if (e) {
 
605
                    if (!(e instanceof LessError)) {
 
606
                        e = new(LessError)(e, env);
 
607
                    }
 
608
 
 
609
                    callback(e);
 
610
                }
 
611
                else {
 
612
                    callback(null, root);
 
613
                }
 
614
            };
 
615
 
 
616
            if (env.processImports !== false) {
 
617
                new tree.importVisitor(this.imports, finish)
 
618
                    .run(root);
 
619
            } else {
 
620
                finish();
 
621
            }
 
622
        },
 
623
 
 
624
        //
 
625
        // Here in, the parsing rules/functions
 
626
        //
 
627
        // The basic structure of the syntax tree generated is as follows:
 
628
        //
 
629
        //   Ruleset ->  Rule -> Value -> Expression -> Entity
 
630
        //
 
631
        // Here's some LESS code:
 
632
        //
 
633
        //    .class {
 
634
        //      color: #fff;
 
635
        //      border: 1px solid #000;
 
636
        //      width: @w + 4px;
 
637
        //      > .child {...}
 
638
        //    }
 
639
        //
 
640
        // And here's what the parse tree might look like:
 
641
        //
 
642
        //     Ruleset (Selector '.class', [
 
643
        //         Rule ("color",  Value ([Expression [Color #fff]]))
 
644
        //         Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
 
645
        //         Rule ("width",  Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
 
646
        //         Ruleset (Selector [Element '>', '.child'], [...])
 
647
        //     ])
 
648
        //
 
649
        //  In general, most rules will try to parse a token with the `$()` function, and if the return
 
650
        //  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
 
651
        //  first, before parsing, that's when we use `peek()`.
 
652
        //
 
653
        parsers: {
 
654
            //
 
655
            // The `primary` rule is the *entry* and *exit* point of the parser.
 
656
            // The rules here can appear at any level of the parse tree.
 
657
            //
 
658
            // The recursive nature of the grammar is an interplay between the `block`
 
659
            // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
 
660
            // as represented by this simplified grammar:
 
661
            //
 
662
            //     primary  →  (ruleset | rule)+
 
663
            //     ruleset  →  selector+ block
 
664
            //     block    →  '{' primary '}'
 
665
            //
 
666
            // Only at one point is the primary rule not called from the
 
667
            // block rule: at the root level.
 
668
            //
 
669
            primary: function () {
 
670
                var node, root = [];
 
671
 
 
672
                while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule)    ||  $(this.ruleset) ||
 
673
                               $(this.mixin.call)       || $(this.comment) ||  $(this.directive))
 
674
                               || $(/^[\s\n]+/) || $(/^;+/)) {
 
675
                    node && root.push(node);
 
676
                }
 
677
                return root;
 
678
            },
 
679
 
 
680
            // We create a Comment node for CSS comments `/* */`,
 
681
            // but keep the LeSS comments `//` silent, by just skipping
 
682
            // over them.
 
683
            comment: function () {
 
684
                var comment;
 
685
 
 
686
                if (input.charAt(i) !== '/') return;
 
687
 
 
688
                if (input.charAt(i + 1) === '/') {
 
689
                    return new(tree.Comment)($(/^\/\/.*/), true);
 
690
                } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
 
691
                    return new(tree.Comment)(comment);
 
692
                }
 
693
            },
 
694
 
 
695
            //
 
696
            // Entities are tokens which can be found inside an Expression
 
697
            //
 
698
            entities: {
 
699
                //
 
700
                // A string, which supports escaping " and '
 
701
                //
 
702
                //     "milky way" 'he\'s the one!'
 
703
                //
 
704
                quoted: function () {
 
705
                    var str, j = i, e, index = i;
 
706
 
 
707
                    if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
 
708
                    if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
 
709
 
 
710
                    e && $('~');
 
711
 
 
712
                    if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
 
713
                        return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo);
 
714
                    }
 
715
                },
 
716
 
 
717
                //
 
718
                // A catch-all word, such as:
 
719
                //
 
720
                //     black border-collapse
 
721
                //
 
722
                keyword: function () {
 
723
                    var k;
 
724
 
 
725
                    if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
 
726
                        if (tree.colors.hasOwnProperty(k)) {
 
727
                            // detect named color
 
728
                            return new(tree.Color)(tree.colors[k].slice(1));
 
729
                        } else {
 
730
                            return new(tree.Keyword)(k);
 
731
                        }
 
732
                    }
 
733
                },
 
734
 
 
735
                //
 
736
                // A function call
 
737
                //
 
738
                //     rgb(255, 0, 255)
 
739
                //
 
740
                // We also try to catch IE's `alpha()`, but let the `alpha` parser
 
741
                // deal with the details.
 
742
                //
 
743
                // The arguments are parsed with the `entities.arguments` parser.
 
744
                //
 
745
                call: function () {
 
746
                    var name, nameLC, args, alpha_ret, index = i;
 
747
 
 
748
                    if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) return;
 
749
 
 
750
                    name = name[1];
 
751
                    nameLC = name.toLowerCase();
 
752
 
 
753
                    if (nameLC === 'url') { return null }
 
754
                    else                  { i += name.length }
 
755
 
 
756
                    if (nameLC === 'alpha') {
 
757
                        alpha_ret = $(this.alpha);
 
758
                        if(typeof alpha_ret !== 'undefined') {
 
759
                            return alpha_ret;
 
760
                        }
 
761
                    }
 
762
 
 
763
                    $('('); // Parse the '(' and consume whitespace.
 
764
 
 
765
                    args = $(this.entities.arguments);
 
766
 
 
767
                    if (! $(')')) {
 
768
                        return;
 
769
                    }
 
770
 
 
771
                    if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); }
 
772
                },
 
773
                arguments: function () {
 
774
                    var args = [], arg;
 
775
 
 
776
                    while (arg = $(this.entities.assignment) || $(this.expression)) {
 
777
                        args.push(arg);
 
778
                        if (! $(',')) { break }
 
779
                    }
 
780
                    return args;
 
781
                },
 
782
                literal: function () {
 
783
                    return $(this.entities.dimension) ||
 
784
                           $(this.entities.color) ||
 
785
                           $(this.entities.quoted) ||
 
786
                           $(this.entities.unicodeDescriptor);
 
787
                },
 
788
 
 
789
                // Assignments are argument entities for calls.
 
790
                // They are present in ie filter properties as shown below.
 
791
                //
 
792
                //     filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
 
793
                //
 
794
 
 
795
                assignment: function () {
 
796
                    var key, value;
 
797
                    if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
 
798
                        return new(tree.Assignment)(key, value);
 
799
                    }
 
800
                },
 
801
 
 
802
                //
 
803
                // Parse url() tokens
 
804
                //
 
805
                // We use a specific rule for urls, because they don't really behave like
 
806
                // standard function calls. The difference is that the argument doesn't have
 
807
                // to be enclosed within a string, so it can't be parsed as an Expression.
 
808
                //
 
809
                url: function () {
 
810
                    var value;
 
811
 
 
812
                    if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
 
813
                    value = $(this.entities.quoted)  || $(this.entities.variable) ||
 
814
                            $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
 
815
 
 
816
                    expect(')');
 
817
 
 
818
                    return new(tree.URL)((value.value != null || value instanceof tree.Variable)
 
819
                                        ? value : new(tree.Anonymous)(value), env.currentFileInfo);
 
820
                },
 
821
 
 
822
                //
 
823
                // A Variable entity, such as `@fink`, in
 
824
                //
 
825
                //     width: @fink + 2px
 
826
                //
 
827
                // We use a different parser for variable definitions,
 
828
                // see `parsers.variable`.
 
829
                //
 
830
                variable: function () {
 
831
                    var name, index = i;
 
832
 
 
833
                    if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
 
834
                        return new(tree.Variable)(name, index, env.currentFileInfo);
 
835
                    }
 
836
                },
 
837
 
 
838
                // A variable entity useing the protective {} e.g. @{var}
 
839
                variableCurly: function () {
 
840
                    var name, curly, index = i;
 
841
 
 
842
                    if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
 
843
                        return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo);
 
844
                    }
 
845
                },
 
846
 
 
847
                //
 
848
                // A Hexadecimal color
 
849
                //
 
850
                //     #4F3C2F
 
851
                //
 
852
                // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
 
853
                //
 
854
                color: function () {
 
855
                    var rgb;
 
856
 
 
857
                    if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
 
858
                        return new(tree.Color)(rgb[1]);
 
859
                    }
 
860
                },
 
861
 
 
862
                //
 
863
                // A Dimension, that is, a number and a unit
 
864
                //
 
865
                //     0.5em 95%
 
866
                //
 
867
                dimension: function () {
 
868
                    var value, c = input.charCodeAt(i);
 
869
                    //Is the first char of the dimension 0-9, '.', '+' or '-'
 
870
                    if ((c > 57 || c < 43) || c === 47 || c == 44) return;
 
871
 
 
872
                    if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) {
 
873
                        return new(tree.Dimension)(value[1], value[2]);
 
874
                    }
 
875
                },
 
876
 
 
877
                //
 
878
                // A unicode descriptor, as is used in unicode-range
 
879
                //
 
880
                // U+0??  or U+00A1-00A9
 
881
                //
 
882
                unicodeDescriptor: function () {
 
883
                    var ud;
 
884
                    
 
885
                    if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) {
 
886
                        return new(tree.UnicodeDescriptor)(ud[0]);
 
887
                    }
 
888
                },
 
889
 
 
890
                //
 
891
                // JavaScript code to be evaluated
 
892
                //
 
893
                //     `window.location.href`
 
894
                //
 
895
                javascript: function () {
 
896
                    var str, j = i, e;
 
897
 
 
898
                    if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
 
899
                    if (input.charAt(j) !== '`') { return }
 
900
 
 
901
                    e && $('~');
 
902
 
 
903
                    if (str = $(/^`([^`]*)`/)) {
 
904
                        return new(tree.JavaScript)(str[1], i, e);
 
905
                    }
 
906
                }
 
907
            },
 
908
 
 
909
            //
 
910
            // The variable part of a variable definition. Used in the `rule` parser
 
911
            //
 
912
            //     @fink:
 
913
            //
 
914
            variable: function () {
 
915
                var name;
 
916
 
 
917
                if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
 
918
            },
 
919
 
 
920
            //
 
921
            // extend syntax - used to extend selectors
 
922
            //
 
923
            extend: function(isRule) {
 
924
                var elements, e, index = i, option, extendList = [];
 
925
 
 
926
                if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; }
 
927
 
 
928
                do {
 
929
                    option = null;
 
930
                    elements = [];
 
931
                    while (true) {
 
932
                        option = $(/^(all)(?=\s*(\)|,))/);
 
933
                        if (option) { break; }
 
934
                        e = $(this.element);
 
935
                        if (!e) { break; }
 
936
                        elements.push(e);
 
937
                    }
 
938
 
 
939
                    option = option && option[1];
 
940
 
 
941
                    extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index));
 
942
 
 
943
                } while($(","))
 
944
                
 
945
                expect(/^\)/);
 
946
 
 
947
                if (isRule) {
 
948
                    expect(/^;/);
 
949
                }
 
950
 
 
951
                return extendList;
 
952
            },
 
953
 
 
954
            //
 
955
            // extendRule - used in a rule to extend all the parent selectors
 
956
            //
 
957
            extendRule: function() {
 
958
                return this.extend(true);
 
959
            },
 
960
            
 
961
            //
 
962
            // Mixins
 
963
            //
 
964
            mixin: {
 
965
                //
 
966
                // A Mixin call, with an optional argument list
 
967
                //
 
968
                //     #mixins > .square(#fff);
 
969
                //     .rounded(4px, black);
 
970
                //     .button;
 
971
                //
 
972
                // The `while` loop is there because mixins can be
 
973
                // namespaced, but we only support the child and descendant
 
974
                // selector for now.
 
975
                //
 
976
                call: function () {
 
977
                    var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false;
 
978
 
 
979
                    if (s !== '.' && s !== '#') { return }
 
980
 
 
981
                    save(); // stop us absorbing part of an invalid selector
 
982
 
 
983
                    while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
 
984
                        elements.push(new(tree.Element)(c, e, i));
 
985
                        c = $('>');
 
986
                    }
 
987
                    if ($('(')) {
 
988
                        args = this.mixin.args.call(this, true).args;
 
989
                        expect(')');
 
990
                    }
 
991
 
 
992
                    args = args || [];
 
993
 
 
994
                    if ($(this.important)) {
 
995
                        important = true;
 
996
                    }
 
997
 
 
998
                    if (elements.length > 0 && ($(';') || peek('}'))) {
 
999
                        return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
 
1000
                    }
 
1001
 
 
1002
                    restore();
 
1003
                },
 
1004
                args: function (isCall) {
 
1005
                    var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg,
 
1006
                        returner = {args:null, variadic: false};
 
1007
                    while (true) {
 
1008
                        if (isCall) {
 
1009
                            arg = $(this.expression);
 
1010
                        } else {
 
1011
                            $(this.comment);
 
1012
                            if (input.charAt(i) === '.' && $(/^\.{3}/)) {
 
1013
                                returner.variadic = true;
 
1014
                                if ($(";") && !isSemiColonSeperated) {
 
1015
                                    isSemiColonSeperated = true;
 
1016
                                }
 
1017
                                (isSemiColonSeperated ? argsSemiColon : argsComma)
 
1018
                                    .push({ variadic: true });
 
1019
                                break;
 
1020
                            }
 
1021
                            arg = $(this.entities.variable) || $(this.entities.literal)
 
1022
                                || $(this.entities.keyword);
 
1023
                        }
 
1024
 
 
1025
                        if (!arg) {
 
1026
                            break;
 
1027
                        }
 
1028
 
 
1029
                        nameLoop = null;
 
1030
                        if (arg.throwAwayComments) {
 
1031
                            arg.throwAwayComments();
 
1032
                        }
 
1033
                        value = arg;
 
1034
                        var val = null;
 
1035
 
 
1036
                        if (isCall) {
 
1037
                            // Variable
 
1038
                            if (arg.value.length == 1) {
 
1039
                                var val = arg.value[0];
 
1040
                            }
 
1041
                        } else {
 
1042
                            val = arg;
 
1043
                        }
 
1044
 
 
1045
                        if (val && val instanceof tree.Variable) {
 
1046
                            if ($(':')) {
 
1047
                                if (expressions.length > 0) {
 
1048
                                    if (isSemiColonSeperated) {
 
1049
                                        error("Cannot mix ; and , as delimiter types");
 
1050
                                    }
 
1051
                                    expressionContainsNamed = true;
 
1052
                                }
 
1053
                                value = expect(this.expression);
 
1054
                                nameLoop = (name = val.name);
 
1055
                            } else if (!isCall && $(/^\.{3}/)) {
 
1056
                                returner.variadic = true;
 
1057
                                if ($(";") && !isSemiColonSeperated) {
 
1058
                                    isSemiColonSeperated = true;
 
1059
                                }
 
1060
                                (isSemiColonSeperated ? argsSemiColon : argsComma)
 
1061
                                    .push({ name: arg.name, variadic: true });
 
1062
                                break;
 
1063
                            } else if (!isCall) {
 
1064
                                name = nameLoop = val.name;
 
1065
                                value = null;
 
1066
                            }
 
1067
                        }
 
1068
 
 
1069
                        if (value) {
 
1070
                            expressions.push(value);
 
1071
                        }
 
1072
 
 
1073
                        argsComma.push({ name:nameLoop, value:value });
 
1074
 
 
1075
                        if ($(',')) {
 
1076
                            continue;
 
1077
                        }
 
1078
 
 
1079
                        if ($(';') || isSemiColonSeperated) {
 
1080
 
 
1081
                            if (expressionContainsNamed) {
 
1082
                                error("Cannot mix ; and , as delimiter types");
 
1083
                            }
 
1084
 
 
1085
                            isSemiColonSeperated = true;
 
1086
 
 
1087
                            if (expressions.length > 1) {
 
1088
                                value = new (tree.Value)(expressions);
 
1089
                            }
 
1090
                            argsSemiColon.push({ name:name, value:value });
 
1091
 
 
1092
                            name = null;
 
1093
                            expressions = [];
 
1094
                            expressionContainsNamed = false;
 
1095
                        }
 
1096
                    }
 
1097
 
 
1098
                    returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
 
1099
                    return returner;
 
1100
                },
 
1101
                //
 
1102
                // A Mixin definition, with a list of parameters
 
1103
                //
 
1104
                //     .rounded (@radius: 2px, @color) {
 
1105
                //        ...
 
1106
                //     }
 
1107
                //
 
1108
                // Until we have a finer grained state-machine, we have to
 
1109
                // do a look-ahead, to make sure we don't have a mixin call.
 
1110
                // See the `rule` function for more information.
 
1111
                //
 
1112
                // We start by matching `.rounded (`, and then proceed on to
 
1113
                // the argument list, which has optional default values.
 
1114
                // We store the parameters in `params`, with a `value` key,
 
1115
                // if there is a value, such as in the case of `@radius`.
 
1116
                //
 
1117
                // Once we've got our params list, and a closing `)`, we parse
 
1118
                // the `{...}` block.
 
1119
                //
 
1120
                definition: function () {
 
1121
                    var name, params = [], match, ruleset, param, value, cond, variadic = false;
 
1122
                    if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
 
1123
                        peek(/^[^{]*\}/)) return;
 
1124
 
 
1125
                    save();
 
1126
 
 
1127
                    if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
 
1128
                        name = match[1];
 
1129
 
 
1130
                        var argInfo = this.mixin.args.call(this, false);
 
1131
                        params = argInfo.args;
 
1132
                        variadic = argInfo.variadic;
 
1133
 
 
1134
                        // .mixincall("@{a}");
 
1135
                        // looks a bit like a mixin definition.. so we have to be nice and restore
 
1136
                        if (!$(')')) {
 
1137
                            furthest = i;
 
1138
                            restore();
 
1139
                        }
 
1140
                        
 
1141
                        $(this.comment);
 
1142
 
 
1143
                        if ($(/^when/)) { // Guard
 
1144
                            cond = expect(this.conditions, 'expected condition');
 
1145
                        }
 
1146
 
 
1147
                        ruleset = $(this.block);
 
1148
 
 
1149
                        if (ruleset) {
 
1150
                            return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
 
1151
                        } else {
 
1152
                            restore();
 
1153
                        }
 
1154
                    }
 
1155
                }
 
1156
            },
 
1157
 
 
1158
            //
 
1159
            // Entities are the smallest recognized token,
 
1160
            // and can be found inside a rule's value.
 
1161
            //
 
1162
            entity: function () {
 
1163
                return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
 
1164
                       $(this.entities.call)    || $(this.entities.keyword)  ||$(this.entities.javascript) ||
 
1165
                       $(this.comment);
 
1166
            },
 
1167
 
 
1168
            //
 
1169
            // A Rule terminator. Note that we use `peek()` to check for '}',
 
1170
            // because the `block` rule will be expecting it, but we still need to make sure
 
1171
            // it's there, if ';' was ommitted.
 
1172
            //
 
1173
            end: function () {
 
1174
                return $(';') || peek('}');
 
1175
            },
 
1176
 
 
1177
            //
 
1178
            // IE's alpha function
 
1179
            //
 
1180
            //     alpha(opacity=88)
 
1181
            //
 
1182
            alpha: function () {
 
1183
                var value;
 
1184
 
 
1185
                if (! $(/^\(opacity=/i)) return;
 
1186
                if (value = $(/^\d+/) || $(this.entities.variable)) {
 
1187
                    expect(')');
 
1188
                    return new(tree.Alpha)(value);
 
1189
                }
 
1190
            },
 
1191
 
 
1192
            //
 
1193
            // A Selector Element
 
1194
            //
 
1195
            //     div
 
1196
            //     + h1
 
1197
            //     #socks
 
1198
            //     input[type="text"]
 
1199
            //
 
1200
            // Elements are the building blocks for Selectors,
 
1201
            // they are made out of a `Combinator` (see combinator rule),
 
1202
            // and an element name, such as a tag a class, or `*`.
 
1203
            //
 
1204
            element: function () {
 
1205
                var e, t, c, v;
 
1206
 
 
1207
                c = $(this.combinator);
 
1208
 
 
1209
                e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
 
1210
                    $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly);
 
1211
 
 
1212
                if (! e) {
 
1213
                    if ($('(')) {
 
1214
                        if ((v = ($(this.selector))) &&
 
1215
                                $(')')) {
 
1216
                            e = new(tree.Paren)(v);
 
1217
                        }
 
1218
                    }
 
1219
                }
 
1220
 
 
1221
                if (e) { return new(tree.Element)(c, e, i) }
 
1222
            },
 
1223
 
 
1224
            //
 
1225
            // Combinators combine elements together, in a Selector.
 
1226
            //
 
1227
            // Because our parser isn't white-space sensitive, special care
 
1228
            // has to be taken, when parsing the descendant combinator, ` `,
 
1229
            // as it's an empty space. We have to check the previous character
 
1230
            // in the input, to see if it's a ` ` character. More info on how
 
1231
            // we deal with this in *combinator.js*.
 
1232
            //
 
1233
            combinator: function () {
 
1234
                var match, c = input.charAt(i);
 
1235
 
 
1236
                if (c === '>' || c === '+' || c === '~' || c === '|') {
 
1237
                    i++;
 
1238
                    while (input.charAt(i).match(/\s/)) { i++ }
 
1239
                    return new(tree.Combinator)(c);
 
1240
                } else if (input.charAt(i - 1).match(/\s/)) {
 
1241
                    return new(tree.Combinator)(" ");
 
1242
                } else {
 
1243
                    return new(tree.Combinator)(null);
 
1244
                }
 
1245
            },
 
1246
 
 
1247
            //
 
1248
            // A CSS Selector
 
1249
            //
 
1250
            //     .class > div + h1
 
1251
            //     li a:hover
 
1252
            //
 
1253
            // Selectors are made out of one or more Elements, see above.
 
1254
            //
 
1255
            selector: function () {
 
1256
                var sel, e, elements = [], c, match, extend, extendList = [];
 
1257
 
 
1258
                while ((extend = $(this.extend)) || (e = $(this.element))) {
 
1259
                    if (extend) {
 
1260
                        extendList.push.apply(extendList, extend);
 
1261
                    } else {
 
1262
                        if (extendList.length) {
 
1263
                            error("Extend can only be used at the end of selector");
 
1264
                        }
 
1265
                        c = input.charAt(i);
 
1266
                        elements.push(e)
 
1267
                        e = null;
 
1268
                    }
 
1269
                    if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break }
 
1270
                }
 
1271
 
 
1272
                if (elements.length > 0) { return new(tree.Selector)(elements, extendList); }
 
1273
                if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
 
1274
            },
 
1275
            attribute: function () {
 
1276
                var attr = '', key, val, op;
 
1277
 
 
1278
                if (! $('[')) return;
 
1279
 
 
1280
                if (!(key = $(this.entities.variableCurly))) {
 
1281
                    key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
 
1282
                }
 
1283
 
 
1284
                if ((op = $(/^[|~*$^]?=/))) {
 
1285
                    val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly);
 
1286
                }
 
1287
 
 
1288
                expect(']');
 
1289
 
 
1290
                return new(tree.Attribute)(key, op, val);
 
1291
            },
 
1292
 
 
1293
            //
 
1294
            // The `block` rule is used by `ruleset` and `mixin.definition`.
 
1295
            // It's a wrapper around the `primary` rule, with added `{}`.
 
1296
            //
 
1297
            block: function () {
 
1298
                var content;
 
1299
                if ($('{') && (content = $(this.primary)) && $('}')) {
 
1300
                    return content;
 
1301
                }
 
1302
            },
 
1303
 
 
1304
            //
 
1305
            // div, .class, body > p {...}
 
1306
            //
 
1307
            ruleset: function () {
 
1308
                var selectors = [], s, rules, match, debugInfo;
 
1309
                
 
1310
                save();
 
1311
 
 
1312
                if (env.dumpLineNumbers)
 
1313
                    debugInfo = getDebugInfo(i, input, env);
 
1314
 
 
1315
                while (s = $(this.selector)) {
 
1316
                    selectors.push(s);
 
1317
                    $(this.comment);
 
1318
                    if (! $(',')) { break }
 
1319
                    $(this.comment);
 
1320
                }
 
1321
 
 
1322
                if (selectors.length > 0 && (rules = $(this.block))) {
 
1323
                    var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
 
1324
                    if (env.dumpLineNumbers)
 
1325
                        ruleset.debugInfo = debugInfo;
 
1326
                    return ruleset;
 
1327
                } else {
 
1328
                    // Backtrack
 
1329
                    furthest = i;
 
1330
                    restore();
 
1331
                }
 
1332
            },
 
1333
            rule: function (tryAnonymous) {
 
1334
                var name, value, c = input.charAt(i), important, match;
 
1335
                save();
 
1336
 
 
1337
                if (c === '.' || c === '#' || c === '&') { return }
 
1338
 
 
1339
                if (name = $(this.variable) || $(this.property)) {
 
1340
                    // prefer to try to parse first if its a variable or we are compressing
 
1341
                    // but always fallback on the other one
 
1342
                    value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ?
 
1343
                        ($(this.value) || $(this.anonymousValue)) :
 
1344
                        ($(this.anonymousValue) || $(this.value));
 
1345
 
 
1346
                    important = $(this.important);
 
1347
 
 
1348
                    if (value && $(this.end)) {
 
1349
                        return new(tree.Rule)(name, value, important, memo, env.currentFileInfo);
 
1350
                    } else {
 
1351
                        furthest = i;
 
1352
                        restore();
 
1353
                        if (value && !tryAnonymous) {
 
1354
                            return this.rule(true);
 
1355
                        }
 
1356
                    }
 
1357
                }
 
1358
            },
 
1359
            anonymousValue: function () {
 
1360
                if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) {
 
1361
                    i += match[0].length - 1;
 
1362
                    return new(tree.Anonymous)(match[1]);
 
1363
                }
 
1364
            },
 
1365
 
 
1366
            //
 
1367
            // An @import directive
 
1368
            //
 
1369
            //     @import "lib";
 
1370
            //
 
1371
            // Depending on our environemnt, importing is done differently:
 
1372
            // In the browser, it's an XHR request, in Node, it would be a
 
1373
            // file-system operation. The function used for importing is
 
1374
            // stored in `import`, which we pass to the Import constructor.
 
1375
            //
 
1376
            "import": function () {
 
1377
                var path, features, index = i;
 
1378
 
 
1379
                save();
 
1380
 
 
1381
                var dir = $(/^@import?\s+/);
 
1382
 
 
1383
                var options = (dir ? $(this.importOptions) : null) || {};
 
1384
 
 
1385
                if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
 
1386
                    features = $(this.mediaFeatures);
 
1387
                    if ($(';')) {
 
1388
                        features = features && new(tree.Value)(features);
 
1389
                        return new(tree.Import)(path, features, options, index, env.currentFileInfo);
 
1390
                    }
 
1391
                }
 
1392
 
 
1393
                restore();
 
1394
            },
 
1395
 
 
1396
            importOptions: function() {
 
1397
                var o, options = {}, optionName, value;
 
1398
 
 
1399
                // list of options, surrounded by parens
 
1400
                if (! $('(')) { return null; }
 
1401
                do {
 
1402
                    if (o = $(this.importOption)) {
 
1403
                        optionName = o;
 
1404
                        value = true;
 
1405
                        switch(optionName) {
 
1406
                            case "css":
 
1407
                                optionName = "less";
 
1408
                                value = false;
 
1409
                            break;
 
1410
                            case "once":
 
1411
                                optionName = "multiple";
 
1412
                                value = false;
 
1413
                            break;
 
1414
                        }
 
1415
                        options[optionName] = value;
 
1416
                        if (! $(',')) { break }
 
1417
                    }
 
1418
                } while (o);
 
1419
                expect(')');
 
1420
                return options;
 
1421
            },
 
1422
 
 
1423
            importOption: function() {
 
1424
                var opt = $(/^(less|css|multiple|once)/);
 
1425
                if (opt) {
 
1426
                    return opt[1];
 
1427
                }
 
1428
            },
 
1429
 
 
1430
            mediaFeature: function () {
 
1431
                var e, p, nodes = [];
 
1432
 
 
1433
                do {
 
1434
                    if (e = $(this.entities.keyword)) {
 
1435
                        nodes.push(e);
 
1436
                    } else if ($('(')) {
 
1437
                        p = $(this.property);
 
1438
                        e = $(this.value);
 
1439
                        if ($(')')) {
 
1440
                            if (p && e) {
 
1441
                                nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true)));
 
1442
                            } else if (e) {
 
1443
                                nodes.push(new(tree.Paren)(e));
 
1444
                            } else {
 
1445
                                return null;
 
1446
                            }
 
1447
                        } else { return null }
 
1448
                    }
 
1449
                } while (e);
 
1450
 
 
1451
                if (nodes.length > 0) {
 
1452
                    return new(tree.Expression)(nodes);
 
1453
                }
 
1454
            },
 
1455
 
 
1456
            mediaFeatures: function () {
 
1457
                var e, features = [];
 
1458
 
 
1459
                do {
 
1460
                  if (e = $(this.mediaFeature)) {
 
1461
                      features.push(e);
 
1462
                      if (! $(',')) { break }
 
1463
                  } else if (e = $(this.entities.variable)) {
 
1464
                      features.push(e);
 
1465
                      if (! $(',')) { break }
 
1466
                  }
 
1467
                } while (e);
 
1468
 
 
1469
                return features.length > 0 ? features : null;
 
1470
            },
 
1471
 
 
1472
            media: function () {
 
1473
                var features, rules, media, debugInfo;
 
1474
 
 
1475
                if (env.dumpLineNumbers)
 
1476
                    debugInfo = getDebugInfo(i, input, env);
 
1477
 
 
1478
                if ($(/^@media/)) {
 
1479
                    features = $(this.mediaFeatures);
 
1480
 
 
1481
                    if (rules = $(this.block)) {
 
1482
                        media = new(tree.Media)(rules, features);
 
1483
                        if(env.dumpLineNumbers)
 
1484
                            media.debugInfo = debugInfo;
 
1485
                        return media;
 
1486
                    }
 
1487
                }
 
1488
            },
 
1489
 
 
1490
            //
 
1491
            // A CSS Directive
 
1492
            //
 
1493
            //     @charset "utf-8";
 
1494
            //
 
1495
            directive: function () {
 
1496
                var name, value, rules, identifier, e, nodes, nonVendorSpecificName,
 
1497
                    hasBlock, hasIdentifier, hasExpression;
 
1498
 
 
1499
                if (input.charAt(i) !== '@') return;
 
1500
 
 
1501
                if (value = $(this['import']) || $(this.media)) {
 
1502
                    return value;
 
1503
                }
 
1504
 
 
1505
                save();
 
1506
 
 
1507
                name = $(/^@[a-z-]+/);
 
1508
                
 
1509
                if (!name) return;
 
1510
 
 
1511
                nonVendorSpecificName = name;
 
1512
                if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
 
1513
                    nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
 
1514
                }
 
1515
 
 
1516
                switch(nonVendorSpecificName) {
 
1517
                    case "@font-face":
 
1518
                        hasBlock = true;
 
1519
                        break;
 
1520
                    case "@viewport":
 
1521
                    case "@top-left":
 
1522
                    case "@top-left-corner":
 
1523
                    case "@top-center":
 
1524
                    case "@top-right":
 
1525
                    case "@top-right-corner":
 
1526
                    case "@bottom-left":
 
1527
                    case "@bottom-left-corner":
 
1528
                    case "@bottom-center":
 
1529
                    case "@bottom-right":
 
1530
                    case "@bottom-right-corner":
 
1531
                    case "@left-top":
 
1532
                    case "@left-middle":
 
1533
                    case "@left-bottom":
 
1534
                    case "@right-top":
 
1535
                    case "@right-middle":
 
1536
                    case "@right-bottom":
 
1537
                        hasBlock = true;
 
1538
                        break;
 
1539
                    case "@page":
 
1540
                    case "@document":
 
1541
                    case "@supports":
 
1542
                    case "@keyframes":
 
1543
                        hasBlock = true;
 
1544
                        hasIdentifier = true;
 
1545
                        break;
 
1546
                    case "@namespace":
 
1547
                        hasExpression = true;
 
1548
                        break;
 
1549
                }
 
1550
 
 
1551
                if (hasIdentifier) {
 
1552
                    name += " " + ($(/^[^{]+/) || '').trim();
 
1553
                }
 
1554
 
 
1555
                if (hasBlock)
 
1556
                {
 
1557
                    if (rules = $(this.block)) {
 
1558
                        return new(tree.Directive)(name, rules);
 
1559
                    }
 
1560
                } else {
 
1561
                    if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
 
1562
                        var directive = new(tree.Directive)(name, value);
 
1563
                        if (env.dumpLineNumbers) {
 
1564
                            directive.debugInfo = getDebugInfo(i, input, env);
 
1565
                        }
 
1566
                        return directive;
 
1567
                    }
 
1568
                }
 
1569
 
 
1570
                restore();
 
1571
            },
 
1572
 
 
1573
            //
 
1574
            // A Value is a comma-delimited list of Expressions
 
1575
            //
 
1576
            //     font-family: Baskerville, Georgia, serif;
 
1577
            //
 
1578
            // In a Rule, a Value represents everything after the `:`,
 
1579
            // and before the `;`.
 
1580
            //
 
1581
            value: function () {
 
1582
                var e, expressions = [], important;
 
1583
 
 
1584
                while (e = $(this.expression)) {
 
1585
                    expressions.push(e);
 
1586
                    if (! $(',')) { break }
 
1587
                }
 
1588
 
 
1589
                if (expressions.length > 0) {
 
1590
                    return new(tree.Value)(expressions);
 
1591
                }
 
1592
            },
 
1593
            important: function () {
 
1594
                if (input.charAt(i) === '!') {
 
1595
                    return $(/^! *important/);
 
1596
                }
 
1597
            },
 
1598
            sub: function () {
 
1599
                var a, e;
 
1600
 
 
1601
                if ($('(')) {
 
1602
                    if (a = $(this.addition)) {
 
1603
                        e = new(tree.Expression)([a]);
 
1604
                        expect(')');
 
1605
                        e.parens = true;
 
1606
                        return e;
 
1607
                    }
 
1608
                }
 
1609
            },
 
1610
            multiplication: function () {
 
1611
                var m, a, op, operation, isSpaced, expression = [];
 
1612
                if (m = $(this.operand)) {
 
1613
                    isSpaced = isWhitespace(input.charAt(i - 1));
 
1614
                    while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) {
 
1615
                        if (a = $(this.operand)) {
 
1616
                            m.parensInOp = true;
 
1617
                            a.parensInOp = true;
 
1618
                            operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
 
1619
                            isSpaced = isWhitespace(input.charAt(i - 1));
 
1620
                        } else {
 
1621
                            break;
 
1622
                        }
 
1623
                    }
 
1624
                    return operation || m;
 
1625
                }
 
1626
            },
 
1627
            addition: function () {
 
1628
                var m, a, op, operation, isSpaced;
 
1629
                if (m = $(this.multiplication)) {
 
1630
                    isSpaced = isWhitespace(input.charAt(i - 1));
 
1631
                    while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) &&
 
1632
                           (a = $(this.multiplication))) {
 
1633
                        m.parensInOp = true;
 
1634
                        a.parensInOp = true;
 
1635
                        operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
 
1636
                        isSpaced = isWhitespace(input.charAt(i - 1));
 
1637
                    }
 
1638
                    return operation || m;
 
1639
                }
 
1640
            },
 
1641
            conditions: function () {
 
1642
                var a, b, index = i, condition;
 
1643
 
 
1644
                if (a = $(this.condition)) {
 
1645
                    while ($(',') && (b = $(this.condition))) {
 
1646
                        condition = new(tree.Condition)('or', condition || a, b, index);
 
1647
                    }
 
1648
                    return condition || a;
 
1649
                }
 
1650
            },
 
1651
            condition: function () {
 
1652
                var a, b, c, op, index = i, negate = false;
 
1653
 
 
1654
                if ($(/^not/)) { negate = true }
 
1655
                expect('(');
 
1656
                if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
 
1657
                    if (op = $(/^(?:>=|=<|[<=>])/)) {
 
1658
                        if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
 
1659
                            c = new(tree.Condition)(op, a, b, index, negate);
 
1660
                        } else {
 
1661
                            error('expected expression');
 
1662
                        }
 
1663
                    } else {
 
1664
                        c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
 
1665
                    }
 
1666
                    expect(')');
 
1667
                    return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
 
1668
                }
 
1669
            },
 
1670
 
 
1671
            //
 
1672
            // An operand is anything that can be part of an operation,
 
1673
            // such as a Color, or a Variable
 
1674
            //
 
1675
            operand: function () {
 
1676
                var negate, p = input.charAt(i + 1);
 
1677
 
 
1678
                if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
 
1679
                var o = $(this.sub) || $(this.entities.dimension) ||
 
1680
                        $(this.entities.color) || $(this.entities.variable) ||
 
1681
                        $(this.entities.call);
 
1682
 
 
1683
                if (negate) {
 
1684
                    o.parensInOp = true;
 
1685
                    o = new(tree.Negative)(o);
 
1686
                }
 
1687
 
 
1688
                return o;
 
1689
            },
 
1690
 
 
1691
            //
 
1692
            // Expressions either represent mathematical operations,
 
1693
            // or white-space delimited Entities.
 
1694
            //
 
1695
            //     1px solid black
 
1696
            //     @var * 2
 
1697
            //
 
1698
            expression: function () {
 
1699
                var e, delim, entities = [], d;
 
1700
 
 
1701
                while (e = $(this.addition) || $(this.entity)) {
 
1702
                    entities.push(e);
 
1703
                    // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
 
1704
                    if (!peek(/^\/[\/*]/) && (delim = $('/'))) {
 
1705
                        entities.push(new(tree.Anonymous)(delim));
 
1706
                    }
 
1707
                }
 
1708
                if (entities.length > 0) {
 
1709
                    return new(tree.Expression)(entities);
 
1710
                }
 
1711
            },
 
1712
            property: function () {
 
1713
                var name;
 
1714
 
 
1715
                if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) {
 
1716
                    return name[1];
 
1717
                }
 
1718
            }
 
1719
        }
 
1720
    };
 
1721
};
 
1722
 
 
1723
if (less.mode === 'browser' || less.mode === 'rhino') {
 
1724
    //
 
1725
    // Used by `@import` directives
 
1726
    //
 
1727
    less.Parser.importer = function (path, currentFileInfo, callback, env) {
 
1728
        if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) {
 
1729
            path = currentFileInfo.currentDirectory + path;
 
1730
        }
 
1731
        var sheetEnv = env.toSheet(path);
 
1732
        sheetEnv.processImports = false;
 
1733
        sheetEnv.currentFileInfo = currentFileInfo;
 
1734
 
 
1735
        // We pass `true` as 3rd argument, to force the reload of the import.
 
1736
        // This is so we can get the syntax tree as opposed to just the CSS output,
 
1737
        // as we need this to evaluate the current stylesheet.
 
1738
        loadStyleSheet(sheetEnv,
 
1739
            function (e, root, data, sheet, _, path) {
 
1740
                callback.call(null, e, root, path);
 
1741
            }, true);
 
1742
    };
 
1743
}
 
1744
 
 
1745
(function (tree) {
 
1746
 
 
1747
tree.functions = {
 
1748
    rgb: function (r, g, b) {
 
1749
        return this.rgba(r, g, b, 1.0);
 
1750
    },
 
1751
    rgba: function (r, g, b, a) {
 
1752
        var rgb = [r, g, b].map(function (c) { return scaled(c, 256); });
 
1753
        a = number(a);
 
1754
        return new(tree.Color)(rgb, a);
 
1755
    },
 
1756
    hsl: function (h, s, l) {
 
1757
        return this.hsla(h, s, l, 1.0);
 
1758
    },
 
1759
    hsla: function (h, s, l, a) {
 
1760
        h = (number(h) % 360) / 360;
 
1761
        s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));
 
1762
 
 
1763
        var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
 
1764
        var m1 = l * 2 - m2;
 
1765
 
 
1766
        return this.rgba(hue(h + 1/3) * 255,
 
1767
                         hue(h)       * 255,
 
1768
                         hue(h - 1/3) * 255,
 
1769
                         a);
 
1770
 
 
1771
        function hue(h) {
 
1772
            h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
 
1773
            if      (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
 
1774
            else if (h * 2 < 1) return m2;
 
1775
            else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
 
1776
            else                return m1;
 
1777
        }
 
1778
    },
 
1779
 
 
1780
    hsv: function(h, s, v) {
 
1781
        return this.hsva(h, s, v, 1.0);
 
1782
    },
 
1783
 
 
1784
    hsva: function(h, s, v, a) {
 
1785
        h = ((number(h) % 360) / 360) * 360;
 
1786
        s = number(s); v = number(v); a = number(a);
 
1787
 
 
1788
        var i, f;
 
1789
        i = Math.floor((h / 60) % 6);
 
1790
        f = (h / 60) - i;
 
1791
 
 
1792
        var vs = [v,
 
1793
                  v * (1 - s),
 
1794
                  v * (1 - f * s),
 
1795
                  v * (1 - (1 - f) * s)];
 
1796
        var perm = [[0, 3, 1],
 
1797
                    [2, 0, 1],
 
1798
                    [1, 0, 3],
 
1799
                    [1, 2, 0],
 
1800
                    [3, 1, 0],
 
1801
                    [0, 1, 2]];
 
1802
 
 
1803
        return this.rgba(vs[perm[i][0]] * 255,
 
1804
                         vs[perm[i][1]] * 255,
 
1805
                         vs[perm[i][2]] * 255,
 
1806
                         a);
 
1807
    },
 
1808
 
 
1809
    hue: function (color) {
 
1810
        return new(tree.Dimension)(Math.round(color.toHSL().h));
 
1811
    },
 
1812
    saturation: function (color) {
 
1813
        return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
 
1814
    },
 
1815
    lightness: function (color) {
 
1816
        return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
 
1817
    },
 
1818
    hsvhue: function(color) {
 
1819
        return new(tree.Dimension)(Math.round(color.toHSV().h));
 
1820
    },
 
1821
    hsvsaturation: function (color) {
 
1822
        return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%');
 
1823
    },
 
1824
    hsvvalue: function (color) {
 
1825
        return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%');
 
1826
    },
 
1827
    red: function (color) {
 
1828
        return new(tree.Dimension)(color.rgb[0]);
 
1829
    },
 
1830
    green: function (color) {
 
1831
        return new(tree.Dimension)(color.rgb[1]);
 
1832
    },
 
1833
    blue: function (color) {
 
1834
        return new(tree.Dimension)(color.rgb[2]);
 
1835
    },
 
1836
    alpha: function (color) {
 
1837
        return new(tree.Dimension)(color.toHSL().a);
 
1838
    },
 
1839
    luma: function (color) {
 
1840
        return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%');
 
1841
    },
 
1842
    saturate: function (color, amount) {
 
1843
        var hsl = color.toHSL();
 
1844
 
 
1845
        hsl.s += amount.value / 100;
 
1846
        hsl.s = clamp(hsl.s);
 
1847
        return hsla(hsl);
 
1848
    },
 
1849
    desaturate: function (color, amount) {
 
1850
        var hsl = color.toHSL();
 
1851
 
 
1852
        hsl.s -= amount.value / 100;
 
1853
        hsl.s = clamp(hsl.s);
 
1854
        return hsla(hsl);
 
1855
    },
 
1856
    lighten: function (color, amount) {
 
1857
        var hsl = color.toHSL();
 
1858
 
 
1859
        hsl.l += amount.value / 100;
 
1860
        hsl.l = clamp(hsl.l);
 
1861
        return hsla(hsl);
 
1862
    },
 
1863
    darken: function (color, amount) {
 
1864
        var hsl = color.toHSL();
 
1865
 
 
1866
        hsl.l -= amount.value / 100;
 
1867
        hsl.l = clamp(hsl.l);
 
1868
        return hsla(hsl);
 
1869
    },
 
1870
    fadein: function (color, amount) {
 
1871
        var hsl = color.toHSL();
 
1872
 
 
1873
        hsl.a += amount.value / 100;
 
1874
        hsl.a = clamp(hsl.a);
 
1875
        return hsla(hsl);
 
1876
    },
 
1877
    fadeout: function (color, amount) {
 
1878
        var hsl = color.toHSL();
 
1879
 
 
1880
        hsl.a -= amount.value / 100;
 
1881
        hsl.a = clamp(hsl.a);
 
1882
        return hsla(hsl);
 
1883
    },
 
1884
    fade: function (color, amount) {
 
1885
        var hsl = color.toHSL();
 
1886
 
 
1887
        hsl.a = amount.value / 100;
 
1888
        hsl.a = clamp(hsl.a);
 
1889
        return hsla(hsl);
 
1890
    },
 
1891
    spin: function (color, amount) {
 
1892
        var hsl = color.toHSL();
 
1893
        var hue = (hsl.h + amount.value) % 360;
 
1894
 
 
1895
        hsl.h = hue < 0 ? 360 + hue : hue;
 
1896
 
 
1897
        return hsla(hsl);
 
1898
    },
 
1899
    //
 
1900
    // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
 
1901
    // http://sass-lang.com
 
1902
    //
 
1903
    mix: function (color1, color2, weight) {
 
1904
        if (!weight) {
 
1905
            weight = new(tree.Dimension)(50);
 
1906
        }
 
1907
        var p = weight.value / 100.0;
 
1908
        var w = p * 2 - 1;
 
1909
        var a = color1.toHSL().a - color2.toHSL().a;
 
1910
 
 
1911
        var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
 
1912
        var w2 = 1 - w1;
 
1913
 
 
1914
        var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
 
1915
                   color1.rgb[1] * w1 + color2.rgb[1] * w2,
 
1916
                   color1.rgb[2] * w1 + color2.rgb[2] * w2];
 
1917
 
 
1918
        var alpha = color1.alpha * p + color2.alpha * (1 - p);
 
1919
 
 
1920
        return new(tree.Color)(rgb, alpha);
 
1921
    },
 
1922
    greyscale: function (color) {
 
1923
        return this.desaturate(color, new(tree.Dimension)(100));
 
1924
    },
 
1925
    contrast: function (color, dark, light, threshold) {
 
1926
        // filter: contrast(3.2);
 
1927
        // should be kept as is, so check for color
 
1928
        if (!color.rgb) {
 
1929
            return null;
 
1930
        }
 
1931
        if (typeof light === 'undefined') {
 
1932
            light = this.rgba(255, 255, 255, 1.0);
 
1933
        }
 
1934
        if (typeof dark === 'undefined') {
 
1935
            dark = this.rgba(0, 0, 0, 1.0);
 
1936
        }
 
1937
        //Figure out which is actually light and dark!
 
1938
        if (dark.luma() > light.luma()) {
 
1939
            var t = light;
 
1940
            light = dark;
 
1941
            dark = t;
 
1942
        }
 
1943
        if (typeof threshold === 'undefined') {
 
1944
            threshold = 0.43;
 
1945
        } else {
 
1946
            threshold = number(threshold);
 
1947
        }
 
1948
        if ((color.luma() * color.alpha) < threshold) {
 
1949
            return light;
 
1950
        } else {
 
1951
            return dark;
 
1952
        }
 
1953
    },
 
1954
    e: function (str) {
 
1955
        return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
 
1956
    },
 
1957
    escape: function (str) {
 
1958
        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"));
 
1959
    },
 
1960
    '%': function (quoted /* arg, arg, ...*/) {
 
1961
        var args = Array.prototype.slice.call(arguments, 1),
 
1962
            str = quoted.value;
 
1963
 
 
1964
        for (var i = 0; i < args.length; i++) {
 
1965
            str = str.replace(/%[sda]/i, function(token) {
 
1966
                var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
 
1967
                return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
 
1968
            });
 
1969
        }
 
1970
        str = str.replace(/%%/g, '%');
 
1971
        return new(tree.Quoted)('"' + str + '"', str);
 
1972
    },
 
1973
    unit: function (val, unit) {
 
1974
        return new(tree.Dimension)(val.value, unit ? unit.toCSS() : "");
 
1975
    },
 
1976
    convert: function (val, unit) {
 
1977
        return val.convertTo(unit.value);
 
1978
    },
 
1979
    round: function (n, f) {
 
1980
        var fraction = typeof(f) === "undefined" ? 0 : f.value;
 
1981
        return this._math(function(num) { return num.toFixed(fraction); }, null, n);
 
1982
    },
 
1983
    pi: function () {
 
1984
        return new(tree.Dimension)(Math.PI);
 
1985
    },
 
1986
    mod: function(a, b) {
 
1987
        return new(tree.Dimension)(a.value % b.value, a.unit);
 
1988
    },
 
1989
    pow: function(x, y) {
 
1990
        if (typeof x === "number" && typeof y === "number") {
 
1991
            x = new(tree.Dimension)(x);
 
1992
            y = new(tree.Dimension)(y);
 
1993
        } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) {
 
1994
            throw { type: "Argument", message: "arguments must be numbers" };
 
1995
        }
 
1996
 
 
1997
        return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit);
 
1998
    },
 
1999
    _math: function (fn, unit, n) {
 
2000
        if (n instanceof tree.Dimension) {
 
2001
            return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit);
 
2002
        } else if (typeof(n) === 'number') {
 
2003
            return fn(n);
 
2004
        } else {
 
2005
            throw { type: "Argument", message: "argument must be a number" };
 
2006
        }
 
2007
    },
 
2008
    argb: function (color) {
 
2009
        return new(tree.Anonymous)(color.toARGB());
 
2010
 
 
2011
    },
 
2012
    percentage: function (n) {
 
2013
        return new(tree.Dimension)(n.value * 100, '%');
 
2014
    },
 
2015
    color: function (n) {
 
2016
        if (n instanceof tree.Quoted) {
 
2017
            return new(tree.Color)(n.value.slice(1));
 
2018
        } else {
 
2019
            throw { type: "Argument", message: "argument must be a string" };
 
2020
        }
 
2021
    },
 
2022
    iscolor: function (n) {
 
2023
        return this._isa(n, tree.Color);
 
2024
    },
 
2025
    isnumber: function (n) {
 
2026
        return this._isa(n, tree.Dimension);
 
2027
    },
 
2028
    isstring: function (n) {
 
2029
        return this._isa(n, tree.Quoted);
 
2030
    },
 
2031
    iskeyword: function (n) {
 
2032
        return this._isa(n, tree.Keyword);
 
2033
    },
 
2034
    isurl: function (n) {
 
2035
        return this._isa(n, tree.URL);
 
2036
    },
 
2037
    ispixel: function (n) {
 
2038
        return (n instanceof tree.Dimension) && n.unit.is('px') ? tree.True : tree.False;
 
2039
    },
 
2040
    ispercentage: function (n) {
 
2041
        return (n instanceof tree.Dimension) && n.unit.is('%') ? tree.True : tree.False;
 
2042
    },
 
2043
    isem: function (n) {
 
2044
        return (n instanceof tree.Dimension) && n.unit.is('em') ? tree.True : tree.False;
 
2045
    },
 
2046
    _isa: function (n, Type) {
 
2047
        return (n instanceof Type) ? tree.True : tree.False;
 
2048
    },
 
2049
    
 
2050
    /* Blending modes */
 
2051
    
 
2052
    multiply: function(color1, color2) {
 
2053
        var r = color1.rgb[0] * color2.rgb[0] / 255;
 
2054
        var g = color1.rgb[1] * color2.rgb[1] / 255;
 
2055
        var b = color1.rgb[2] * color2.rgb[2] / 255;
 
2056
        return this.rgb(r, g, b);
 
2057
    },
 
2058
    screen: function(color1, color2) {
 
2059
        var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
 
2060
        var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
 
2061
        var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
 
2062
        return this.rgb(r, g, b);
 
2063
    },
 
2064
    overlay: function(color1, color2) {
 
2065
        var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
 
2066
        var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
 
2067
        var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
 
2068
        return this.rgb(r, g, b);
 
2069
    },
 
2070
    softlight: function(color1, color2) {
 
2071
        var t = color2.rgb[0] * color1.rgb[0] / 255;
 
2072
        var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255;
 
2073
        t = color2.rgb[1] * color1.rgb[1] / 255;
 
2074
        var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255;
 
2075
        t = color2.rgb[2] * color1.rgb[2] / 255;
 
2076
        var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255;
 
2077
        return this.rgb(r, g, b);
 
2078
    },
 
2079
    hardlight: function(color1, color2) {
 
2080
        var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255;
 
2081
        var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255;
 
2082
        var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255;
 
2083
        return this.rgb(r, g, b);
 
2084
    },
 
2085
    difference: function(color1, color2) {
 
2086
        var r = Math.abs(color1.rgb[0] - color2.rgb[0]);
 
2087
        var g = Math.abs(color1.rgb[1] - color2.rgb[1]);
 
2088
        var b = Math.abs(color1.rgb[2] - color2.rgb[2]);
 
2089
        return this.rgb(r, g, b);
 
2090
    },
 
2091
    exclusion: function(color1, color2) {
 
2092
        var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255;
 
2093
        var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255;
 
2094
        var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255;
 
2095
        return this.rgb(r, g, b);
 
2096
    },
 
2097
    average: function(color1, color2) {
 
2098
        var r = (color1.rgb[0] + color2.rgb[0]) / 2;
 
2099
        var g = (color1.rgb[1] + color2.rgb[1]) / 2;
 
2100
        var b = (color1.rgb[2] + color2.rgb[2]) / 2;
 
2101
        return this.rgb(r, g, b);
 
2102
    },
 
2103
    negation: function(color1, color2) {
 
2104
        var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]);
 
2105
        var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]);
 
2106
        var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]);
 
2107
        return this.rgb(r, g, b);
 
2108
    },
 
2109
    tint: function(color, amount) {
 
2110
        return this.mix(this.rgb(255,255,255), color, amount);
 
2111
    },
 
2112
    shade: function(color, amount) {
 
2113
        return this.mix(this.rgb(0, 0, 0), color, amount);
 
2114
    },
 
2115
    extract: function(values, index) {
 
2116
        index = index.value - 1; // (1-based index)
 
2117
        return values.value[index];
 
2118
    },
 
2119
 
 
2120
    "data-uri": function(mimetypeNode, filePathNode) {
 
2121
 
 
2122
        if (typeof window !== 'undefined') {
 
2123
            return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
 
2124
        }
 
2125
 
 
2126
        var mimetype = mimetypeNode.value;
 
2127
        var filePath = (filePathNode && filePathNode.value);
 
2128
 
 
2129
        var fs = require("fs"),
 
2130
            path = require("path"),
 
2131
            useBase64 = false;
 
2132
 
 
2133
        if (arguments.length < 2) {
 
2134
            filePath = mimetype;
 
2135
        }
 
2136
 
 
2137
        if (this.env.isPathRelative(filePath)) {
 
2138
            if (this.currentFileInfo.relativeUrls) {
 
2139
                filePath = path.join(this.currentFileInfo.currentDirectory, filePath);
 
2140
            } else {
 
2141
                filePath = path.join(this.currentFileInfo.entryPath, filePath);
 
2142
            }
 
2143
        }
 
2144
 
 
2145
        // detect the mimetype if not given
 
2146
        if (arguments.length < 2) {
 
2147
            var mime;
 
2148
            try {
 
2149
                mime = require('mime');
 
2150
            } catch (ex) {
 
2151
                mime = tree._mime;
 
2152
            }
 
2153
 
 
2154
            mimetype = mime.lookup(filePath);
 
2155
 
 
2156
            // use base 64 unless it's an ASCII or UTF-8 format
 
2157
            var charset = mime.charsets.lookup(mimetype);
 
2158
            useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
 
2159
            if (useBase64) mimetype += ';base64';
 
2160
        }
 
2161
        else {
 
2162
            useBase64 = /;base64$/.test(mimetype)
 
2163
        }
 
2164
 
 
2165
        var buf = fs.readFileSync(filePath);
 
2166
 
 
2167
        // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
 
2168
        // and the --ieCompat flag is enabled, return a normal url() instead.
 
2169
        var DATA_URI_MAX_KB = 32,
 
2170
            fileSizeInKB = parseInt((buf.length / 1024), 10);
 
2171
        if (fileSizeInKB >= DATA_URI_MAX_KB) {
 
2172
 
 
2173
            if (this.env.ieCompat !== false) {
 
2174
                if (!this.env.silent) {
 
2175
                    console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB);
 
2176
                }
 
2177
 
 
2178
                return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
 
2179
            } else if (!this.env.silent) {
 
2180
                // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn
 
2181
                console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB);
 
2182
            }
 
2183
        }
 
2184
 
 
2185
        buf = useBase64 ? buf.toString('base64')
 
2186
                        : encodeURIComponent(buf);
 
2187
 
 
2188
        var uri = "'data:" + mimetype + ',' + buf + "'";
 
2189
        return new(tree.URL)(new(tree.Anonymous)(uri));
 
2190
    }
 
2191
};
 
2192
 
 
2193
// these static methods are used as a fallback when the optional 'mime' dependency is missing
 
2194
tree._mime = {
 
2195
    // this map is intentionally incomplete
 
2196
    // if you want more, install 'mime' dep
 
2197
    _types: {
 
2198
        '.htm' : 'text/html',
 
2199
        '.html': 'text/html',
 
2200
        '.gif' : 'image/gif',
 
2201
        '.jpg' : 'image/jpeg',
 
2202
        '.jpeg': 'image/jpeg',
 
2203
        '.png' : 'image/png'
 
2204
    },
 
2205
    lookup: function (filepath) {
 
2206
        var ext = require('path').extname(filepath),
 
2207
            type = tree._mime._types[ext];
 
2208
        if (type === undefined) {
 
2209
            throw new Error('Optional dependency "mime" is required for ' + ext);
 
2210
        }
 
2211
        return type;
 
2212
    },
 
2213
    charsets: {
 
2214
        lookup: function (type) {
 
2215
            // assumes all text types are UTF-8
 
2216
            return type && (/^text\//).test(type) ? 'UTF-8' : '';
 
2217
        }
 
2218
    }
 
2219
};
 
2220
 
 
2221
var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"},
 
2222
        {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""},
 
2223
        {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}],
 
2224
    createMathFunction = function(name, unit) {
 
2225
        return function(n) {
 
2226
            if (unit != null) {
 
2227
                n = n.unify();
 
2228
            }
 
2229
            return this._math(Math[name], unit, n);
 
2230
        };
 
2231
    };
 
2232
 
 
2233
for(var i = 0; i < mathFunctions.length; i++) {
 
2234
    tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit);
 
2235
}
 
2236
 
 
2237
function hsla(color) {
 
2238
    return tree.functions.hsla(color.h, color.s, color.l, color.a);
 
2239
}
 
2240
 
 
2241
function scaled(n, size) {
 
2242
    if (n instanceof tree.Dimension && n.unit.is('%')) {
 
2243
        return parseFloat(n.value * size / 100);
 
2244
    } else {
 
2245
        return number(n);
 
2246
    }
 
2247
}
 
2248
 
 
2249
function number(n) {
 
2250
    if (n instanceof tree.Dimension) {
 
2251
        return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
 
2252
    } else if (typeof(n) === 'number') {
 
2253
        return n;
 
2254
    } else {
 
2255
        throw {
 
2256
            error: "RuntimeError",
 
2257
            message: "color functions take numbers as parameters"
 
2258
        };
 
2259
    }
 
2260
}
 
2261
 
 
2262
function clamp(val) {
 
2263
    return Math.min(1, Math.max(0, val));
 
2264
}
 
2265
 
 
2266
tree.functionCall = function(env, currentFileInfo) {
 
2267
    this.env = env;
 
2268
    this.currentFileInfo = currentFileInfo;
 
2269
};
 
2270
 
 
2271
tree.functionCall.prototype = tree.functions;
 
2272
 
 
2273
})(require('./tree'));
 
2274
(function (tree) {
 
2275
    tree.colors = {
 
2276
        'aliceblue':'#f0f8ff',
 
2277
        'antiquewhite':'#faebd7',
 
2278
        'aqua':'#00ffff',
 
2279
        'aquamarine':'#7fffd4',
 
2280
        'azure':'#f0ffff',
 
2281
        'beige':'#f5f5dc',
 
2282
        'bisque':'#ffe4c4',
 
2283
        'black':'#000000',
 
2284
        'blanchedalmond':'#ffebcd',
 
2285
        'blue':'#0000ff',
 
2286
        'blueviolet':'#8a2be2',
 
2287
        'brown':'#a52a2a',
 
2288
        'burlywood':'#deb887',
 
2289
        'cadetblue':'#5f9ea0',
 
2290
        'chartreuse':'#7fff00',
 
2291
        'chocolate':'#d2691e',
 
2292
        'coral':'#ff7f50',
 
2293
        'cornflowerblue':'#6495ed',
 
2294
        'cornsilk':'#fff8dc',
 
2295
        'crimson':'#dc143c',
 
2296
        'cyan':'#00ffff',
 
2297
        'darkblue':'#00008b',
 
2298
        'darkcyan':'#008b8b',
 
2299
        'darkgoldenrod':'#b8860b',
 
2300
        'darkgray':'#a9a9a9',
 
2301
        'darkgrey':'#a9a9a9',
 
2302
        'darkgreen':'#006400',
 
2303
        'darkkhaki':'#bdb76b',
 
2304
        'darkmagenta':'#8b008b',
 
2305
        'darkolivegreen':'#556b2f',
 
2306
        'darkorange':'#ff8c00',
 
2307
        'darkorchid':'#9932cc',
 
2308
        'darkred':'#8b0000',
 
2309
        'darksalmon':'#e9967a',
 
2310
        'darkseagreen':'#8fbc8f',
 
2311
        'darkslateblue':'#483d8b',
 
2312
        'darkslategray':'#2f4f4f',
 
2313
        'darkslategrey':'#2f4f4f',
 
2314
        'darkturquoise':'#00ced1',
 
2315
        'darkviolet':'#9400d3',
 
2316
        'deeppink':'#ff1493',
 
2317
        'deepskyblue':'#00bfff',
 
2318
        'dimgray':'#696969',
 
2319
        'dimgrey':'#696969',
 
2320
        'dodgerblue':'#1e90ff',
 
2321
        'firebrick':'#b22222',
 
2322
        'floralwhite':'#fffaf0',
 
2323
        'forestgreen':'#228b22',
 
2324
        'fuchsia':'#ff00ff',
 
2325
        'gainsboro':'#dcdcdc',
 
2326
        'ghostwhite':'#f8f8ff',
 
2327
        'gold':'#ffd700',
 
2328
        'goldenrod':'#daa520',
 
2329
        'gray':'#808080',
 
2330
        'grey':'#808080',
 
2331
        'green':'#008000',
 
2332
        'greenyellow':'#adff2f',
 
2333
        'honeydew':'#f0fff0',
 
2334
        'hotpink':'#ff69b4',
 
2335
        'indianred':'#cd5c5c',
 
2336
        'indigo':'#4b0082',
 
2337
        'ivory':'#fffff0',
 
2338
        'khaki':'#f0e68c',
 
2339
        'lavender':'#e6e6fa',
 
2340
        'lavenderblush':'#fff0f5',
 
2341
        'lawngreen':'#7cfc00',
 
2342
        'lemonchiffon':'#fffacd',
 
2343
        'lightblue':'#add8e6',
 
2344
        'lightcoral':'#f08080',
 
2345
        'lightcyan':'#e0ffff',
 
2346
        'lightgoldenrodyellow':'#fafad2',
 
2347
        'lightgray':'#d3d3d3',
 
2348
        'lightgrey':'#d3d3d3',
 
2349
        'lightgreen':'#90ee90',
 
2350
        'lightpink':'#ffb6c1',
 
2351
        'lightsalmon':'#ffa07a',
 
2352
        'lightseagreen':'#20b2aa',
 
2353
        'lightskyblue':'#87cefa',
 
2354
        'lightslategray':'#778899',
 
2355
        'lightslategrey':'#778899',
 
2356
        'lightsteelblue':'#b0c4de',
 
2357
        'lightyellow':'#ffffe0',
 
2358
        'lime':'#00ff00',
 
2359
        'limegreen':'#32cd32',
 
2360
        'linen':'#faf0e6',
 
2361
        'magenta':'#ff00ff',
 
2362
        'maroon':'#800000',
 
2363
        'mediumaquamarine':'#66cdaa',
 
2364
        'mediumblue':'#0000cd',
 
2365
        'mediumorchid':'#ba55d3',
 
2366
        'mediumpurple':'#9370d8',
 
2367
        'mediumseagreen':'#3cb371',
 
2368
        'mediumslateblue':'#7b68ee',
 
2369
        'mediumspringgreen':'#00fa9a',
 
2370
        'mediumturquoise':'#48d1cc',
 
2371
        'mediumvioletred':'#c71585',
 
2372
        'midnightblue':'#191970',
 
2373
        'mintcream':'#f5fffa',
 
2374
        'mistyrose':'#ffe4e1',
 
2375
        'moccasin':'#ffe4b5',
 
2376
        'navajowhite':'#ffdead',
 
2377
        'navy':'#000080',
 
2378
        'oldlace':'#fdf5e6',
 
2379
        'olive':'#808000',
 
2380
        'olivedrab':'#6b8e23',
 
2381
        'orange':'#ffa500',
 
2382
        'orangered':'#ff4500',
 
2383
        'orchid':'#da70d6',
 
2384
        'palegoldenrod':'#eee8aa',
 
2385
        'palegreen':'#98fb98',
 
2386
        'paleturquoise':'#afeeee',
 
2387
        'palevioletred':'#d87093',
 
2388
        'papayawhip':'#ffefd5',
 
2389
        'peachpuff':'#ffdab9',
 
2390
        'peru':'#cd853f',
 
2391
        'pink':'#ffc0cb',
 
2392
        'plum':'#dda0dd',
 
2393
        'powderblue':'#b0e0e6',
 
2394
        'purple':'#800080',
 
2395
        'red':'#ff0000',
 
2396
        'rosybrown':'#bc8f8f',
 
2397
        'royalblue':'#4169e1',
 
2398
        'saddlebrown':'#8b4513',
 
2399
        'salmon':'#fa8072',
 
2400
        'sandybrown':'#f4a460',
 
2401
        'seagreen':'#2e8b57',
 
2402
        'seashell':'#fff5ee',
 
2403
        'sienna':'#a0522d',
 
2404
        'silver':'#c0c0c0',
 
2405
        'skyblue':'#87ceeb',
 
2406
        'slateblue':'#6a5acd',
 
2407
        'slategray':'#708090',
 
2408
        'slategrey':'#708090',
 
2409
        'snow':'#fffafa',
 
2410
        'springgreen':'#00ff7f',
 
2411
        'steelblue':'#4682b4',
 
2412
        'tan':'#d2b48c',
 
2413
        'teal':'#008080',
 
2414
        'thistle':'#d8bfd8',
 
2415
        'tomato':'#ff6347',
 
2416
        // 'transparent':'rgba(0,0,0,0)',
 
2417
        'turquoise':'#40e0d0',
 
2418
        'violet':'#ee82ee',
 
2419
        'wheat':'#f5deb3',
 
2420
        'white':'#ffffff',
 
2421
        'whitesmoke':'#f5f5f5',
 
2422
        'yellow':'#ffff00',
 
2423
        'yellowgreen':'#9acd32'
 
2424
    };
 
2425
})(require('./tree'));
 
2426
(function (tree) {
 
2427
 
 
2428
tree.Alpha = function (val) {
 
2429
    this.value = val;
 
2430
};
 
2431
tree.Alpha.prototype = {
 
2432
    type: "Alpha",
 
2433
    accept: function (visitor) {
 
2434
        this.value = visitor.visit(this.value);
 
2435
    },
 
2436
    eval: function (env) {
 
2437
        if (this.value.eval) { this.value = this.value.eval(env) }
 
2438
        return this;
 
2439
    },
 
2440
    toCSS: function () {
 
2441
        return "alpha(opacity=" +
 
2442
               (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
 
2443
    }
 
2444
};
 
2445
 
 
2446
})(require('../tree'));
 
2447
(function (tree) {
 
2448
 
 
2449
tree.Anonymous = function (string) {
 
2450
    this.value = string.value || string;
 
2451
};
 
2452
tree.Anonymous.prototype = {
 
2453
    type: "Anonymous",
 
2454
    toCSS: function () {
 
2455
        return this.value;
 
2456
    },
 
2457
    eval: function () { return this },
 
2458
    compare: function (x) {
 
2459
        if (!x.toCSS) {
 
2460
            return -1;
 
2461
        }
 
2462
        
 
2463
        var left = this.toCSS(),
 
2464
            right = x.toCSS();
 
2465
        
 
2466
        if (left === right) {
 
2467
            return 0;
 
2468
        }
 
2469
        
 
2470
        return left < right ? -1 : 1;
 
2471
    }
 
2472
};
 
2473
 
 
2474
})(require('../tree'));
 
2475
(function (tree) {
 
2476
 
 
2477
tree.Assignment = function (key, val) {
 
2478
    this.key = key;
 
2479
    this.value = val;
 
2480
};
 
2481
tree.Assignment.prototype = {
 
2482
    type: "Assignment",
 
2483
    accept: function (visitor) {
 
2484
        this.value = visitor.visit(this.value);
 
2485
    },
 
2486
    toCSS: function () {
 
2487
        return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
 
2488
    },
 
2489
    eval: function (env) {
 
2490
        if (this.value.eval) {
 
2491
            return new(tree.Assignment)(this.key, this.value.eval(env));
 
2492
        }
 
2493
        return this;
 
2494
    }
 
2495
};
 
2496
 
 
2497
})(require('../tree'));(function (tree) {
 
2498
 
 
2499
//
 
2500
// A function call node.
 
2501
//
 
2502
tree.Call = function (name, args, index, currentFileInfo) {
 
2503
    this.name = name;
 
2504
    this.args = args;
 
2505
    this.index = index;
 
2506
    this.currentFileInfo = currentFileInfo;
 
2507
};
 
2508
tree.Call.prototype = {
 
2509
    type: "Call",
 
2510
    accept: function (visitor) {
 
2511
        this.args = visitor.visit(this.args);
 
2512
    },
 
2513
    //
 
2514
    // When evaluating a function call,
 
2515
    // we either find the function in `tree.functions` [1],
 
2516
    // in which case we call it, passing the  evaluated arguments,
 
2517
    // if this returns null or we cannot find the function, we 
 
2518
    // simply print it out as it appeared originally [2].
 
2519
    //
 
2520
    // The *functions.js* file contains the built-in functions.
 
2521
    //
 
2522
    // The reason why we evaluate the arguments, is in the case where
 
2523
    // we try to pass a variable to a function, like: `saturate(@color)`.
 
2524
    // The function should receive the value, not the variable.
 
2525
    //
 
2526
    eval: function (env) {
 
2527
        var args = this.args.map(function (a) { return a.eval(env); }),
 
2528
            nameLC = this.name.toLowerCase(),
 
2529
            result, func;
 
2530
 
 
2531
        if (nameLC in tree.functions) { // 1.
 
2532
            try {
 
2533
                func = new tree.functionCall(env, this.currentFileInfo);
 
2534
                result = func[nameLC].apply(func, args);
 
2535
                if (result != null) {
 
2536
                    return result;
 
2537
                }
 
2538
            } catch (e) {
 
2539
                throw { type: e.type || "Runtime",
 
2540
                        message: "error evaluating function `" + this.name + "`" +
 
2541
                                 (e.message ? ': ' + e.message : ''),
 
2542
                        index: this.index, filename: this.currentFileInfo.filename };
 
2543
            }
 
2544
        }
 
2545
        
 
2546
        // 2.
 
2547
        return new(tree.Anonymous)(this.name +
 
2548
            "(" + args.map(function (a) { return a.toCSS(env); }).join(', ') + ")");
 
2549
    },
 
2550
 
 
2551
    toCSS: function (env) {
 
2552
        return this.eval(env).toCSS();
 
2553
    }
 
2554
};
 
2555
 
 
2556
})(require('../tree'));
 
2557
(function (tree) {
 
2558
//
 
2559
// RGB Colors - #ff0014, #eee
 
2560
//
 
2561
tree.Color = function (rgb, a) {
 
2562
    //
 
2563
    // The end goal here, is to parse the arguments
 
2564
    // into an integer triplet, such as `128, 255, 0`
 
2565
    //
 
2566
    // This facilitates operations and conversions.
 
2567
    //
 
2568
    if (Array.isArray(rgb)) {
 
2569
        this.rgb = rgb;
 
2570
    } else if (rgb.length == 6) {
 
2571
        this.rgb = rgb.match(/.{2}/g).map(function (c) {
 
2572
            return parseInt(c, 16);
 
2573
        });
 
2574
    } else {
 
2575
        this.rgb = rgb.split('').map(function (c) {
 
2576
            return parseInt(c + c, 16);
 
2577
        });
 
2578
    }
 
2579
    this.alpha = typeof(a) === 'number' ? a : 1;
 
2580
};
 
2581
tree.Color.prototype = {
 
2582
    type: "Color",
 
2583
    eval: function () { return this },
 
2584
    luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); },
 
2585
 
 
2586
    //
 
2587
    // If we have some transparency, the only way to represent it
 
2588
    // is via `rgba`. Otherwise, we use the hex representation,
 
2589
    // which has better compatibility with older browsers.
 
2590
    // Values are capped between `0` and `255`, rounded and zero-padded.
 
2591
    //
 
2592
    toCSS: function (env, doNotCompress) {
 
2593
        var compress = env && env.compress && !doNotCompress;
 
2594
        if (this.alpha < 1.0) {
 
2595
            return "rgba(" + this.rgb.map(function (c) {
 
2596
                return Math.round(c);
 
2597
            }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")";
 
2598
        } else {
 
2599
            var color = this.rgb.map(function (i) {
 
2600
                i = Math.round(i);
 
2601
                i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
 
2602
                return i.length === 1 ? '0' + i : i;
 
2603
            }).join('');
 
2604
 
 
2605
            if (compress) {
 
2606
                color = color.split('');
 
2607
 
 
2608
                // Convert color to short format
 
2609
                if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) {
 
2610
                    color = color[0] + color[2] + color[4];
 
2611
                } else {
 
2612
                    color = color.join('');
 
2613
                }
 
2614
            }
 
2615
 
 
2616
            return '#' + color;
 
2617
        }
 
2618
    },
 
2619
 
 
2620
    //
 
2621
    // Operations have to be done per-channel, if not,
 
2622
    // channels will spill onto each other. Once we have
 
2623
    // our result, in the form of an integer triplet,
 
2624
    // we create a new Color node to hold the result.
 
2625
    //
 
2626
    operate: function (env, op, other) {
 
2627
        var result = [];
 
2628
 
 
2629
        if (! (other instanceof tree.Color)) {
 
2630
            other = other.toColor();
 
2631
        }
 
2632
 
 
2633
        for (var c = 0; c < 3; c++) {
 
2634
            result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]);
 
2635
        }
 
2636
        return new(tree.Color)(result, this.alpha + other.alpha);
 
2637
    },
 
2638
 
 
2639
    toHSL: function () {
 
2640
        var r = this.rgb[0] / 255,
 
2641
            g = this.rgb[1] / 255,
 
2642
            b = this.rgb[2] / 255,
 
2643
            a = this.alpha;
 
2644
 
 
2645
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
 
2646
        var h, s, l = (max + min) / 2, d = max - min;
 
2647
 
 
2648
        if (max === min) {
 
2649
            h = s = 0;
 
2650
        } else {
 
2651
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
 
2652
 
 
2653
            switch (max) {
 
2654
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
 
2655
                case g: h = (b - r) / d + 2;               break;
 
2656
                case b: h = (r - g) / d + 4;               break;
 
2657
            }
 
2658
            h /= 6;
 
2659
        }
 
2660
        return { h: h * 360, s: s, l: l, a: a };
 
2661
    },
 
2662
    //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
 
2663
    toHSV: function () {
 
2664
        var r = this.rgb[0] / 255,
 
2665
            g = this.rgb[1] / 255,
 
2666
            b = this.rgb[2] / 255,
 
2667
            a = this.alpha;
 
2668
 
 
2669
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
 
2670
        var h, s, v = max;
 
2671
 
 
2672
        var d = max - min;
 
2673
        if (max === 0) {
 
2674
            s = 0;
 
2675
        } else {
 
2676
            s = d / max;
 
2677
        }
 
2678
 
 
2679
        if (max === min) {
 
2680
            h = 0;
 
2681
        } else {
 
2682
            switch(max){
 
2683
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
 
2684
                case g: h = (b - r) / d + 2; break;
 
2685
                case b: h = (r - g) / d + 4; break;
 
2686
            }
 
2687
            h /= 6;
 
2688
        }
 
2689
        return { h: h * 360, s: s, v: v, a: a };
 
2690
    },
 
2691
    toARGB: function () {
 
2692
        var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
 
2693
        return '#' + argb.map(function (i) {
 
2694
            i = Math.round(i);
 
2695
            i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
 
2696
            return i.length === 1 ? '0' + i : i;
 
2697
        }).join('');
 
2698
    },
 
2699
    compare: function (x) {
 
2700
        if (!x.rgb) {
 
2701
            return -1;
 
2702
        }
 
2703
        
 
2704
        return (x.rgb[0] === this.rgb[0] &&
 
2705
            x.rgb[1] === this.rgb[1] &&
 
2706
            x.rgb[2] === this.rgb[2] &&
 
2707
            x.alpha === this.alpha) ? 0 : -1;
 
2708
    }
 
2709
};
 
2710
 
 
2711
 
 
2712
})(require('../tree'));
 
2713
(function (tree) {
 
2714
 
 
2715
tree.Comment = function (value, silent) {
 
2716
    this.value = value;
 
2717
    this.silent = !!silent;
 
2718
};
 
2719
tree.Comment.prototype = {
 
2720
    type: "Comment",
 
2721
    toCSS: function (env) {
 
2722
        return env.compress ? '' : this.value;
 
2723
    },
 
2724
    eval: function () { return this }
 
2725
};
 
2726
 
 
2727
})(require('../tree'));
 
2728
(function (tree) {
 
2729
 
 
2730
tree.Condition = function (op, l, r, i, negate) {
 
2731
    this.op = op.trim();
 
2732
    this.lvalue = l;
 
2733
    this.rvalue = r;
 
2734
    this.index = i;
 
2735
    this.negate = negate;
 
2736
};
 
2737
tree.Condition.prototype = {
 
2738
    type: "Condition",
 
2739
    accept: function (visitor) {
 
2740
        this.lvalue = visitor.visit(this.lvalue);
 
2741
        this.rvalue = visitor.visit(this.rvalue);
 
2742
    },
 
2743
    eval: function (env) {
 
2744
        var a = this.lvalue.eval(env),
 
2745
            b = this.rvalue.eval(env);
 
2746
 
 
2747
        var i = this.index, result;
 
2748
 
 
2749
        var result = (function (op) {
 
2750
            switch (op) {
 
2751
                case 'and':
 
2752
                    return a && b;
 
2753
                case 'or':
 
2754
                    return a || b;
 
2755
                default:
 
2756
                    if (a.compare) {
 
2757
                        result = a.compare(b);
 
2758
                    } else if (b.compare) {
 
2759
                        result = b.compare(a);
 
2760
                    } else {
 
2761
                        throw { type: "Type",
 
2762
                                message: "Unable to perform comparison",
 
2763
                                index: i };
 
2764
                    }
 
2765
                    switch (result) {
 
2766
                        case -1: return op === '<' || op === '=<';
 
2767
                        case  0: return op === '=' || op === '>=' || op === '=<';
 
2768
                        case  1: return op === '>' || op === '>=';
 
2769
                    }
 
2770
            }
 
2771
        })(this.op);
 
2772
        return this.negate ? !result : result;
 
2773
    }
 
2774
};
 
2775
 
 
2776
})(require('../tree'));
 
2777
(function (tree) {
 
2778
 
 
2779
//
 
2780
// A number with a unit
 
2781
//
 
2782
tree.Dimension = function (value, unit) {
 
2783
    this.value = parseFloat(value);
 
2784
    this.unit = (unit && unit instanceof tree.Unit) ? unit :
 
2785
      new(tree.Unit)(unit ? [unit] : undefined);
 
2786
};
 
2787
 
 
2788
tree.Dimension.prototype = {
 
2789
    type: "Dimension",
 
2790
    accept: function (visitor) {
 
2791
        this.unit = visitor.visit(this.unit);
 
2792
    },
 
2793
    eval: function (env) {
 
2794
        return this;
 
2795
    },
 
2796
    toColor: function () {
 
2797
        return new(tree.Color)([this.value, this.value, this.value]);
 
2798
    },
 
2799
    toCSS: function (env) {
 
2800
        if ((!env || env.strictUnits !== false) && !this.unit.isSingular()) {
 
2801
            throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());
 
2802
        }
 
2803
 
 
2804
        var value = this.value,
 
2805
            strValue = String(value);
 
2806
 
 
2807
        if (value !== 0 && value < 0.000001 && value > -0.000001) {
 
2808
            // would be output 1e-6 etc.
 
2809
            strValue = value.toFixed(20).replace(/0+$/, "");
 
2810
        }
 
2811
 
 
2812
        if (env && env.compress) {
 
2813
            // Zero values doesn't need a unit
 
2814
            if (value === 0 && !this.unit.isAngle()) {
 
2815
                return strValue;
 
2816
            }
 
2817
 
 
2818
            // Float values doesn't need a leading zero
 
2819
            if (value > 0 && value < 1) {
 
2820
                strValue = (strValue).substr(1);
 
2821
            }
 
2822
        }
 
2823
 
 
2824
        return this.unit.isEmpty() ? strValue : (strValue + this.unit.toCSS());
 
2825
    },
 
2826
 
 
2827
    // In an operation between two Dimensions,
 
2828
    // we default to the first Dimension's unit,
 
2829
    // so `1px + 2` will yield `3px`.
 
2830
    operate: function (env, op, other) {
 
2831
        var value = tree.operate(env, op, this.value, other.value),
 
2832
            unit = this.unit.clone();
 
2833
 
 
2834
        if (op === '+' || op === '-') {
 
2835
            if (unit.numerator.length === 0 && unit.denominator.length === 0) {
 
2836
                unit.numerator = other.unit.numerator.slice(0);
 
2837
                unit.denominator = other.unit.denominator.slice(0);
 
2838
            } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) {
 
2839
                // do nothing
 
2840
            } else {
 
2841
                other = other.convertTo(this.unit.usedUnits());
 
2842
 
 
2843
                if(env.strictUnits !== false && other.unit.toString() !== unit.toString()) {
 
2844
                  throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() +
 
2845
                    "' and '" + other.unit.toString() + "'.");
 
2846
                }
 
2847
 
 
2848
                value = tree.operate(env, op, this.value, other.value);
 
2849
            }
 
2850
        } else if (op === '*') {
 
2851
            unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
 
2852
            unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
 
2853
            unit.cancel();
 
2854
        } else if (op === '/') {
 
2855
            unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
 
2856
            unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
 
2857
            unit.cancel();
 
2858
        }
 
2859
        return new(tree.Dimension)(value, unit);
 
2860
    },
 
2861
 
 
2862
    compare: function (other) {
 
2863
        if (other instanceof tree.Dimension) {
 
2864
            var a = this.unify(), b = other.unify(),
 
2865
                aValue = a.value, bValue = b.value;
 
2866
 
 
2867
            if (bValue > aValue) {
 
2868
                return -1;
 
2869
            } else if (bValue < aValue) {
 
2870
                return 1;
 
2871
            } else {
 
2872
                if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) {
 
2873
                    return -1;
 
2874
                }
 
2875
                return 0;
 
2876
            }
 
2877
        } else {
 
2878
            return -1;
 
2879
        }
 
2880
    },
 
2881
 
 
2882
    unify: function () {
 
2883
      return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
 
2884
    },
 
2885
 
 
2886
    convertTo: function (conversions) {
 
2887
      var value = this.value, unit = this.unit.clone(),
 
2888
          i, groupName, group, conversion, targetUnit, derivedConversions = {};
 
2889
 
 
2890
      if (typeof conversions === 'string') {
 
2891
          for(i in tree.UnitConversions) {
 
2892
              if (tree.UnitConversions[i].hasOwnProperty(conversions)) {
 
2893
                  derivedConversions = {};
 
2894
                  derivedConversions[i] = conversions;
 
2895
              }
 
2896
          }
 
2897
          conversions = derivedConversions;
 
2898
      }
 
2899
 
 
2900
      for (groupName in conversions) {
 
2901
        if (conversions.hasOwnProperty(groupName)) {
 
2902
          targetUnit = conversions[groupName];
 
2903
          group = tree.UnitConversions[groupName];
 
2904
 
 
2905
          unit.map(function (atomicUnit, denominator) {
 
2906
            if (group.hasOwnProperty(atomicUnit)) {
 
2907
              if (denominator) {
 
2908
                value = value / (group[atomicUnit] / group[targetUnit]);
 
2909
              } else {
 
2910
                value = value * (group[atomicUnit] / group[targetUnit]);
 
2911
              }
 
2912
 
 
2913
              return targetUnit;
 
2914
            }
 
2915
 
 
2916
            return atomicUnit;
 
2917
          });
 
2918
        }
 
2919
      }
 
2920
 
 
2921
      unit.cancel();
 
2922
 
 
2923
      return new(tree.Dimension)(value, unit);
 
2924
    }
 
2925
};
 
2926
 
 
2927
// http://www.w3.org/TR/css3-values/#absolute-lengths
 
2928
tree.UnitConversions = {
 
2929
  length: {
 
2930
     'm': 1,
 
2931
    'cm': 0.01,
 
2932
    'mm': 0.001,
 
2933
    'in': 0.0254,
 
2934
    'pt': 0.0254 / 72,
 
2935
    'pc': 0.0254 / 72 * 12
 
2936
  },
 
2937
  duration: {
 
2938
    's': 1,
 
2939
    'ms': 0.001
 
2940
  },
 
2941
  angle: {
 
2942
    'rad': 1/(2*Math.PI),
 
2943
    'deg': 1/360,
 
2944
    'grad': 1/400,
 
2945
    'turn': 1
 
2946
  }
 
2947
};
 
2948
 
 
2949
tree.Unit = function (numerator, denominator) {
 
2950
  this.numerator = numerator ? numerator.slice(0).sort() : [];
 
2951
  this.denominator = denominator ? denominator.slice(0).sort() : [];
 
2952
};
 
2953
 
 
2954
tree.Unit.prototype = {
 
2955
  type: "Unit",
 
2956
  clone: function () {
 
2957
    return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0));
 
2958
  },
 
2959
 
 
2960
  toCSS: function () {
 
2961
    if (this.numerator.length >= 1) {
 
2962
        return this.numerator[0];
 
2963
    }
 
2964
    if (this.denominator.length >= 1) {
 
2965
        return this.denominator[0];
 
2966
    }
 
2967
    return "";
 
2968
  },
 
2969
 
 
2970
  toString: function () {
 
2971
      var i, returnStr = this.numerator.join("*");
 
2972
      for (i = 0; i < this.denominator.length; i++) {
 
2973
          returnStr += "/" + this.denominator[i];
 
2974
      }
 
2975
      return returnStr;
 
2976
  },
 
2977
  
 
2978
  compare: function (other) {
 
2979
    return this.is(other.toCSS()) ? 0 : -1;
 
2980
  },
 
2981
 
 
2982
  is: function (unitString) {
 
2983
    return this.toCSS() === unitString;
 
2984
  },
 
2985
 
 
2986
  isAngle: function () {
 
2987
    return tree.UnitConversions.angle.hasOwnProperty(this.toCSS());
 
2988
  },
 
2989
 
 
2990
  isEmpty: function () {
 
2991
    return this.numerator.length == 0 && this.denominator.length == 0;
 
2992
  },
 
2993
 
 
2994
  isSingular: function() {
 
2995
      return this.numerator.length <= 1 && this.denominator.length == 0;
 
2996
  },
 
2997
 
 
2998
  map: function(callback) {
 
2999
    var i;
 
3000
 
 
3001
    for (i = 0; i < this.numerator.length; i++) {
 
3002
      this.numerator[i] = callback(this.numerator[i], false);
 
3003
    }
 
3004
 
 
3005
    for (i = 0; i < this.denominator.length; i++) {
 
3006
      this.denominator[i] = callback(this.denominator[i], true);
 
3007
    }
 
3008
  },
 
3009
 
 
3010
  usedUnits: function() {
 
3011
    var group, groupName, result = {};
 
3012
 
 
3013
    for (groupName in tree.UnitConversions) {
 
3014
      if (tree.UnitConversions.hasOwnProperty(groupName)) {
 
3015
        group = tree.UnitConversions[groupName];
 
3016
 
 
3017
        this.map(function (atomicUnit) {
 
3018
          if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
 
3019
            result[groupName] = atomicUnit;
 
3020
          }
 
3021
 
 
3022
          return atomicUnit;
 
3023
        });
 
3024
      }
 
3025
    }
 
3026
 
 
3027
    return result;
 
3028
  },
 
3029
 
 
3030
  cancel: function () {
 
3031
    var counter = {}, atomicUnit, i;
 
3032
 
 
3033
    for (i = 0; i < this.numerator.length; i++) {
 
3034
      atomicUnit = this.numerator[i];
 
3035
      counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
 
3036
    }
 
3037
 
 
3038
    for (i = 0; i < this.denominator.length; i++) {
 
3039
      atomicUnit = this.denominator[i];
 
3040
      counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
 
3041
    }
 
3042
 
 
3043
    this.numerator = [];
 
3044
    this.denominator = [];
 
3045
 
 
3046
    for (atomicUnit in counter) {
 
3047
      if (counter.hasOwnProperty(atomicUnit)) {
 
3048
        var count = counter[atomicUnit];
 
3049
 
 
3050
        if (count > 0) {
 
3051
          for (i = 0; i < count; i++) {
 
3052
            this.numerator.push(atomicUnit);
 
3053
          }
 
3054
        } else if (count < 0) {
 
3055
          for (i = 0; i < -count; i++) {
 
3056
            this.denominator.push(atomicUnit);
 
3057
          }
 
3058
        }
 
3059
      }
 
3060
    }
 
3061
 
 
3062
    this.numerator.sort();
 
3063
    this.denominator.sort();
 
3064
  }
 
3065
};
 
3066
 
 
3067
})(require('../tree'));
 
3068
(function (tree) {
 
3069
 
 
3070
tree.Directive = function (name, value) {
 
3071
    this.name = name;
 
3072
 
 
3073
    if (Array.isArray(value)) {
 
3074
        this.ruleset = new(tree.Ruleset)([], value);
 
3075
        this.ruleset.allowImports = true;
 
3076
    } else {
 
3077
        this.value = value;
 
3078
    }
 
3079
};
 
3080
tree.Directive.prototype = {
 
3081
    type: "Directive",
 
3082
    accept: function (visitor) {
 
3083
        this.ruleset = visitor.visit(this.ruleset);
 
3084
        this.value = visitor.visit(this.value);
 
3085
    },
 
3086
    toCSS: function (env) {
 
3087
        if (this.ruleset) {
 
3088
            this.ruleset.root = true;
 
3089
            return this.name + (env.compress ? '{' : ' {\n  ') +
 
3090
                   this.ruleset.toCSS(env).trim().replace(/\n/g, '\n  ') +
 
3091
                               (env.compress ? '}': '\n}\n');
 
3092
        } else {
 
3093
            return this.name + ' ' + this.value.toCSS() + ';\n';
 
3094
        }
 
3095
    },
 
3096
    eval: function (env) {
 
3097
        var evaldDirective = this;
 
3098
        if (this.ruleset) {
 
3099
            env.frames.unshift(this);
 
3100
            evaldDirective = new(tree.Directive)(this.name);
 
3101
            evaldDirective.ruleset = this.ruleset.eval(env);
 
3102
            env.frames.shift();
 
3103
        }
 
3104
        return evaldDirective;
 
3105
    },
 
3106
    variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
 
3107
    find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
 
3108
    rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
 
3109
};
 
3110
 
 
3111
})(require('../tree'));
 
3112
(function (tree) {
 
3113
 
 
3114
tree.Element = function (combinator, value, index) {
 
3115
    this.combinator = combinator instanceof tree.Combinator ?
 
3116
                      combinator : new(tree.Combinator)(combinator);
 
3117
 
 
3118
    if (typeof(value) === 'string') {
 
3119
        this.value = value.trim();
 
3120
    } else if (value) {
 
3121
        this.value = value;
 
3122
    } else {
 
3123
        this.value = "";
 
3124
    }
 
3125
    this.index = index;
 
3126
};
 
3127
tree.Element.prototype = {
 
3128
    type: "Element",
 
3129
    accept: function (visitor) {
 
3130
        this.combinator = visitor.visit(this.combinator);
 
3131
        this.value = visitor.visit(this.value);
 
3132
    },
 
3133
    eval: function (env) {
 
3134
        return new(tree.Element)(this.combinator,
 
3135
                                 this.value.eval ? this.value.eval(env) : this.value,
 
3136
                                 this.index);
 
3137
    },
 
3138
    toCSS: function (env) {
 
3139
        var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
 
3140
        if (value == '' && this.combinator.value.charAt(0) == '&') {
 
3141
            return '';
 
3142
        } else {
 
3143
            return this.combinator.toCSS(env || {}) + value;
 
3144
        }
 
3145
    }
 
3146
};
 
3147
 
 
3148
tree.Attribute = function (key, op, value) {
 
3149
    this.key = key;
 
3150
    this.op = op;
 
3151
    this.value = value;
 
3152
};
 
3153
tree.Attribute.prototype = {
 
3154
    type: "Attribute",
 
3155
    accept: function (visitor) {
 
3156
        this.value = visitor.visit(this.value);
 
3157
    },
 
3158
    eval: function (env) {
 
3159
        return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key,
 
3160
            this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value);
 
3161
    },
 
3162
    toCSS: function (env) {
 
3163
        var value = this.key.toCSS ? this.key.toCSS(env) : this.key;
 
3164
 
 
3165
        if (this.op) {
 
3166
            value += this.op;
 
3167
            value += (this.value.toCSS ? this.value.toCSS(env) : this.value);
 
3168
        }
 
3169
 
 
3170
        return '[' + value + ']';
 
3171
    }
 
3172
};
 
3173
 
 
3174
tree.Combinator = function (value) {
 
3175
    if (value === ' ') {
 
3176
        this.value = ' ';
 
3177
    } else {
 
3178
        this.value = value ? value.trim() : "";
 
3179
    }
 
3180
};
 
3181
tree.Combinator.prototype = {
 
3182
    type: "Combinator",
 
3183
    toCSS: function (env) {
 
3184
        return {
 
3185
            ''  : '',
 
3186
            ' ' : ' ',
 
3187
            ':' : ' :',
 
3188
            '+' : env.compress ? '+' : ' + ',
 
3189
            '~' : env.compress ? '~' : ' ~ ',
 
3190
            '>' : env.compress ? '>' : ' > ',
 
3191
            '|' : env.compress ? '|' : ' | '
 
3192
        }[this.value];
 
3193
    }
 
3194
};
 
3195
 
 
3196
})(require('../tree'));
 
3197
(function (tree) {
 
3198
 
 
3199
tree.Expression = function (value) { this.value = value; };
 
3200
tree.Expression.prototype = {
 
3201
    type: "Expression",
 
3202
    accept: function (visitor) {
 
3203
        this.value = visitor.visit(this.value);
 
3204
    },
 
3205
    eval: function (env) {
 
3206
        var returnValue,
 
3207
            inParenthesis = this.parens && !this.parensInOp,
 
3208
            doubleParen = false;
 
3209
        if (inParenthesis) {
 
3210
            env.inParenthesis();
 
3211
        }
 
3212
        if (this.value.length > 1) {
 
3213
            returnValue = new(tree.Expression)(this.value.map(function (e) {
 
3214
                return e.eval(env);
 
3215
            }));
 
3216
        } else if (this.value.length === 1) {
 
3217
            if (this.value[0].parens && !this.value[0].parensInOp) {
 
3218
                doubleParen = true;
 
3219
            }
 
3220
            returnValue = this.value[0].eval(env);
 
3221
        } else {
 
3222
            returnValue = this;
 
3223
        }
 
3224
        if (inParenthesis) {
 
3225
            env.outOfParenthesis();
 
3226
        }
 
3227
        if (this.parens && this.parensInOp && !(env.isMathsOn()) && !doubleParen) {
 
3228
            returnValue = new(tree.Paren)(returnValue);
 
3229
        }
 
3230
        return returnValue;
 
3231
    },
 
3232
    toCSS: function (env) {
 
3233
        return this.value.map(function (e) {
 
3234
            return e.toCSS ? e.toCSS(env) : '';
 
3235
        }).join(' ');
 
3236
    },
 
3237
    throwAwayComments: function () {
 
3238
        this.value = this.value.filter(function(v) {
 
3239
            return !(v instanceof tree.Comment);
 
3240
        });
 
3241
    }
 
3242
};
 
3243
 
 
3244
})(require('../tree'));
 
3245
(function (tree) {
 
3246
 
 
3247
tree.Extend = function Extend(selector, option, index) {
 
3248
    this.selector = selector;
 
3249
    this.option = option;
 
3250
    this.index = index;
 
3251
 
 
3252
    switch(option) {
 
3253
        case "all":
 
3254
            this.allowBefore = true;
 
3255
            this.allowAfter = true;
 
3256
        break;
 
3257
        default:
 
3258
            this.allowBefore = false;
 
3259
            this.allowAfter = false;
 
3260
        break;
 
3261
    }
 
3262
};
 
3263
 
 
3264
tree.Extend.prototype = {
 
3265
    type: "Extend",
 
3266
    accept: function (visitor) {
 
3267
        this.selector = visitor.visit(this.selector);
 
3268
    },
 
3269
    eval: function (env) {
 
3270
        return new(tree.Extend)(this.selector.eval(env), this.option, this.index);
 
3271
    },
 
3272
    clone: function (env) {
 
3273
        return new(tree.Extend)(this.selector, this.option, this.index);
 
3274
    },
 
3275
    findSelfSelectors: function (selectors) {
 
3276
        var selfElements = [];
 
3277
 
 
3278
        for(i = 0; i < selectors.length; i++) {
 
3279
            selfElements = selfElements.concat(selectors[i].elements);
 
3280
        }
 
3281
 
 
3282
        this.selfSelectors = [{ elements: selfElements }];
 
3283
    }
 
3284
};
 
3285
 
 
3286
})(require('../tree'));
 
3287
(function (tree) {
 
3288
//
 
3289
// CSS @import node
 
3290
//
 
3291
// The general strategy here is that we don't want to wait
 
3292
// for the parsing to be completed, before we start importing
 
3293
// the file. That's because in the context of a browser,
 
3294
// most of the time will be spent waiting for the server to respond.
 
3295
//
 
3296
// On creation, we push the import path to our import queue, though
 
3297
// `import,push`, we also pass it a callback, which it'll call once
 
3298
// the file has been fetched, and parsed.
 
3299
//
 
3300
tree.Import = function (path, features, options, index, currentFileInfo) {
 
3301
    var that = this;
 
3302
 
 
3303
    this.options = options;
 
3304
    this.index = index;
 
3305
    this.path = path;
 
3306
    this.features = features;
 
3307
    this.currentFileInfo = currentFileInfo;
 
3308
 
 
3309
    if (this.options.less !== undefined) {
 
3310
        this.css = !this.options.less;
 
3311
    } else {
 
3312
        var pathValue = this.getPath();
 
3313
        if (pathValue && /css([\?;].*)?$/.test(pathValue)) {
 
3314
            this.css = true;
 
3315
        }
 
3316
    }
 
3317
};
 
3318
 
 
3319
//
 
3320
// The actual import node doesn't return anything, when converted to CSS.
 
3321
// The reason is that it's used at the evaluation stage, so that the rules
 
3322
// it imports can be treated like any other rules.
 
3323
//
 
3324
// In `eval`, we make sure all Import nodes get evaluated, recursively, so
 
3325
// we end up with a flat structure, which can easily be imported in the parent
 
3326
// ruleset.
 
3327
//
 
3328
tree.Import.prototype = {
 
3329
    type: "Import",
 
3330
    accept: function (visitor) {
 
3331
        this.features = visitor.visit(this.features);
 
3332
        this.path = visitor.visit(this.path);
 
3333
        this.root = visitor.visit(this.root);
 
3334
    },
 
3335
    toCSS: function (env) {
 
3336
        var features = this.features ? ' ' + this.features.toCSS(env) : '';
 
3337
 
 
3338
        if (this.css) {
 
3339
            return "@import " + this.path.toCSS() + features + ';\n';
 
3340
        } else {
 
3341
            return "";
 
3342
        }
 
3343
    },
 
3344
    getPath: function () {
 
3345
        if (this.path instanceof tree.Quoted) {
 
3346
            var path = this.path.value;
 
3347
            return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
 
3348
        } else if (this.path instanceof tree.URL) {
 
3349
            return this.path.value.value;
 
3350
        }
 
3351
        return null;
 
3352
    },
 
3353
    evalForImport: function (env) {
 
3354
        return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo);
 
3355
    },
 
3356
    evalPath: function (env) {
 
3357
        var path = this.path.eval(env);
 
3358
        var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
 
3359
        if (rootpath && !(path instanceof tree.URL)) {
 
3360
            var pathValue = path.value;
 
3361
            // Add the base path if the import is relative
 
3362
            if (pathValue && env.isPathRelative(pathValue)) {
 
3363
                path.value =  rootpath + pathValue;
 
3364
            }
 
3365
        }
 
3366
        return path;
 
3367
    },
 
3368
    eval: function (env) {
 
3369
        var ruleset, features = this.features && this.features.eval(env);
 
3370
 
 
3371
        if (this.skip) { return []; }
 
3372
 
 
3373
        if (this.css) {
 
3374
            var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index);
 
3375
            if (!newImport.css && this.error) {
 
3376
                throw this.error;
 
3377
            }
 
3378
            return newImport;
 
3379
        } else {
 
3380
            ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
 
3381
 
 
3382
            ruleset.evalImports(env);
 
3383
 
 
3384
            return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
 
3385
        }
 
3386
    }
 
3387
};
 
3388
 
 
3389
})(require('../tree'));
 
3390
(function (tree) {
 
3391
 
 
3392
tree.JavaScript = function (string, index, escaped) {
 
3393
    this.escaped = escaped;
 
3394
    this.expression = string;
 
3395
    this.index = index;
 
3396
};
 
3397
tree.JavaScript.prototype = {
 
3398
    type: "JavaScript",
 
3399
    eval: function (env) {
 
3400
        var result,
 
3401
            that = this,
 
3402
            context = {};
 
3403
 
 
3404
        var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
 
3405
            return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
 
3406
        });
 
3407
 
 
3408
        try {
 
3409
            expression = new(Function)('return (' + expression + ')');
 
3410
        } catch (e) {
 
3411
            throw { message: "JavaScript evaluation error: `" + expression + "`" ,
 
3412
                    index: this.index };
 
3413
        }
 
3414
 
 
3415
        for (var k in env.frames[0].variables()) {
 
3416
            context[k.slice(1)] = {
 
3417
                value: env.frames[0].variables()[k].value,
 
3418
                toJS: function () {
 
3419
                    return this.value.eval(env).toCSS();
 
3420
                }
 
3421
            };
 
3422
        }
 
3423
 
 
3424
        try {
 
3425
            result = expression.call(context);
 
3426
        } catch (e) {
 
3427
            throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
 
3428
                    index: this.index };
 
3429
        }
 
3430
        if (typeof(result) === 'string') {
 
3431
            return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
 
3432
        } else if (Array.isArray(result)) {
 
3433
            return new(tree.Anonymous)(result.join(', '));
 
3434
        } else {
 
3435
            return new(tree.Anonymous)(result);
 
3436
        }
 
3437
    }
 
3438
};
 
3439
 
 
3440
})(require('../tree'));
 
3441
 
 
3442
(function (tree) {
 
3443
 
 
3444
tree.Keyword = function (value) { this.value = value };
 
3445
tree.Keyword.prototype = {
 
3446
    type: "Keyword",
 
3447
    eval: function () { return this; },
 
3448
    toCSS: function () { return this.value; },
 
3449
    compare: function (other) {
 
3450
        if (other instanceof tree.Keyword) {
 
3451
            return other.value === this.value ? 0 : 1;
 
3452
        } else {
 
3453
            return -1;
 
3454
        }
 
3455
    }
 
3456
};
 
3457
 
 
3458
tree.True = new(tree.Keyword)('true');
 
3459
tree.False = new(tree.Keyword)('false');
 
3460
 
 
3461
})(require('../tree'));
 
3462
(function (tree) {
 
3463
 
 
3464
tree.Media = function (value, features) {
 
3465
    var selectors = this.emptySelectors();
 
3466
 
 
3467
    this.features = new(tree.Value)(features);
 
3468
    this.ruleset = new(tree.Ruleset)(selectors, value);
 
3469
    this.ruleset.allowImports = true;
 
3470
};
 
3471
tree.Media.prototype = {
 
3472
    type: "Media",
 
3473
    accept: function (visitor) {
 
3474
        this.features = visitor.visit(this.features);
 
3475
        this.ruleset = visitor.visit(this.ruleset);
 
3476
    },
 
3477
    toCSS: function (env) {
 
3478
        var features = this.features.toCSS(env);
 
3479
 
 
3480
        return '@media ' + features + (env.compress ? '{' : ' {\n  ') +
 
3481
               this.ruleset.toCSS(env).trim().replace(/\n/g, '\n  ') +
 
3482
                           (env.compress ? '}': '\n}\n');
 
3483
    },
 
3484
    eval: function (env) {
 
3485
        if (!env.mediaBlocks) {
 
3486
            env.mediaBlocks = [];
 
3487
            env.mediaPath = [];
 
3488
        }
 
3489
        
 
3490
        var media = new(tree.Media)([], []);
 
3491
        if(this.debugInfo) {
 
3492
            this.ruleset.debugInfo = this.debugInfo;
 
3493
            media.debugInfo = this.debugInfo;
 
3494
        }
 
3495
        var strictMathsBypass = false;
 
3496
        if (env.strictMaths === false) {
 
3497
            strictMathsBypass = true;
 
3498
            env.strictMaths = true;
 
3499
        }
 
3500
        try {
 
3501
            media.features = this.features.eval(env);
 
3502
        }
 
3503
        finally {
 
3504
            if (strictMathsBypass) {
 
3505
                env.strictMaths = false;
 
3506
            }
 
3507
        }
 
3508
        
 
3509
        env.mediaPath.push(media);
 
3510
        env.mediaBlocks.push(media);
 
3511
        
 
3512
        env.frames.unshift(this.ruleset);
 
3513
        media.ruleset = this.ruleset.eval(env);
 
3514
        env.frames.shift();
 
3515
        
 
3516
        env.mediaPath.pop();
 
3517
 
 
3518
        return env.mediaPath.length === 0 ? media.evalTop(env) :
 
3519
                    media.evalNested(env)
 
3520
    },
 
3521
    variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
 
3522
    find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
 
3523
    rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
 
3524
    emptySelectors: function() { 
 
3525
        var el = new(tree.Element)('', '&', 0);
 
3526
        return [new(tree.Selector)([el])];
 
3527
    },
 
3528
 
 
3529
    evalTop: function (env) {
 
3530
        var result = this;
 
3531
 
 
3532
        // Render all dependent Media blocks.
 
3533
        if (env.mediaBlocks.length > 1) {
 
3534
            var selectors = this.emptySelectors();
 
3535
            result = new(tree.Ruleset)(selectors, env.mediaBlocks);
 
3536
            result.multiMedia = true;
 
3537
        }
 
3538
 
 
3539
        delete env.mediaBlocks;
 
3540
        delete env.mediaPath;
 
3541
 
 
3542
        return result;
 
3543
    },
 
3544
    evalNested: function (env) {
 
3545
        var i, value,
 
3546
            path = env.mediaPath.concat([this]);
 
3547
 
 
3548
        // Extract the media-query conditions separated with `,` (OR).
 
3549
        for (i = 0; i < path.length; i++) {
 
3550
            value = path[i].features instanceof tree.Value ?
 
3551
                        path[i].features.value : path[i].features;
 
3552
            path[i] = Array.isArray(value) ? value : [value];
 
3553
        }
 
3554
 
 
3555
        // Trace all permutations to generate the resulting media-query.
 
3556
        //
 
3557
        // (a, b and c) with nested (d, e) ->
 
3558
        //    a and d
 
3559
        //    a and e
 
3560
        //    b and c and d
 
3561
        //    b and c and e
 
3562
        this.features = new(tree.Value)(this.permute(path).map(function (path) {
 
3563
            path = path.map(function (fragment) {
 
3564
                return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
 
3565
            });
 
3566
 
 
3567
            for(i = path.length - 1; i > 0; i--) {
 
3568
                path.splice(i, 0, new(tree.Anonymous)("and"));
 
3569
            }
 
3570
 
 
3571
            return new(tree.Expression)(path);
 
3572
        }));
 
3573
 
 
3574
        // Fake a tree-node that doesn't output anything.
 
3575
        return new(tree.Ruleset)([], []);
 
3576
    },
 
3577
    permute: function (arr) {
 
3578
      if (arr.length === 0) {
 
3579
          return [];
 
3580
      } else if (arr.length === 1) {
 
3581
          return arr[0];
 
3582
      } else {
 
3583
          var result = [];
 
3584
          var rest = this.permute(arr.slice(1));
 
3585
          for (var i = 0; i < rest.length; i++) {
 
3586
              for (var j = 0; j < arr[0].length; j++) {
 
3587
                  result.push([arr[0][j]].concat(rest[i]));
 
3588
              }
 
3589
          }
 
3590
          return result;
 
3591
      }
 
3592
    },
 
3593
    bubbleSelectors: function (selectors) {
 
3594
      this.ruleset = new(tree.Ruleset)(selectors.slice(0), [this.ruleset]);
 
3595
    }
 
3596
};
 
3597
 
 
3598
})(require('../tree'));
 
3599
(function (tree) {
 
3600
 
 
3601
tree.mixin = {};
 
3602
tree.mixin.Call = function (elements, args, index, currentFileInfo, important) {
 
3603
    this.selector = new(tree.Selector)(elements);
 
3604
    this.arguments = args;
 
3605
    this.index = index;
 
3606
    this.currentFileInfo = currentFileInfo;
 
3607
    this.important = important;
 
3608
};
 
3609
tree.mixin.Call.prototype = {
 
3610
    type: "MixinCall",
 
3611
    accept: function (visitor) {
 
3612
        this.selector = visitor.visit(this.selector);
 
3613
        this.arguments = visitor.visit(this.arguments);
 
3614
    },
 
3615
    eval: function (env) {
 
3616
        var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound;
 
3617
 
 
3618
        args = this.arguments && this.arguments.map(function (a) {
 
3619
            return { name: a.name, value: a.value.eval(env) };
 
3620
        });
 
3621
 
 
3622
        for (i = 0; i < env.frames.length; i++) {
 
3623
            if ((mixins = env.frames[i].find(this.selector)).length > 0) {
 
3624
                isOneFound = true;
 
3625
                for (m = 0; m < mixins.length; m++) {
 
3626
                    mixin = mixins[m];
 
3627
                    isRecursive = false;
 
3628
                    for(f = 0; f < env.frames.length; f++) {
 
3629
                        if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
 
3630
                            isRecursive = true;
 
3631
                            break;
 
3632
                        }
 
3633
                    }
 
3634
                    if (isRecursive) {
 
3635
                        continue;
 
3636
                    }
 
3637
                    if (mixin.matchArgs(args, env)) {
 
3638
                        if (!mixin.matchCondition || mixin.matchCondition(args, env)) {
 
3639
                            try {
 
3640
                                Array.prototype.push.apply(
 
3641
                                      rules, mixin.eval(env, args, this.important).rules);
 
3642
                            } catch (e) {
 
3643
                                throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
 
3644
                            }
 
3645
                        }
 
3646
                        match = true;
 
3647
                    }
 
3648
                }
 
3649
                if (match) {
 
3650
                    return rules;
 
3651
                }
 
3652
            }
 
3653
        }
 
3654
        if (isOneFound) {
 
3655
            throw { type:    'Runtime',
 
3656
                    message: 'No matching definition was found for `' +
 
3657
                              this.selector.toCSS().trim() + '('      +
 
3658
                              (args ? args.map(function (a) {
 
3659
                                  var argValue = "";
 
3660
                                  if (a.name) {
 
3661
                                      argValue += a.name + ":";
 
3662
                                  }
 
3663
                                  if (a.value.toCSS) {
 
3664
                                      argValue += a.value.toCSS();
 
3665
                                  } else {
 
3666
                                      argValue += "???";
 
3667
                                  }
 
3668
                                  return argValue;
 
3669
                              }).join(', ') : "") + ")`",
 
3670
                    index:   this.index, filename: this.currentFileInfo.filename };
 
3671
        } else {
 
3672
            throw { type: 'Name',
 
3673
                message: this.selector.toCSS().trim() + " is undefined",
 
3674
                index: this.index, filename: this.currentFileInfo.filename };
 
3675
        }
 
3676
    }
 
3677
};
 
3678
 
 
3679
tree.mixin.Definition = function (name, params, rules, condition, variadic) {
 
3680
    this.name = name;
 
3681
    this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
 
3682
    this.params = params;
 
3683
    this.condition = condition;
 
3684
    this.variadic = variadic;
 
3685
    this.arity = params.length;
 
3686
    this.rules = rules;
 
3687
    this._lookups = {};
 
3688
    this.required = params.reduce(function (count, p) {
 
3689
        if (!p.name || (p.name && !p.value)) { return count + 1 }
 
3690
        else                                 { return count }
 
3691
    }, 0);
 
3692
    this.parent = tree.Ruleset.prototype;
 
3693
    this.frames = [];
 
3694
};
 
3695
tree.mixin.Definition.prototype = {
 
3696
    type: "MixinDefinition",
 
3697
    accept: function (visitor) {
 
3698
        this.params = visitor.visit(this.params);
 
3699
        this.rules = visitor.visit(this.rules);
 
3700
        this.condition = visitor.visit(this.condition);
 
3701
    },
 
3702
    toCSS:     function ()     { return ""; },
 
3703
    variable:  function (name) { return this.parent.variable.call(this, name); },
 
3704
    variables: function ()     { return this.parent.variables.call(this); },
 
3705
    find:      function ()     { return this.parent.find.apply(this, arguments); },
 
3706
    rulesets:  function ()     { return this.parent.rulesets.apply(this); },
 
3707
 
 
3708
    evalParams: function (env, mixinEnv, args, evaldArguments) {
 
3709
        var frame = new(tree.Ruleset)(null, []),
 
3710
            varargs, arg,
 
3711
            params = this.params.slice(0),
 
3712
            i, j, val, name, isNamedFound, argIndex;
 
3713
 
 
3714
        mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
 
3715
        
 
3716
        if (args) {
 
3717
            args = args.slice(0);
 
3718
 
 
3719
            for(i = 0; i < args.length; i++) {
 
3720
                arg = args[i];
 
3721
                if (name = (arg && arg.name)) {
 
3722
                    isNamedFound = false;
 
3723
                    for(j = 0; j < params.length; j++) {
 
3724
                        if (!evaldArguments[j] && name === params[j].name) {
 
3725
                            evaldArguments[j] = arg.value.eval(env);
 
3726
                            frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env)));
 
3727
                            isNamedFound = true;
 
3728
                            break;
 
3729
                        }
 
3730
                    }
 
3731
                    if (isNamedFound) {
 
3732
                        args.splice(i, 1);
 
3733
                        i--;
 
3734
                        continue;
 
3735
                    } else {
 
3736
                        throw { type: 'Runtime', message: "Named argument for " + this.name +
 
3737
                            ' ' + args[i].name + ' not found' };
 
3738
                    }
 
3739
                }
 
3740
            }
 
3741
        }
 
3742
        argIndex = 0;
 
3743
        for (i = 0; i < params.length; i++) {
 
3744
            if (evaldArguments[i]) continue;
 
3745
            
 
3746
            arg = args && args[argIndex];
 
3747
 
 
3748
            if (name = params[i].name) {
 
3749
                if (params[i].variadic && args) {
 
3750
                    varargs = [];
 
3751
                    for (j = argIndex; j < args.length; j++) {
 
3752
                        varargs.push(args[j].value.eval(env));
 
3753
                    }
 
3754
                    frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
 
3755
                } else {
 
3756
                    val = arg && arg.value;
 
3757
                    if (val) {
 
3758
                        val = val.eval(env);
 
3759
                    } else if (params[i].value) {
 
3760
                        val = params[i].value.eval(mixinEnv);
 
3761
                        frame.resetCache();
 
3762
                    } else {
 
3763
                        throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
 
3764
                            ' (' + args.length + ' for ' + this.arity + ')' };
 
3765
                    }
 
3766
                    
 
3767
                    frame.rules.unshift(new(tree.Rule)(name, val));
 
3768
                    evaldArguments[i] = val;
 
3769
                }
 
3770
            }
 
3771
            
 
3772
            if (params[i].variadic && args) {
 
3773
                for (j = argIndex; j < args.length; j++) {
 
3774
                    evaldArguments[j] = args[j].value.eval(env);
 
3775
                }
 
3776
            }
 
3777
            argIndex++;
 
3778
        }
 
3779
 
 
3780
        return frame;
 
3781
    },
 
3782
    eval: function (env, args, important) {
 
3783
        var _arguments = [],
 
3784
            mixinFrames = this.frames.concat(env.frames),
 
3785
            frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
 
3786
            context, rules, start, ruleset;
 
3787
 
 
3788
        frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
 
3789
 
 
3790
        rules = important ?
 
3791
            this.parent.makeImportant.apply(this).rules : this.rules.slice(0);
 
3792
 
 
3793
        ruleset = new(tree.Ruleset)(null, rules).eval(new(tree.evalEnv)(env,
 
3794
                                                    [this, frame].concat(mixinFrames)));
 
3795
        ruleset.originalRuleset = this;
 
3796
        return ruleset;
 
3797
    },
 
3798
    matchCondition: function (args, env) {
 
3799
 
 
3800
        if (this.condition && !this.condition.eval(
 
3801
            new(tree.evalEnv)(env,
 
3802
                [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])]
 
3803
                    .concat(env.frames)))) {
 
3804
            return false;
 
3805
        }
 
3806
        return true;
 
3807
    },
 
3808
    matchArgs: function (args, env) {
 
3809
        var argsLength = (args && args.length) || 0, len, frame;
 
3810
 
 
3811
        if (! this.variadic) {
 
3812
            if (argsLength < this.required)                               { return false }
 
3813
            if (argsLength > this.params.length)                          { return false }
 
3814
            if ((this.required > 0) && (argsLength > this.params.length)) { return false }
 
3815
        }
 
3816
 
 
3817
        len = Math.min(argsLength, this.arity);
 
3818
 
 
3819
        for (var i = 0; i < len; i++) {
 
3820
            if (!this.params[i].name && !this.params[i].variadic) {
 
3821
                if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
 
3822
                    return false;
 
3823
                }
 
3824
            }
 
3825
        }
 
3826
        return true;
 
3827
    }
 
3828
};
 
3829
 
 
3830
})(require('../tree'));
 
3831
(function (tree) {
 
3832
 
 
3833
tree.Negative = function (node) {
 
3834
    this.value = node;
 
3835
};
 
3836
tree.Negative.prototype = {
 
3837
    type: "Negative",
 
3838
    accept: function (visitor) {
 
3839
        this.value = visitor.visit(this.value);
 
3840
    },
 
3841
    toCSS: function (env) {
 
3842
        return '-' + this.value.toCSS(env);
 
3843
    },
 
3844
    eval: function (env) {
 
3845
        if (env.isMathsOn()) {
 
3846
            return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env);
 
3847
        }
 
3848
        return new(tree.Negative)(this.value.eval(env));
 
3849
    }
 
3850
};
 
3851
 
 
3852
})(require('../tree'));
 
3853
(function (tree) {
 
3854
 
 
3855
tree.Operation = function (op, operands, isSpaced) {
 
3856
    this.op = op.trim();
 
3857
    this.operands = operands;
 
3858
    this.isSpaced = isSpaced;
 
3859
};
 
3860
tree.Operation.prototype = {
 
3861
    type: "Operation",
 
3862
    accept: function (visitor) {
 
3863
        this.operands = visitor.visit(this.operands);
 
3864
    },
 
3865
    eval: function (env) {
 
3866
        var a = this.operands[0].eval(env),
 
3867
            b = this.operands[1].eval(env),
 
3868
            temp;
 
3869
 
 
3870
        if (env.isMathsOn()) {
 
3871
            if (a instanceof tree.Dimension && b instanceof tree.Color) {
 
3872
                if (this.op === '*' || this.op === '+') {
 
3873
                    temp = b, b = a, a = temp;
 
3874
                } else {
 
3875
                    throw { type: "Operation",
 
3876
                            message: "Can't substract or divide a color from a number" };
 
3877
                }
 
3878
            }
 
3879
            if (!a.operate) {
 
3880
                throw { type: "Operation",
 
3881
                        message: "Operation on an invalid type" };
 
3882
            }
 
3883
 
 
3884
            return a.operate(env, this.op, b);
 
3885
        } else {
 
3886
            return new(tree.Operation)(this.op, [a, b], this.isSpaced);
 
3887
        }
 
3888
    },
 
3889
    toCSS: function (env) {
 
3890
        var separator = this.isSpaced ? " " : "";
 
3891
        return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS();
 
3892
    }
 
3893
};
 
3894
 
 
3895
tree.operate = function (env, op, a, b) {
 
3896
    switch (op) {
 
3897
        case '+': return a + b;
 
3898
        case '-': return a - b;
 
3899
        case '*': return a * b;
 
3900
        case '/': return a / b;
 
3901
    }
 
3902
};
 
3903
 
 
3904
})(require('../tree'));
 
3905
 
 
3906
(function (tree) {
 
3907
 
 
3908
tree.Paren = function (node) {
 
3909
    this.value = node;
 
3910
};
 
3911
tree.Paren.prototype = {
 
3912
    type: "Paren",
 
3913
    accept: function (visitor) {
 
3914
        this.value = visitor.visit(this.value);
 
3915
    },
 
3916
    toCSS: function (env) {
 
3917
        return '(' + this.value.toCSS(env).trim() + ')';
 
3918
    },
 
3919
    eval: function (env) {
 
3920
        return new(tree.Paren)(this.value.eval(env));
 
3921
    }
 
3922
};
 
3923
 
 
3924
})(require('../tree'));
 
3925
(function (tree) {
 
3926
 
 
3927
tree.Quoted = function (str, content, escaped, index, currentFileInfo) {
 
3928
    this.escaped = escaped;
 
3929
    this.value = content || '';
 
3930
    this.quote = str.charAt(0);
 
3931
    this.index = index;
 
3932
    this.currentFileInfo = currentFileInfo;
 
3933
};
 
3934
tree.Quoted.prototype = {
 
3935
    type: "Quoted",
 
3936
    toCSS: function () {
 
3937
        if (this.escaped) {
 
3938
            return this.value;
 
3939
        } else {
 
3940
            return this.quote + this.value + this.quote;
 
3941
        }
 
3942
    },
 
3943
    eval: function (env) {
 
3944
        var that = this;
 
3945
        var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
 
3946
            return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
 
3947
        }).replace(/@\{([\w-]+)\}/g, function (_, name) {
 
3948
            var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true);
 
3949
            return (v instanceof tree.Quoted) ? v.value : v.toCSS();
 
3950
        });
 
3951
        return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
 
3952
    },
 
3953
    compare: function (x) {
 
3954
        if (!x.toCSS) {
 
3955
            return -1;
 
3956
        }
 
3957
        
 
3958
        var left = this.toCSS(),
 
3959
            right = x.toCSS();
 
3960
        
 
3961
        if (left === right) {
 
3962
            return 0;
 
3963
        }
 
3964
        
 
3965
        return left < right ? -1 : 1;
 
3966
    }
 
3967
};
 
3968
 
 
3969
})(require('../tree'));
 
3970
(function (tree) {
 
3971
 
 
3972
tree.Rule = function (name, value, important, index, currentFileInfo, inline) {
 
3973
    this.name = name;
 
3974
    this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
 
3975
    this.important = important ? ' ' + important.trim() : '';
 
3976
    this.index = index;
 
3977
    this.currentFileInfo = currentFileInfo;
 
3978
    this.inline = inline || false;
 
3979
 
 
3980
    if (name.charAt(0) === '@') {
 
3981
        this.variable = true;
 
3982
    } else { this.variable = false }
 
3983
};
 
3984
 
 
3985
tree.Rule.prototype = {
 
3986
    type: "Rule",
 
3987
    accept: function (visitor) {
 
3988
        this.value = visitor.visit(this.value);
 
3989
    },
 
3990
    toCSS: function (env) {
 
3991
        if (this.variable) { return "" }
 
3992
        else {
 
3993
            try {
 
3994
                return this.name + (env.compress ? ':' : ': ') +
 
3995
                   this.value.toCSS(env) +
 
3996
                   this.important + (this.inline ? "" : ";");
 
3997
            }
 
3998
            catch(e) {
 
3999
                e.index = this.index;
 
4000
                e.filename = this.currentFileInfo.filename;
 
4001
                throw e;
 
4002
            }
 
4003
        }
 
4004
    },
 
4005
    eval: function (env) {
 
4006
        var strictMathsBypass = false;
 
4007
        if (this.name === "font" && env.strictMaths === false) {
 
4008
            strictMathsBypass = true;
 
4009
            env.strictMaths = true;
 
4010
        }
 
4011
        try {
 
4012
            return new(tree.Rule)(this.name,
 
4013
                              this.value.eval(env),
 
4014
                              this.important,
 
4015
                              this.index, this.currentFileInfo, this.inline);
 
4016
        }
 
4017
        finally {
 
4018
            if (strictMathsBypass) {
 
4019
                env.strictMaths = false;
 
4020
            }
 
4021
        }
 
4022
    },
 
4023
    makeImportant: function () {
 
4024
        return new(tree.Rule)(this.name,
 
4025
                              this.value,
 
4026
                              "!important",
 
4027
                              this.index, this.currentFileInfo, this.inline);
 
4028
    }
 
4029
};
 
4030
 
 
4031
})(require('../tree'));
 
4032
(function (tree) {
 
4033
 
 
4034
tree.Ruleset = function (selectors, rules, strictImports) {
 
4035
    this.selectors = selectors;
 
4036
    this.rules = rules;
 
4037
    this._lookups = {};
 
4038
    this.strictImports = strictImports;
 
4039
};
 
4040
tree.Ruleset.prototype = {
 
4041
    type: "Ruleset",
 
4042
    accept: function (visitor) {
 
4043
        this.selectors = visitor.visit(this.selectors);
 
4044
        this.rules = visitor.visit(this.rules);
 
4045
    },
 
4046
    eval: function (env) {
 
4047
        var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
 
4048
        var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
 
4049
        var rules;
 
4050
        
 
4051
        ruleset.originalRuleset = this;
 
4052
        ruleset.root = this.root;
 
4053
        ruleset.firstRoot = this.firstRoot;
 
4054
        ruleset.allowImports = this.allowImports;
 
4055
 
 
4056
        if(this.debugInfo) {
 
4057
            ruleset.debugInfo = this.debugInfo;
 
4058
        }
 
4059
 
 
4060
        // push the current ruleset to the frames stack
 
4061
        env.frames.unshift(ruleset);
 
4062
 
 
4063
        // currrent selectors
 
4064
        if (!env.selectors) {
 
4065
            env.selectors = [];
 
4066
        }
 
4067
        env.selectors.unshift(this.selectors);
 
4068
 
 
4069
        // Evaluate imports
 
4070
        if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
 
4071
            ruleset.evalImports(env);
 
4072
        }
 
4073
 
 
4074
        // Store the frames around mixin definitions,
 
4075
        // so they can be evaluated like closures when the time comes.
 
4076
        for (var i = 0; i < ruleset.rules.length; i++) {
 
4077
            if (ruleset.rules[i] instanceof tree.mixin.Definition) {
 
4078
                ruleset.rules[i].frames = env.frames.slice(0);
 
4079
            }
 
4080
        }
 
4081
        
 
4082
        var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
 
4083
 
 
4084
        // Evaluate mixin calls.
 
4085
        for (var i = 0; i < ruleset.rules.length; i++) {
 
4086
            if (ruleset.rules[i] instanceof tree.mixin.Call) {
 
4087
                rules = ruleset.rules[i].eval(env).filter(function(r) {
 
4088
                    if ((r instanceof tree.Rule) && r.variable) {
 
4089
                        // do not pollute the scope if the variable is
 
4090
                        // already there. consider returning false here
 
4091
                        // but we need a way to "return" variable from mixins
 
4092
                        return !(ruleset.variable(r.name));
 
4093
                    }
 
4094
                    return true;
 
4095
                });
 
4096
                ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
 
4097
                i += rules.length-1;
 
4098
                ruleset.resetCache();
 
4099
            }
 
4100
        }
 
4101
        
 
4102
        // Evaluate everything else
 
4103
        for (var i = 0, rule; i < ruleset.rules.length; i++) {
 
4104
            rule = ruleset.rules[i];
 
4105
 
 
4106
            if (! (rule instanceof tree.mixin.Definition)) {
 
4107
                ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
 
4108
            }
 
4109
        }
 
4110
 
 
4111
        // Pop the stack
 
4112
        env.frames.shift();
 
4113
        env.selectors.shift();
 
4114
        
 
4115
        if (env.mediaBlocks) {
 
4116
            for(var i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
 
4117
                env.mediaBlocks[i].bubbleSelectors(selectors);
 
4118
            }
 
4119
        }
 
4120
 
 
4121
        return ruleset;
 
4122
    },
 
4123
    evalImports: function(env) {
 
4124
        var i, rules;
 
4125
        for (i = 0; i < this.rules.length; i++) {
 
4126
            if (this.rules[i] instanceof tree.Import) {
 
4127
                rules = this.rules[i].eval(env);
 
4128
                if (typeof rules.length === "number") {
 
4129
                    this.rules.splice.apply(this.rules, [i, 1].concat(rules));
 
4130
                    i+= rules.length-1;
 
4131
                } else {
 
4132
                    this.rules.splice(i, 1, rules);
 
4133
                }
 
4134
                this.resetCache();
 
4135
            }
 
4136
        }
 
4137
    },
 
4138
    makeImportant: function() {
 
4139
        return new tree.Ruleset(this.selectors, this.rules.map(function (r) {
 
4140
                    if (r.makeImportant) {
 
4141
                        return r.makeImportant();
 
4142
                    } else {
 
4143
                        return r;
 
4144
                    }
 
4145
                }), this.strictImports);
 
4146
    },
 
4147
    matchArgs: function (args) {
 
4148
        return !args || args.length === 0;
 
4149
    },
 
4150
    resetCache: function () {
 
4151
        this._rulesets = null;
 
4152
        this._variables = null;
 
4153
        this._lookups = {};
 
4154
    },
 
4155
    variables: function () {
 
4156
        if (this._variables) { return this._variables }
 
4157
        else {
 
4158
            return this._variables = this.rules.reduce(function (hash, r) {
 
4159
                if (r instanceof tree.Rule && r.variable === true) {
 
4160
                    hash[r.name] = r;
 
4161
                }
 
4162
                return hash;
 
4163
            }, {});
 
4164
        }
 
4165
    },
 
4166
    variable: function (name) {
 
4167
        return this.variables()[name];
 
4168
    },
 
4169
    rulesets: function () {
 
4170
        return this.rules.filter(function (r) {
 
4171
            return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
 
4172
        });
 
4173
    },
 
4174
    find: function (selector, self) {
 
4175
        self = self || this;
 
4176
        var rules = [], rule, match,
 
4177
            key = selector.toCSS();
 
4178
 
 
4179
        if (key in this._lookups) { return this._lookups[key] }
 
4180
 
 
4181
        this.rulesets().forEach(function (rule) {
 
4182
            if (rule !== self) {
 
4183
                for (var j = 0; j < rule.selectors.length; j++) {
 
4184
                    if (match = selector.match(rule.selectors[j])) {
 
4185
                        if (selector.elements.length > rule.selectors[j].elements.length) {
 
4186
                            Array.prototype.push.apply(rules, rule.find(
 
4187
                                new(tree.Selector)(selector.elements.slice(1)), self));
 
4188
                        } else {
 
4189
                            rules.push(rule);
 
4190
                        }
 
4191
                        break;
 
4192
                    }
 
4193
                }
 
4194
            }
 
4195
        });
 
4196
        return this._lookups[key] = rules;
 
4197
    },
 
4198
    //
 
4199
    // Entry point for code generation
 
4200
    //
 
4201
    //     `context` holds an array of arrays.
 
4202
    //
 
4203
    toCSS: function (env) {
 
4204
        var css = [],      // The CSS output
 
4205
            rules = [],    // node.Rule instances
 
4206
           _rules = [],    //
 
4207
            rulesets = [], // node.Ruleset instances
 
4208
            selector,      // The fully rendered selector
 
4209
            debugInfo,     // Line number debugging
 
4210
            rule;
 
4211
 
 
4212
        // Compile rules and rulesets
 
4213
        for (var i = 0; i < this.rules.length; i++) {
 
4214
            rule = this.rules[i];
 
4215
 
 
4216
            if (rule.rules || (rule instanceof tree.Media)) {
 
4217
                rulesets.push(rule.toCSS(env));
 
4218
            } else if (rule instanceof tree.Directive) {
 
4219
                var cssValue = rule.toCSS(env);
 
4220
                // Output only the first @charset definition as such - convert the others
 
4221
                // to comments in case debug is enabled
 
4222
                if (rule.name === "@charset") {
 
4223
                    // Only output the debug info together with subsequent @charset definitions
 
4224
                    // a comment (or @media statement) before the actual @charset directive would
 
4225
                    // be considered illegal css as it has to be on the first line
 
4226
                    if (env.charset) {
 
4227
                        if (rule.debugInfo) {
 
4228
                            rulesets.push(tree.debugInfo(env, rule));
 
4229
                            rulesets.push(new tree.Comment("/* "+cssValue.replace(/\n/g, "")+" */\n").toCSS(env));
 
4230
                        }
 
4231
                        continue;
 
4232
                    }
 
4233
                    env.charset = true;
 
4234
                }
 
4235
                rulesets.push(cssValue);
 
4236
            } else if (rule instanceof tree.Comment) {
 
4237
                if (!rule.silent) {
 
4238
                    if (this.root) {
 
4239
                        rulesets.push(rule.toCSS(env));
 
4240
                    } else {
 
4241
                        rules.push(rule.toCSS(env));
 
4242
                    }
 
4243
                }
 
4244
            } else {
 
4245
                if (rule.toCSS && !rule.variable) {
 
4246
                    if (this.firstRoot && rule instanceof tree.Rule) {
 
4247
                        throw { message: "properties must be inside selector blocks, they cannot be in the root.",
 
4248
                            index: rule.index, filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null};
 
4249
                    }
 
4250
                    rules.push(rule.toCSS(env));
 
4251
                } else if (rule.value && !rule.variable) {
 
4252
                    rules.push(rule.value.toString());
 
4253
                }
 
4254
            }
 
4255
        } 
 
4256
 
 
4257
        // Remove last semicolon
 
4258
        if (env.compress && rules.length) {
 
4259
            rule = rules[rules.length - 1];
 
4260
            if (rule.charAt(rule.length - 1) === ';') {
 
4261
                rules[rules.length - 1] = rule.substring(0, rule.length - 1);
 
4262
            }
 
4263
        }
 
4264
 
 
4265
        rulesets = rulesets.join('');
 
4266
 
 
4267
        // If this is the root node, we don't render
 
4268
        // a selector, or {}.
 
4269
        // Otherwise, only output if this ruleset has rules.
 
4270
        if (this.root) {
 
4271
            css.push(rules.join(env.compress ? '' : '\n'));
 
4272
        } else {
 
4273
            if (rules.length > 0) {
 
4274
                debugInfo = tree.debugInfo(env, this);
 
4275
                selector = this.paths.map(function (p) {
 
4276
                    return p.map(function (s) {
 
4277
                        return s.toCSS(env);
 
4278
                    }).join('').trim();
 
4279
                }).join(env.compress ? ',' : ',\n');
 
4280
 
 
4281
                // Remove duplicates
 
4282
                for (var i = rules.length - 1; i >= 0; i--) {
 
4283
                    if (rules[i].slice(0, 2) === "/*" ||  _rules.indexOf(rules[i]) === -1) {
 
4284
                        _rules.unshift(rules[i]);
 
4285
                    }
 
4286
                }
 
4287
                rules = _rules;
 
4288
 
 
4289
                css.push(debugInfo + selector + 
 
4290
                        (env.compress ? '{' : ' {\n  ') +
 
4291
                        rules.join(env.compress ? '' : '\n  ') +
 
4292
                        (env.compress ? '}' : '\n}\n'));
 
4293
            }
 
4294
        }
 
4295
        css.push(rulesets);
 
4296
 
 
4297
        return css.join('')  + (env.compress ? '\n' : '');
 
4298
    },
 
4299
 
 
4300
    joinSelectors: function (paths, context, selectors) {
 
4301
        for (var s = 0; s < selectors.length; s++) {
 
4302
            this.joinSelector(paths, context, selectors[s]);
 
4303
        }
 
4304
    },
 
4305
 
 
4306
    joinSelector: function (paths, context, selector) {
 
4307
 
 
4308
        var i, j, k, 
 
4309
            hasParentSelector, newSelectors, el, sel, parentSel, 
 
4310
            newSelectorPath, afterParentJoin, newJoinedSelector, 
 
4311
            newJoinedSelectorEmpty, lastSelector, currentElements,
 
4312
            selectorsMultiplied;
 
4313
    
 
4314
        for (i = 0; i < selector.elements.length; i++) {
 
4315
            el = selector.elements[i];
 
4316
            if (el.value === '&') {
 
4317
                hasParentSelector = true;
 
4318
            }
 
4319
        }
 
4320
    
 
4321
        if (!hasParentSelector) {
 
4322
            if (context.length > 0) {
 
4323
                for(i = 0; i < context.length; i++) {
 
4324
                    paths.push(context[i].concat(selector));
 
4325
                }
 
4326
            }
 
4327
            else {
 
4328
                paths.push([selector]);
 
4329
            }
 
4330
            return;
 
4331
        }
 
4332
 
 
4333
        // The paths are [[Selector]]
 
4334
        // The first list is a list of comma seperated selectors
 
4335
        // The inner list is a list of inheritance seperated selectors
 
4336
        // e.g.
 
4337
        // .a, .b {
 
4338
        //   .c {
 
4339
        //   }
 
4340
        // }
 
4341
        // == [[.a] [.c]] [[.b] [.c]]
 
4342
        //
 
4343
 
 
4344
        // the elements from the current selector so far
 
4345
        currentElements = [];
 
4346
        // the current list of new selectors to add to the path.
 
4347
        // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
 
4348
        // by the parents
 
4349
        newSelectors = [[]];
 
4350
 
 
4351
        for (i = 0; i < selector.elements.length; i++) {
 
4352
            el = selector.elements[i];
 
4353
            // non parent reference elements just get added
 
4354
            if (el.value !== "&") {
 
4355
                currentElements.push(el);
 
4356
            } else {
 
4357
                // the new list of selectors to add
 
4358
                selectorsMultiplied = [];
 
4359
 
 
4360
                // merge the current list of non parent selector elements
 
4361
                // on to the current list of selectors to add
 
4362
                if (currentElements.length > 0) {
 
4363
                    this.mergeElementsOnToSelectors(currentElements, newSelectors);
 
4364
                }
 
4365
 
 
4366
                // loop through our current selectors
 
4367
                for(j = 0; j < newSelectors.length; j++) {
 
4368
                    sel = newSelectors[j];
 
4369
                    // if we don't have any parent paths, the & might be in a mixin so that it can be used
 
4370
                    // whether there are parents or not
 
4371
                    if (context.length == 0) {
 
4372
                        // the combinator used on el should now be applied to the next element instead so that
 
4373
                        // it is not lost
 
4374
                        if (sel.length > 0) {
 
4375
                            sel[0].elements = sel[0].elements.slice(0);
 
4376
                            sel[0].elements.push(new(tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator,  ""));
 
4377
                        }
 
4378
                        selectorsMultiplied.push(sel);
 
4379
                    }
 
4380
                    else {
 
4381
                        // and the parent selectors
 
4382
                        for(k = 0; k < context.length; k++) {
 
4383
                            parentSel = context[k];
 
4384
                            // We need to put the current selectors
 
4385
                            // then join the last selector's elements on to the parents selectors
 
4386
 
 
4387
                            // our new selector path
 
4388
                            newSelectorPath = [];
 
4389
                            // selectors from the parent after the join
 
4390
                            afterParentJoin = [];
 
4391
                            newJoinedSelectorEmpty = true;
 
4392
 
 
4393
                            //construct the joined selector - if & is the first thing this will be empty,
 
4394
                            // if not newJoinedSelector will be the last set of elements in the selector
 
4395
                            if (sel.length > 0) {
 
4396
                                newSelectorPath = sel.slice(0);
 
4397
                                lastSelector = newSelectorPath.pop();
 
4398
                                newJoinedSelector = new(tree.Selector)(lastSelector.elements.slice(0), selector.extendList);
 
4399
                                newJoinedSelectorEmpty = false;
 
4400
                            }
 
4401
                            else {
 
4402
                                newJoinedSelector = new(tree.Selector)([], selector.extendList);
 
4403
                            }
 
4404
 
 
4405
                            //put together the parent selectors after the join
 
4406
                            if (parentSel.length > 1) {
 
4407
                                afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
 
4408
                            }
 
4409
 
 
4410
                            if (parentSel.length > 0) {
 
4411
                                newJoinedSelectorEmpty = false;
 
4412
 
 
4413
                                // join the elements so far with the first part of the parent
 
4414
                                newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, 0));
 
4415
                                newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
 
4416
                            }
 
4417
 
 
4418
                            if (!newJoinedSelectorEmpty) {
 
4419
                                // now add the joined selector
 
4420
                                newSelectorPath.push(newJoinedSelector);
 
4421
                            }
 
4422
 
 
4423
                            // and the rest of the parent
 
4424
                            newSelectorPath = newSelectorPath.concat(afterParentJoin);
 
4425
 
 
4426
                            // add that to our new set of selectors
 
4427
                            selectorsMultiplied.push(newSelectorPath);
 
4428
                        }
 
4429
                    }
 
4430
                }
 
4431
 
 
4432
                // our new selectors has been multiplied, so reset the state
 
4433
                newSelectors = selectorsMultiplied;
 
4434
                currentElements = [];
 
4435
            }
 
4436
        }
 
4437
 
 
4438
        // if we have any elements left over (e.g. .a& .b == .b)
 
4439
        // add them on to all the current selectors
 
4440
        if (currentElements.length > 0) {
 
4441
            this.mergeElementsOnToSelectors(currentElements, newSelectors);
 
4442
        }
 
4443
 
 
4444
        for(i = 0; i < newSelectors.length; i++) {
 
4445
            if (newSelectors[i].length > 0) {
 
4446
                paths.push(newSelectors[i]);
 
4447
            }
 
4448
        }
 
4449
    },
 
4450
    
 
4451
    mergeElementsOnToSelectors: function(elements, selectors) {
 
4452
        var i, sel, extendList;
 
4453
 
 
4454
        if (selectors.length == 0) {
 
4455
            selectors.push([ new(tree.Selector)(elements) ]);
 
4456
            return;
 
4457
        }
 
4458
 
 
4459
        for(i = 0; i < selectors.length; i++) {
 
4460
            sel = selectors[i];
 
4461
 
 
4462
            // if the previous thing in sel is a parent this needs to join on to it
 
4463
            if (sel.length > 0) {
 
4464
                sel[sel.length - 1] = new(tree.Selector)(sel[sel.length - 1].elements.concat(elements), sel[sel.length - 1].extendList);
 
4465
            }
 
4466
            else {
 
4467
                sel.push(new(tree.Selector)(elements));
 
4468
            }
 
4469
        }
 
4470
    }
 
4471
};
 
4472
})(require('../tree'));
 
4473
(function (tree) {
 
4474
 
 
4475
tree.Selector = function (elements, extendList) {
 
4476
    this.elements = elements;
 
4477
    this.extendList = extendList || [];
 
4478
};
 
4479
tree.Selector.prototype = {
 
4480
    type: "Selector",
 
4481
    accept: function (visitor) {
 
4482
        this.elements = visitor.visit(this.elements);
 
4483
        this.extendList = visitor.visit(this.extendList)
 
4484
    },
 
4485
    match: function (other) {
 
4486
        var elements = this.elements,
 
4487
            len = elements.length,
 
4488
            oelements, olen, max, i;
 
4489
 
 
4490
        oelements = other.elements.slice(
 
4491
            (other.elements.length && other.elements[0].value === "&") ? 1 : 0);
 
4492
        olen = oelements.length;
 
4493
        max = Math.min(len, olen);
 
4494
 
 
4495
        if (olen === 0 || len < olen) {
 
4496
            return false;
 
4497
        } else {
 
4498
            for (i = 0; i < max; i++) {
 
4499
                if (elements[i].value !== oelements[i].value) {
 
4500
                    return false;
 
4501
                }
 
4502
            }
 
4503
        }
 
4504
        return true;
 
4505
    },
 
4506
    eval: function (env) {
 
4507
        return new(tree.Selector)(this.elements.map(function (e) {
 
4508
            return e.eval(env);
 
4509
        }), this.extendList.map(function(extend) {
 
4510
            return extend.eval(env);
 
4511
        }));
 
4512
    },
 
4513
    toCSS: function (env) {
 
4514
        if (this._css) { return this._css }
 
4515
 
 
4516
        if (this.elements[0].combinator.value === "") {
 
4517
            this._css = ' ';
 
4518
        } else {
 
4519
            this._css = '';
 
4520
        }
 
4521
 
 
4522
        this._css += this.elements.map(function (e) {
 
4523
            if (typeof(e) === 'string') {
 
4524
                return ' ' + e.trim();
 
4525
            } else {
 
4526
                return e.toCSS(env);
 
4527
            }
 
4528
        }).join('');
 
4529
 
 
4530
        return this._css;
 
4531
    }
 
4532
};
 
4533
 
 
4534
})(require('../tree'));
 
4535
(function (tree) {
 
4536
 
 
4537
tree.UnicodeDescriptor = function (value) {
 
4538
    this.value = value;
 
4539
};
 
4540
tree.UnicodeDescriptor.prototype = {
 
4541
    type: "UnicodeDescriptor",
 
4542
    toCSS: function (env) {
 
4543
        return this.value;
 
4544
    },
 
4545
    eval: function () { return this }
 
4546
};
 
4547
 
 
4548
})(require('../tree'));
 
4549
(function (tree) {
 
4550
 
 
4551
tree.URL = function (val, currentFileInfo) {
 
4552
    this.value = val;
 
4553
    this.currentFileInfo = currentFileInfo;
 
4554
};
 
4555
tree.URL.prototype = {
 
4556
    type: "Url",
 
4557
    accept: function (visitor) {
 
4558
        this.value = visitor.visit(this.value);
 
4559
    },
 
4560
    toCSS: function () {
 
4561
        return "url(" + this.value.toCSS() + ")";
 
4562
    },
 
4563
    eval: function (ctx) {
 
4564
        var val = this.value.eval(ctx), rootpath;
 
4565
 
 
4566
        // Add the base path if the URL is relative
 
4567
        rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
 
4568
        if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) {
 
4569
            if (!val.quote) {
 
4570
                rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
 
4571
            }
 
4572
            val.value = rootpath + val.value;
 
4573
        }
 
4574
 
 
4575
        return new(tree.URL)(val, null);
 
4576
    }
 
4577
};
 
4578
 
 
4579
})(require('../tree'));
 
4580
(function (tree) {
 
4581
 
 
4582
tree.Value = function (value) {
 
4583
    this.value = value;
 
4584
};
 
4585
tree.Value.prototype = {
 
4586
    type: "Value",
 
4587
    accept: function (visitor) {
 
4588
        this.value = visitor.visit(this.value);
 
4589
    },
 
4590
    eval: function (env) {
 
4591
        if (this.value.length === 1) {
 
4592
            return this.value[0].eval(env);
 
4593
        } else {
 
4594
            return new(tree.Value)(this.value.map(function (v) {
 
4595
                return v.eval(env);
 
4596
            }));
 
4597
        }
 
4598
    },
 
4599
    toCSS: function (env) {
 
4600
        return this.value.map(function (e) {
 
4601
            return e.toCSS(env);
 
4602
        }).join(env.compress ? ',' : ', ');
 
4603
    }
 
4604
};
 
4605
 
 
4606
})(require('../tree'));
 
4607
(function (tree) {
 
4608
 
 
4609
tree.Variable = function (name, index, currentFileInfo) { this.name = name, this.index = index, this.currentFileInfo = currentFileInfo };
 
4610
tree.Variable.prototype = {
 
4611
    type: "Variable",
 
4612
    eval: function (env) {
 
4613
        var variable, v, name = this.name;
 
4614
 
 
4615
        if (name.indexOf('@@') == 0) {
 
4616
            name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
 
4617
        }
 
4618
        
 
4619
        if (this.evaluating) {
 
4620
            throw { type: 'Name',
 
4621
                    message: "Recursive variable definition for " + name,
 
4622
                    filename: this.currentFileInfo.file,
 
4623
                    index: this.index };
 
4624
        }
 
4625
        
 
4626
        this.evaluating = true;
 
4627
 
 
4628
        if (variable = tree.find(env.frames, function (frame) {
 
4629
            if (v = frame.variable(name)) {
 
4630
                return v.value.eval(env);
 
4631
            }
 
4632
        })) { 
 
4633
            this.evaluating = false;
 
4634
            return variable;
 
4635
        }
 
4636
        else {
 
4637
            throw { type: 'Name',
 
4638
                    message: "variable " + name + " is undefined",
 
4639
                    filename: this.currentFileInfo.filename,
 
4640
                    index: this.index };
 
4641
        }
 
4642
    }
 
4643
};
 
4644
 
 
4645
})(require('../tree'));
 
4646
(function (tree) {
 
4647
 
 
4648
tree.debugInfo = function(env, ctx) {
 
4649
    var result="";
 
4650
    if (env.dumpLineNumbers && !env.compress) {
 
4651
        switch(env.dumpLineNumbers) {
 
4652
            case 'comments':
 
4653
                result = tree.debugInfo.asComment(ctx);
 
4654
                break;
 
4655
            case 'mediaquery':
 
4656
                result = tree.debugInfo.asMediaQuery(ctx);
 
4657
                break;
 
4658
            case 'all':
 
4659
                result = tree.debugInfo.asComment(ctx)+tree.debugInfo.asMediaQuery(ctx);
 
4660
                break;
 
4661
        }
 
4662
    }
 
4663
    return result;
 
4664
};
 
4665
 
 
4666
tree.debugInfo.asComment = function(ctx) {
 
4667
    return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
 
4668
};
 
4669
 
 
4670
tree.debugInfo.asMediaQuery = function(ctx) {
 
4671
    return '@media -sass-debug-info{filename{font-family:' +
 
4672
        ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function(a){if(a=='\\') a = '\/'; return '\\' + a}) +
 
4673
        '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
 
4674
};
 
4675
 
 
4676
tree.find = function (obj, fun) {
 
4677
    for (var i = 0, r; i < obj.length; i++) {
 
4678
        if (r = fun.call(obj, obj[i])) { return r }
 
4679
    }
 
4680
    return null;
 
4681
};
 
4682
tree.jsify = function (obj) {
 
4683
    if (Array.isArray(obj.value) && (obj.value.length > 1)) {
 
4684
        return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
 
4685
    } else {
 
4686
        return obj.toCSS(false);
 
4687
    }
 
4688
};
 
4689
 
 
4690
})(require('./tree'));
 
4691
(function (tree) {
 
4692
 
 
4693
    var parseCopyProperties = [
 
4694
        'paths',            // option - unmodified - paths to search for imports on
 
4695
        'optimization',     // option - optimization level (for the chunker)
 
4696
        'files',            // list of files that have been imported, used for import-once
 
4697
        'contents',         // browser-only, contents of all the files
 
4698
        'relativeUrls',     // option - whether to adjust URL's to be relative
 
4699
        'strictImports',    // option -
 
4700
        'dumpLineNumbers',  // option - whether to dump line numbers
 
4701
        'compress',         // option - whether to compress
 
4702
        'processImports',   // option - whether to process imports. if false then imports will not be imported
 
4703
        'mime',             // browser only - mime type for sheet import
 
4704
        'currentFileInfo'   // information about the current file - for error reporting and importing and making urls relative etc.
 
4705
    ];
 
4706
 
 
4707
    //currentFileInfo = {
 
4708
    //  'relativeUrls' - option - whether to adjust URL's to be relative
 
4709
    //  'filename' - full resolved filename of current file
 
4710
    //  'rootpath' - path to append to normal URLs for this node
 
4711
    //  'currentDirectory' - path to the current file, absolute
 
4712
    //  'rootFilename' - filename of the base file
 
4713
    //  'entryPath' = absolute path to the entry file
 
4714
 
 
4715
    tree.parseEnv = function(options) {
 
4716
        copyFromOriginal(options, this, parseCopyProperties);
 
4717
 
 
4718
        if (!this.contents) { this.contents = {}; }
 
4719
        if (!this.files) { this.files = {}; }
 
4720
 
 
4721
        if (!this.currentFileInfo) {
 
4722
            var filename = options.filename || "input";
 
4723
            options.filename = null;
 
4724
            var entryPath = filename.replace(/[^\/\\]*$/, "");
 
4725
            this.currentFileInfo = {
 
4726
                filename: filename,
 
4727
                relativeUrls: this.relativeUrls,
 
4728
                rootpath: options.rootpath || "",
 
4729
                currentDirectory: entryPath,
 
4730
                entryPath: entryPath,
 
4731
                rootFilename: filename
 
4732
            };
 
4733
        }
 
4734
    };
 
4735
 
 
4736
    tree.parseEnv.prototype.toSheet = function (path) {
 
4737
        var env = new tree.parseEnv(this);
 
4738
        env.href = path;
 
4739
        //env.title = path;
 
4740
        env.type = this.mime;
 
4741
        return env;
 
4742
    };
 
4743
 
 
4744
    var evalCopyProperties = [
 
4745
        'silent',      // whether to swallow errors and warnings
 
4746
        'verbose',     // whether to log more activity
 
4747
        'compress',    // whether to compress
 
4748
        'ieCompat',    // whether to enforce IE compatibility (IE8 data-uri)
 
4749
        'strictMaths', // whether maths has to be within parenthesis
 
4750
        'strictUnits'  // whether units need to evaluate correctly
 
4751
        ];
 
4752
 
 
4753
    tree.evalEnv = function(options, frames) {
 
4754
        copyFromOriginal(options, this, evalCopyProperties);
 
4755
 
 
4756
        this.frames = frames || [];
 
4757
    };
 
4758
 
 
4759
    tree.evalEnv.prototype.inParenthesis = function () {
 
4760
        if (!this.parensStack) {
 
4761
            this.parensStack = [];
 
4762
        }
 
4763
        this.parensStack.push(true);
 
4764
    };
 
4765
 
 
4766
    tree.evalEnv.prototype.outOfParenthesis = function () {
 
4767
        this.parensStack.pop();
 
4768
    };
 
4769
 
 
4770
    tree.evalEnv.prototype.isMathsOn = function () {
 
4771
        return this.strictMaths === false ? true : (this.parensStack && this.parensStack.length);
 
4772
    };
 
4773
 
 
4774
    tree.evalEnv.prototype.isPathRelative = function (path) {
 
4775
        return !/^(?:[a-z-]+:|\/)/.test(path);
 
4776
    };
 
4777
 
 
4778
    //todo - do the same for the toCSS env
 
4779
    //tree.toCSSEnv = function (options) {
 
4780
    //};
 
4781
 
 
4782
    var copyFromOriginal = function(original, destination, propertiesToCopy) {
 
4783
        if (!original) { return; }
 
4784
 
 
4785
        for(var i = 0; i < propertiesToCopy.length; i++) {
 
4786
            if (original.hasOwnProperty(propertiesToCopy[i])) {
 
4787
                destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
 
4788
            }
 
4789
        }
 
4790
    }
 
4791
})(require('./tree'));(function (tree) {
 
4792
 
 
4793
    tree.visitor = function(implementation) {
 
4794
        this._implementation = implementation;
 
4795
    };
 
4796
 
 
4797
    tree.visitor.prototype = {
 
4798
        visit: function(node) {
 
4799
 
 
4800
            if (node instanceof Array) {
 
4801
                return this.visitArray(node);
 
4802
            }
 
4803
 
 
4804
            if (!node || !node.type) {
 
4805
                return node;
 
4806
            }
 
4807
 
 
4808
            var funcName = "visit" + node.type,
 
4809
                func = this._implementation[funcName],
 
4810
                visitArgs, newNode;
 
4811
            if (func) {
 
4812
                visitArgs = {visitDeeper: true};
 
4813
                newNode = func.call(this._implementation, node, visitArgs);
 
4814
                if (this._implementation.isReplacing) {
 
4815
                    node = newNode;
 
4816
                }
 
4817
            }
 
4818
            if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) {
 
4819
                node.accept(this);
 
4820
            }
 
4821
            funcName = funcName + "Out";
 
4822
            if (this._implementation[funcName]) {
 
4823
                this._implementation[funcName](node);
 
4824
            }
 
4825
            return node;
 
4826
        },
 
4827
        visitArray: function(nodes) {
 
4828
            var i, newNodes = [];
 
4829
            for(i = 0; i < nodes.length; i++) {
 
4830
                var evald = this.visit(nodes[i]);
 
4831
                if (evald instanceof Array) {
 
4832
                    newNodes = newNodes.concat(evald);
 
4833
                } else {
 
4834
                    newNodes.push(evald);
 
4835
                }
 
4836
            }
 
4837
            if (this._implementation.isReplacing) {
 
4838
                return newNodes;
 
4839
            }
 
4840
            return nodes;
 
4841
        }
 
4842
    };
 
4843
 
 
4844
})(require('./tree'));(function (tree) {
 
4845
    tree.importVisitor = function(importer, finish, evalEnv) {
 
4846
        this._visitor = new tree.visitor(this);
 
4847
        this._importer = importer;
 
4848
        this._finish = finish;
 
4849
        this.env = evalEnv || new tree.evalEnv();
 
4850
        this.importCount = 0;
 
4851
    };
 
4852
 
 
4853
    tree.importVisitor.prototype = {
 
4854
        isReplacing: true,
 
4855
        run: function (root) {
 
4856
            var error;
 
4857
            try {
 
4858
                // process the contents
 
4859
                this._visitor.visit(root);
 
4860
            }
 
4861
            catch(e) {
 
4862
                error = e;
 
4863
            }
 
4864
 
 
4865
            this.isFinished = true;
 
4866
 
 
4867
            if (this.importCount === 0) {
 
4868
                this._finish(error);
 
4869
            }
 
4870
        },
 
4871
        visitImport: function (importNode, visitArgs) {
 
4872
            var importVisitor = this,
 
4873
                evaldImportNode;
 
4874
 
 
4875
            if (!importNode.css) {
 
4876
 
 
4877
                try {
 
4878
                    evaldImportNode = importNode.evalForImport(this.env);
 
4879
                } catch(e){
 
4880
                    if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
 
4881
                    // attempt to eval properly and treat as css
 
4882
                    importNode.css = true;
 
4883
                    // if that fails, this error will be thrown
 
4884
                    importNode.error = e;
 
4885
                }
 
4886
 
 
4887
                if (evaldImportNode && !evaldImportNode.css) {
 
4888
                    importNode = evaldImportNode;
 
4889
                    this.importCount++;
 
4890
                    var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
 
4891
                    this._importer.push(importNode.getPath(), importNode.currentFileInfo, function (e, root, imported) {
 
4892
                        if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
 
4893
                        if (imported && !importNode.options.multiple) { importNode.skip = imported; }
 
4894
 
 
4895
                        var subFinish = function(e) {
 
4896
                            importVisitor.importCount--;
 
4897
 
 
4898
                            if (importVisitor.importCount === 0 && importVisitor.isFinished) {
 
4899
                                importVisitor._finish(e);
 
4900
                            }
 
4901
                        };
 
4902
 
 
4903
                        if (root) {
 
4904
                            importNode.root = root;
 
4905
                            new(tree.importVisitor)(importVisitor._importer, subFinish, env)
 
4906
                                .run(root);
 
4907
                        } else {
 
4908
                            subFinish();
 
4909
                        }
 
4910
                    });
 
4911
                }
 
4912
            }
 
4913
            visitArgs.visitDeeper = false;
 
4914
            return importNode;
 
4915
        },
 
4916
        visitRule: function (ruleNode, visitArgs) {
 
4917
            visitArgs.visitDeeper = false;
 
4918
            return ruleNode;
 
4919
        },
 
4920
        visitDirective: function (directiveNode, visitArgs) {
 
4921
            this.env.frames.unshift(directiveNode);
 
4922
            return directiveNode;
 
4923
        },
 
4924
        visitDirectiveOut: function (directiveNode) {
 
4925
            this.env.frames.shift();
 
4926
        },
 
4927
        visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
 
4928
            this.env.frames.unshift(mixinDefinitionNode);
 
4929
            return mixinDefinitionNode;
 
4930
        },
 
4931
        visitMixinDefinitionOut: function (mixinDefinitionNode) {
 
4932
            this.env.frames.shift();
 
4933
        },
 
4934
        visitRuleset: function (rulesetNode, visitArgs) {
 
4935
            this.env.frames.unshift(rulesetNode);
 
4936
            return rulesetNode;
 
4937
        },
 
4938
        visitRulesetOut: function (rulesetNode) {
 
4939
            this.env.frames.shift();
 
4940
        },
 
4941
        visitMedia: function (mediaNode, visitArgs) {
 
4942
            this.env.frames.unshift(mediaNode.ruleset);
 
4943
            return mediaNode;
 
4944
        },
 
4945
        visitMediaOut: function (mediaNode) {
 
4946
            this.env.frames.shift();
 
4947
        }
 
4948
    };
 
4949
 
 
4950
})(require('./tree'));(function (tree) {
 
4951
    tree.joinSelectorVisitor = function() {
 
4952
        this.contexts = [[]];
 
4953
        this._visitor = new tree.visitor(this);
 
4954
    };
 
4955
 
 
4956
    tree.joinSelectorVisitor.prototype = {
 
4957
        run: function (root) {
 
4958
            return this._visitor.visit(root);
 
4959
        },
 
4960
        visitRule: function (ruleNode, visitArgs) {
 
4961
            visitArgs.visitDeeper = false;
 
4962
        },
 
4963
        visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
 
4964
            visitArgs.visitDeeper = false;
 
4965
        },
 
4966
 
 
4967
        visitRuleset: function (rulesetNode, visitArgs) {
 
4968
            var context = this.contexts[this.contexts.length - 1];
 
4969
            var paths = [];
 
4970
            this.contexts.push(paths);
 
4971
 
 
4972
            if (! rulesetNode.root) {
 
4973
                rulesetNode.joinSelectors(paths, context, rulesetNode.selectors);
 
4974
                rulesetNode.paths = paths;
 
4975
            }
 
4976
        },
 
4977
        visitRulesetOut: function (rulesetNode) {
 
4978
            this.contexts.length = this.contexts.length - 1;
 
4979
        },
 
4980
        visitMedia: function (mediaNode, visitArgs) {
 
4981
            var context = this.contexts[this.contexts.length - 1];
 
4982
            mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia);
 
4983
        }
 
4984
    };
 
4985
 
 
4986
})(require('./tree'));(function (tree) {
 
4987
    tree.extendFinderVisitor = function() {
 
4988
        this._visitor = new tree.visitor(this);
 
4989
        this.contexts = [];
 
4990
        this.allExtendsStack = [[]];
 
4991
    };
 
4992
 
 
4993
    tree.extendFinderVisitor.prototype = {
 
4994
        run: function (root) {
 
4995
            root = this._visitor.visit(root);
 
4996
            root.allExtends = this.allExtendsStack[0];
 
4997
            return root;
 
4998
        },
 
4999
        visitRule: function (ruleNode, visitArgs) {
 
5000
            visitArgs.visitDeeper = false;
 
5001
        },
 
5002
        visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
 
5003
            visitArgs.visitDeeper = false;
 
5004
        },
 
5005
        visitRuleset: function (rulesetNode, visitArgs) {
 
5006
 
 
5007
            if (rulesetNode.root) {
 
5008
                return;
 
5009
            }
 
5010
 
 
5011
            var i, j, extend, allSelectorsExtendList = [], extendList;
 
5012
 
 
5013
            // get &:extend(.a); rules which apply to all selectors in this ruleset
 
5014
            for(i = 0; i < rulesetNode.rules.length; i++) {
 
5015
                if (rulesetNode.rules[i] instanceof tree.Extend) {
 
5016
                    allSelectorsExtendList.push(rulesetNode.rules[i]);
 
5017
                }
 
5018
            }
 
5019
 
 
5020
            // now find every selector and apply the extends that apply to all extends
 
5021
            // and the ones which apply to an individual extend
 
5022
            for(i = 0; i < rulesetNode.paths.length; i++) {
 
5023
                var selectorPath = rulesetNode.paths[i],
 
5024
                    selector = selectorPath[selectorPath.length-1];
 
5025
                extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) {
 
5026
                    return allSelectorsExtend.clone();
 
5027
                });
 
5028
                for(j = 0; j < extendList.length; j++) {
 
5029
                    this.foundExtends = true;
 
5030
                    extend = extendList[j];
 
5031
                    extend.findSelfSelectors(selectorPath);
 
5032
                    extend.ruleset = rulesetNode;
 
5033
                    if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
 
5034
                    this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
 
5035
                }
 
5036
            }
 
5037
 
 
5038
            this.contexts.push(rulesetNode.selectors);
 
5039
        },
 
5040
        visitRulesetOut: function (rulesetNode) {
 
5041
            if (!rulesetNode.root) {
 
5042
                this.contexts.length = this.contexts.length - 1;
 
5043
            }
 
5044
        },
 
5045
        visitMedia: function (mediaNode, visitArgs) {
 
5046
            mediaNode.allExtends = [];
 
5047
            this.allExtendsStack.push(mediaNode.allExtends);
 
5048
        },
 
5049
        visitMediaOut: function (mediaNode) {
 
5050
            this.allExtendsStack.length = this.allExtendsStack.length - 1;
 
5051
        },
 
5052
        visitDirective: function (directiveNode, visitArgs) {
 
5053
            directiveNode.allExtends = [];
 
5054
            this.allExtendsStack.push(directiveNode.allExtends);
 
5055
        },
 
5056
        visitDirectiveOut: function (directiveNode) {
 
5057
            this.allExtendsStack.length = this.allExtendsStack.length - 1;
 
5058
        }
 
5059
    };
 
5060
 
 
5061
    tree.processExtendsVisitor = function() {
 
5062
        this._visitor = new tree.visitor(this);
 
5063
    };
 
5064
 
 
5065
    tree.processExtendsVisitor.prototype = {
 
5066
        run: function(root) {
 
5067
            var extendFinder = new tree.extendFinderVisitor();
 
5068
            extendFinder.run(root);
 
5069
            if (!extendFinder.foundExtends) { return root; }
 
5070
            root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
 
5071
            this.allExtendsStack = [root.allExtends];
 
5072
            return this._visitor.visit(root);
 
5073
        },
 
5074
        doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
 
5075
            //
 
5076
            // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
 
5077
            // the selector we would do normally, but we are also adding an extend with the same target selector
 
5078
            // this means this new extend can then go and alter other extends
 
5079
            //
 
5080
            // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
 
5081
            // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
 
5082
            // we look at each selector at a time, as is done in visitRuleset
 
5083
 
 
5084
            var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend;
 
5085
 
 
5086
            iterationCount = iterationCount || 0;
 
5087
 
 
5088
            //loop through comparing every extend with every target extend.
 
5089
            // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
 
5090
            // e.g.  .a:extend(.b) {}  and .b:extend(.c) {} then the first extend extends the second one
 
5091
            // and the second is the target.
 
5092
            // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
 
5093
            // case when processing media queries
 
5094
            for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
 
5095
                for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
 
5096
 
 
5097
                    extend = extendsList[extendIndex];
 
5098
                    targetExtend = extendsListTarget[targetExtendIndex];
 
5099
 
 
5100
                    // look for circular references
 
5101
                    if (this.inInheritanceChain(targetExtend, extend)) { continue; }
 
5102
 
 
5103
                    // find a match in the target extends self selector (the bit before :extend)
 
5104
                    selectorPath = [targetExtend.selfSelectors[0]];
 
5105
                    matches = extendVisitor.findMatch(extend, selectorPath);
 
5106
 
 
5107
                    if (matches.length) {
 
5108
 
 
5109
                        // we found a match, so for each self selector..
 
5110
                        extend.selfSelectors.forEach(function(selfSelector) {
 
5111
 
 
5112
                            // process the extend as usual
 
5113
                            newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
 
5114
 
 
5115
                            // but now we create a new extend from it
 
5116
                            newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0);
 
5117
                            newExtend.selfSelectors = newSelector;
 
5118
 
 
5119
                            // add the extend onto the list of extends for that selector
 
5120
                            newSelector[newSelector.length-1].extendList = [newExtend];
 
5121
 
 
5122
                            // record that we need to add it.
 
5123
                            extendsToAdd.push(newExtend);
 
5124
                            newExtend.ruleset = targetExtend.ruleset;
 
5125
 
 
5126
                            //remember its parents for circular references
 
5127
                            newExtend.parents = [targetExtend, extend];
 
5128
 
 
5129
                            // only process the selector once.. if we have :extend(.a,.b) then multiple
 
5130
                            // extends will look at the same selector path, so when extending
 
5131
                            // we know that any others will be duplicates in terms of what is added to the css
 
5132
                            if (targetExtend.firstExtendOnThisSelectorPath) {
 
5133
                                newExtend.firstExtendOnThisSelectorPath = true;
 
5134
                                targetExtend.ruleset.paths.push(newSelector);
 
5135
                            }
 
5136
                        });
 
5137
                    }
 
5138
                }
 
5139
            }
 
5140
 
 
5141
            if (extendsToAdd.length) {
 
5142
                // try to detect circular references to stop a stack overflow.
 
5143
                // may no longer be needed.
 
5144
                this.extendChainCount++;
 
5145
                if (iterationCount > 100) {
 
5146
                    var selectorOne = "{unable to calculate}";
 
5147
                    var selectorTwo = "{unable to calculate}";
 
5148
                    try
 
5149
                    {
 
5150
                        selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
 
5151
                        selectorTwo = extendsToAdd[0].selector.toCSS();
 
5152
                    }
 
5153
                    catch(e) {}
 
5154
                    throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
 
5155
                }
 
5156
 
 
5157
                // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
 
5158
                return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
 
5159
            } else {
 
5160
                return extendsToAdd;
 
5161
            }
 
5162
        },
 
5163
        inInheritanceChain: function (possibleParent, possibleChild) {
 
5164
            if (possibleParent === possibleChild) {
 
5165
                return true;
 
5166
            }
 
5167
            if (possibleChild.parents) {
 
5168
                if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) {
 
5169
                    return true;
 
5170
                }
 
5171
                if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) {
 
5172
                    return true;
 
5173
                }
 
5174
            }
 
5175
            return false;
 
5176
        },
 
5177
        visitRule: function (ruleNode, visitArgs) {
 
5178
            visitArgs.visitDeeper = false;
 
5179
        },
 
5180
        visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
 
5181
            visitArgs.visitDeeper = false;
 
5182
        },
 
5183
        visitSelector: function (selectorNode, visitArgs) {
 
5184
            visitArgs.visitDeeper = false;
 
5185
        },
 
5186
        visitRuleset: function (rulesetNode, visitArgs) {
 
5187
            if (rulesetNode.root) {
 
5188
                return;
 
5189
            }
 
5190
            var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this;
 
5191
 
 
5192
            // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
 
5193
 
 
5194
            for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
 
5195
                for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
 
5196
 
 
5197
                    selectorPath = rulesetNode.paths[pathIndex];
 
5198
 
 
5199
                    // extending extends happens initially, before the main pass
 
5200
                    if (selectorPath[selectorPath.length-1].extendList.length) { continue; }
 
5201
 
 
5202
                    matches = this.findMatch(allExtends[extendIndex], selectorPath);
 
5203
 
 
5204
                    if (matches.length) {
 
5205
 
 
5206
                        allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
 
5207
                            selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
 
5208
                        });
 
5209
                    }
 
5210
                }
 
5211
            }
 
5212
            rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
 
5213
        },
 
5214
        findMatch: function (extend, haystackSelectorPath) {
 
5215
            //
 
5216
            // look through the haystack selector path to try and find the needle - extend.selector
 
5217
            // returns an array of selector matches that can then be replaced
 
5218
            //
 
5219
            var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
 
5220
                targetCombinator, i,
 
5221
                needleElements = extend.selector.elements,
 
5222
                potentialMatches = [], potentialMatch, matches = [];
 
5223
 
 
5224
            // loop through the haystack elements
 
5225
            for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
 
5226
                hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
 
5227
 
 
5228
                for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
 
5229
 
 
5230
                    haystackElement = hackstackSelector.elements[hackstackElementIndex];
 
5231
 
 
5232
                    // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
 
5233
                    if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) {
 
5234
                        potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
 
5235
                    }
 
5236
 
 
5237
                    for(i = 0; i < potentialMatches.length; i++) {
 
5238
                        potentialMatch = potentialMatches[i];
 
5239
 
 
5240
                        // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
 
5241
                        // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
 
5242
                        // what the resulting combinator will be
 
5243
                        targetCombinator = haystackElement.combinator.value;
 
5244
                        if (targetCombinator == '' && hackstackElementIndex === 0) {
 
5245
                            targetCombinator = ' ';
 
5246
                        }
 
5247
 
 
5248
                        // if we don't match, null our match to indicate failure
 
5249
                        if (needleElements[potentialMatch.matched].value !== haystackElement.value ||
 
5250
                            (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
 
5251
                            potentialMatch = null;
 
5252
                        } else {
 
5253
                            potentialMatch.matched++;
 
5254
                        }
 
5255
 
 
5256
                        // if we are still valid and have finished, test whether we have elements after and whether these are allowed
 
5257
                        if (potentialMatch) {
 
5258
                            potentialMatch.finished = potentialMatch.matched === needleElements.length;
 
5259
                            if (potentialMatch.finished &&
 
5260
                                (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
 
5261
                                potentialMatch = null;
 
5262
                            }
 
5263
                        }
 
5264
                        // if null we remove, if not, we are still valid, so either push as a valid match or continue
 
5265
                        if (potentialMatch) {
 
5266
                            if (potentialMatch.finished) {
 
5267
                                potentialMatch.length = needleElements.length;
 
5268
                                potentialMatch.endPathIndex = haystackSelectorIndex;
 
5269
                                potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
 
5270
                                potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
 
5271
                                matches.push(potentialMatch);
 
5272
                            }
 
5273
                        } else {
 
5274
                            potentialMatches.splice(i, 1);
 
5275
                            i--;
 
5276
                        }
 
5277
                    }
 
5278
                }
 
5279
            }
 
5280
            return matches;
 
5281
        },
 
5282
        extendSelector:function (matches, selectorPath, replacementSelector) {
 
5283
 
 
5284
            //for a set of matches, replace each match with the replacement selector
 
5285
 
 
5286
            var currentSelectorPathIndex = 0,
 
5287
                currentSelectorPathElementIndex = 0,
 
5288
                path = [],
 
5289
                matchIndex,
 
5290
                selector,
 
5291
                firstElement;
 
5292
 
 
5293
            for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
 
5294
                match = matches[matchIndex];
 
5295
                selector = selectorPath[match.pathIndex];
 
5296
                firstElement = new tree.Element(
 
5297
                    match.initialCombinator,
 
5298
                    replacementSelector.elements[0].value,
 
5299
                    replacementSelector.elements[0].index
 
5300
                );
 
5301
 
 
5302
                if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
 
5303
                    path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
 
5304
                    currentSelectorPathElementIndex = 0;
 
5305
                    currentSelectorPathIndex++;
 
5306
                }
 
5307
 
 
5308
                path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
 
5309
 
 
5310
                path.push(new tree.Selector(
 
5311
                    selector.elements
 
5312
                        .slice(currentSelectorPathElementIndex, match.index)
 
5313
                        .concat([firstElement])
 
5314
                        .concat(replacementSelector.elements.slice(1))
 
5315
                ));
 
5316
                currentSelectorPathIndex = match.endPathIndex;
 
5317
                currentSelectorPathElementIndex = match.endPathElementIndex;
 
5318
                if (currentSelectorPathElementIndex >= selector.elements.length) {
 
5319
                    currentSelectorPathElementIndex = 0;
 
5320
                    currentSelectorPathIndex++;
 
5321
                }
 
5322
            }
 
5323
 
 
5324
            if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
 
5325
                path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
 
5326
                currentSelectorPathElementIndex = 0;
 
5327
                currentSelectorPathIndex++;
 
5328
            }
 
5329
 
 
5330
            path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
 
5331
 
 
5332
            return path;
 
5333
        },
 
5334
        visitRulesetOut: function (rulesetNode) {
 
5335
        },
 
5336
        visitMedia: function (mediaNode, visitArgs) {
 
5337
            var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
 
5338
            newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
 
5339
            this.allExtendsStack.push(newAllExtends);
 
5340
        },
 
5341
        visitMediaOut: function (mediaNode) {
 
5342
            this.allExtendsStack.length = this.allExtendsStack.length - 1;
 
5343
        },
 
5344
        visitDirective: function (directiveNode, visitArgs) {
 
5345
            var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
 
5346
            newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
 
5347
            this.allExtendsStack.push(newAllExtends);
 
5348
        },
 
5349
        visitDirectiveOut: function (directiveNode) {
 
5350
            this.allExtendsStack.length = this.allExtendsStack.length - 1;
 
5351
        }
 
5352
    };
 
5353
 
 
5354
})(require('./tree'));//
 
5355
// browser.js - client-side engine
 
5356
//
 
5357
 
 
5358
var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);
 
5359
 
 
5360
less.env = less.env || (location.hostname == '127.0.0.1' ||
 
5361
                        location.hostname == '0.0.0.0'   ||
 
5362
                        location.hostname == 'localhost' ||
 
5363
                        location.port.length > 0         ||
 
5364
                        isFileProtocol                   ? 'development'
 
5365
                                                         : 'production');
 
5366
 
 
5367
// Load styles asynchronously (default: false)
 
5368
//
 
5369
// This is set to `false` by default, so that the body
 
5370
// doesn't start loading before the stylesheets are parsed.
 
5371
// Setting this to `true` can result in flickering.
 
5372
//
 
5373
less.async = less.async || false;
 
5374
less.fileAsync = less.fileAsync || false;
 
5375
 
 
5376
// Interval between watch polls
 
5377
less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
 
5378
 
 
5379
//Setup user functions
 
5380
if (less.functions) {
 
5381
    for(var func in less.functions) {
 
5382
        less.tree.functions[func] = less.functions[func];
 
5383
   }
 
5384
}
 
5385
 
 
5386
var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);
 
5387
if (dumpLineNumbers) {
 
5388
    less.dumpLineNumbers = dumpLineNumbers[1];
 
5389
}
 
5390
 
 
5391
//
 
5392
// Watch mode
 
5393
//
 
5394
less.watch   = function () {
 
5395
    if (!less.watchMode ){
 
5396
        less.env = 'development';
 
5397
         initRunningMode();
 
5398
    }
 
5399
    return this.watchMode = true 
 
5400
};
 
5401
 
 
5402
less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; };
 
5403
 
 
5404
function initRunningMode(){
 
5405
    if (less.env === 'development') {
 
5406
        less.optimization = 0;
 
5407
        less.watchTimer = setInterval(function () {
 
5408
            if (less.watchMode) {
 
5409
                loadStyleSheets(function (e, root, _, sheet, env) {
 
5410
                    if (e) {
 
5411
                        error(e, sheet.href);
 
5412
                    } else if (root) {
 
5413
                        createCSS(root.toCSS(less), sheet, env.lastModified);
 
5414
                    }
 
5415
                });
 
5416
            }
 
5417
        }, less.poll);
 
5418
    } else {
 
5419
        less.optimization = 3;
 
5420
    }
 
5421
}
 
5422
 
 
5423
if (/!watch/.test(location.hash)) {
 
5424
    less.watch();
 
5425
}
 
5426
 
 
5427
var cache = null;
 
5428
 
 
5429
if (less.env != 'development') {
 
5430
    try {
 
5431
        cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
 
5432
    } catch (_) {}
 
5433
}
 
5434
 
 
5435
//
 
5436
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
 
5437
//
 
5438
var links = document.getElementsByTagName('link');
 
5439
var typePattern = /^text\/(x-)?less$/;
 
5440
 
 
5441
less.sheets = [];
 
5442
 
 
5443
for (var i = 0; i < links.length; i++) {
 
5444
    if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
 
5445
       (links[i].type.match(typePattern)))) {
 
5446
        less.sheets.push(links[i]);
 
5447
    }
 
5448
}
 
5449
 
 
5450
//
 
5451
// With this function, it's possible to alter variables and re-render
 
5452
// CSS without reloading less-files
 
5453
//
 
5454
var session_cache = '';
 
5455
less.modifyVars = function(record) {
 
5456
    var str = session_cache;
 
5457
    for (name in record) {
 
5458
        str += ((name.slice(0,1) === '@')? '' : '@') + name +': '+ 
 
5459
                ((record[name].slice(-1) === ';')? record[name] : record[name] +';');
 
5460
    }
 
5461
    new(less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) {
 
5462
        if (e) {
 
5463
            error(e, "session_cache");
 
5464
        } else {
 
5465
            createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]);
 
5466
        }
 
5467
    });
 
5468
};
 
5469
 
 
5470
less.refresh = function (reload) {
 
5471
    var startTime, endTime;
 
5472
    startTime = endTime = new(Date);
 
5473
 
 
5474
    loadStyleSheets(function (e, root, _, sheet, env) {
 
5475
        if (e) {
 
5476
            return error(e, sheet.href);
 
5477
        }
 
5478
        if (env.local) {
 
5479
            log("loading " + sheet.href + " from cache.");
 
5480
        } else {
 
5481
            log("parsed " + sheet.href + " successfully.");
 
5482
            createCSS(root.toCSS(less), sheet, env.lastModified);
 
5483
        }
 
5484
        log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
 
5485
        (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
 
5486
        endTime = new(Date);
 
5487
    }, reload);
 
5488
 
 
5489
    loadStyles();
 
5490
};
 
5491
less.refreshStyles = loadStyles;
 
5492
 
 
5493
less.refresh(less.env === 'development');
 
5494
 
 
5495
function loadStyles() {
 
5496
    var styles = document.getElementsByTagName('style');
 
5497
    for (var i = 0; i < styles.length; i++) {
 
5498
        if (styles[i].type.match(typePattern)) {
 
5499
            var env = new less.tree.parseEnv(less);
 
5500
            env.filename = document.location.href.replace(/#.*$/, '');
 
5501
 
 
5502
            new(less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) {
 
5503
                if (e) {
 
5504
                    return error(e, "inline");
 
5505
                }
 
5506
                var css = cssAST.toCSS(less);
 
5507
                var style = styles[i];
 
5508
                style.type = 'text/css';
 
5509
                if (style.styleSheet) {
 
5510
                    style.styleSheet.cssText = css;
 
5511
                } else {
 
5512
                    style.innerHTML = css;
 
5513
                }
 
5514
            });
 
5515
        }
 
5516
    }
 
5517
}
 
5518
 
 
5519
function loadStyleSheets(callback, reload) {
 
5520
    for (var i = 0; i < less.sheets.length; i++) {
 
5521
        loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
 
5522
    }
 
5523
}
 
5524
 
 
5525
function pathDiff(url, baseUrl) {
 
5526
    // diff between two paths to create a relative path
 
5527
 
 
5528
    var urlParts = extractUrlParts(url),
 
5529
        baseUrlParts = extractUrlParts(baseUrl),
 
5530
        i, max, urlDirectories, baseUrlDirectories, diff = "";
 
5531
    if (urlParts.hostPart !== baseUrlParts.hostPart) {
 
5532
        return "";
 
5533
    }
 
5534
    max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
 
5535
    for(i = 0; i < max; i++) {
 
5536
        if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
 
5537
    }
 
5538
    baseUrlDirectories = baseUrlParts.directories.slice(i);
 
5539
    urlDirectories = urlParts.directories.slice(i);
 
5540
    for(i = 0; i < baseUrlDirectories.length-1; i++) {
 
5541
        diff += "../";
 
5542
    }
 
5543
    for(i = 0; i < urlDirectories.length-1; i++) {
 
5544
        diff += urlDirectories[i] + "/";
 
5545
    }
 
5546
    return diff;
 
5547
}
 
5548
 
 
5549
function extractUrlParts(url, baseUrl) {
 
5550
    // urlParts[1] = protocol&hostname || /
 
5551
    // urlParts[2] = / if path relative to host base
 
5552
    // urlParts[3] = directories
 
5553
    // urlParts[4] = filename
 
5554
    // urlParts[5] = parameters
 
5555
 
 
5556
    var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/,
 
5557
        urlParts = url.match(urlPartsRegex),
 
5558
        returner = {}, directories = [], i, baseUrlParts;
 
5559
 
 
5560
    if (!urlParts) {
 
5561
        throw new Error("Could not parse sheet href - '"+url+"'");
 
5562
    }
 
5563
 
 
5564
    // Stylesheets in IE don't always return the full path    
 
5565
    if (!urlParts[1] || urlParts[2]) {
 
5566
        baseUrlParts = baseUrl.match(urlPartsRegex);
 
5567
        if (!baseUrlParts) {
 
5568
            throw new Error("Could not parse page url - '"+baseUrl+"'");
 
5569
        }
 
5570
        urlParts[1] = baseUrlParts[1];
 
5571
        if (!urlParts[2]) {
 
5572
            urlParts[3] = baseUrlParts[3] + urlParts[3];
 
5573
        }
 
5574
    }
 
5575
    
 
5576
    if (urlParts[3]) {
 
5577
        directories = urlParts[3].replace("\\", "/").split("/");
 
5578
 
 
5579
        for(i = 0; i < directories.length; i++) {
 
5580
            if (directories[i] === ".." && i > 0) {
 
5581
                directories.splice(i-1, 2);
 
5582
                i -= 2;
 
5583
            }
 
5584
        }
 
5585
    }
 
5586
 
 
5587
    returner.hostPart = urlParts[1];
 
5588
    returner.directories = directories;
 
5589
    returner.path = urlParts[1] + directories.join("/");
 
5590
    returner.fileUrl = returner.path + (urlParts[4] || "");
 
5591
    returner.url = returner.fileUrl + (urlParts[5] || "");
 
5592
    return returner;
 
5593
}
 
5594
 
 
5595
function loadStyleSheet(sheet, callback, reload, remaining) {
 
5596
 
 
5597
    // sheet may be set to the stylesheet for the initial load or a collection of properties including
 
5598
    // some env variables for imports
 
5599
    var hrefParts = extractUrlParts(sheet.href, window.location.href);
 
5600
    var href      = hrefParts.url;
 
5601
    var css       = cache && cache.getItem(href);
 
5602
    var timestamp = cache && cache.getItem(href + ':timestamp');
 
5603
    var styles    = { css: css, timestamp: timestamp };
 
5604
    var env;
 
5605
    var newFileInfo = {
 
5606
            relativeUrls: less.relativeUrls,
 
5607
            currentDirectory: hrefParts.path,
 
5608
            filename: href
 
5609
        };
 
5610
 
 
5611
    if (sheet instanceof less.tree.parseEnv) {
 
5612
        env = new less.tree.parseEnv(sheet);
 
5613
        newFileInfo.entryPath = env.currentFileInfo.entryPath;
 
5614
        newFileInfo.rootpath = env.currentFileInfo.rootpath;
 
5615
        newFileInfo.rootFilename = env.currentFileInfo.rootFilename;
 
5616
    } else {
 
5617
        env = new less.tree.parseEnv(less);
 
5618
        env.mime = sheet.type;
 
5619
        newFileInfo.entryPath = hrefParts.path;
 
5620
        newFileInfo.rootpath = less.rootpath || hrefParts.path;
 
5621
        newFileInfo.rootFilename = href;
 
5622
    }
 
5623
 
 
5624
    if (env.relativeUrls) {
 
5625
        //todo - this relies on option being set on less object rather than being passed in as an option
 
5626
        //     - need an originalRootpath
 
5627
        if (less.rootpath) {
 
5628
            newFileInfo.rootpath = extractUrlParts(less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path;
 
5629
        } else {
 
5630
            newFileInfo.rootpath = hrefParts.path;
 
5631
        }
 
5632
    }
 
5633
 
 
5634
    xhr(href, sheet.type, function (data, lastModified) {
 
5635
        // Store data this session
 
5636
        session_cache += data.replace(/@import .+?;/ig, '');
 
5637
 
 
5638
        if (!reload && styles && lastModified &&
 
5639
           (new(Date)(lastModified).valueOf() ===
 
5640
            new(Date)(styles.timestamp).valueOf())) {
 
5641
            // Use local copy
 
5642
            createCSS(styles.css, sheet);
 
5643
            callback(null, null, data, sheet, { local: true, remaining: remaining }, href);
 
5644
        } else {
 
5645
            // Use remote copy (re-parse)
 
5646
            try {
 
5647
                env.contents[href] = data;  // Updating content cache
 
5648
                env.paths = [hrefParts.path];
 
5649
                env.currentFileInfo = newFileInfo;
 
5650
 
 
5651
                new(less.Parser)(env).parse(data, function (e, root) {
 
5652
                    if (e) { return callback(e, null, null, sheet); }
 
5653
                    try {
 
5654
                        callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining }, href);
 
5655
                        //TODO - there must be a better way? A generic less-to-css function that can both call error
 
5656
                        //and removeNode where appropriate
 
5657
                        //should also add tests
 
5658
                        if (env.currentFileInfo.rootFilename === href) {
 
5659
                            removeNode(document.getElementById('less-error-message:' + extractId(href)));
 
5660
                        }
 
5661
                    } catch (e) {
 
5662
                        callback(e, null, null, sheet);
 
5663
                    }
 
5664
                });
 
5665
            } catch (e) {
 
5666
                callback(e, null, null, sheet);
 
5667
            }
 
5668
        }
 
5669
    }, function (status, url) {
 
5670
        callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, null, sheet);
 
5671
    });
 
5672
}
 
5673
 
 
5674
function extractId(href) {
 
5675
    return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' )  // Remove protocol & domain
 
5676
               .replace(/^\//,                 '' )  // Remove root /
 
5677
               .replace(/\.[a-zA-Z]+$/,        '' )  // Remove simple extension
 
5678
               .replace(/[^\.\w-]+/g,          '-')  // Replace illegal characters
 
5679
               .replace(/\./g,                 ':'); // Replace dots with colons(for valid id)
 
5680
}
 
5681
 
 
5682
function createCSS(styles, sheet, lastModified) {
 
5683
    // Strip the query-string
 
5684
    var href = sheet.href || '';
 
5685
 
 
5686
    // If there is no title set, use the filename, minus the extension
 
5687
    var id = 'less:' + (sheet.title || extractId(href));
 
5688
 
 
5689
    // If this has already been inserted into the DOM, we may need to replace it
 
5690
    var oldCss = document.getElementById(id);
 
5691
    var keepOldCss = false;
 
5692
 
 
5693
    // Create a new stylesheet node for insertion or (if necessary) replacement
 
5694
    var css = document.createElement('style');
 
5695
    css.setAttribute('type', 'text/css');
 
5696
    if (sheet.media) {
 
5697
        css.setAttribute('media', sheet.media);
 
5698
    }
 
5699
    css.id = id;
 
5700
 
 
5701
    if (css.styleSheet) { // IE
 
5702
        try {
 
5703
            css.styleSheet.cssText = styles;
 
5704
        } catch (e) {
 
5705
            throw new(Error)("Couldn't reassign styleSheet.cssText.");
 
5706
        }
 
5707
    } else {
 
5708
        css.appendChild(document.createTextNode(styles));
 
5709
 
 
5710
        // If new contents match contents of oldCss, don't replace oldCss
 
5711
        keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 &&
 
5712
            oldCss.firstChild.nodeValue === css.firstChild.nodeValue);
 
5713
    }
 
5714
 
 
5715
    var head = document.getElementsByTagName('head')[0];
 
5716
 
 
5717
    // If there is no oldCss, just append; otherwise, only append if we need
 
5718
    // to replace oldCss with an updated stylesheet
 
5719
    if (oldCss == null || keepOldCss === false) {
 
5720
        var nextEl = sheet && sheet.nextSibling || null;
 
5721
        (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl);
 
5722
    }
 
5723
    if (oldCss && keepOldCss === false) {
 
5724
        head.removeChild(oldCss);
 
5725
    }
 
5726
 
 
5727
    // Don't update the local store if the file wasn't modified
 
5728
    if (lastModified && cache) {
 
5729
        log('saving ' + href + ' to cache.');
 
5730
        try {
 
5731
            cache.setItem(href, styles);
 
5732
            cache.setItem(href + ':timestamp', lastModified);
 
5733
        } catch(e) {
 
5734
            //TODO - could do with adding more robust error handling
 
5735
            log('failed to save');
 
5736
        }
 
5737
    }
 
5738
}
 
5739
 
 
5740
function xhr(url, type, callback, errback) {
 
5741
    var xhr = getXMLHttpRequest();
 
5742
    var async = isFileProtocol ? less.fileAsync : less.async;
 
5743
 
 
5744
    if (typeof(xhr.overrideMimeType) === 'function') {
 
5745
        xhr.overrideMimeType('text/css');
 
5746
    }
 
5747
    xhr.open('GET', url, async);
 
5748
    xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
 
5749
    xhr.send(null);
 
5750
 
 
5751
    if (isFileProtocol && !less.fileAsync) {
 
5752
        if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
 
5753
            callback(xhr.responseText);
 
5754
        } else {
 
5755
            errback(xhr.status, url);
 
5756
        }
 
5757
    } else if (async) {
 
5758
        xhr.onreadystatechange = function () {
 
5759
            if (xhr.readyState == 4) {
 
5760
                handleResponse(xhr, callback, errback);
 
5761
            }
 
5762
        };
 
5763
    } else {
 
5764
        handleResponse(xhr, callback, errback);
 
5765
    }
 
5766
 
 
5767
    function handleResponse(xhr, callback, errback) {
 
5768
        if (xhr.status >= 200 && xhr.status < 300) {
 
5769
            callback(xhr.responseText,
 
5770
                     xhr.getResponseHeader("Last-Modified"));
 
5771
        } else if (typeof(errback) === 'function') {
 
5772
            errback(xhr.status, url);
 
5773
        }
 
5774
    }
 
5775
}
 
5776
 
 
5777
function getXMLHttpRequest() {
 
5778
    if (window.XMLHttpRequest) {
 
5779
        return new(XMLHttpRequest);
 
5780
    } else {
 
5781
        try {
 
5782
            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
 
5783
        } catch (e) {
 
5784
            log("browser doesn't support AJAX.");
 
5785
            return null;
 
5786
        }
 
5787
    }
 
5788
}
 
5789
 
 
5790
function removeNode(node) {
 
5791
    return node && node.parentNode.removeChild(node);
 
5792
}
 
5793
 
 
5794
function log(str) {
 
5795
    if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
 
5796
}
 
5797
 
 
5798
function error(e, rootHref) {
 
5799
    var id = 'less-error-message:' + extractId(rootHref || "");
 
5800
    var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
 
5801
    var elem = document.createElement('div'), timer, content, error = [];
 
5802
    var filename = e.filename || rootHref;
 
5803
    var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
 
5804
 
 
5805
    elem.id        = id;
 
5806
    elem.className = "less-error-message";
 
5807
 
 
5808
    content = '<h3>'  + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
 
5809
              '</h3>' + '<p>in <a href="' + filename   + '">' + filenameNoPath + "</a> ";
 
5810
 
 
5811
    var errorline = function (e, i, classname) {
 
5812
        if (e.extract[i] != undefined) {
 
5813
            error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1))
 
5814
                               .replace(/\{class\}/, classname)
 
5815
                               .replace(/\{content\}/, e.extract[i]));
 
5816
        }
 
5817
    };
 
5818
 
 
5819
    if (e.extract) {
 
5820
        errorline(e, 0, '');
 
5821
        errorline(e, 1, 'line');
 
5822
        errorline(e, 2, '');
 
5823
        content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
 
5824
                    '<ul>' + error.join('') + '</ul>';
 
5825
    } else if (e.stack) {
 
5826
        content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
 
5827
    }
 
5828
    elem.innerHTML = content;
 
5829
 
 
5830
    // CSS for error messages
 
5831
    createCSS([
 
5832
        '.less-error-message ul, .less-error-message li {',
 
5833
            'list-style-type: none;',
 
5834
            'margin-right: 15px;',
 
5835
            'padding: 4px 0;',
 
5836
            'margin: 0;',
 
5837
        '}',
 
5838
        '.less-error-message label {',
 
5839
            'font-size: 12px;',
 
5840
            'margin-right: 15px;',
 
5841
            'padding: 4px 0;',
 
5842
            'color: #cc7777;',
 
5843
        '}',
 
5844
        '.less-error-message pre {',
 
5845
            'color: #dd6666;',
 
5846
            'padding: 4px 0;',
 
5847
            'margin: 0;',
 
5848
            'display: inline-block;',
 
5849
        '}',
 
5850
        '.less-error-message pre.line {',
 
5851
            'color: #ff0000;',
 
5852
        '}',
 
5853
        '.less-error-message h3 {',
 
5854
            'font-size: 20px;',
 
5855
            'font-weight: bold;',
 
5856
            'padding: 15px 0 5px 0;',
 
5857
            'margin: 0;',
 
5858
        '}',
 
5859
        '.less-error-message a {',
 
5860
            'color: #10a',
 
5861
        '}',
 
5862
        '.less-error-message .error {',
 
5863
            'color: red;',
 
5864
            'font-weight: bold;',
 
5865
            'padding-bottom: 2px;',
 
5866
            'border-bottom: 1px dashed red;',
 
5867
        '}'
 
5868
    ].join('\n'), { title: 'error-message' });
 
5869
 
 
5870
    elem.style.cssText = [
 
5871
        "font-family: Arial, sans-serif",
 
5872
        "border: 1px solid #e00",
 
5873
        "background-color: #eee",
 
5874
        "border-radius: 5px",
 
5875
        "-webkit-border-radius: 5px",
 
5876
        "-moz-border-radius: 5px",
 
5877
        "color: #e00",
 
5878
        "padding: 15px",
 
5879
        "margin-bottom: 15px"
 
5880
    ].join(';');
 
5881
 
 
5882
    if (less.env == 'development') {
 
5883
        timer = setInterval(function () {
 
5884
            if (document.body) {
 
5885
                if (document.getElementById(id)) {
 
5886
                    document.body.replaceChild(elem, document.getElementById(id));
 
5887
                } else {
 
5888
                    document.body.insertBefore(elem, document.body.firstChild);
 
5889
                }
 
5890
                clearInterval(timer);
 
5891
            }
 
5892
        }, 10);
 
5893
    }
 
5894
}
 
5895
// amd.js
 
5896
//
 
5897
// Define Less as an AMD module.
 
5898
if (typeof define === "function" && define.amd) {
 
5899
    define(function () { return less; } );
 
5900
}
 
5901
})(window);