PageSourceSearch

https://www.kendalmountainfestival.com/js/less.js

js kendalmountainfestival.com collected 2026-10-02 07:17:33 UTC 419,344 bytes, 11,890 lines download raw bytes

1/*!
2 * Less - Leaner CSS v3.5.0-beta
3 * http://lesscss.org
4 *
5 * Copyright (c) 2009-2018, Alexis Sellier <[email protected]>
6 * Licensed under the Apache-2.0 License.
7 *
8 */
9
10 /** * @license Apache-2.0
11 */
12
13(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.less = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
14var addDataAttr = require('./utils').addDataAttr,
15    browser = require('./browser');
16
17module.exports = function(window, options) {
18
19    // use options from the current script tag data attribues
20    addDataAttr(options, browser.currentScript(window));
21
22    if (options.isFileProtocol === undefined) {
23        options.isFileProtocol = /^(file|(chrome|safari)(-extension)?|resource|qrc|app):/.test(window.location.protocol);
24    }
25
26    // Load styles asynchronously (default: false)
27    //
28    // This is set to `false` by default, so that the body
29    // doesn't start loading before the stylesheets are parsed.
30    // Setting this to `true` can result in flickering.
31    //
32    options.async = options.async || false;
33    options.fileAsync = options.fileAsync || false;
34
35    // Interval between watch polls
36    options.poll = options.poll || (options.isFileProtocol ? 1000 : 1500);
37
38    options.env = options.env || (window.location.hostname == '127.0.0.1' ||
39        window.location.hostname == '0.0.0.0'   ||
40        window.location.hostname == 'localhost' ||
41        (window.location.port &&
42            window.location.port.length > 0)      ||
43        options.isFileProtocol                   ? 'development'
44        : 'production');
45
46    var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(window.location.hash);
47    if (dumpLineNumbers) {
48        options.dumpLineNumbers = dumpLineNumbers[1];
49    }
50
51    if (options.useFileCache === undefined) {
52        options.useFileCache = true;
53    }
54
55    if (options.onReady === undefined) {
56        options.onReady = true;
57    }
58
59    // TODO: deprecate and remove 'inlineJavaScript' thing - where it came from at all?
60    options.javascriptEnabled = (options.javascriptEnabled || options.inlineJavaScript) ? true : false;
61
62};
63
64},{"./browser":3,"./utils":11}],2:[function(require,module,exports){
65/**
66 * Kicks off less and compiles any stylesheets
67 * used in the browser distributed version of less
68 * to kick-start less using the browser api
69 */
70/* global window, document */
71
72// TODO - consider switching this out for a recommendation for this polyfill?
73// <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
74// Browsers have good Promise support
75require('promise/polyfill');
76
77var options = require('../less/default-options')();
78
79if (window.less) {
80    for (key in window.less) {
81        if (window.less.hasOwnProperty(key)) {
82            options[key] = window.less[key];
83        }
84    }
85}
86require('./add-default-options')(window, options);
87
88options.plugins = options.plugins || [];
89
90if (window.LESS_PLUGINS) {
91    options.plugins = options.plugins.concat(window.LESS_PLUGINS);
92}
93
94var less = module.exports = require('./index')(window, options);
95
96window.less = less;
97
98var css, head, style;
99
100// Always restore page visibility
101function resolveOrReject(data) {
102    if (data.filename) {
103        console.warn(data);
104    }
105    if (!options.async) {
106        head.removeChild(style);
107    }
108}
109
110if (options.onReady) {
111    if (/!watch/.test(window.location.hash)) {
112        less.watch();
113    }
114    // Simulate synchronous stylesheet loading by hiding page rendering
115    if (!options.async) {
116        css = 'body { display: none !important }';
117        head = document.head || document.getElementsByTagName('head')[0];
118        style = document.createElement('style');
119
120        style.type = 'text/css';
121        if (style.styleSheet) {
122            style.styleSheet.cssText = css;
123        } else {
124            style.appendChild(document.createTextNode(css));
125        }
126
127        head.appendChild(style);
128    }
129    less.registerStylesheetsImmediately();
130    less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject);
131}
132
133},{"../less/default-options":16,"./add-default-options":1,"./index":8,"promise/polyfill":100}],3:[function(require,module,exports){
134var utils = require('./utils');
135module.exports = {
136    createCSS: function (document, styles, sheet) {
137        // Strip the query-string
138        var href = sheet.href || '';
139
140        // If there is no title set, use the filename, minus the extension
141        var id = 'less:' + (sheet.title || utils.extractId(href));
142
143        // If this has already been inserted into the DOM, we may 
143need to replace it
144        var oldStyleNode = document.getElementById(id);
145        var keepOldStyleNode = false;
146
147        // Create a new stylesheet node for insertion or (if necessary) replacement
148        var styleNode = document.createElement('style');
149        styleNode.setAttribute('type', 'text/css');
150        if (sheet.media) {
151            styleNode.setAttribute('media', sheet.media);
152        }
153        styleNode.id = id;
154
155        if (!styleNode.styleSheet) {
156            styleNode.appendChild(document.createTextNode(styles));
157
158            // If new contents match contents of oldStyleNode, don't replace oldStyleNode
159            keepOldStyleNode = (oldStyleNode !== null && oldStyleNode.childNodes.length > 0 && styleNode.childNodes.length > 0 &&
160                oldStyleNode.firstChild.nodeValue === styleNode.firstChild.nodeValue);
161        }
162
163        var head = document.getElementsByTagName('head')[0];
164
165        // If there is no oldStyleNode, just append; otherwise, only append if we need
166        // to replace oldStyleNode with an updated stylesheet
167        if (oldStyleNode === null || keepOldStyleNode === false) {
168            var nextEl = sheet && sheet.nextSibling || null;
169            if (nextEl) {
170                nextEl.parentNode.insertBefore(styleNode, nextEl);
171            } else {
172                head.appendChild(styleNode);
173            }
174        }
175        if (oldStyleNode && keepOldStyleNode === false) {
176            oldStyleNode.parentNode.removeChild(oldStyleNode);
177        }
178
179        // For IE.
180        // This needs to happen *after* the style element is added to the DOM, otherwise IE 7 and 8 may crash.
181        // See http://social.msdn.microsoft.com/Forums/en-US/7e081b65-878a-4c22-8e68-c10d39c2ed32/internet-explorer-crashes-appending-style-element-to-head
182        if (styleNode.styleSheet) {
183            try {
184                styleNode.styleSheet.cssText = styles;
185            } catch (e) {
186                throw new Error('Couldn\'t reassign styleSheet.cssText.');
187            }
188        }
189    },
190    currentScript: function(window) {
191        var document = window.document;
192        return document.currentScript || (function() {
193            var scripts = document.getElementsByTagName('script');
194            return scripts[scripts.length - 1];
195        })();
196    }
197};
198
199},{"./utils":11}],4:[function(require,module,exports){
200// Cache system is a bit outdated and could do with work
201
202module.exports = function(window, options, logger) {
203    var cache = null;
204    if (options.env !== 'development') {
205        try {
206            cache = (typeof window.localStorage === 'undefined') ? null : window.localStorage;
207        } catch (_) {}
208    }
209    return {
210        setCSS: function(path, lastModified, modifyVars, styles) {
211            if (cache) {
212                logger.info('saving ' + path + ' to cache.');
213                try {
214                    cache.setItem(path, styles);
215                    cache.setItem(path + ':timestamp', lastModified);
216                    if (modifyVars) {
217                        cache.setItem(path + ':vars', JSON.stringify(modifyVars));
218                    }
219                } catch (e) {
220                    // TODO - could do with adding more robust error handling
221                    logger.error('failed to save "' + path + '" to local storage for caching.');
222                }
223            }
224        },
225        getCSS: function(path, webInfo, modifyVars) {
226            var css       = cache && cache.getItem(path),
227                timestamp = cache && cache.getItem(path + ':timestamp'),
228                vars      = cache && cache.getItem(path + ':vars');
229
230            modifyVars = modifyVars || {};
231
232            if (timestamp && webInfo.lastModified &&
233                (new Date(webInfo.lastModified).valueOf() ===
234                    new Date(timestamp).valueOf()) &&
235                (!modifyVars && !vars || JSON.stringify(modifyVars) === vars)) {
236                // Use local copy
237                return css;
238            }
239        }
240    };
241};
242
243},{}],5:[function(require,module,exports){
244var utils = require('./utils'),
245    browser = require('./browser');
246
247module.exports = function(window, less, options) {
248
249    function errorHTML(e, rootHref) {
250        var id = 'less-error-message:' + utils.extractId(rootHref || '');
251        var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
252        var elem = window.document.createElement('div'), timer, content, errors = [];
253        var filename = e.filename || rootHref;
254        var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
255
256        elem.id        = id;
257        elem.className = 'less-error-message';
258
259        content = '<h3>'  + (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') +
260            '</h3>' + '<p>in <a href="' + filename   + '">' + filenameNoPath + '</a> ';
261
262        var errorline = function (e, i, classname) {
263            if (e.extract[i] !== undefined) {
264                errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
265                    .replace(/\{class\}/, classname)
266                    .replace(/\{content\}/, e.extract[i]));
267            }
268        };
269
270        if (e.line) {
271            errorline(e, 0, '');
272            errorline(e, 1, 'line');
273            errorline(e, 2, '');
274            content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
275                '<ul>' + errors.join('') + '</ul>';
276        }
277        if (e.stack && (e.extract || options.logLevel >= 4)) {
278            content += '<br/>Stack Trace</br />' + e.stack.split('\n').slice(1).join('<br/>');
279        }
280        elem.innerHTML = content;
281
282        // CSS for error messages
283        browser.createCSS(window.document, [
284            '.less-error-message ul, .less-error-message li {',
285            'list-style-type: none;',
286            'margin-right: 15px;',
287            'padding: 4px 0;',
288            'margin: 0;',
289            '}',
290            '.less-error-message label {',
291            'font-size: 12px;',
292            'margin-right: 15px;',
293            'padding: 4px 0;',
294            'color: #cc7777;',
295            '}',
296            '.less-error-message pre {',
297            'color: #dd6666;',
298            'padding: 4px 0;',
299            'margin: 0;',
300            'display: inline-block;',
301            '}',
302            '.less-error-message pre.line {',
303            'color: #ff0000;',
304            '}',
305            '.less-error-message h3 {',
306            'font-size: 20px;',
307            'font-weight: bold;',
308            'padding: 15px 0 5px 0;',
309            'margin: 0;',
310            '}',
311            '.less-error-message a {',
312            'color: #10a',
313            '}',
314            '.less-error-message .error {',
315            'color: red;',
316            'font-weight: bold;',
317            'padding-bottom: 2px;',
318            'border-bottom: 1px dashed red;',
319            '}'
320        ].join('\n'), { title: 'error-message' });
321
322        elem.style.cssText = [
323            'font-family: Arial, sans-serif',
324            'border: 1px solid #e00',
325            'background-color: #eee',
326            'border-radius: 5px',
327            '-webkit-border-radius: 5px',
328            '-moz-border-radius: 5px',
329            'color: #e00',
330            'padding: 15px',
331            'margin-bottom: 15px'
332        ].join(';');
333
334        if (options.env === 'development') {
335            timer = setInterval(function () {
336                var document = window.document,
337                    body = document.body;
338                if (body) {
339                    if (document.getElementById(id)) {
340                        body.replaceChild(elem, document.getElementById(id));
341                    } else {
342                        body.insertBefore(elem, body.firstChild);
343                    }
344                    clearInterval(timer);
345                }
346            }, 10);
347        }
348    }
349
350    function removeErrorHTML(path) {
351        var node = window.document.getElementById('less-error-message:' + utils.extractId(path));
352        if (node) {
353            node.parentNode.removeChild(node);
354        }
355    }
356
357    function removeErrorConsole(path) {
358        // no action
359    }
360
361    function removeError(path) {
362        if (!options.errorReporting || options.errorReporting === 'html') {
363            removeErrorHTML(path);
364        } else if (options.errorReporting === 'console') {
365            removeErrorConsole(path);
366        } else if (typeof options.errorReporting === 'function') {
367            options.errorReporting('remove', path);
368        }
369    }
370
371    function errorConsole(e, rootHref) {
372        var template = '{line} {content}';
373        var filename = e.filename || rootHref;
374        var errors = [];
375        var content = (e.type || 'Syntax') + 'Error: ' + (e.message || 'There is an error in your .less file') +
376            ' in ' + filename;
377
378        var errorline = function (e, i, classname) {
379            if (e.extract[i] !== undefined) {
380                errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
381                    .replace(/\{class\}/, classname)
382                    .replace(/\{content\}/, e.extract[i]));
383            }
384        };
385
386        if (e.line) {
387            errorline(e, 0, '');
388            errorline(e, 1, 'line');
389            errorline(e, 2, '');
390            content += ' on line ' + e.line + ', column ' + (e.column + 1) + ':\n' +
391                errors.join('\n');
392        }
393        if (e.stack && (e.extract || options.logLevel >= 4)) {
394            content += '\nStack Trace\n' + e.stack;
395        }
396        less.logger.error(content);
397    }
398
399    function error(e, rootHref) {
400        if (!options.errorReporting || options.errorReporting === 'html') {
401            errorHTML(e, rootHref);
402        } else if (options.errorReporting === 'console') {
403            errorConsole(e, rootHref);
404        } else if (typeof options.errorReporting === 'function') {
405            options.errorReporting('add', e, rootHref);
406        }
407    }
408
409    return {
410        add: error,
411        remove: removeError
412    };
413};
414
415},{"./browser":3,"./utils":11}],6:[function(require,module,exports){
416/* global window, XMLHttpRequest */
417
418module.exports = function(options, logger) {
419
420    var AbstractFileManager = require('../less/environment/abstract-file-manager.js');
421
422    var fileCache = {};
423
424    // TODOS - move log somewhere. pathDiff and doing something similar in node. use pathDiff in the other browser file for the initial load
425    var FileManager = function() {
426    };
427
428    FileManager.prototype = new AbstractFileManager();
429
430    FileManager.prototype.alwaysMakePathsAbsolute = function alwaysMakePathsAbsolute() {
431        return true;
432    };
433    FileManager.prototype.join = function join(basePath, laterPath) {
434        if (!basePath) {
435            return laterPath;
436        }
437        return this.extractUrlParts(laterPath, basePath).path;
438    };
439    FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) {
440
441        var xhr = new XMLHttpRequest();
442        var async = options.isFileProtocol ? options.fileAsync : true;
443
444        if (typeof xhr.overrideMimeType === 'function') {
445            xhr.overrideMimeType('text/css');
446        }
447        logger.debug('XHR: Getting \'' + url + '\'');
448        xhr.open('GET', url, async);
449        xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
450        xhr.send(null);
451
452        function handleResponse(xhr, callback, errback) {
453            if (xhr.status >= 200 && xhr.status < 300) {
454                callback(xhr.responseText,
455                    xhr.getResponseHeader('Last-Modified'));
456            } else if (typeof errback === 'function') {
457                errback(xhr.status, url);
458            }
459        }
460
461        if (options.isFileProtocol && !options.fileAsync) {
462            if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
463                callback(xhr.responseText);
464            } else {
465                errback(xhr.status, url);
466            }
467        } else if (async) {
468            xhr.onreadystatechange = function () {
469                if (xhr.readyState == 4) {
470                    handleResponse(xhr, callback, errback);
471                }
472            };
473        } else {
474            handleResponse(xhr, callback, errback);
475        }
476    };
477    FileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
478        return true;
479    };
480
481    FileManager.prototype.clearFileCache = function() {
482        fileCache = {};
483    };
484
485    FileManager.prototype.loadFile = function loadFile(filename, currentDirectory, options, environment) {
486        // TODO: Add prefix support like less-node?
487        // What about multiple paths?
488
489        if (currentDirectory && !this.isPathAbsolute(filename)) {
490            filename = currentDirectory + filename;
491        }
492
493        filename = options.ext ? this.tryAppendExtension(filename, options.ext) : filename;
494
495        options = options || {};
496
497        // sheet may be set to the stylesheet for the initial load or a collection of properties including
498        // some context variables for imports
499        var hrefParts = this.extractUrlParts(filename, window.location.href);
500        var href      = hrefParts.url;
501        var self      = this;
502        
503        return new Promise(function(resolve, reject) {
504            if (options.useFileCache && fileCache[href]) {
505                try {
506                    var lessText = fileCache[href];
507                    return resolve({ contents: lessText, filename: href, webInfo: { lastModified: new Date() }});
508                } catch (e) {
509                    return reject({ filename: href, message: 'Error loading file ' + href + ' error was ' + e.message });
510                }
511            }
512
513            self.doXHR(href, options.mime, function doXHRCallback(data, lastModified) {
514                // per file cache
515                fileCache[href] = data;
516
517                // Use remote copy (re-parse)
518                resolve({ contents: data, filename: href, webInfo: { lastModified: lastModified }});
519            }, function doXHRError(status, url) {
520                reject({ type: 'File', message: '\'' + url + '\' wasn\'t found (' + status + ')', href: href });
521            });
522        });
523    };
524
525    return FileManager;
526};
527
528},{"../less/environment/abstract-file-manager.js":17}],7:[function(require,module,exports){
529module.exports = function() {
530
531    var functionRegistry = require('./../less/functions/function-registry');
532
533    function imageSize() {
534        throw {
535            type: 'Runtime',
536            message: 'Image size functions are not supported in browser version of less'
537        };
538    }
539
540    var imageFunctions = {
541        'image-size': function(filePathNode) {
542            imageSize(this, filePathNode);
543            return -1;
544        },
545        'image-width': function(filePathNode) {
546            imageSize(this, filePathNode);
547            return -1;
548        },
549        'image-height': function(filePathNode) {
550            imageSize(this, filePathNode);
551            return -1;
552        }
553    };
554
555    functionRegistry.addMultiple(imageFunctions);
556};
557
558},{"./../less/functions/function-registry":26}],8:[function(require,module,exports){
559//
560// index.js
561// Should expose the additional browser functions on to the less object
562//
563var addDataAttr = require('./utils').addDataAttr,
564    browser = require('./browser');
565
566module.exports = function(window, options) {
567    var document = window.document;
568    var less = require('../less')();
569    
570    less.options = options;
571    var environment = less.environment,
572        FileManager = require('./file-manager')(options, less.logger),
573        fileManager = new FileManager();
574    environment.addFileManager(fileManager);
575    less.FileManager = FileManager;
576    less.PluginLoader = require('./plugin-loader');
577
578    require('./log-listener')(less, options);
579    var errors = require('./error-reporting')(window, less, options);
580    var cache = less.cache = options.cache || require('./cache')(window, options, less.logger);
581    require('./image-size')(less.environment);
582
583    // Setup user functions - Deprecate?
584    if (options.functions) {
585        less.functions.functionRegistry.addMultiple(options.functions);
586    }
587
588    var typePattern = /^text\/(x-)?less$/;
589
590    function clone(obj) {
591        return JSON.parse(JSON.stringify(obj || {}));
592    }
593
594    // only really needed for phantom
595    function bind(func, thisArg) {
596        var curryArgs = Array.prototype.slice.call(arguments, 2);
597        return function() {
598            var args = curryArgs.concat(Array.prototype.slice.call(arguments, 0));
599            return func.apply(thisArg, args);
600        };
601    }
602
603    function loadStyles(modifyVars) {
604        var styles = document.getElementsByTagName('style'),
605            style;
606
607        for (var i = 0; i < styles.length; i++) {
608            style = styles[i];
609            if (style.type.match(typePattern)) {
610                var instanceOptions = clone(options);
611                instanceOptions.modifyVars = modifyVars;
612                var lessText = style.innerHTML || '';
613                instanceOptions.filename = document.location.href.replace(/#.*$/, '');
614
615                /* jshint loopfunc:true */
616                // use closure to store current style
617                less.render(lessText, instanceOptions,
618                        bind(function(style, e, result) {
619                            if (e) {
620                                errors.add(e, 'inline');
621                            } else {
622                                style.type = 'text/css';
623                                if (style.styleSheet) {
624                                    style.styleSheet.cssText = result.css;
625                                } else {
626                                    style.innerHTML = result.css;
627                                }
628                            }
629                        }, null, style));
630            }
631        }
632    }
633
634    function loadStyleSheet(sheet, callback, reload, remaining, modifyVars) {
635
636        var instanceOptions = clone(options);
637        addDataAttr(instanceOptions, sheet);
638        instanceOptions.mime = sheet.type;
639
640        if (modifyVars) {
641            instanceOptions.modifyVars = modifyVars;
642        }
643
644        function loadInitialFileCallback(loadedFile) {
645
646            var data = loadedFile.contents,
647                path = loadedFile.filename,
648                webInfo = loadedFile.webInfo;
649
650            var newFileInfo = {
651                currentDirectory: fileManager.getPath(path),
652                filename: path,
653                rootFilename: path,
654                relativeUrls: instanceOptions.relativeUrls};
655
656            newFileInfo.entryPath = newFileInfo.currentDirectory;
657            newFileInfo.rootpath = instanceOptions.rootpath || newFileInfo.currentDirectory;
658
659            if (webInfo) {
660                webInfo.remaining = remaining;
661
662                var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);
663                if (!reload && css) {
664                    webInfo.local = true;
665                    callback(null, css, data, sheet, webInfo, path);
666                    return;
667                }
668
669            }
670
671            // TODO add tests around how this behaves when reloading
672            errors.remove(path);
673
674            instanceOptions.rootFileInfo = newFileInfo;
675            less.render(data, instanceOptions, function(e, result) {
676                if (e) {
677                    e.href = path;
678                    callback(e);
679                } else {
680                    cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);
681                    callback(null, result.css, data, sheet, webInfo, path);
682                }
683            });
684        }
685
686        fileManager.loadFile(sheet.href, null, instanceOptions, environment)
687            .then(function(loadedFile) {
688                loadInitialFileCallback(loadedFile);
689            }).catch(function(err) {
690                console.log(err);
691                callback(err);
692            });
693
694    }
695
696    function loadStyleSheets(callback, reload, modifyVars) {
697        for (var i = 0; i < less.sheets.length; i++) {
698            loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), modifyVars);
699        }
700    }
701
702    function initRunningMode() {
703        if (less.env === 'development') {
704            less.watchTimer = setInterval(function () {
705                if (less.watchMode) {
706                    fileManager.clearFileCache();
707                    loadStyleSheets(function (e, css, _, sheet, webInfo) {
708                        if (e) {
709                            errors.add(e, e.href || sheet.href);
710                        } else if (css) {
711                            browser.createCSS(window.document, css, sheet);
712                        }
713                    });
714                }
715            }, options.poll);
716        }
717    }
718
719    //
720    // Watch mode
721    //
722    less.watch   = function () {
723        if (!less.watchMode ) {
724            less.env = 'development';
725            initRunningMode();
726        }
727        this.watchMode = true;
728        return true;
729    };
730
731    less.unwatch = function () {clearInterval(less.watchTimer); this.watchMode = false; return false; };
732
733    //
734    // Synchronously get all <link> tags with the 'rel' attribute set to
735    // "stylesheet/less".
736    //
737    less.registerStylesheetsImmediately = function() {
738        var links = document.getElementsByTagName('link');
739        less.sheets = [];
740
741        for (var i = 0; i < links.length; i++) {
742            if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
743                (links[i].type.match(typePattern)))) {
744                less.sheets.push(links[i]);
745            }
746        }
747    };
748
749    //
750    // Asynchronously get all <link> tags with the 'rel' attribute set to
751    // "stylesheet/less", returning a Promise.
752    //
753    less.registerStylesheets = function() {
754        return new Promise(function(resolve, reject) {
755            less.registerStylesheetsImmediately();
756            resolve();
757        });
758    };
759
760    //
761    // With this function, it's possible to alter variables and re-render
762    // CSS without reloading less-files
763    //
764    less.modifyVars = function(record) {
765        return less.refresh(true, record, false);
766    };
767
768    less.refresh = function (reload, modifyVars, clearFileCache) {
769        if ((reload || clearFileCache) && clearFileCache !== false) {
770            fileManager.clearFileCache();
771        }
772        return new Promise(function (resolve, reject) {
773            var startTime, endTime, totalMilliseconds, remainingSheets;
774            startTime = endTime = new Date();
775
776            // Set counter for remaining unprocessed sheets
777            remainingSheets = less.sheets.length;
778
779            if (remainingSheets === 0) {
780
781                endTime = new Date();
782                totalMilliseconds = endTime - startTime;
783                less.logger.info('Less has finished and no sheets were loaded.');
784                resolve({
785                    startTime: startTime,
786                    endTime: endTime,
787                    totalMilliseconds: totalMilliseconds,
788                    sheets: less.sheets.length
789                });
790
791            } else {
792                // Relies on less.sheets array, callback seems to be guaranteed to be called for every element of the array
793                loadStyleSheets(function (e, css, _, sheet, webInfo) {
794                    if (e) {
795                        errors.add(e, e.href || sheet.href);
796                        reject(e);
797                        return;
798                    }
799                    if (webInfo.local) {
800                        less.logger.info('Loading ' + sheet.href + ' from cache.');
801                    } else {
802                        less.logger.info('Rendered ' + sheet.href + ' successfully.');
803                    }
804                    browser.createCSS(window.document, css, sheet);
805                    less.logger.info('CSS for ' + sheet.href + ' generated in ' + (ne
805w Date() - endTime) + 'ms');
806
807                    // Count completed sheet
808                    remainingSheets--;
809
810                    // Check if the last remaining sheet was processed and then call the promise
811                    if (remainingSheets === 0) {
812                        totalMilliseconds = new Date() - startTime;
813                        less.logger.info('Less has finished. CSS generated in ' + totalMilliseconds + 'ms');
814                        resolve({
815                            startTime: startTime,
816                            endTime: endTime,
817                            totalMilliseconds: totalMilliseconds,
818                            sheets: less.sheets.length
819                        });
820                    }
821                    endTime = new Date();
822                }, reload, modifyVars);
823            }
824
825            loadStyles(modifyVars);
826        });
827    };
828
829    less.refreshStyles = loadStyles;
830    return less;
831};
832
833},{"../less":35,"./browser":3,"./cache":4,"./error-reporting":5,"./file-manager":6,"./image-size":7,"./log-listener":9,"./plugin-loader":10,"./utils":11}],9:[function(require,module,exports){
834module.exports = function(less, options) {
835
836    var logLevel_debug = 4,
837        logLevel_info = 3,
838        logLevel_warn = 2,
839        logLevel_error = 1;
840
841    // The amount of logging in the javascript console.
842    // 3 - Debug, information and errors
843    // 2 - Information and errors
844    // 1 - Errors
845    // 0 - None
846    // Defaults to 2
847    options.logLevel = typeof options.logLevel !== 'undefined' ? options.logLevel : (options.env === 'development' ?  logLevel_info : logLevel_error);
848
849    if (!options.loggers) {
850        options.loggers = [{
851            debug: function(msg) {
852                if (options.logLevel >= logLevel_debug) {
853                    console.log(msg);
854                }
855            },
856            info: function(msg) {
857                if (options.logLevel >= logLevel_info) {
858                    console.log(msg);
859                }
860            },
861            warn: function(msg) {
862                if (options.logLevel >= logLevel_warn) {
863                    console.warn(msg);
864                }
865            },
866            error: function(msg) {
867                if (options.logLevel >= logLevel_error) {
868                    console.error(msg);
869                }
870            }
871        }];
872    }
873    for (var i = 0; i < options.loggers.length; i++) {
874        less.logger.addListener(options.loggers[i]);
875    }
876};
877
878},{}],10:[function(require,module,exports){
879// TODO: Add tests for browser @plugin
880/* global window */
881
882var AbstractPluginLoader = require('../less/environment/abstract-plugin-loader.js');
883
884/**
885 * Browser Plugin Loader
886 */
887var PluginLoader = function(less) {
888    this.less = less;
889    // shim for browser require?
890    this.require = require;
891};
892
893PluginLoader.prototype = new AbstractPluginLoader();
894
895PluginLoader.prototype.loadPlugin = function(filename, basePath, context, environment, fileManager) {
896    return new Promise(function(fulfill, reject) {
897        fileManager.loadFile(filename, basePath, context, environment)
898            .then(fulfill).catch(reject);
899    });
900};
901
902module.exports = PluginLoader;
903
904
905},{"../less/environment/abstract-plugin-loader.js":18}],11:[function(require,module,exports){
906module.exports = {
907    extractId: function(href) {
908        return href.replace(/^[a-z-]+:\/+?[^\/]+/, '')  // Remove protocol & domain
909            .replace(/[\?\&]livereload=\w+/, '')        // Remove LiveReload cachebuster
910            .replace(/^\//, '')                         // Remove root /
911            .replace(/\.[a-zA-Z]+$/, '')                // Remove simple extension
912            .replace(/[^\.\w-]+/g, '-')                 // Replace illegal characters
913            .replace(/\./g, ':');
913                       // Replace dots with colons(for valid id)
914    },
915    addDataAttr: function(options, tag) {
916        for (var opt in tag.dataset) {
917            if (tag.dataset.hasOwnProperty(opt)) {
918                if (opt === 'env' || opt === 'dumpLineNumbers' || opt === 'rootpath' || opt === 'errorReporting') {
919                    options[opt] = tag.dataset[opt];
920                } else {
921                    try {
922                        options[opt] = JSON.parse(tag.dataset[opt]);
923                    }
924                    catch (_) {}
925                }
926            }
927        }
928    }
929};
930
931},{}],12:[function(require,module,exports){
932var contexts = {};
933module.exports = contexts;
934
935var copyFromOriginal = function copyFromOriginal(original, destination, propertiesToCopy) {
936    if (!original) { return; }
937
938    for (var i = 0; i < propertiesToCopy.length; i++) {
939        if (original.hasOwnProperty(propertiesToCopy[i])) {
940            destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
941        }
942    }
943};
944
945/*
946 parse is used whilst parsing
947 */
948var parseCopyProperties = [
949    // options
950    'paths',            // option - unmodified - paths to search for imports on
951    'relativeUrls',     // option - whether to adjust URL's to be relative
952    'rootpath',         // option - rootpath to append to URL's
953    'strictImports',    // option -
954    'insecure',         // option - whether to allow imports from insecure ssl hosts
955    'dumpLineNumbers',  // option - whether to dump line numbers
956    'compress',         // option - whether to compress
957    'syncImport',       // option - whether to import synchronously
958    'chunkInput',       // option - whether to chunk input. more performant but causes parse issues.
959    'mime',             // browser only - mime type for sheet import
960    'useFileCache',     // browser only - whether to use the per file session cache
961    // context
962    'processImports',   // option & context - whether to process imports. if false then imports will not be imported.
963                        // Used by the import manager to stop multiple import visitors being created.
964    'pluginManager'     // Used as the plugin manager for the session
965];
966
967contexts.Parse = function(options) {
968    copyFromOriginal(options, this, parseCopyProperties);
969
970    if (typeof this.paths === 'string') { this.paths = [this.paths]; }
971};
972
973var evalCopyProperties = [
974    'paths',             // additional include paths
975    'compress',          // whether to compress
976    'ieCompat',          // whether to enforce IE compatibility (IE8 data-uri)
977    'strictMath',        // whether math has to be within parenthesis
978    'strictUnits',       // whether units need to evaluate correctly
979    'sourceMap',         // whether to output a source map
980    'importMultiple',    // whether we are currently importing multiple copies
981    'urlArgs',           // whether to add args into url tokens
982    'javascriptEnabled', // option - whether Inline JavaScript is enabled. if undefined, defaults to false
983    'pluginManager',     // Used as the plugin manager for the session
984    'importantScope'     // used to bubble up !important statements
985];
986
987contexts.Eval = function(options, frames) {
988    copyFromOriginal(options, this, evalCopyProperties);
989
990    if (typeof this.paths === 'string') { this.paths = [this.paths]; }
991
992    this.frames = frames || [];
993    this.importantScope = this.importantScope || [];
994};
995
996contexts.Eval.prototype.inParenthesis = function () {
997    if (!this.parensStack) {
998        this.parensStack = [];
999    }
1000    this.parensStack.push(true);
1001};
1002
1003contexts.Eval.prototype.outOfParenthesis = function () {
1004    this.parensStack.pop();
1005};
1006
1007contexts.Eval.prototype.mathOn = true;
1008contexts.Eval.prototype.isMathOn = function () {
1009    if (!this.mathOn) {
1010        return false;
1011    }
1012    return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
1013};
1014
1015contexts.Eval.prototype.isPathRelative = function (path) {
1016    return !/^(?:[a-z-]+:|\/|#)/i.test(path);
1017};
1018
1019contexts.Eval.prototype.normalizePath = function( path ) {
1020    var
1021        segments = path.split('/').reverse(),
1022        segment;
1023
1024    path = [];
1025    while (segments.length !== 0 ) {
1026        segment = segments.pop();
1027        switch ( segment ) {
1028            case '.':
1029                break;
1030            case '..':
1031                if ((path.length === 0) || (path[path.length - 1] === '..')) {
1032                    path.push( segment );
1033                } else {
1034                    path.pop();
1035                }
1036                break;
1037            default:
1038                path.push( segment );
1039                break;
1040        }
1041    }
1042
1043    return path.join('/');
1044};
1045
1046// todo - do the same for the toCSS ?
1047
1048},{}],13:[function(require,module,exports){
1049module.exports = {
1050    'aliceblue':'#f0f8ff',
1051    'antiquewhite':'#faebd7',
1052    'aqua':'#00ffff',
1053    'aquamarine':'#7fffd4',
1054    'azure':'#f0ffff',
1055    'beige':'#f5f5dc',
1056    'bisque':'#ffe4c4',
1057    'black':'#000000',
1058    'blanchedalmond':'#ffebcd',
1059    'blue':'#0000ff',
1060    'blueviolet':'#8a2be2',
1061    'brown':'#a52a2a',
1062    'burlywood':'#deb887',
1063    'cadetblue':'#5f9ea0',
1064    'chartreuse':'#7fff00',
1065    'chocolate':'#d2691e',
1066    'coral':'#ff7f50',
1067    'cornflowerblue':'#6495ed',
1068    'cornsilk':'#fff8dc',
1069    'crimson':'#dc143c',
1070    'cyan':'#00ffff',
1071    'darkblue':'#00008b',
1072    'darkcyan':'#008b8b',
1073    'darkgoldenrod':'#b8860b',
1074    'darkgray':'#a9a9a9',
1075    'darkgrey':'#a9a9a9',
1076    'darkgreen':'#006400',
1077    'darkkhaki':'#bdb76b',
1078    'darkmagenta':'#8b008b',
1079    'darkolivegreen':'#556b2f',
1080    'darkorange':'#ff8c00',
1081    'darkorchid':'#9932cc',
1082    'darkred':'#8b0000',
1083    'darksalmon':'#e9967a',
1084    'darkseagreen':'#8fbc8f',
1085    'darkslateblue':'#483d8b',
1086    'darkslategray':'#2f4f4f',
1087    'darkslategrey':'#2f4f4f',
1088    'darkturquoise':'#00ced1',
1089    'darkviolet':'#9400d3',
1090    'deeppink':'#ff1493',
1091    'deepskyblue':'#00bfff',
1092    'dimgray':'#696969',
1093    'dimgrey':'#696969',
1094    'dodgerblue':'#1e90ff',
1095    'firebrick':'#b22222',
1096    'floralwhite':'#fffaf0',
1097    'forestgreen':'#228b22',
1098    'fuchsia':'#ff00ff',
1099    'gainsboro':'#dcdcdc',
1100    'ghostwhite':'#f8f8ff',
1101    'gold':'#ffd700',
1102    'goldenrod':'#daa520',
1103    'gray':'#808080',
1104    'grey':'#808080',
1105    'green':'#008000',
1106    'greenyellow':'#adff2f',
1107    'honeydew':'#f0fff0',
1108    'hotpink':'#ff69b4',
1109    'indianred':'#cd5c5c',
1110    'indigo':'#4b0082',
1111    'ivory':'#fffff0',
1112    'khaki':'#f0e68c',
1113    'lavender':'#e6e6fa',
1114    'lavenderblush':'#fff0f5',
1115    'lawngreen':'#7cfc00',
1116    'lemonchiffon':'#fffacd',
1117    'lightblue':'#add8e6',
1118    'lightcoral':'#f08080',
1119    'lightcyan':'#e0ffff',
1120    'lightgoldenrodyellow':'#fafad2',
1121    'lightgray':'#d3d3d3',
1122    'lightgrey':'#d3d3d3',
1123    'lightgreen':'#90ee90',
1124    'lightpink':'#ffb6c1',
1125    'lightsalmon':'#ffa07a',
1126    'lightseagreen':'#20b2aa',
1127    'lightskyblue':'#87cefa',
1128    'lightslategray':'#778899',
1129    'lightslategrey':'#778899',
1130    'lightsteelblue':'#b0c4de',
1131    'lightyellow':'#ffffe0',
1132    'lime':'#00ff00',
1133    'limegreen':'#32cd32',
1134    'linen':'#faf0e6',
1135    'magenta':'#ff00ff',
1136    'maroon':'#800000',
1137    'mediumaquamarine':'#66cdaa',
1138    'mediumblue':'#0000cd',
1139    'mediumorchid':'#ba55d3',
1140    'mediumpurple':'#9370d8',
1141    'mediumseagreen':'#3cb371',
1142    'mediumslateblue':'#7b68ee',
1143    'mediumspringgreen':'#00fa9a',
1144    'mediumturquoise':'#48d1cc',
1145    'mediumvioletred':'#c71585',
1146    'midnightblue':'#191970',
1147    'mintcream':'#f5fffa',
1148    'mistyrose':'#ffe4e1',
1149    'moccasin':'#ffe4b5',
1150    'navajowhite':'#ffdead',
1151    'navy':'#000080',
1152    'oldlace':'#fdf5e6',
1153    'olive':'#808000',
1154    'olivedrab':'#6b8e23',
1155    'orange':'#ffa500',
1156    'orangered':'#ff4500',
1157    'orchid':'#da70d6',
1158    'palegoldenrod':'#eee8aa',
1159    'palegreen':'#98fb98',
1160    'paleturquoise':'#afeeee',
1161    'palevioletred':'#d87093',
1162    'papayawhip':'#ffefd5',
1163    'peachpuff':'#ffdab9',
1164    'peru':'#cd853f',
1165    'pink':'#ffc0cb',
1166    'plum':'#dda0dd',
1167    'powderblue':'#b0e0e6',
1168    'purple':'#800080',
1169    'rebeccapurple':'#663399',
1170    'red':'#ff0000',
1171    'rosybrown':'#bc8f8f',
1172    'royalblue':'#4169e1',
1173    'saddlebrown':'#8b4513',
1174    'salmon':'#fa8072',
1175    'sandybrown':'#f4a460',
1176    'seagreen':'#2e8b57',
1177    'seashell':'#fff5ee',
1178    'sienna':'#a0522d',
1179    'silver':'#c0c0c0',
1180    'skyblue':'#87ceeb',
1181    'slateblue':'#6a5acd',
1182    'slategray':'#708090',
1183    'slategrey':'#708090',
1184    'snow':'#fffafa',
1185    'springgreen':'#00ff7f',
1186    'steelblue':'#4682b4',
1187    'tan':'#d2b48c',
1188    'teal':'#008080',
1189    'thistle':'#d8bfd8',
1190    'tomato':'#ff6347',
1191    'turquoise':'#40e0d0',
1192    'violet':'#ee82ee',
1193    'wheat':'#f5deb3',
1194    'white':'#ffffff',
1195    'whitesmoke':'#f5f5f5',
1196    'yellow':'#ffff00',
1197    'yellowgreen':'#9acd32'
1198};
1199},{}],14:[function(require,module,exports){
1200module.exports = {
1201    colors: require('./colors'),
1202    unitConversions: require('./unit-conversions')
1203};
1204
1205},{"./colors":13,"./unit-conversions":15}],15:[function(require,module,exports){
1206module.exports = {
1207    length: {
1208        'm': 1,
1209        'cm': 0.01,
1210        'mm': 0.001,
1211        'in': 0.0254,
1212        'px': 0.0254 / 96,
1213        'pt': 0.0254 / 72,
1214        'pc': 0.0254 / 72 * 12
1215    },
1216    duration: {
1217        's': 1,
1218        'ms': 0.001
1219    },
1220    angle: {
1221        'rad': 1 / (2 * Math.PI),
1222        'deg': 1 / 360,
1223        'grad': 1 / 400,
1224        'turn': 1
1225    }
1226};
1227},{}],16:[function(require,module,exports){
1228// Export a new default each time
1229module.exports = function() {
1230    return {
1231        /* Outputs a makefile import dependency list to stdout. */
1232        depends: false,
1233
1234        /* Compress using less built-in compression. 
1235         * This does an okay job but does not utilise all the tricks of 
1236         * dedicated css compression. */
1237        compress: false,
1238
1239        /* Runs the less parser and just reports errors without any output. */
1240        lint: false,
1241
1242        /* Sets available include paths.
1243         * If the file in an @import rule does not exist at that exact location, 
1244         * less will look for it at the location(s) passed to this option. 
1245         * You might use this for instance to specify a path to a library which 
1246         * you want to be referenced simply and relatively in the less files. */
1247        paths: [],
1248
1249        /* color output in the terminal */
1250        color: true,
1251
1252        /* The strictImports controls whether the compiler will allow an @import inside of either 
1253         * @media blocks or (a later addition) other selector blocks.
1254         * See: https://github.com/less/less.js/issues/656 */
1255        strictImports: false,
1256
1257        /* Allow Imports from Insecure HTTPS Hosts */
1258        insecure: false,
1259
1260        /* Allows you to add a path to every generated import and url in your css. 
1261         * This does not affect less import statements that are processed, just ones 
1262         * that are left in the output css. */
1263        rootpath: '',
1264
1265        /* By default URLs are kept as-is, so if you import a file in a sub-directory 
1266         * that references an image, exactly the same URL will be output in the css. 
1267         * This option allows you to re-write URL's in imported files so that the 
1268         * URL is always relative to the base imported file */
1269        relativeUrls: false,
1270
1271        /* Compatibility with IE8. Used for limiting data-uri length */
1272        ieCompat: false,  // true until 3.0
1273
1274        /* Without this option on, Less will try and process all math in your css */
1275        strictMath: false,
1276
1277        /* Without this option, less attempts to guess at the output unit when it does maths. */
1278        strictUnits: false,
1279
1280        /* Effectively the declaration is put at the top of your base Less file, 
1281         * meaning it can be used but it also can be overridden if this variable 
1282         * is defined in the file. */
1283        globalVars: null,
1284
1285        /* As opposed to the global variable option, this puts the declaration at the
1286         * end of your base file, meaning it will override anything defined in your Less file. */
1287        modifyVars: null,
1288
1289        /* This option allows you to specify a argument to go on to every URL.  */
1290        urlArgs: ''
1291    }
1292}
1293},{}],17:[function(require,module,exports){
1294var abstractFileManager = function() {
1295};
1296
1297abstractFileManager.prototype.getPath = function (filename) {
1298    var j = filename.lastIndexOf('?');
1299    if (j > 0) {
1300        filename = filename.slice(0, j);
1301    }
1302    j = filename.lastIndexOf('/');
1303    if (j < 0) {
1304        j = filename.lastIndexOf('\\');
1305    }
1306    if (j < 0) {
1307        return '';
1308    }
1309    return filename.slice(0, j + 1);
1310};
1311
1312abstractFileManager.prototype.tryAppendExtension = function(path, ext) {
1313    return /(\.[a-z]*$)|([\?;].*)$/.test(path) ? path : path + ext;
1314};
1315
1316abstractFileManager.prototype.tryAppendLessExtension = function(path) {
1317    return this.tryAppendExtension(path, '.less');
1318};
1319
1320abstractFileManager.prototype.supportsSync = function() {
1321    return false;
1322};
1323
1324abstractFileManager.prototype.alwaysMakePathsAbsolute = function() {
1325    return false;
1326};
1327
1328abstractFileManager.prototype.isPathAbsolute = function(filename) {
1329    return (/^(?:[a-z-]+:|\/|\\|#)/i).test(filename);
1330};
1331// TODO: pull out / replace?
1332abstractFileManager.prototype.join = function(basePath, laterPath) {
1333    if (!basePath) {
1334        return laterPath;
1335    }
1336    return basePath + laterPath;
1337};
1338
1339abstractFileManager.prototype.pathDiff = function pathDiff(url, baseUrl) {
1340    // diff between two paths to create a relative path
1341
1342    var urlParts = this.extractUrlParts(url),
1343        baseUrlParts = this.extractUrlParts(baseUrl),
1344        i, max, urlDirectories, baseUrlDirectories, diff = '';
1345    if (urlParts.hostPart !== baseUrlParts.hostPart) {
1346        return '';
1347    }
1348    max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
1349    for (i = 0; i < max; i++) {
1350        if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
1351    }
1352    baseUrlDirectories = baseUrlParts.directories.slice(i);
1353    urlDirectories = urlParts.directories.slice(i);
1354    for (i = 0; i < baseUrlDirectories.length - 1; i++) {
1355        diff += '../';
1356    }
1357    for (i = 0; i < urlDirectories.length - 1; i++) {
1358        diff += urlDirectories[i] + '/';
1359    }
1360    return diff;
1361};
1362// helper function, not part of API
1363abstractFileManager.prototype.extractUrlParts = function extractUrlParts(url, baseUrl) {
1364    // urlParts[1] = protocol://hostname/ OR /
1365    // urlParts[2] = / if path relative to host base
1366    // urlParts[3] = directories
1367    // urlParts[4] = filename
1368    // urlParts[5] = parameters
1369
1370    var urlPartsRegex = /^((?:[a-z-]+:)?\/{2}(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
1371        urlParts = url.match(urlPartsRegex),
1372        returner = {}, rawDirectories = [], directories = [], i, baseUrlParts;
1373
1374    if (!urlParts) {
1375        throw new Error('Could not parse sheet href - \'' + url + '\'');
1376    }
1377
1378    // Stylesheets in IE don't always return the full path
1379    if (baseUrl && (!urlParts[1] || urlParts[2])) {
1380        baseUrlParts = baseUrl.match(urlPartsRegex);
1381        if (!baseUrlParts) {
1382            throw new Error('Could not parse page url - \'' + baseUrl + '\'');
1383        }
1384        urlParts[1] = urlParts[1] || baseUrlParts[1] || '';
1385        if (!urlParts[2]) {
1386            urlParts[3] = baseUrlParts[3] + urlParts[3];
1387        }
1388    }
1389
1390    if (urlParts[3]) {
1391        rawDirectories = urlParts[3].replace(/\\/g, '/').split('/');
1392
1393        // collapse '..' and skip '.'
1394        for (i = 0; i < rawDirectories.length; i++) {
1395
1396            if (rawDirectories[i] === '..') {
1397                directories.pop();
1398            }
1399            else if (rawDirectories[i] !== '.') {
1400                directories.push(rawDirectories[i]);
1401            }
1402        
1403        }
1404    }
1405
1406    returner.hostPart = urlParts[1];
1407    returner.directories = directories;
1408    returner.rawPath = (urlParts[1] || '') + rawDirectories.join('/');
1409    returner.path = (urlParts[1] || '') + directories.join('/');
1410    returner.filename = urlParts[4];
1411    returner.fileUrl = returner.path + (urlParts[4] || '');
1412    returner.url = returner.fileUrl + (urlParts[5] || '');
1413    return returner;
1414};
1415
1416module.exports = abstractFileManager;
1417
1418},{}],18:[function(require,module,exports){
1419var functionRegistry = require('../functions/function-registry'),
1420    LessError = require('../less-error');
1421
1422var AbstractPluginLoader = function() {
1423};
1424
1425function error(msg, type) {
1426    throw new LessError(
1427        {
1428            type: type || 'Syntax',
1429            message: msg
1430        }
1431    );
1432}
1433AbstractPluginLoader.prototype.evalPlugin = function(contents, context, imports, pluginOptions, fileInfo) {
1434
1435    var loader,
1436        registry,
1437        pluginObj,
1438        localModule,
1439        pluginManager,
1440        filename;
1441
1442    pluginManager = context.pluginManager;
1443
1444    if (fileInfo) {
1445        if (typeof fileInfo === 'string') {
1446            filename = fileInfo;
1447        }
1448        else {
1449            filename = fileInfo.filename;
1450        }
1451    }
1452    var shortname = (new this.less.FileManager()).extractUrlParts(filename).filename;
1453
1454    if (filename) {
1455        pluginObj = pluginManager.get(filename);
1456
1457        if (pluginObj) {
1458            this.trySetOptions(pluginObj, filename, shortname, pluginOptions);
1459            try {
1460                if (pluginObj.use) {
1461                    pluginObj.use.call(this.context, pluginObj);
1462                }
1463            }
1464            catch (e) {
1465                e.message = 'Error during @plugin call';
1466                return new this.less.LessError(e, imports, filename);
1467            }
1468            return pluginObj;
1469        }
1470    }
1471    localModule = {
1472        exports: {},
1473        pluginManager: pluginManager,
1474        fileInfo: fileInfo
1475    };
1476    registry = functionRegistry.create();
1477
1478    var registerPlugin = function(obj) {
1479        pluginObj = obj;
1480    };
1481
1482    try {
1483        loader = new Function('module', 'require', 'registerPlugin', 'functions', 'tree', 'less', 'fileInfo', contents);
1484        loader(localModule, this.require, registerPlugin, registry, this.less.tree, this.less, fileInfo);
1485    } catch (e) {
1486        return new this.less.LessError(e, imports, filename);
1487    }
1488
1489    if (!pluginObj) {
1490        pluginObj = localModule.exports;
1491    }
1492    pluginObj = this.validatePlugin(pluginObj, filename, shortname);
1493
1494    if (pluginObj) {
1495        // Run on first load
1496        pluginManager.addPlugin(pluginObj, fileInfo.filename, registry);
1497        pluginObj.functions = registry.getLocalFunctions();
1498        pluginObj.imports = imports;
1499        pluginObj.filename = filename;
1500
1501        this.trySetOptions(pluginObj, filename, shortname, pluginOptions);
1502
1503        // Run every @plugin call
1504        try {
1505            if (pluginObj.use) {
1506                pluginObj.use.call(this.context, pluginObj);
1507            }
1508        }
1509        catch (e) {
1510            e.message = 'Error during @plugin call';
1511            return new this.less.LessError(e, imports, filename);
1512        }
1513
1514    }
1515    else {
1516        return new this.less.LessError({ message: 'Not a valid plugin' });
1517    }
1518
1519    return pluginObj;
1520
1521};
1522
1523AbstractPluginLoader.prototype.trySetOptions = function(plugin, filename, name, options) {
1524    if (options) {
1525        if (!plugin.setOptions) {
1526            error('Options have been provided but the plugin ' + n
1526ame + ' does not support any options.');
1527            return null;
1528        }
1529        try {
1530            plugin.setOptions(options);
1531        }
1532        catch (e) {
1533            error('Error setting options on plugin ' + name + '\n' + e.message);
1534            return null;
1535        }
1536    }
1537};
1538
1539AbstractPluginLoader.prototype.validatePlugin = function(plugin, filename, name) {
1540    if (plugin) {
1541        // support plugins being a function
1542        // so that the plugin can be more usable programmatically
1543        if (typeof plugin === 'function') {
1544            plugin = new plugin();
1545        }
1546
1547        if (plugin.minVersion) {
1548            if (this.compareVersion(plugin.minVersion, this.less.version) < 0) {
1549                error('Plugin ' + name + ' requires version ' + this.versionToString(plugin.minVersion));
1550                return null;
1551            }
1552        }
1553        return plugin;
1554    }
1555    return null;
1556};
1557
1558AbstractPluginLoader.prototype.compareVersion = function(aVersion, bVersion) {
1559    if (typeof aVersion === 'string') {
1560        aVersion = aVersion.match(/^(\d+)\.?(\d+)?\.?(\d+)?/);
1561        aVersion.shift();
1562    }
1563    for (var i = 0; i < aVersion.length; i++) {
1564        if (aVersion[i] !== bVersion[i]) {
1565            return parseInt(aVersion[i]) > parseInt(bVersion[i]) ? -1 : 1;
1566        }
1567    }
1568    return 0;
1569};
1570AbstractPluginLoader.prototype.versionToString = function(version) {
1571    var versionString = '';
1572    for (var i = 0; i < version.length; i++) {
1573        versionString += (versionString ? '.' : '') + version[i];
1574    }
1575    return versionString;
1576};
1577AbstractPluginLoader.prototype.printUsage = function(plugins) {
1578    for (var i = 0; i < plugins.length; i++) {
1579        var plugin = plugins[i];
1580        if (plugin.printUsage) {
1581            plugin.printUsage();
1582        }
1583    }
1584};
1585
1586module.exports = AbstractPluginLoader;
1587
1588
1589},{"../functions/function-registry":26,"../less-error":36}],19:[function(require,module,exports){
1590/**
1591 * @todo Document why this abstraction exists, and the relationship between
1592 *       environment, file managers, and plugin manager
1593 */
1594
1595var logger = require('../logger');
1596var environment = function(externalEnvironment, fileManagers) {
1597    this.fileManagers = fileManagers || [];
1598    externalEnvironment = externalEnvironment || {};
1599
1600    var optionalFunctions = ['encodeBase64', 'mimeLookup', 'charsetLookup', 'getSourceMapGenerator'],
1601        requiredFunctions = [],
1602        functions = requiredFunctions.concat(optionalFunctions);
1603
1604    for (var i = 0; i < functions.length; i++) {
1605        var propName = functions[i],
1606            environmentFunc = externalEnvironment[propName];
1607        if (environmentFunc) {
1608            this[propName] = environmentFunc.bind(externalEnvironment);
1609        } else if (i < requiredFunctions.length) {
1610            this.warn('missing required function in environment - ' + propName);
1611        }
1612    }
1613};
1614
1615environment.prototype.getFileManager = function (filename, currentDirectory, options, environment, isSync) {
1616
1617    if (!filename) {
1618        logger.warn('getFileManager called with no filename.. Please report this issue. continuing.');
1619    }
1620    if (currentDirectory == null) {
1621        logger.warn('getFileManager called with null directory.. Please report this issue. continuing.');
1622    }
1623
1624    var fileManagers = this.fileManagers;
1625    if (options.pluginManager) {
1626        fileManagers = [].concat(fileManagers).concat(options.pluginManager.getFileManagers());
1627    }
1628    for (var i = fileManagers.length - 1; i >= 0 ; i--) {
1629        var fileManager = fileManagers[i];
1630        if (fileManager[isSync ? 'supportsSync' : 'supports'](filename, currentDirectory, options, environment)) {
1631            return fileManager;
1632        }
1633    }
1634    return null;
1635};
1636
1637environment.prototype.addFileManager = function (fileManager) {
1638    this.fileManagers.push(fileManager);
1639};
1640
1641environment.prototype.clearFileManagers = function () {
1642    this.fileManagers = [];
1643};
1644
1645module.exports = environment;
1646
1647},{"../logger":37}],20:[function(require,module,exports){
1648
1649var functionRegistry = require('./function-registry'),
1650    Anonymous = require('../tree/anonymous'),
1651    Keyword = require('../tree/keyword');
1652
1653functionRegistry.addMultiple({
1654    boolean: function(condition) {
1655        return condition ? Keyword.True : Keyword.False;
1656    },
1657
1658    'if': function(condition, trueValue, falseValue) {
1659        return condition ? trueValue
1660            : (falseValue || new Anonymous);
1661    }
1662});
1663
1664},{"../tree/anonymous":48,"../tree/keyword":68,"./function-registry":26}],21:[function(require,module,exports){
1665var Color = require('../tree/color'),
1666    functionRegistry = require('./function-registry');
1667
1668// Color Blending
1669// ref: http://www.w3.org/TR/compositing-1
1670
1671function colorBlend(mode, color1, color2) {
1672    var ab = color1.alpha, cb, // backdrop
1673        as = color2.alpha, cs, // source
1674        ar, cr, r = [];        // result
1675
1676    ar = as + ab * (1 - as);
1677    for (var i = 0; i < 3; i++) {
1678        cb = color1.rgb[i] / 255;
1679        cs = color2.rgb[i] / 255;
1680        cr = mode(cb, cs);
1681        if (ar) {
1682            cr = (as * cs + ab * (cb -
1683                  as * (cb + cs - cr))) / ar;
1684        }
1685        r[i] = cr * 255;
1686    }
1687
1688    return new Color(r, ar);
1689}
1690
1691var colorBlendModeFunctions = {
1692    multiply: function(cb, cs) {
1693        return cb * cs;
1694    },
1695    screen: function(cb, cs) {
1696        return cb + cs - cb * cs;
1697    },
1698    overlay: function(cb, cs) {
1699        cb *= 2;
1700        return (cb <= 1) ?
1701            colorBlendModeFunctions.multiply(cb, cs) :
1702            colorBlendModeFunctions.screen(cb - 1, cs);
1703    },
1704    softlight: function(cb, cs) {
1705        var d = 1, e = cb;
1706        if (cs > 0.5) {
1707            e = 1;
1708            d = (cb > 0.25) ? Math.sqrt(cb)
1709                : ((16 * cb - 12) * cb + 4) * cb;
1710        }
1711        return cb - (1 - 2 * cs) * e * (d - cb);
1712    },
1713    hardlight: function(cb, cs) {
1714        return colorBlendModeFunctions.overlay(cs, cb);
1715    },
1716    difference: function(cb, cs) {
1717        return Math.abs(cb - cs);
1718    },
1719    exclusion: function(cb, cs) {
1720        return cb + cs - 2 * cb * cs;
1721    },
1722
1723    // non-w3c functions:
1724    average: function(cb, cs) {
1725        return (cb + cs) / 2;
1726    },
1727    negation: function(cb, cs) {
1728        return 1 - Math.abs(cb + cs - 1);
1729    }
1730};
1731
1732for (var f in colorBlendModeFunctions) {
1733    if (colorBlendModeFunctions.hasOwnProperty(f)) {
1734        colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]);
1735    }
1736}
1737
1738functionRegistry.addMultiple(colorBlend);
1739
1740},{"../tree/color":53,"./function-registry":26}],22:[function(require,module,exports){
1741var Dimension = require('../tree/dimension'),
1742    Color = require('../tree/color'),
1743    Quoted = require('../tree/quoted'),
1744    Anonymous = require('../tree/anonymous'),
1745    functionRegistry = require('./function-registry'),
1746    colorFunctions;
1747
1748function clamp(val) {
1749    return Math.min(1, Math.max(0, val));
1750}
1751function hsla(color) {
1752    return colorFunctions.hsla(color.h, color.s, color.l, color.a);
1753}
1754function number(n) {
1755    if (n instanceof Dimension) {
1756        return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
1757    } else if (typeof n === 'number') {
1758        return n;
1759    } else {
1760        throw {
1761            type: 'Argument',
1762            message: 'color functions take numbers as parameters'
1763        };
1764    }
1765}
1766function scaled(n, size) {
1767    if (n instanceof Dimension && n.unit.is('%')) {
1768        return parseFloat(n.value * size / 100);
1769    } else {
1770        return number(n);
1771    }
1772}
1773colorFunctions = {
1774    rgb: function (r, g, b) {
1775        return colorFunctions.rgba(r, g, b, 1.0);
1776    },
1777    rgba: function (r, g, b, a) {
1778        var rgb = [r, g, b].map(function (c) { return scaled(c, 255); });
1779        a = number(a);
1780        return new Color(rgb, a);
1781    },
1782    hsl: function (h, s, l) {
1783        return colorFunctions.hsla(h, s, l, 1.0);
1784    },
1785    hsla: function (h, s, l, a) {
1786
1787        var m1, m2;
1788
1789        function hue(h) {
1790            h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1791            if (h * 6 < 1) {
1792                return m1 + (m2 - m1) * h * 6;
1793            }
1794            else if (h * 2 < 1) {
1795                return m2;
1796            }
1797            else if (h * 3 < 2) {
1798                return m1 + (m2 - m1) * (2 / 3 - h) * 6;
1799            }
1800            else {
1801                return m1;
1802            }
1803        }
1804
1805        h = (number(h) % 360) / 360;
1806        s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));
1807
1808        m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1809        m1 = l * 2 - m2;
1810
1811        return colorFunctions.rgba(hue(h + 1 / 3) * 255,
1812            hue(h)       * 255,
1813            hue(h - 1 / 3) * 255,
1814            a);
1815    },
1816
1817    hsv: function(h, s, v) {
1818        return colorFunctions.hsva(h, s, v, 1.0);
1819    },
1820
1821    hsva: function(h, s, v, a) {
1822        h = ((number(h) % 360) / 360) * 360;
1823        s = number(s); v = number(v); a = number(a);
1824
1825        var i, f;
1826        i = Math.floor((h / 60) % 6);
1827        f = (h / 60) - i;
1828
1829        var vs = [v,
1830            v * (1 - s),
1831            v * (1 - f * s),
1832            v * (1 - (1 - f) * s)];
1833        var perm = [[0, 3, 1],
1834            [2, 0, 1],
1835            [1, 0, 3],
1836            [1, 2, 0],
1837            [3, 1, 0],
1838            [0, 1, 2]];
1839
1840        return colorFunctions.rgba(vs[perm[i][0]] * 255,
1841            vs[perm[i][1]] * 255,
1842            vs[perm[i][2]] * 255,
1843            a);
1844    },
1845
1846    hue: function (color) {
1847        return new Dimension(color.toHSL().h);
1848    },
1849    saturation: function (color) {
1850        return new Dimension(color.toHSL().s * 100, '%');
1851    },
1852    lightness: function (color) {
1853        return new Dimension(color.toHSL().l * 100, '%');
1854    },
1855    hsvhue: function(color) {
1856        return new Dimension(color.toHSV().h);
1857    },
1858    hsvsaturation: function (color) {
1859        return new Dimension(color.toHSV().s * 100, '%');
1860    },
1861    hsvvalue: function (color) {
1862        return new Dimension(color.toHSV().v * 100, '%');
1863    },
1864    red: function (color) {
1865        return new Dimension(color.rgb[0]);
1866    },
1867    green: function (color) {
1868        return new Dimension(color.rgb[1]);
1869    },
1870    blue: function (color) {
1871        return new Dimension(color.rgb[2]);
1872    },
1873    alpha: function (color) {
1874        return new Dimension(color.toHSL().a);
1875    },
1876    luma: function (color) {
1877        return new Dimension(color.luma() * color.alpha * 100, '%');
1878    },
1879    luminance: function (color) {
1880        var luminance =
1881            (0.2126 * color.rgb[0] / 255) +
1882                (0.7152 * color.rgb[1] / 255) +
1883                (0.0722 * color.rgb[2] / 255);
1884
1885        return new Dimension(luminance * color.alpha * 100, '%');
1886    },
1887    saturate: function (color, amount, method) {
1888        // filter: saturate(3.2);
1889        // should be kept as is, so check for color
1890        if (!color.rgb) {
1891            return null;
1892        }
1893        var hsl = color.toHSL();
1894
1895        if (typeof method !== 'undefined' && method.value === 'relative') {
1896            hsl.s +=  hsl.s * amount.value / 100;
1897        }
1898        else {
1899            hsl.s += amount.value / 100;
1900        }
1901        hsl.s = clamp(hsl.s);
1902        return hsla(hsl);
1903    },
1904    desaturate: function (color, amount, method) {
1905        var hsl = color.toHSL();
1906
1907        if (typeof method !== 'undefined' && method.value === 'relative') {
1908            hsl.s -=  hsl.s * amount.value / 100;
1909        }
1910        else {
1911            hsl.s -= amount.value / 100;
1912        }
1913        hsl.s = clamp(hsl.s);
1914        return hsla(hsl);
1915    },
1916    lighten: function (color, amount, method) {
1917        var hsl = color.toHSL();
1918
1919        if (typeof method !== 'undefined' && method.value === 'relative') {
1920            hsl.l +=  hsl.l * amount.value / 100;
1921        }
1922        else {
1923            hsl.l += amount.value / 100;
1924        }
1925        hsl.l = clamp(hsl.l);
1926        return hsla(hsl);
1927    },
1928    darken: function (color, amount, method) {
1929        var hsl = color.toHSL();
1930
1931        if (typeof method !== 'undefined' && method.value === 'relative') {
1932            hsl.l -=  hsl.l * amount.value / 100;
1933        }
1934        else {
1935            hsl.l -= amount.value / 100;
1936        }
1937        hsl.l = clamp(hsl.l);
1938        return hsla(hsl);
1939    },
1940    fadein: function (color, amount, method) {
1941        var hsl = color.toHSL();
1942
1943        if (typeof method !== 'undefined' && method.value === 'relative') {
1944            hsl.a +=  hsl.a * amount.value / 100;
1945        }
1946        else {
1947            hsl.a += amount.value / 100;
1948        }
1949        hsl.a = clamp(hsl.a);
1950        return hsla(hsl);
1951    },
1952    fadeout: function (color, amount, method) {
1953        var hsl = color.toHSL();
1954
1955        if (typeof method !== 'undefined' && method.value === 'relative') {
1956            hsl.a -=  hsl.a * amount.value / 100;
1957        }
1958        else {
1959            hsl.a -= amount.value / 100;
1960        }
1961        hsl.a = clamp(hsl.a);
1962        return hsla(hsl);
1963    },
1964    fade: function (color, amount) {
1965        var hsl = color.toHSL();
1966
1967        hsl.a = amount.value / 100;
1968        hsl.a = clamp(hsl.a);
1969        return hsla(hsl);
1970    },
1971    spin: function (color, amount) {
1972        var hsl = color.toHSL();
1973        var hue = (hsl.h + amount.value) % 360;
1974
1975        hsl.h = hue < 0 ? 360 + hue : hue;
1976
1977        return hsla(hsl);
1978    },
1979    //
1980    // Copyright (c) 2006-2009 Hampton Catlin, Natalie Weizenbaum, and Chris Eppstein
1981    // http://sass-lang.com
1982    //
1983    mix: function (color1, color2, weight) {
1984        if (!color1.toHSL || !color2.toHSL) {
1985            console.log(color2.type);
1986            console.dir(color2);
1987        }
1988        if (!weight) {
1989            weight = new Dimension(50);
1990        }
1991        var p = weight.value / 100.0;
1992        var w = p * 2 - 1;
1993        var a = color1.toHSL().a - color2.toHSL().a;
1994
1995        var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1996        var w2 = 1 - w1;
1997
1998        var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1999            color1.rgb[1] * w1 + color2.rgb[1] * w2,
2000            color1.rgb[2] * w1 + color2.rgb[2] * w2];
2001
2002        var alpha = color1.alpha * p + color2.alpha * (1 - p);
2003
2004        return new Color(rgb, alpha);
2005    },
2006    greyscale: function (color) {
2007        return colorFunctions.desaturate(color, new Dimension(100));
2008    },
2009    contrast: function (color, dark, light, threshold) {
2010        // filter: contrast(3.2);
2011        // should be kept as is, so check for color
2012        if (!color.rgb) {
2013            return null;
2014        }
2015        if (typeof light === 'undefined') {
2016            light = colorFunctions.rgba(255, 255, 255, 1.0);
2017        }
2018        if (typeof dark === 'undefined') {
2019            dark = colorFunctions.rgba(0, 0, 0, 1.0);
2020        }
2021        // Figure out which is actually light and dark:
2022        if (dark.luma() > light.luma()) {
2023            var t = light;
2024            light = dark;
2025            dark = t;
2026        }
2027        if (typeof threshold === 'undefined') {
2028            threshold = 0.43;
2029        } else {
2030            threshold = number(threshold);
2031        }
2032        if (color.luma() < threshold) {
2033            return light;
2034        } else {
2035            return dark;
2036        }
2037    },
2038    // Changes made in 2.7.0 - Reverted in 3.0.0
2039    // contrast: function (color, color1, color2, threshold) {
2040    //     // Return which of `color1` and `color2` has the greatest contrast with `color`
2041    //     // according to the standard WCAG contrast ratio calculation.
2042    //     // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
2043    //     // The threshold param is no longer used, in line with SASS.
2044    //     // filter: contrast(3.2);
2045    //     // should be kept as is, so check for color
2046    //     if (!color.rgb) {
2047    //         return null;
2048    //     }
2049    //     if (typeof color1 === 'undefined') {
2050    //         color1 = colorFunctions.rgba(0, 0, 0, 1.0);
2051    //     }
2052    //     if (typeof color2 === 'undefined') {
2053    //         color2 = colorFunctions.rgba(255, 255, 255, 1.0);
2054    //     }
2055    //     var contrast1, contrast2;
2056    //     var luma = color.luma();
2057    //     var luma1 = color1.luma();
2058    //     var luma2 = color2.luma();
2059    //     // Calculate contrast ratios for each color
2060    //     if (luma > luma1) {
2061    //         contrast1 = (luma + 0.05) / (luma1 + 0.05);
2062    //     } else {
2063    //         contrast1 = (luma1 + 0.05) / (luma + 0.05);
2064    //     }
2065    //     if (luma > luma2) {
2066    //         contrast2 = (luma + 0.05) / (luma2 + 0.05);
2067    //     } else {
2068    //         contrast2 = (luma2 + 0.05) / (luma + 0.05);
2069    //     }
2070    //     if (contrast1 > contrast2) {
2071    //         return color1;
2072    //     } else {
2073    //         return color2;
2074    //     }
2075    // },
2076    argb: function (color) {
2077        return new Anonymous(color.toARGB());
2078    },
2079    color: function(c) {
2080        if ((c instanceof Quoted) &&
2081            (/^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(c.value))) {
2082            return new Color(c.value.slice(1));
2083        }
2084        if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) {
2085            c.value = undefined;
2086            return c;
2087        }
2088        throw {
2089            type:    'Argument',
2090            message: 'argument must be a color keyword or 3/6 digit hex e.g. #FFF'
2091        };
2092    },
2093    tint: function(color, amount) {
2094        return colorFunctions.mix(colorFunctions.rgb(255, 255, 255), color, amount);
2095    },
2096    shade: function(color, amount) {
2097        return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount);
2098    }
2099};
2100functionRegistry.addMultiple(colorFunctions);
2101
2102},{"../tree/anonymous":48,"../tree/color":53,"../tree/dimension":60,"../tree/quoted":77,"./function-registry":26}],23:[function(require,module,exports){
2103module.exports = function(environment) {
2104    var Quoted = require('../tree/quoted'),
2105        URL = require('../tree/url'),
2106        utils = require('../utils'),
2107        functionRegistry = require('./function-registry'),
2108        fallback = function(functionThis, node) {
2109            return new URL(node, functionThis.index, functionThis.currentFileInfo).eval(functionThis.context);
2110        },
2111        logger = require('../logger');
2112
2113    functionRegistry.add('data-uri', function(mimetypeNode, filePathNode) {
2114
2115        if (!filePathNode) {
2116            filePathNode = mimetypeNode;
2117            mimetypeNode = null;
2118        }
2119
2120        var mimetype = mimetypeNode && mimetypeNode.value;
2121        var filePath = filePathNode.value;
2122        var currentFileInfo = this.currentFileInfo;
2123        var currentDirectory = currentFileInfo.relativeUrls ?
2124            currentFileInfo.currentDirectory : currentFileInfo.entryPath;
2125
2126        var fragmentStart = filePath.indexOf('#');
2127        var fragment = '';
2128        if (fragmentStart !== -1) {
2129            fragment = filePath.slice(fragmentStart);
2130            filePath = filePath.slice(0, fragmentStart);
2131        }
2132        var context = utils.clone(this.context);
2133        context.rawBuffer = true;
2134
2135        var fileManager = environment.getFileManager(filePath, currentDirectory, context, environment, true);
2136
2137        if (!fileManager) {
2138            return fallback(this, filePathNode);
2139        }
2140
2141        var useBase64 = false;
2142
2143        // detect the mimetype if not given
2144        if (!mimetypeNode) {
2145
2146            mimetype = environment.mimeLookup(filePath);
2147
2148            if (mimetype === 'image/svg+xml') {
2149                useBase64 = false;
2150            } else {
2151                // use base 64 unless it's an ASCII or UTF-8 format
2152                var charset = environment.charsetLookup(mimetype);
2153                useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
2154            }
2155            if (useBase64) { mimetype += ';base64'; }
2156        }
2157        else {
2158            useBase64 = /;base64$/.test(mimetype);
2159        }
2160
2161        var fileSync = fileManager.loadFileSync(filePath, currentDirectory, context, environment);
2162        if (!fileSync.contents) {
2163            logger.warn('Skipped data-uri embedding of ' + filePath + ' because file not found');
2164            return fallback(this, filePathNode || mimetypeNode);
2165        }
2166        var buf = fileSync.contents;
2167        if (useBase64 && !environment.encodeBase64) {
2168            return fallback(this, filePathNode);
2169        }
2170
2171        buf = useBase64 ? environment.encodeBase64(buf) : encodeURIComponent(buf);
2172
2173        var uri = 'data:' + mimetype + ',' + buf + fragment;
2174
2175        // IE8 cannot handle a data-uri larger than 32,768 characters. If this is exceeded
2176        // and the --ieCompat flag is enabled, return a normal url() instead.
2177        var DATA_URI_MAX = 32768;
2178        if (uri.length >= DATA_URI_MAX) {
2179
2180            if (this.context.ieCompat !== false) {
2181                logger.warn('Skipped data-uri embedding of ' + filePath + ' because its size (' + uri.length +
2182                    ' characters) exceeds IE8-safe ' + DATA_URI_MAX + ' characters!');
2183
2184                return fallback(this, filePathNode || mimetypeNode);
2185            }
2186        }
2187
2188        return new URL(new Quoted('"' + uri + '"', uri, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
2189    });
2190};
2191
2192},{"../logger":37,"../tree/quoted":77,"../tree/url":82,"../utils":86,"./function-registry":26}],24:[function(require,module,exports){
2193var Keyword = require('../tree/keyword'),
2194    functionRegistry = require('./function-registry');
2195
2196var defaultFunc = {
2197    eval: function () {
2198        var v = this.value_, e = this.error_;
2199        if (e) {
2200            throw e;
2201        }
2202        if (v != null) {
2203            return v ? Keyword.True : Keyword.False;
2204        }
2205    },
2206    value: function (v) {
2207        this.value_ = v;
2208    },
2209    error: function (e) {
2210        this.error_ = e;
2211    },
2212    reset: function () {
2213        this.value_ = this.error_ = null;
2214    }
2215};
2216
2217functionRegistry.add('default', defaultFunc.eval.bind(defaultFunc));
2218
2219module.exports = defaultFunc;
2220
2221},{"../tree/keyword":68,"./function-registry":26}],25:[function(require,module,exports){
2222var Expression = require('../tree/expression');
2223
2224var functionCaller = function(name, context, index, currentFileInfo) {
2225    this.name = name.toLowerCase();
2226    this.index = index;
2227    this.context = context;
2228    this.currentFileInfo = currentFileInfo;
2229
2230    this.func = context.frames[0].functionRegistry.get(this.name);
2231};
2232functionCaller.prototype.isValid = function() {
2233    return Boolean(this.func);
2234};
2235
2236functionCaller.prototype.call = function(args) {
2237    // This code is terrible and should be replaced as per this issue...
2238    // https://github.com/less/less.js/issues/2477
2239    if (Array.isArray(args)) {
2240        args = args.filter(function (item) {
2241            if (item.type === 'Comment') {
2242                return false;
2243            }
2244            return true;
2245        })
2246        .map(function(item) {
2247            if (item.type === 'Expression') {
2248                var subNodes = item.value.filter(function (item) {
2249                    if (item.type === 'Comment') {
2250                        return false;
2251                    }
2252                    return true;
2253                });
2254                if (subNodes.length === 1) {
2255                    return subNodes[0];
2256                } else {
2257                    return new Expression(subNodes);
2258                }
2259            }
2260            return item;
2261        });
2262    }
2263
2264    return this.func.apply(this, args);
2265};
2266
2267module.exports = functionCaller;
2268
2269},{"../tree/expression":62}],26:[function(require,module,exports){
2270function makeRegistry( base ) {
2271    return {
2272        _data: {},
2273        add: function(name, func) {
2274            // precautionary case conversion, as later querying of
2275            // the registry by function-caller uses lower case as well.
2276            name = name.toLowerCase();
2277
2278            if (this._data.hasOwnProperty(name)) {
2279                // TODO warn
2280            }
2281            this._data[name] = func;
2282        },
2283        addMultiple: function(functions) {
2284            Object.keys(functions).forEach(
2285                function(name) {
2286                    this.add(name, functions[name]);
2287                }.bind(this));
2288        },
2289        get: function(name) {
2290            return this._data[name] || ( base && base.get( name ));
2291        },
2292        getLocalFunctions: function() {
2293            return this._data;
2294        },
2295        inherit: function() {
2296            return makeRegistry( this );
2297        },
2298        create: function(base) {
2299            return makeRegistry(base);
2300        }
2301    };
2302}
2303
2304module.exports = makeRegistry( null );
2305},{}],27:[function(require,module,exports){
2306module.exports = function(environment) {
2307    var functions = {
2308        functionRegistry: require('./function-registry'),
2309        functionCaller: require('./function-caller')
2310    };
2311
2312    // register functions
2313    require('./boolean');
2314    require('./default');
2315    require('./color');
2316    require('./color-blending');
2317    require('./data-uri')(environment);
2318    require('./math');
2319    require('./number');
2320    require('./string');
2321    require('./svg')(environment);
2322    require('./types');
2323
2324    return functions;
2325};
2326
2327},{"./boolean":20,"./color":22,"./color-blending":21,"./data-uri":23,"./default":24,"./function-caller":25,"./function-registry":26,"./math":29,"./number":30,"./string":31,"./svg":32,"./types":33}],28:[function(require,module,exports){
2328var Dimension = require('../tree/dimension');
2329
2330var MathHelper = function() {
2331};
2332MathHelper._math = function (fn, unit, n) {
2333    if (!(n instanceof Dimension)) {
2334        throw { type: 'Argument', message: 'argument must be a number' };
2335    }
2336    if (unit == null) {
2337        unit = n.unit;
2338    } else {
2339        n = n.unify();
2340    }
2341    return new Dimension(fn(parseFloat(n.value)), unit);
2342};
2343module.exports = MathHelper;
2344},{"../tree/dimension":60}],29:[function(require,module,exports){
2345var functionRegistry = require('./function-registry'),
2346    mathHelper = require('./math-helper.js');
2347
2348var mathFunctions = {
2349    // name,  unit
2350    ceil:  null,
2351    floor: null,
2352    sqrt:  null,
2353    abs:   null,
2354    tan:   '',
2355    sin:   '',
2356    cos:   '',
2357    atan:  'rad',
2358    asin:  'rad',
2359    acos:  'rad'
2360};
2361
2362for (var f in mathFunctions) {
2363    if (mathFunctions.hasOwnProperty(f)) {
2364        mathFunctions[f] = mathHelper._math.bind(null, Math[f], mathFunctions[f]);
2365    }
2366}
2367
2368mathFunctions.round = function (n, f) {
2369    var fraction = typeof f === 'undefined' ? 0 : f.value;
2370    return mathHelper._math(function(num) { return num.toFixed(fraction); }, null, n);
2371};
2372
2373functionRegistry.addMultiple(mathFunctions);
2374
2375},{"./function-registry":26,"./math-helper.js":28}],30:[function(require,module,exports){
2376var Dimension = require('../tree/dimension'),
2377    Anonymous = require('../tree/anonymous'),
2378    functionRegistry = require('./function-registry'),
2379    mathHelper = require('./math-helper.js');
2380
2381var minMax = function (isMin, args) {
2382    args = Array.prototype.slice.call(args);
2383    switch (args.length) {
2384        case 0: throw { type: 'Argument', message: 'one or more arguments required' };
2385    }
2386    var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone,
2387        order  = [], // elems only contains original argument values.
2388        values = {}; // key is the unit.toString() for unified Dimension values,
2389    // value is the index into the order array.
2390    for (i = 0; i < args.length; i++) {
2391        current = args[i];
2392        if (!(current instanceof Dimension)) {
2393            if (Array.isArray(args[i].value)) {
2394                Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value));
2395            }
2396            continue;
2397        }
2398        currentUnified = current.unit.toString() === '' && unitClone !== undefined ? new Dimension(current.value, unitClone).unify() : current.unify();
2399        unit = currentUnified.unit.toString() === '' && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString();
2400        unitStatic = unit !== '' && unitStatic === undefined || unit !== '' && order[0].unify().unit.toString() === '' ? unit : unitStatic;
2401        unitClone = unit !== '' && unitClone === undefined ? current.unit.toString() : unitClone;
2402        j = values[''] !== undefined && unit !== '' && unit === unitStatic ? values[''] : values[unit];
2403        if (j === undefined) {
2404            if (unitStatic !== undefined && unit !== unitStatic) {
2405                throw { type: 'Argument', message: 'incompatible types' };
2406            }
2407            values[unit] = order.length;
2408            order.push(current);
2409            continue;
2410        }
2411        referenceUnified = order[j].unit.toString() === '' && unitClone !== undefined ? new Dimension(order[j].value, unitClone).unify() : order[j].unify();
2412        if ( isMin && currentUnified.value < referenceUnified.value ||
2413            !isMin && currentUnified.value > referenceUnified.value) {
2414            order[j] = current;
2415        }
2416    }
2417    if (order.length == 1) {
2418        return order[0];
2419    }
2420    args = order.map(function (a) { return a.toCSS(this.context); }).join(this.context.compress ? ',' : ', ');
2421    return new Anonymous((isMin ? 'min' : 'max') + '(' + args + ')');
2422};
2423functionRegistry.addMultiple({
2424    min: function () {
2425        return minMax(true, arguments);
2426    },
2427    max: function () {
2428        return minMax(false, arguments);
2429    },
2430    convert: function (val, unit) {
2431        return val.convertTo(unit.value);
2432    },
2433    pi: function () {
2434        return new Dimension(Math.PI);
2435    },
2436    mod: function(a, b) {
2437        return new Dimension(a.value % b.value, a.unit);
2438    },
2439    pow: function(x, y) {
2440        if (typeof x === 'number' && typeof y === 'number') {
2441            x = new Dimension(x);
2442            y = new Dimension(y);
2443        } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) {
2444            throw { type: 'Argument', message: 'arguments must be numbers' };
2445        }
2446
2447        return new Dimension(Math.pow(x.value, y.value), x.unit);
2448    },
2449    percentage: function (n) {
2450        var result = mathHelper._math(function(num) {
2451            return num * 100;
2452        }, '%', n);
2453
2454        return result;
2455    }
2456});
2457
2458},{"../tree/anonymous":48,"../tree/dimension":60,"./function-registry":26,"./math-helper.js":28}],31:[function(require,module,exports){
2459var Quoted = require('../tree/quoted'),
2460    Anonymous = require('../tree/anonymous'),
2461    JavaScript = require('../tree/javascript'),
2462    functionRegistry = require('./function-registry');
2463
2464functionRegistry.addMultiple({
2465    e: function (str) {
2466        return new Anonymous(str instanceof JavaScript ? str.evaluated : str.value);
2467    },
2468    escape: function (str) {
2469        return new Anonymous(
2470            encodeURI(str.value).replace(/=/g, '%3D').replace(/:/g, '%3A').replace(/#/g, '%23').replace(/;/g, '%3B')
2471                .replace(/\(/g, '%28').replace(/\)/g, '%29'));
2472    },
2473    replace: function (string, pattern, replacement, flags) {
2474        var result = string.value;
2475        replacement = (replacement.type === 'Quoted') ?
2476            replacement.value : replacement.toCSS();
2477        result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement);
2478        return new Quoted(string.quote || '', result, string.escaped);
2479    },
2480    '%': function (string /* arg, arg, ... */) {
2481        var args = Array.prototype.slice.call(arguments, 1),
2482            result = string.value;
2483
2484        for (var i = 0; i < args.length; i++) {
2485            /* jshint loopfunc:true */
2486            result = result.replace(/%[sda]/i, function(token) {
2487                var value = ((args[i].type === 'Quoted') &&
2488                    token.match(/s/i)) ? args[i].value : args[i].toCSS();
2489                return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
2490            });
2491        }
2492        result = result.replace(/%%/g, '%');
2493        return new Quoted(string.quote || '', result, string.escaped);
2494    }
2495});
2496
2497},{"../tree/anonymous":48,"../tree/javascript":66,"../tree/quoted":77,"./function-registry":26}],32:[function(require,module,exports){
2498module.exports = function(environment) {
2499    var Dimension = require('../tree/dimension'),
2500        Color = require('../tree/color'),
2501        Expression = require('../tree/expression'),
2502        Quoted = require('../tree/quoted'),
2503        URL = require('../tree/url'),
2504        functionRegistry = require('./function-registry');
2505
2506    functionRegistry.add('svg-gradient', function(direction) {
2507
2508        var stops,
2509            gradientDirectionSvg,
2510            gradientType = 'linear',
2511            rectangleDimension = 'x="0" y="0" width="1" height="1"',
2512            renderEnv = {compress: false},
2513            returner,
2514            directionValue = direction.toCSS(renderEnv),
2515            i, color, position, positionValue, alpha;
2516
2517        function throwArgumentDescriptor() {
2518            throw { type: 'Argument',
2519                message: 'svg-gradient expects direction, start_color [start_position], [color position,]...,' +
2520                            ' end_color [end_position] or direction, color list' };
2521        }
2522
2523        if (arguments.length == 2) {
2524            if (arguments[1].value.length < 2) {
2525                throwArgumentDescriptor();
2526            }
2527            stops = arguments[1].value;
2528        } else if (arguments.length < 3) {
2529            throwArgumentDescriptor();
2530        } else {
2531            stops = Array.prototype.slice.call(arguments, 1);
2532        }
2533
2534        switch (directionValue) {
2535            case 'to bottom':
2536                gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="
2536100%"';
2537                break;
2538            case 'to right':
2539                gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
2540                break;
2541            case 'to bottom right':
2542                gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
2543                break;
2544            case 'to top right':
2545                gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
2546                break;
2547            case 'ellipse':
2548            case 'ellipse at center':
2549                gradientType = 'radial';
2550                gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
2551                rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
2552                break;
2553            default:
2554                throw { type: 'Argument', message: 'svg-gradient direction must be \'to bottom\', \'to right\',' +
2555                    ' \'to bottom right\', \'to top right\' or \'ellipse at center\'' };
2556        }
2557        returner = '<?xml version="1.0" ?>' +
2558            '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
2559            '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
2560
2561        for (i = 0; i < stops.length; i += 1) {
2562            if (stops[i] instanceof Expression) {
2563                color = stops[i].value[0];
2564                position = stops[i].value[1];
2565            } else {
2566                color = stops[i];
2567                position = undefined;
2568            }
2569
2570            if (!(color instanceof Color) || (!((i === 0 || i + 1 === stops.length) && position === undefined) && !(position instanceof Dimension))) {
2571                throwArgumentDescriptor();
2572            }
2573            positionValue = position ? position.toCSS(renderEnv) : i === 0 ? '0%' : '100%';
2574            alpha = color.alpha;
2575            returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
2576        }
2577        returner += '</' + gradientType + 'Gradient>' +
2578            '<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';
2579
2580        returner = encodeURIComponent(returner);
2581
2582        returner = 'data:image/svg+xml,' + returner;
2583        return new URL(new Quoted('\'' + returner + '\'', returner, false, this.index, this.currentFileInfo), this.index, this.currentFileInfo);
2584    });
2585};
2586
2587},{"../tree/color":53,"../tree/dimension":60,"../tree/expression":62,"../tree/quoted":77,"../tree/url":82,"./function-registry":26}],33:[function(require,module,exports){
2588var Keyword = require('../tree/keyword'),
2589    DetachedRuleset = require('../tree/detached-ruleset'),
2590    Dimension = require('../tree/dimension'),
2591    Color = require('../tree/color'),
2592    Quoted = require('../tree/quoted'),
2593    Anonymous = require('../tree/anonymous'),
2594    URL = require('../tree/url'),
2595    Operation = require('../tree/operation'),
2596    functionRegistry = require('./function-registry');
2597
2598var isa = function (n, Type) {
2599        return (n instanceof Type) ? Keyword.True : Keyword.False;
2600    },
2601    isunit = function (n, unit) {
2602        if (unit === undefined) {
2603            throw { type: 'Argument', message: 'missing the required second argument to isunit.' };
2604        }
2605        unit = typeof unit.value === 'string' ? unit.value : unit;
2606        if (typeof unit !== 'string') {
2607            throw { type: 'Argument', message: 'Second argument to isunit should be a unit or a string.' };
2608        }
2609        return (n instanceof Dimension) && n.unit.is(unit) ? Keyword.True : Keyword.False;
2610    },
2611    getItemsFromNode = function(node) {
2612        // handle non-array values as an array of length 1
2613        // return 'undefined' if index is invalid
2614        var items = Array.isArray(node.value) ?
2615            node.value : Array(node);
2616
2617        return items;
2618    };
2619functionRegistry.addMultiple({
2620    isruleset: function (n) {
2621        return isa(n, DetachedRuleset);
2622    },
2623    iscolor: function (n) {
2624        return isa(n, Color);
2625    },
2626    isnumber: function (n) {
2627        return isa(n, Dimension);
2628    },
2629    isstring: function (n) {
2630        return isa(n, Quoted);
2631    },
2632    iskeyword: function (n) {
2633        return isa(n, Keyword);
2634    },
2635    isurl: function (n) {
2636        return isa(n, URL);
2637    },
2638    ispixel: function (n) {
2639        return isunit(n, 'px');
2640    },
2641    ispercentage: function (n) {
2642        return isunit(n, '%');
2643    },
2644    isem: function (n) {
2645        return isunit(n, 'em');
2646    },
2647    isunit: isunit,
2648    unit: function (val, unit) {
2649        if (!(val instanceof Dimension)) {
2650            throw { type: 'Argument',
2651                message: 'the first argument to unit must be a number' +
2652                    (val instanceof Operation ? '. Have you forgotten parenthesis?' : '') };
2653        }
2654        if (unit) {
2655            if (unit instanceof Keyword) {
2656                unit = unit.value;
2657            } else {
2658                unit = unit.toCSS();
2659            }
2660        } else {
2661            unit = '';
2662        }
2663        return new Dimension(val.value, unit);
2664    },
2665    'get-unit': function (n) {
2666        return new Anonymous(n.unit);
2667    },
2668    extract: function(values, index) {
2669        index = index.value - 1; // (1-based index)
2670
2671        return getItemsFromNode(values)[index];
2672    },
2673    length: function(values) {
2674        return new Dimension(getItemsFromNode(values).length);
2675    }
2676});
2677
2678},{"../tree/anonymous":48,"../tree/color":53,"../tree/detached-ruleset":59,"../tree/dimension":60,"../tree/keyword":68,"../tree/operation":74,"../tree/quoted":77,"../tree/url":82,"./function-registry":26}],34:[function(require,module,exports){
2679var contexts = require('./contexts'),
2680    Parser = require('./parser/parser'),
2681    LessError = require('./less-error'),
2682    utils = require('./utils'),
2683    PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise,
2684    logger = require('./logger');
2685
2686module.exports = function(environment) {
2687
2688    // FileInfo = {
2689    //  'relativeUrls' - option - whether to adjust URL's to be relative
2690    //  'filename' - full resolved filename of current file
2691    //  'rootpath' - path to append to normal URLs for this node
2692    //  'currentDirectory' - path to the current file, absolute
2693    //  'rootFilename' - filename of the base file
2694    //  'entryPath' - absolute path to the entry file
2695    //  'reference' - whether the file should not be output and only output parts that are referenced
2696
2697    var ImportManager = function(less, context, rootFileInfo) {
2698        this.less = less;
2699        this.rootFilename = rootFileInfo.filename;
2700        this.paths = context.paths || [];  // Search paths, when importing
2701        this.contents = {};             // map - filename to contents of all the files
2702        this.contentsIgnoredChars = {}; // map - filename to lines at the beginning of each file to ignore
2703        this.mime = context.mime;
2704        this.error = null;
2705        this.context = context;
2706        // Deprecated? Unused outside of here, could be useful.
2707        this.queue = [];        // Files which haven't been imported yet
2708        this.files = {};        // Holds the imported parse trees.
2709    };
2710
2711    /**
2712     * Add an import to be imported
2713     * @param path - the raw path
2714     * @param tryAppendExtension - whether to try appending a file extension (.less or .js if the path has no extension)
2715     * @param currentFileInfo - the current file info (used for instance to work out relative paths)
2716     * @param importOptions - import options
2717     * @param callback - callback for when it is imported
2718     */
2719    ImportManager.prototype.push = function (path, tryAppendExtension, currentFileInfo, importOptions, callback) {
2720        var importManager = this,
2721            pluginLoader = this.context.pluginManager.Loader;
2722
2723        this.queue.push(path);
2724
2725        var fileParsedFunc = function (e, root, fullPath) {
2726            importManager.queue.splice(importManager.queue.indexOf(path), 1); // Remove the path from the queue
2727
2728            var importedEqualsRoot = fullPath === importManager.rootFilename;
2729            if (importOptions.optional && e) {
2730                callback(null, {rules:[]}, false, null);
2731                logger.info('The file ' + fullPath + ' was skipped because it was not found and the import was marked optional.');
2732            }
2733            else {
2734                // Inline imports aren't cached here.
2735                // If we start to cache them, please make sure they won't conflict with non-inline imports of the
2736                // same name as they used to do before this comment and the condition below have been added.
2737                if (!importManager.files[fullPath] && !importOptions.inline) {
2738                    importManager.files[fullPath] = { root: root, options: importOptions };
2739                }
2740                if (e && !importManager.error) { importManager.error = e; }
2741                callback(e, root, importedEqualsRoot, fullPath);
2742            }
2743        };
2744
2745        var newFileInfo = {
2746            relativeUrls: this.context.relativeUrls,
2747            entryPath: currentFileInfo.entryPath,
2748            rootpath: currentFileInfo.rootpath,
2749            rootFilename: currentFileInfo.rootFilename
2750        };
2751
2752        var fileManager = environment.getFileManager(path, currentFileInfo.currentDirectory, this.context, environment);
2753
2754        if (!fileManager) {
2755            fileParsedFunc({ message: 'Could not find a file-manager for ' + path });
2756            return;
2757        }
2758
2759        var loadFileCallback = function(loadedFile) {
2760            var plugin,
2761                resolvedFilename = loadedFile.filename,
2762                contents = loadedFile.contents.replace(/^\uFEFF/, '');
2763
2764            // Pass on an updated rootpath if path of imported file is relative and file
2765            // is in a (sub|sup) directory
2766            //
2767            // Examples:
2768            // - If path of imported file is 'module/nav/nav.less' and rootpath is 'less/',
2769            //   then rootpath should become 'less/module/nav/'
2770            // - If path of imported file is '../mixins.less' and rootpath is 'less/',
2771            //   then rootpath should become 'less/../'
2772            newFileInfo.currentDirectory = fileManager.getPath(resolvedFilename);
2773            if (newFileInfo.relativeUrls) {
2774                newFileInfo.rootpath = fileManager.join(
2775                    (importManager.context.rootpath || ''),
2776                    fileManager.pathDiff(newFileInfo.currentDirectory, newFileInfo.entryPath));
2777
2778                if (!fileManager.isPathAbsolute(newFileInfo.rootpath) && fileManager.alwaysMakePathsAbsolute()) {
2779                    newFileInfo.rootpath = fileManager.join(newFileInfo.entryPath, newFileInfo.rootpath);
2780                }
2781            }
2782            newFileInfo.filename = resolvedFilename;
2783
2784            var newEnv = new contexts.Parse(importManager.context);
2785
2786            newEnv.processImports = false;
2787            importManager.contents[resolvedFilename] = contents;
2788
2789            if (currentFileInfo.reference || importOptions.reference) {
2790                newFileInfo.reference = true;
2791            }
2792
2793            if (importOptions.isPlugin) {
2794                plugin = pluginLoader.evalPlugin(contents, newEnv, importManager, importOptions.pluginArgs, newFileInfo);
2795                if (plugin instanceof LessError) {
2796                    fileParsedFunc(plugin, null, resolvedFilename);
2797                }
2798                else {
2799                    fileParsedFunc(null, plugin, resolvedFilename);
2800                }
2801            } else if (importOptions.inline) {
2802                fileParsedFunc(null, contents, resolvedFilename);
2803            } else {
2804
2805                // import (multiple) parse trees apparently get altered and can't be cached.
2806                // TODO: investigate why this is
2807                if (importManager.files[resolvedFilename]
2808                    && !importManager.files[resolvedFilename].options.multiple
2809                    && !importOptions.multiple) {
2810
2811                    fileParsedFunc(null, importManager.files[resolvedFilename].root, resolvedFilename);
2812                }
2813                else {
2814                    new Parser(newEnv, importManager, newFileInfo).parse(contents, function (e, root) {
2815                        fileParsedFunc(e, root, resolvedFilename);
2816                    });
2817                }
2818            }
2819        };
2820        var promise, context = utils.clone(this.context);
2821
2822        if (tryAppendExtension) {
2823            context.ext = importOptions.isPlugin ? '.js' : '.less';
2824        }
2825
2826        if (importOptions.isPlugin) {
2827            promise = pluginLoader.loadPlugin(path, currentFileInfo.currentDirectory, context, environment, fileManager);
2828        }
2829        else {
2830            promise = fileManager.loadFile(path, currentFileInfo.currentDirectory, context, environment,
2831                function(err, loadedFile) {
2832                    if (err) {
2833                        fileParsedFunc(err);
2834                    } else {
2835                        loadFileCallback(loadedFile);
2836                    }
2837                });
2838        }
2839        if (promise) {
2840            promise.then(loadFileCallback, fileParsedFunc);
2841        }
2842
2843    };
2844    return ImportManager;
2845};
2846
2847},{"./contexts":12,"./less-error":36,"./logger":37,"./parser/parser":42,"./utils":86,"promise":undefined}],35:[function(require,module,exports){
2848module.exports = function(environment, fileManagers) {
2849    var SourceMapOutput, SourceMapBuilder, ParseTree, ImportManager, Environment;
2850
2851    var initial = {
2852        version: [3, 5, 0],
2853        data: require('./data'),
2854        tree: require('./tree'),
2855        Environment: (Environment = require('./environment/environment')),
2856        AbstractFileManager: require('./environment/abstract-file-manager'),
2857        AbstractPluginLoader: require('./environment/abstract-plugin-loader'),
2858        environment: (environment = new Environment(environment, fileManagers)),
2859        visitors: require('./visitors'),
2860        Parser: require('./parser/parser'),
2861        functions: require('./functions')(environment),
2862        contexts: require('./contexts'),
2863        SourceMapOutput: (SourceMapOutput = require('./source-map-output')(environment)),
2864        SourceMapBuilder: (SourceMapBuilder = require('./source-map-builder')(SourceMapOutput, environment)),
2865        ParseTree: (ParseTree = require('./parse-tree')(SourceMapBuilder)),
2866        ImportManager: (ImportManager = require('./import-manager')(environment)),
2867        render: require('./render')(environment, ParseTree, ImportManager),
2868        parse: require('./parse')(environment, ParseTree, ImportManager),
2869        LessError: require('./less-error'),
2870        transformTree: require('./transform-tree'),
2871        utils: require('./utils'),
2872        PluginManager: require('./plugin-manager'),
2873        logger: require('./logger')
2874    };
2875
2876    // Create a public API
2877
2878    var ctor = function(t) {
2879        return function() {
2880            var obj = Object.create(t.prototype);
2881            t.apply(obj, Array.prototype.slice.call(arguments, 0));
2882            return obj;
2883        };
2884    };
2885    var t, api = Object.create(initial);
2886    for (var n in initial.tree) {
2887        /* eslint guard-for-in: 0 */
2888        t = initial.tree[n];
2889        if (typeof t === 'function') {
2890            api[n.toLowerCase()] = ctor(t);
2891        }
2892        else {
2893            api[n] = Object.create(null);
2894            for (var o in t) {
2895                /* eslint guard-for-in: 0 */
2896                api[n][o.toLowerCase()] = ctor(t[o]);
2897            }
2898        }
2899    }
2900
2901    return api;
2902};
2903
2904},{"./contexts":12,"./data":14,"./environment/abstract-file-manager"
2904:17,"./environment/abstract-plugin-loader":18,"./environment/environment":19,"./functions":27,"./import-manager":34,"./less-error":36,"./logger":37,"./parse":39,"./parse-tree":38,"./parser/parser":42,"./plugin-manager":43,"./render":44,"./source-map-builder":45,"./source-map-output":46,"./transform-tree":47,"./tree":65,"./utils":86,"./visitors":90}],36:[function(require,module,exports){
2905var utils = require('./utils');
2906/**
2907 * This is a centralized class of any error that could be thrown internally (mostly by the parser).
2908 * Besides standard .message it keeps some additional data like a path to the file where the error
2909 * occurred along with line and column numbers.
2910 *
2911 * @class
2912 * @extends Error
2913 * @type {module.LessError}
2914 *
2915 * @prop {string} type
2916 * @prop {string} filename
2917 * @prop {number} index
2918 * @prop {number} line
2919 * @prop {number} column
2920 * @prop {number} callLine
2921 * @prop {number} callExtract
2922 * @prop {string[]} extract
2923 *
2924 * @param {Object} e              - An error object to wrap around or just a descriptive object
2925 * @param {Object} fileContentMap - An object with file contents in 'contents' property (like importManager) @todo - move to fileManager?
2926 * @param {string} [currentFilename]
2927 */
2928var LessError = module.exports = function LessError(e, fileContentMap, currentFilename) {
2929    Error.call(this);
2930
2931    var filename = e.filename || currentFilename;
2932
2933    this.message = e.message;
2934    this.stack = e.stack;
2935
2936    if (fileContentMap && filename) {
2937        var input = fileContentMap.contents[filename],
2938            loc = utils.getLocation(e.index, input),
2939            line = loc.line,
2940            col  = loc.column,
2941            callLine = e.call && utils.getLocation(e.call, input).line,
2942            lines = input ? input.split('\n') : '';
2943
2944        this.type = e.type || 'Syntax';
2945        this.filename = filename;
2946        this.index = e.index;
2947        this.line = typeof line === 'number' ? line + 1 : null;
2948        this.column = col;
2949
2950        if (!this.line && this.stack) {
2951            var found = this.stack.match(/(<anonymous>|Function):(\d+):(\d+)/);
2952
2953            if (found) {
2954                if (found[2]) {
2955                    this.line = parseInt(found[2]) - 2;
2956                }
2957                if (found[3]) {
2958                    this.column = parseInt(found[3]);
2959                }
2960            }
2961        }
2962
2963        this.callLine = callLine + 1;
2964        this.callExtract = lines[callLine];
2965
2966        this.extract = [
2967            lines[this.line - 2],
2968            lines[this.line - 1],
2969            lines[this.line]
2970        ];
2971
2972    }
2973
2974};
2975
2976if (typeof Object.create === 'undefined') {
2977    var F = function () {};
2978    F.prototype = Error.prototype;
2979    LessError.prototype = new F();
2980} else {
2981    LessError.prototype = Object.create(Error.prototype);
2982}
2983
2984LessError.prototype.constructor = LessError;
2985
2986/**
2987 * An overridden version of the default Object.prototype.toString
2988 * which uses additional information to create a helpful message.
2989 *
2990 * @param {Object} options
2991 * @returns {string}
2992 */
2993LessError.prototype.toString = function(options) {
2994    options = options || {};
2995
2996    var message = '';
2997    var extract = this.extract || [];
2998    var error = [];
2999    var stylize = function (str) { return str; };
3000    if (options.stylize) {
3001        var type = typeof options.stylize;
3002        if (type !== 'function') {
3003            throw Error('options.stylize should be a function, got a ' + type + '!');
3004        }
3005        stylize = options.stylize;
3006    }
3007
3008    if (this.line !== null) {
3009        if (typeof extract[0] === 'string') {
3010            error.push(stylize((this.line - 1) + ' ' + extract[0], 'grey'));
3011        }
3012
3013        if (typeof extract[1] === 'string') {
3014            var errorTxt = this.line + ' ';
3015            if (extract[1]) {
3016                errorTxt += extract[1].slice(0, this.column) +
3017                    stylize(stylize(stylize(extract[1].substr(this.column, 1), 'bold') +
3018                        extract[1].slice(this.column + 1), 'red'), 'inverse');
3019            }
3020            error.push(errorTxt);
3021        }
3022
3023        if (typeof extract[2] === 'string') {
3024            error.push(stylize((this.line + 1) + ' ' + extract[2], 'grey'));
3025        }
3026        error = error.join('\n') + stylize('', 'reset') + '\n';
3027    }
3028
3029    message += stylize(this.type + 'Error: ' + this.message, 'red');
3030    if (this.filename) {
3031        message += stylize(' in ', 'red') + this.filename;
3032    }
3033    if (this.line) {
3034        message += stylize(' on line ' + this.line + ', column ' + (this.column + 1) + ':', 'grey');
3035    }
3036
3037    message += '\n' + error;
3038
3039    if (this.callLine) {
3040        message += stylize('from ', 'red') + (this.filename || '') + '/n';
3041        message += stylize(this.callLine, 'grey') + ' ' + this.callExtract + '/n';
3042    }
3043
3044    return message;
3045};
3046
3047},{"./utils":86}],37:[function(require,module,exports){
3048module.exports = {
3049    error: function(msg) {
3050        this._fireEvent('error', msg);
3051    },
3052    warn: function(msg) {
3053        this._fireEvent('warn', msg);
3054    },
3055    info: function(msg) {
3056        this._fireEvent('info', msg);
3057    },
3058    debug: function(msg) {
3059        this._fireEvent('debug', msg);
3060    },
3061    addListener: function(listener) {
3062        this._listeners.push(listener);
3063    },
3064    removeListener: function(listener) {
3065        for (var i = 0; i < this._listeners.length; i++) {
3066            if (this._listeners[i] === listener) {
3067                this._listeners.splice(i, 1);
3068                return;
3069            }
3070        }
3071    },
3072    _fireEvent: function(type, msg) {
3073        for (var i = 0; i < this._listeners.length; i++) {
3074            var logFunction = this._listeners[i][type];
3075            if (logFunction) {
3076                logFunction(msg);
3077            }
3078        }
3079    },
3080    _listeners: []
3081};
3082
3083},{}],38:[function(require,module,exports){
3084var LessError = require('./less-error'),
3085    transformTree = require('./transform-tree'),
3086    logger = require('./logger');
3087
3088module.exports = function(SourceMapBuilder) {
3089    var ParseTree = function(root, imports) {
3090        this.root = root;
3091        this.imports = imports;
3092    };
3093
3094    ParseTree.prototype.toCSS = function(options) {
3095        var evaldRoot, result = {}, sourceMapBuilder;
3096        try {
3097            evaldRoot = transformTree(this.root, options);
3098        } catch (e) {
3099            throw new LessError(e, this.imports);
3100        }
3101
3102        try {
3103            var compress = Boolean(options.compress);
3104            if (compress) {
3105                logger.warn('The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.');
3106            }
3107
3108            var toCSSOptions = {
3109                compress: compress,
3110                dumpLineNumbers: options.dumpLineNumbers,
3111                strictUnits: Boolean(options.strictUnits),
3112                numPrecision: 8};
3113
3114            if (options.sourceMap) {
3115                sourceMapBuilder = new SourceMapBuilder(options.sourceMap);
3116                result.css = sourceMapBuilder.toCSS(evaldRoot, toCSSOptions, this.imports);
3117            } else {
3118                result.css = evaldRoot.toCSS(toCSSOptions);
3119            }
3120        } catch (e) {
3121            throw new LessError(e, this.imports);
3122        }
3123
3124        if (options.pluginManager) {
3125            var postProcessors = options.pluginManager.getPostProcessors();
3126            for (var i = 0; i < postProcessors.length; i++) {
3127                result.css = postProcessors[i].process(result.css, { sourceMap: sourceMapBuilder, options: options, imports: this.imports });
3128            }
3129        }
3130        if (options.sourceMap) {
3131            result.map = sourceMapBuilder.getExternalSourceMap();
3132        }
3133
3134        result.imports = [];
3135        for (var file in this.imports.files) {
3136            if (this.imports.files.hasOwnProperty(file) && file !== this.imports.rootFilename) {
3137                result.imports.push(file);
3138            }
3139        }
3140        return result;
3141    };
3142    return ParseTree;
3143};
3144
3145},{"./less-error":36,"./logger":37,"./transform-tree":47}],39:[function(require,module,exports){
3146var PromiseConstructor,
3147    contexts = require('./contexts'),
3148    Parser = require('./parser/parser'),
3149    PluginManager = require('./plugin-manager'),
3150    LessError = require('./less-error'),
3151    utils = require('./utils');
3152
3153module.exports = function(environment, ParseTree, ImportManager) {
3154    var parse = function (input, options, callback) {
3155
3156        if (typeof options === 'function') {
3157            callback = options;
3158            options = utils.defaults(this.options, {});
3159        }
3160        else {
3161            options = utils.defaults(this.options, options || {});
3162        }
3163
3164        if (!callback) {
3165            if (!PromiseConstructor) {
3166                PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
3167            }
3168            var self = this;
3169            return new PromiseConstructor(function (resolve, reject) {
3170                parse.call(self, input, options, function(err, output) {
3171                    if (err) {
3172                        reject(err);
3173                    } else {
3174                        resolve(output);
3175                    }
3176                });
3177            });
3178        } else {
3179            var context,
3180                rootFileInfo,
3181                pluginManager = new PluginManager(this, !options.reUsePluginManager);
3182
3183            options.pluginManager = pluginManager;
3184
3185            context = new contexts.Parse(options);
3186
3187            if (options.rootFileInfo) {
3188                rootFileInfo = options.rootFileInfo;
3189            } else {
3190                var filename = options.filename || 'input';
3191                var entryPath = filename.replace(/[^\/\\]*$/, '');
3192                rootFileInfo = {
3193                    filename: filename,
3194                    relativeUrls: context.relativeUrls,
3195                    rootpath: context.rootpath || '',
3196                    currentDirectory: entryPath,
3197                    entryPath: entryPath,
3198                    rootFilename: filename
3199                };
3200                // add in a missing trailing slash
3201                if (rootFileInfo.rootpath && rootFileInfo.rootpath.slice(-1) !== '/') {
3202                    rootFileInfo.rootpath += '/';
3203                }
3204            }
3205
3206            var imports = new ImportManager(this, context, rootFileInfo);
3207            this.importManager = imports;
3208
3209            // TODO: allow the plugins to be just a list of paths or names
3210            // Do an async plugin queue like lessc
3211
3212            if (options.plugins) {
3213                options.plugins.forEach(function(plugin) {
3214                    var evalResult, contents;
3215                    if (plugin.fileContent) {
3216                        contents = plugin.fileContent.replace(/^\uFEFF/, '');
3217                        evalResult = pluginManager.Loader.evalPlugin(contents, context, imports, plugin.options, plugin.filename);
3218                        if (evalResult instanceof LessError) {
3219                            return callback(evalResult);
3220                        }
3221                    }
3222                    else {
3223                        pluginManager.addPlugin(plugin);
3224                    }
3225                });
3226            }
3227
3228            new Parser(context, imports, rootFileInfo)
3229                .parse(input, function (e, root) {
3230                    if (e) { return callback(e); }
3231                    callback(null, root, imports, options);
3232                }, options);
3233        }
3234    };
3235    return parse;
3236};
3237
3238},{"./contexts":12,"./less-error":36,"./parser/parser":42,"./plugin-manager"
3238:43,"./utils":86,"promise":undefined}],40:[function(require,module,exports){
3239// Split the input into chunks.
3240module.exports = function (input, fail) {
3241    var len = input.length, level = 0, parenLevel = 0,
3242        lastOpening, lastOpeningParen, lastMultiComment, lastMultiCommentEndBrace,
3243        chunks = [], emitFrom = 0,
3244        chunkerCurrentIndex, currentChunkStartIndex, cc, cc2, matched;
3245
3246    function emitChunk(force) {
3247        var len = chunkerCurrentIndex - emitFrom;
3248        if (((len < 512) && !force) || !len) {
3249            return;
3250        }
3251        chunks.push(input.slice(emitFrom, chunkerCurrentIndex + 1));
3252        emitFrom = chunkerCurrentIndex + 1;
3253    }
3254
3255    for (chunkerCurrentIndex = 0; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
3256        cc = input.charCodeAt(chunkerCurrentIndex);
3257        if (((cc >= 97) && (cc <= 122)) || (cc < 34)) {
3258            // a-z or whitespace
3259            continue;
3260        }
3261
3262        switch (cc) {
3263            case 40:                        // (
3264                parenLevel++;
3265                lastOpeningParen = chunkerCurrentIndex;
3266                continue;
3267            case 41:                        // )
3268                if (--parenLevel < 0) {
3269                    return fail('missing opening `(`', chunkerCurrentIndex);
3270                }
3271                continue;
3272            case 59:                        // ;
3273                if (!parenLevel) { emitChunk(); }
3274                continue;
3275            case 123:                       // {
3276                level++;
3277                lastOpening = chunkerCurrentIndex;
3278                continue;
3279            case 125:                       // }
3280                if (--level < 0) {
3281                    return fail('missing opening `{`', chunkerCurrentIndex);
3282                }
3283                if (!level && !parenLevel) { emitChunk(); }
3284                continue;
3285            case 92:                        // \
3286                if (chunkerCurrentIndex < len - 1) { chunkerCurrentIndex++; continue; }
3287                return fail('unescaped `\\`', chunkerCurrentIndex);
3288            case 34:
3289            case 39:
3290            case 96:                        // ", ' and `
3291                matched = 0;
3292                currentChunkStartIndex = chunkerCurrentIndex;
3293                for (chunkerCurrentIndex = chunkerCurrentIndex + 1; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
3294                    cc2 = input.charCodeAt(chunkerCurrentIndex);
3295                    if (cc2 > 96) { continue; }
3296                    if (cc2 == cc) { matched = 1; break; }
3297                    if (cc2 == 92) {        // \
3298                        if (chunkerCurrentIndex == len - 1) {
3299                            return fail('unescaped `\\`', chunkerCurrentIndex);
3300                        }
3301                        chunkerCurrentIndex++;
3302                    }
3303                }
3304                if (matched) { continue; }
3305                return fail('unmatched `' + String.fromCharCode(cc) + '`', currentChunkStartIndex);
3306            case 47:                        // /, check for comment
3307                if (parenLevel || (chunkerCurrentIndex == len - 1)) { continue; }
3308                cc2 = input.charCodeAt(chunkerCurrentIndex + 1);
3309                if (cc2 == 47) {
3310                    // //, find lnfeed
3311                    for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len; chunkerCurrentIndex++) {
3312                        cc2 = input.charCodeAt(chunkerCurrentIndex);
3313                        if ((cc2 <= 13) && ((cc2 == 10) || (cc2 == 13))) { break; }
3314                    }
3315                } else if (cc2 == 42) {
3316                    // /*, find */
3317                    lastMultiComment = currentChunkStartIndex = chunkerCurrentIndex;
3318                    for (chunkerCurrentIndex = chunkerCurrentIndex + 2; chunkerCurrentIndex < len - 1; chunkerCurrentIndex++) {
3319                        cc2 = input.charCodeAt(chunkerCurrentIndex);
3320                        if (cc2 == 125) { lastMultiCommentEndBrace = chunkerCurrentIndex; }
3321                        if (cc2 != 42) { continue; }
3322                        if (input.charCodeAt(chunkerCurrentIndex + 1) == 47) { break; }
3323                    }
3324                    if (chunkerCurrentIndex == len - 1) {
3325                        return fail('missing closing `*/`', currentChunkStartIndex);
3326                    }
3327                    chunkerCurrentIndex++;
3328                }
3329                continue;
3330            case 42:                       // *, check for unmatched */
3331                if ((chunkerCurrentIndex < len - 1) && (input.charCodeAt(chunkerCurrentIndex + 1) == 47)) {
3332                    return fail('unmatched `/*`', chunkerCurrentIndex);
3333                }
3334                continue;
3335        }
3336    }
3337
3338    if (level !== 0) {
3339        if ((lastMultiComment > lastOpening) && (lastMultiCommentEndBrace > lastMultiComment)) {
3340            return fail('missing closing `}` or `*/`', lastOpening);
3341        } else {
3342            return fail('missing closing `}`', lastOpening);
3343        }
3344    } else if (parenLevel !== 0) {
3345        return fail('missing closing `)`', lastOpeningParen);
3346    }
3347
3348    emitChunk(true);
3349    return chunks;
3350};
3351
3352},{}],41:[function(require,module,exports){
3353var chunker = require('./chunker');
3354
3355module.exports = function() {
3356    var input,       // Less input string
3357        j,           // current chunk
3358        saveStack = [],   // holds state for backtracking
3359        furthest,    // furthest index the parser has gone to
3360        furthestPossibleErrorMessage, // if this is furthest we got to, this is the probably cause
3361        chunks,      // chunkified input
3362        current,     // current chunk
3363        currentPos,  // index of current chunk, in `input`
3364        parserInput = {};
3365
3366    var CHARCODE_SPACE = 32,
3367        CHARCODE_TAB = 9,
3368        CHARCODE_LF = 10,
3369        CHARCODE_CR = 13,
3370        CHARCODE_PLUS = 43,
3371        CHARCODE_COMMA = 44,
3372        CHARCODE_FORWARD_SLASH = 47,
3373        CHARCODE_9 = 57;
3374
3375    function skipWhitespace(length) {
3376        var oldi = parserInput.i, oldj = j,
3377            curr = parserInput.i - currentPos,
3378            endIndex = parserInput.i + current.length - curr,
3379            mem = (parserInput.i += length),
3380            inp = input,
3381            c, nextChar, comment;
3382
3383        for (; parserInput.i < endIndex; parserInput.i++) {
3384            c = inp.charCodeAt(parserInput.i);
3385
3386            if (parserInput.autoCommentAbsorb && c === CHARCODE_FORWARD_SLASH) {
3387                nextChar = inp.charAt(parserInput.i + 1);
3388                if (nextChar === '/') {
3389                    comment = {index: parserInput.i, isLineComment: true};
3390                    var nextNewLine = inp.indexOf('\n', parserInput.i + 2);
3391                    if (nextNewLine < 0) {
3392                        nextNewLine = endIndex;
3393                    }
3394                    parserInput.i = nextNewLine;
3395                    comment.text = inp.substr(comment.index, parserInput.i - comment.index);
3396                    parserInput.commentStore.push(comment);
3397                    continue;
3398                } else if (nextChar === '*') {
3399                    var nextStarSlash = inp.indexOf('*/', parserInput.i + 2);
3400                    if (nextStarSlash >= 0) {
3401                        comment = {
3402                            index: parserInput.i,
3403                            text: inp.substr(parserInput.i, nextStarSlash + 2 - parserInput.i),
3404                            isLineComment: false
3405                        };
3406                        parserInput.i += comment.text.length - 1;
3407                        parserInput.commentStore.push(comment);
3408                        continue;
3409                    }
3410                }
3411                break;
3412            }
3413
3414            if ((c !== CHARCODE_SPACE) && (c !== CHARCODE_LF) && (c !== CHARCODE_TAB) && (c !== CHARCODE_CR)) {
3415                break;
3416            }
3417        }
3418
3419        current = current.slice(length + parserInput.i - mem + curr);
3420        currentPos = parserInput.i;
3421
3422        if (!current.length) {
3423            if (j < chunks.length - 1) {
3424                current = chunks[++j];
3425                skipWhitespace(0); // skip space at the beginning of a chunk
3426                return true; // things changed
3427            }
3428            parserInput.finished = true;
3429        }
3430
3431        return oldi !== parserInput.i || oldj !== j;
3432    }
3433
3434    parserInput.save = function() {
3435        currentPos = parserInput.i;
3436        saveStack.push( { current: current, i: parserInput.i, j: j });
3437    };
3438    parserInput.restore = function(possibleErrorMessage) {
3439
3440        if (parserInput.i > furthest || (parserInput.i === furthest && possibleErrorMessage && !furthestPossibleErrorMessage)) {
3441            furthest = parserInput.i;
3442            furthestPossibleErrorMessage = possibleErrorMessage;
3443        }
3444        var state = saveStack.pop();
3445        current = state.current;
3446        currentPos = parserInput.i = state.i;
3447        j = state.j;
3448    };
3449    parserInput.forget = function() {
3450        saveStack.pop();
3451    };
3452    parserInput.isWhitespace = function (offset) {
3453        var pos = parserInput.i + (offset || 0),
3454            code = input.charCodeAt(pos);
3455        return (code === CHARCODE_SPACE || code === CHARCODE_CR || code === CHARCODE_TAB || code === CHARCODE_LF);
3456    };
3457
3458    // Specialization of $(tok)
3459    parserInput.$re = function(tok) {
3460        if (parserInput.i > currentPos) {
3461            current = current.slice(parserInput.i - currentPos);
3462            currentPos = parserInput.i;
3463        }
3464
3465        var m = tok.exec(current);
3466        if (!m) {
3467            return null;
3468        }
3469
3470        skipWhitespace(m[0].length);
3471        if (typeof m === 'string') {
3472            return m;
3473        }
3474
3475        return m.length === 1 ? m[0] : m;
3476    };
3477
3478    parserInput.$char = function(tok) {
3479        if (input.charAt(parserInput.i) !== tok) {
3480            return null;
3481        }
3482        skipWhitespace(1);
3483        return tok;
3484    };
3485
3486    parserInput.$str = function(tok) {
3487        var tokLength = tok.length;
3488
3489        // https://jsperf.com/string-startswith/21
3490        for (var i = 0; i < tokLength; i++) {
3491            if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
3492                return null;
3493            }
3494        }
3495
3496        skipWhitespace(tokLength);
3497        return tok;
3498    };
3499
3500    parserInput.$quoted = function(loc) {
3501        var pos = loc || parserInput.i,
3502            startChar = input.charAt(pos);
3503
3504        if (startChar !== '\'' && startChar !== '"') {
3505            return;
3506        }
3507        var length = input.length,
3508            currentPosition = pos;
3509
3510        for (var i = 1; i + currentPosition < length; i++) {
3511            var nextChar = input.charAt(i + currentPosition);
3512            switch (nextChar) {
3513                case '\\':
3514                    i++;
3515                    continue;
3516                case '\r':
3517                case '\n':
3518                    break;
3519                case startChar:
3520                    var str = input.substr(currentPosition, i + 1);
3521                    if (!loc && loc !== 0) {
3522                        skipWhitespace(i + 1);
3523                        return str
3524                    }
3525                    return [startChar, str];
3526                default:
3527            }
3528        }
3529        return null;
3530    };
3531
3532    /**
3533     * Permissive parsing. Ignores everything except matching {} [] () and quotes
3534     * until matching token (outside of blocks)
3535     */
3536    parserInput.$parseUntil = function(tok) {
3537        var quote = '',
3538            returnVal = null,
3539            inComment = false,
3540            blockDepth = 0,
3541            blockStack = [],
3542            parseGroups = [],
3543            length = input.length,
3544            startPos = parserInput.i,
3545            lastPos = parserInput.i,
3546            i = parserInput.i,
3547            loop = true,
3548            testChar;
3549
3550        if (typeof tok === 'string') {
3551            testChar = function(char) {
3552                return char === tok;
3553            }
3554        } else {
3555            testChar = function(char) {
3556                return tok.test(char);
3557            }
3558        }
3559
3560        do {
3561            var prevChar, nextChar = input.charAt(i);
3562            if (blockDepth === 0 && testChar(nextChar)) {
3563                returnVal = input.substr(lastPos, i - lastPos);
3564                if (returnVal) {
3565                    parseGroups.push(returnVal);
3566                    returnVal = parseGroups;
3567                }
3568                else {
3569                    returnVal = [' '];
3570                }
3571                skipWhitespace(i - startPos);
3572                loop = false
3573            } else {
3574                if (inComment) {
3575                    if (nextChar === '*' && 
3576                        input.charAt(i + 1) === '/') {
3577                        i++;
3578                        blockDepth--;
3579                        inComment = false;
3580                    }
3581                    i++;
3582                    continue;
3583                }
3584                switch (nextChar) {
3585                    case '\\':
3586                        i++;
3587                        nextChar = input.charAt(i);
3588                        parseGroups.push(input.substr(lastPos, i - lastPos + 1));
3589                        lastPos = i + 1;
3590                        break;
3591                    case '/':
3592                        if (input.charAt(i + 1) === '*') {
3593                            i++;
3594                            console.log(input.substr(lastPos, i - lastPos));
3595                            inComment = true;
3596                            blockDepth++;
3597                        }
3598                        break;
3599                    case '\'':
3600                    case '"':
3601                        quote = parserInput.$quoted(i);
3602                        if (quote) {
3603                            parseGroups.push(input.substr(lastPos, i - lastPos), quote);
3604                            i += quote[1].length - 1;
3605                            lastPos = i + 1;
3606                        }
3607                        else {
3608                            skipWhitespace(i - startPos);
3609                            returnVal = nextChar;
3610                            loop = false;
3611                        }
3612                        break;
3613                    case '{':
3614                        blockStack.push('}');
3615                        blockDepth++;
3616                        break;
3617                    case '(':
3618                        blockStack.push(')');
3619                        blockDepth++;
3620                        break;
3621                    case '[':
3622                        blockStack.push(']');
3623                        blockDepth++;
3624                        break;
3625                    case '}':
3626                    case ')':
3627                    case ']':
3628                        var expected = blockStack.pop();
3629                        if (nextChar === expected) {
3630                            blockDepth--;
3631                        } else {
3632                            // move the parser to the error and return expected
3633                            skipWhitespace(i - startPos);
3634                            returnVal = expected;
3635                            loop = false;
3636                        }
3637                }
3638                i++;
3639                if (i > length) {
3640                    loop = false;
3641                }
3642            }
3643            prevChar = nextChar;
3644        } while (loop);
3645
3646        return returnVal ? returnVal : null;
3647    }
3648
3649    parserInput.autoCommentAbsorb = true;
3650    parserInput.commentStore = [];
3651    parserInput.finished = false;
3652
3653    // Same as $(), but don't change the state of the parser,
3654    // just return the match.
3655    parserInput.peek = function(tok) {
3656        if (typeof tok === 'string') {
3657            // https://jsperf.com/string-startswith/21
3658            for (var i = 0; i < tok.length; i++) {
3659                if (input.charAt(parserInput.i + i) !== tok.charAt(i)) {
3660                    return false;
3661                }
3662            }
3663            return true;
3664        } else {
3665            return tok.test(current);
3666        }
3667    };
3668
3669    // Specialization of peek()
3670    // TODO remove or change some currentChar calls to peekChar
3671    parserInput.peekChar = function(tok) {
3672        return input.charAt(parserInput.i) === tok;
3673    };
3674
3675    parserInput.currentChar = function() {
3676        return input.charAt(parserInput.i);
3677    };
3678
3679    parserInput.getInput = function() {
3680        return input;
3681    };
3682
3683    parserInput.peekNotNumeric = function() {
3684        var c = input.charCodeAt(parserInput.i);
3685        // Is the first char of the dimension 0-9, '.', '+' or '-'
3686        return (c > CHARCODE_9 || c < CHARCODE_PLUS) || c === CHARCODE_FORWARD_SLASH || c === CHARCODE_COMMA;
3687    };
3688
3689    parserInput.start = function(str, chunkInput, failFunction) {
3690        input = str;
3691        parserInput.i = j = currentPos = furthest = 0;
3692
3693        // chunking apparently makes things quicker (but my tests indicate
3694        // it might actually make things slower in node at least)
3695        // and it is a non-perfect parse - it can't recognise
3696        // unquoted urls, meaning it can't distinguish comments
3697        // meaning comments with quotes or {}() in them get 'counted'
3698        // and then lead to parse errors.
3699        // In addition if the chunking chunks in the wrong place we might
3700        // not be able to parse a parser statement in one go
3701        // this is officially deprecated but can be switched on via an option
3702        // in the case it causes too much performance issues.
3703        if (chunkInput) {
3704            chunks = chunker(str, failFunction);
3705        } else {
3706            chunks = [str];
3707        }
3708
3709        current = chunks[0];
3710
3711        skipWhitespace(0);
3712    };
3713
3714    parserInput.end = function() {
3715        var message,
3716            isFinished = parserInput.i >= input.length;
3717
3718        if (parserInput.i < furthest) {
3719            message = furthestPossibleErrorMessage;
3720            parserInput.i = furthest;
3721        }
3722        return {
3723            isFinished: isFinished,
3724            furthest: parserInput.i,
3725            furthestPossibleErrorMessage: message,
3726            furthestReachedEnd: parserInput.i >= input.length - 1,
3727            furthestChar: input[parserInput.i]
3728        };
3729    };
3730
3731    return parserInput;
3732};
3733
3734},{"./chunker":40}],42:[function(require,module,exports){
3735var LessError = require('../less-error'),
3736    tree = require('../tree'),
3737    visitors = require('../visitors'),
3738    getParserInput = require('./parser-input'),
3739    utils = require('../utils'),
3740    functionRegistry = require('../functions/function-registry');
3741
3742//
3743// less.js - parser
3744//
3745//    A relatively straight-forward predictive parser.
3746//    There is no tokenization/lexing stage, the input is parsed
3747//    in one sweep.
3748//
3749//    To make the parser fast enough to run in the browser, several
3750//    optimization had to be made:
3751//
3752//    - Matching and slicing on a huge input is often cause of slowdowns.
3753//      The solution is to chunkify the input into smaller strings.
3754//      The chunks are stored in the `chunks` var,
3755//      `j` holds the current chunk index, and `currentPos` holds
3756//      the index of the current chunk in relation to `input`.
3757//      This gives us an almost 4x speed-up.
3758//
3759//    - In many cases, we don't need to match individual tokens;
3760//      for example, if a value doesn't hold any variables, operations
3761//      or dynamic references, the parser can effectively 'skip' it,
3762//      treating it as a literal.
3763//      An example would be '1px solid #000' - which evaluates to itself,
3764//      we don't need to know what the individual components are.
3765//      The drawback, of course is that you don't get the benefits of
3766//      syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
3767//      and a smaller speed-up in the code-gen.
3768//
3769//
3770//    Token matching is done with the `$` function, which either takes
3771//    a terminal string or regexp, or a non-terminal function to call.
3772//    It also takes care of moving all the indices forwards.
3773//
3774
3775var Parser = function Parser(context, imports, fileInfo) {
3776    var parsers,
3777        parserInput = getParserInput();
3778
3779    function error(msg, type) {
3780        throw new LessError(
3781            {
3782                index: parserInput.i,
3783                filename: fileInfo.filename,
3784                type: type || 'Syntax',
3785                message: msg
3786            },
3787            imports
3788        );
3789    }
3790
3791    function expect(arg, msg, index) {
3792        // some older browsers return typeof 'function' for RegExp
3793        var result = (arg instanceof Function) ? arg.call(parsers) : parserInput.$re(arg);
3794        if (result) {
3795            return result;
3796        }
3797        error(msg || (typeof arg === 'string' ? 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\''
3798                                               : 'unexpected token'));
3799    }
3800
3801    // Specialization of expect()
3802    function expectChar(arg, msg) {
3803        if (parserInput.$char(arg)) {
3804            return arg;
3805        }
3806        error(msg || 'expected \'' + arg + '\' got \'' + parserInput.currentChar() + '\'');
3807    }
3808
3809    function getDebugInfo(index) {
3810        var filename = fileInfo.filename;
3811
3812        return {
3813            lineNumber: utils.getLocation(index, parserInput.getInput()).line + 1,
3814            fileName: filename
3815        };
3816    }
3817
3818    /**
3819     *  Used after initial parsing to create nodes on the fly
3820     * 
3821     *  @param {String} str          - string to parse 
3822     *  @param {Array}  parseList    - array of parsers to run input through e.g. ["value", "important"]
3823     *  @param {Number} currentIndex - start number to begin indexing
3824     *  @param {Object} fileInfo     - fileInfo to attach to created nodes
3825     */
3826    function parseNode(str, parseList, currentIndex, fileInfo, callback) {
3827        var result, returnNodes = [];
3828        var parser = parserInput;
3829
3830        try {
3831            parser.start(str, false, function fail(msg, index) {
3832                callback({
3833                    message: msg,
3834                    index: index + currentIndex
3835                });
3836            });
3837            for (var x = 0, p, i; (p = parseList[x]); x++) {
3838                i = parser.i;
3839                result = parsers[p]();
3840                if (result) {
3841                    result._index = i + currentIndex;
3842                    result._fileInfo = fileInfo;
3843                    returnNodes.push(result);
3844                }
3845                else {
3846                    returnNodes.push(null);
3847                }
3848            }
3849
3850            var endInfo = parser.end();
3851            if (endInfo.isFinished) {
3852                callback(null, returnNodes);
3853            }
3854            else {
3855                callback(true, null);
3856            }
3857        } catch (e) {
3858            throw new LessError({
3859                index: e.index + currentIndex,
3860                message: e.message
3861            }, imports, fileInfo.filename);
3862        }
3863    }
3864    
3865    //
3866    // The Parser
3867    //
3868    return {
3869        parserInput: parserInput,
3870        imports: imports,
3871        fileInfo: fileInfo,
3872        parseNode: parseNode,
3873        //
3874        // Parse an input string into an abstract syntax tree,
3875        // @param str A string containing 'less' markup
3876        // @param callback call `callback` when done.
3877        // @param [additionalData] An optional map which can contains vars - a map (key, value) of variables to apply
3878        //
3879        parse: function (str, callback, additionalData) {
3880            var root, error = null, globalVars, modifyVars, ignored, preText = '';
3881
3882            globalVars = (additionalData && additionalData.globalVars) ? Parser.serializeVars(additionalData.globalVars) + '\n' : '';
3883            modifyVars = (additionalData && additionalData.modifyVars) ? '\n' + Parser.serializeVars(additionalData.modifyVars) : '';
3884
3885            if (context.pluginManager) {
3886                var preProcessors = context.pluginManager.getPreProcessors();
3887                for (var i = 0; i < preProcessors.length; i++) {
3888                    str = preProcessors[i].process(str, { context: context, imports: imports, fileInfo: fileInfo });
3889                }
3890            }
3891
3892            if (globalVars || (additionalData && additionalData.banner)) {
3893                preText = ((additionalData && additionalData.banner) ? additionalData.banner : '') + globalVars;
3894                ignored = imports.contentsIgnoredChars;
3895                ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;
3896                ignored[fileInfo.filename] += preText.length;
3897            }
3898
3899            str = str.replace(/\r\n?/g, '\n');
3900            // Remove potential UTF Byte Order Mark
3901            str = preText + str.replace(/^\uFEFF/, '') + modifyVars;
3902            imports.contents[fileInfo.filename] = str;
3903
3904            // Start with the primary rule.
3905            // The whole syntax tree is held under a Ruleset node,
3906            // with the `root` property set to true, so no `{}` are
3907            // output. The callback is called when the input is parsed.
3908            try {
3909                parserInput.start(str, context.chunkInput, function fail(msg, index) {
3910                    throw new LessError({
3911                        index: index,
3912                        type: 'Parse',
3913                        message: msg,
3914                        filename: fileInfo.filename
3915                    }, imports);
3916                });
3917
3918                tree.Node.prototype.parse = this;
3919                root = new tree.Ruleset(null, this.parsers.primary());
3920                tree.Node.prototype.rootNode = root;
3921                root.root = true;
3922                root.firstRoot = true;
3923                root.functionRegistry = functionRegistry.inherit();
3924                
3925            } catch (e) {
3926                return callback(new LessError(e, imports, fileInfo.filename));
3927            }
3928
3929            // If `i` is smaller than the `input.length - 1`,
3930            // it means the parser wasn't able to parse the whole
3931            // string, so we've got a parsing error.
3932            //
3933            // We try to extract a \n delimited string,
3934            // showing the line where the parse error occurred.
3935            // We split it up into two parts (the part which parsed,
3936            // and the part which didn't), so we can color them differently.
3937            var endInfo = parserInput.end();
3938            if (!endInfo.isFinished) {
3939
3940                var message = endInfo.furthestPossibleErrorMessage;
3941
3942                if (!message) {
3943                    message = 'Unrecognised input';
3944                    if (endInfo.furthestChar === '}') {
3945                        message += '. Possibly missing opening \'{\'';
3946                    } else if (endInfo.furthestChar === ')') {
3947                        message += '. Possibly missing opening \'(\'';
3948                    } else if (endInfo.furthestReachedEnd) {
3949                        message += '. Possibly missing something';
3950                    }
3951                }
3952
3953                error = new LessError({
3954                    type: 'Parse',
3955                    message: message,
3956                    index: endInfo.furthest,
3957                    filename: fileInfo.filename
3958                }, imports);
3959            }
3960
3961            var finish = function (e) {
3962                e = error || e || imports.error;
3963
3964                if (e) {
3965                    if (!(e instanceof LessError)) {
3966                        e = new LessError(e, imports, fileInfo.filename);
3967                    }
3968
3969                    return callback(e);
3970                }
3971                else {
3972                    return callback(null, root);
3973                }
3974            };
3975
3976            if (context.processImports !== false) {
3977                new visitors.ImportVisitor(imports, finish)
3978                    .run(root);
3979            } else {
3980                return finish();
3981            }
3982        },
3983
3984        //
3985        // Here in, the parsing rules/functions
3986        //
3987        // The basic structure of the syntax tree generated is as follows:
3988        //
3989        //   Ruleset ->  Declaration -> Value -> Expression -> Entity
3990        //
3991        // Here's some Less code:
3992        //
3993        //    .class {
3994        //      color: #fff;
3995        //      border: 1px solid #000;
3996        //      width: @w + 4px;
3997        //      > .child {...}
3998        //    }
3999        //
4000        // And here's what the parse tree might look like:
4001        //
4002        //     Ruleset (Selector '.class', [
4003        //         Declaration ("color",  Value ([Expression [Color #fff]]))
4004        //         Declaration ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
4005        //         Declaration ("width",  Value ([Expression [Operation " + " [Variable "@w"][Dimension 4px]]]))
4006        //         Ruleset (Selector [Element '>', '.child'], [...])
4007        //     ])
4008        //
4009        //  In general, most rules will try to parse a token with the `$re()` function, and if the return
4010        //  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
4011        //  first, before parsing, that's when we use `peek()`.
4012        //
4013        parsers: parsers = {
4014            //
4015            // The `primary` rule is the *entry* and *exit* point of the parser.
4016            // The rules here can appear at any level of the parse tree.
4017            //
4018            // The recursive nature of the grammar is an interplay between the `block`
4019            // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
4020            // as represented by this simplified grammar:
4021            //
4022            //     primary  →  (ruleset | declaration)+
4023            //     ruleset  →  selector+ block
4024            //     block    →  '{' primary '}'
4025            //
4026            // Only at one point is the primary rule not called from the
4027            // block rule: at the root level.
4028            //
4029            primary: function () {
4030                var mixin = this.mixin, root = [], node;
4031
4032                while (true) {
4033                    while (true) {
4034                        node = this.comment();
4035                        if (!node) { break; }
4036                        root.push(node);
4037                    }
4038                    // always process comments before deciding if finished
4039                    if (parserInput.finished) {
4040                        break;
4041                    }
4042                    if (parserInput.peek('}')) {
4043                        break;
4044                    }
4045
4046                    node = this.extendRule();
4047                    if (node) {
4048                        root = root.concat(node);
4049                        continue;
4050                    }
4051
4052                    node = mixin.definition() || this.declaration() || this.ruleset() ||
4053                        mixin.call() || this.variableCall() || this.entities.call() || this.atrule();
4054                    if (node) {
4055                        root.push(node);
4056                    } else {
4057                        var foundSemiColon = false;
4058                        while (parserInput.$char(';')) {
4059                            foundSemiColon = true;
4060                        }
4061                        if (!foundSemiColon) {
4062                            break;
4063                        }
4064                    }
4065                }
4066
4067                return root;
4068            },
4069
4070            // comments are collected by the main parsing mechanism and then assigned to nodes
4071            // where the current structure allows it
4072            comment: function () {
4073                if (parserInput.commentStore.length) {
4074                    var comment = parserInput.commentStore.shift();
4075                    return new(tree.Comment)(comment.text, comment.isLineComment, comment.index, fileInfo);
4076                }
4077            },
4078
4079            //
4080            // Entities are tokens which can be found inside an Expression
4081            //
4082            entities: {
4083                //
4084                // A string, which supports escaping " and '
4085                //
4086                //     "milky way" 'he\'s the one!'
4087                //
4088                quoted: function () {
4089                    var str, index = parserInput.i, isEscaped = false;
4090
4091                    parserInput.save();
4092                    if (parserInput.$char('~')) {
4093                        isEscaped = true;
4094                    }
4095                    str = parserInput.$quoted();
4096                    if (!str) {
4097                        parserInput.restore();
4098                        return;
4099                    }
4100                    parserInput.forget();
4101
4102                    return new(tree.Quoted)(str.charAt(0), str.substr(1, str.length - 2), isEscaped, index, fileInfo);
4103                },
4104
4105                //
4106                // A catch-all word, such as:
4107                //
4108                //     black border-collapse
4109                //
4110                keyword: function () {
4111                    var k = parserInput.$char('%') || parserInput.$re(/^\[?[_A-Za-z-][_A-Za-z0-9-]*\]?/);
4112                    if (k) {
4113                        return tree.Color.fromKeyword(k) || new(tree.Keyword)(k);
4114                    }
4115                },
4116
4117                //
4118                // A function call
4119                //
4120                //     rgb(255, 0, 255)
4121                //
4122                // The arguments are parsed with the `entities.arguments` parser.
4123                //
4124                call: function () {
4125                    var name, args, func, index = parserInput.i;
4126
4127                    // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
4128                    if (parserInput.peek(/^url\(/i)) {
4129                        return;
4130                    }
4131
4132                    parserInput.save();
4133
4134                    name = parserInput.$re(/^([\w-]+|%|progid:[\w\.]+)\(/);
4135                    if (!name) {
4136                        parserInput.forget(); 
4137                        return;
4138                    }
4139
4140                    name = name[1];
4141                    func = this.customFuncCall(name);
4142                    if (func) {
4143                        args = func.parse();
4144                        if (args && func.stop) {
4145                            parserInput.forget();
4146                            return args;
4147                        }
4148                    }
4149
4150                    args = this.arguments(args);
4151
4152                    if (!parserInput.$char(')')) {
4153                        parserInput.restore('Could not parse call arguments or missing \')\'');
4154                        return;
4155                    }
4156
4157                    parserInput.forget();
4158                    
4159                    return new(tree.Call)(name, args, index, fileInfo);
4160                },
4161                
4162                //
4163                // Parsing rules for functions with non-standard args, e.g.:
4164                //
4165                //     boolean(not(2 > 1))
4166                //
4167                //     This is a quick prototype, to be modified/improved when
4168                //     more custom-parsed funcs come (e.g. `selector(...)`)
4169                //
4170
4171                customFuncCall: function (name) {
4172                    /* Ideally the table is to be moved out of here for faster perf.,
4173                       but it's quite tricky since it relies on all these `parsers`
4174                       and `expect` available only here */
4175                    return {
4176                        alpha:   f(parsers.ieAlpha, true),
4177                        boolean: f(condition),
4178                        'if':    f(condition)
4179                    }[name.toLowerCase()];
4180
4181                    function f(parse, stop) {
4182                        return {
4183                            parse: parse, // parsing function
4184                            stop:  stop   // when true - stop after parse() and return its result, 
4185                                          // otherwise continue for plain args
4186                        };
4187                    }
4188                
4189                    function condition() {
4190                        return [expect(parsers.condition, 'expected condition')];
4191                    }
4192                },
4193
4194                arguments: function (prevArgs) {
4195                    var argsComma = prevArgs || [],
4196                        argsSemiColon = [],
4197                        isSemiColonSeparated, value;
4198
4199                    parserInput.save();
4200
4201                    while (true) {
4202                        if (prevArgs) {
4203                            prevArgs = false;
4204                        } else {
4205                            value = parsers.detachedRuleset() || this.assignment() || parsers.expression();
4206                            if (!value) {
4207                                break;
4208                            }
4209
4210                            if (value.value && value.value.length == 1) {
4211                                value = value.value[0];
4212                            }
4213
4214                            argsComma.push(value);
4215                        }
4216
4217                        if (parserInput.$char(',')) {
4218                            continue;
4219                        }
4220
4221                        if (parserInput.$char(';') || isSemiColonSeparated) {
4222                            isSemiColonSeparated = true;
4223                            value = (argsComma.length < 1) ? argsComma[0]
4224                                : new tree.Value(argsComma);
4225                            argsSemiColon.push(value);
4226                            argsComma = [];
4227                        }
4228                    }
4229
4230                    parserInput.forget();
4231                    return isSemiColonSeparated ? argsSemiColon : argsComma;
4232                },
4233                literal: function () {
4234                    return this.dimension() ||
4235                           this.color() ||
4236                           this.quoted() ||
4237                           this.unicodeDescriptor();
4238                },
4239
4240                // Assignments are argument entities for calls.
4241                // They are present in ie filter properties as shown below.
4242                //
4243                //     filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
4244                //
4245
4246                assignment: function () {
4247                    var key, value;
4248                    parserInput.save();
4249                    key = parserInput.$re(/^\w+(?=\s?=)/i);
4250                    if (!key) {
4251                        parserInput.restore();
4252                        return;
4253                    }
4254                    if (!parserInput.$char('=')) {
4255                        parserInput.restore();
4256                        return;
4257                    }
4258                    value = parsers.entity();
4259                    if (value) {
4260                        parserInput.forget();
4261                        return new(tree.Assignment)(key, value);
4262                    } else {
4263                        parserInput.restore();
4264                    }
4265                },
4266
4267                //
4268                // Parse url() tokens
4269                //
4270                // We use a specific rule for urls, because they don't really behave like
4271                // standard function calls. The difference is that the argument doesn't have
4272                // to be enclosed within a string, so it can't be parsed as an Expression.
4273                //
4274                url: function () {
4275                    var value, index = parserInput.i;
4276
4277                    parserInput.autoCommentAbsorb = false;
4278
4279                    if (!parserInput.$str('url(')) {
4280                        parserInput.autoCommentAbsorb = true;
4281                        return;
4282                    }
4283
4284                    value = this.quoted() || this.variable() || this.property() ||
4285                            parserInput.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || '';
4286
4287                    parserInput.autoCommentAbsorb = true;
4288
4289                    expectChar(')');
4290
4291                    return new(tree.URL)((value.value != null || 
4292                        value instanceof tree.Variable || 
4293                        value instanceof tree.Property) ?
4294                        value : new(tree.Anonymous)(value, index), index, fileInfo);
4295                },
4296
4297                //
4298                // A Variable entity, such as `@fink`, in
4299                //
4300                //     width: @fink + 2px
4301                //
4302                // We use a different parser for variable definitions,
4303                // see `parsers.variable`.
4304                //
4305                variable: function () {
4306                    var name, index = parserInput.i;
4307
4308                    if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^@@?[\w-]+/))) {
4309                        return new(tree.Variable)(name, index, fileInfo);
4310                    }
4311                },
4312
4313                // A variable entity using the protective {} e.g. @{var}
4314                variableCurly: function () {
4315                    var curly, index = parserInput.i;
4316
4317                    if (parserInput.currentChar() === '@' && (curly = parserInput.$re(/^@\{([\w-]+)\}/))) {
4318                        return new(tree.Variable)('@' + curly[1], index, fileInfo);
4319                    }
4320                },
4321                //
4322                // A Property accessor, such as `$color`, in
4323                //
4324                //     background-color: $color
4325                //
4326                property: function () {
4327                    var name, index = parserInput.i;
4328
4329                    if (parserInput.currentChar() === '$' && (name = parserInput.$re(/^\$[\w-]+/))) {
4330                        return new(tree.Property)(name, index, fileInfo);
4331                    }
4332                },
4333
4334                // A property entity useing the protective {} e.g. ${prop}
4335                propertyCurly: function () {
4336                    var curly, index = parserInput.i;
4337
4338                    if (parserInput.currentChar() === '$' && (curly = parserInput.$re(/^\$\{([\w-]+)\}/))) {
4339                        return new(tree.Property)('$' + curly[1], index, fileInfo);
4340                    }
4341                },
4342                //
4343                // A Hexadecimal color
4344                //
4345                //     #4F3C2F
4346                //
4347                // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
4348                //
4349                color: function () {
4350                    var rgb;
4351
4352                    if (parserInput.currentChar() === '#' && (rgb = parserInput.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
4353                        // strip colons, brackets, whitespaces and other characters that should not
4354                        // definitely be part of color string
4355                        var colorCandidateString = rgb.input.match(/^#([\w]+).*/);
4356                        colorCandidateString = colorCandidateString[1];
4357                        if (!colorCandidateString.match(/^[A-Fa-f0-9]+$/)) { // verify if candidate consists only of allowed HEX characters
4358                            error('Invalid HEX color code');
4359                        }
4360                        return new(tree.Color)(rgb[1], undefined, '#' + colorCandidateString);
4361                    }
4362                },
4363
4364                colorKeyword: function () {
4365                    parserInput.save();
4366                    var autoCommentAbsorb = parserInput.autoCommentAbsorb;
4367                    parserInput.autoCommentAbsorb = false;
4368                    var k = parserInput.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/);
4369                    parserInput.autoCommentAbsorb = autoCommentAbsorb;
4370                    if (!k) {
4371                        parserInput.forget();
4372                        return;
4373                    }
4374                    parserInput.restore();
4375                    var color = tree.Color.fromKeyword(k);
4376                    if (color) {
4377                        parserInput.$str(k);
4378                        return color;
4379                    }
4380                },
4381
4382                //
4383                // A Dimension, that is, a number and a unit
4384                //
4385                //     0.5em 95%
4386                //
4387                dimension: function () {
4388                    if (parserInput.peekNotNumeric()) {
4389                        return;
4390                    }
4391
4392                    var value = parserInput.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i);
4393                    if (value) {
4394                        return new(tree.Dimension)(value[1], value[2]);
4395                    }
4396                },
4397
4398                //
4399                // A unicode descriptor, as is used in unicode-range
4400                //
4401                // U+0??  or U+00A1-00A9
4402                //
4403                unicodeDescriptor: function () {
4404                    var ud;
4405
4406                    ud = parserInput.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/);
4407                    if (ud) {
4408                        return new(tree.UnicodeDescriptor)(ud[0]);
4409                    }
4410                },
4411
4412                //
4413                // JavaScript code to be evaluated
4414                //
4415                //     `window.location.href`
4416                //
4417                javascript: function () {
4418                    var js, index = parserInput.i;
4419
4420                    parserInput.save();
4421
4422                    var escape = parserInput.$char('~');
4423                    var jsQuote = parserInput.$char('`');
4424
4425                    if (!jsQuote) {
4426                        parserInput.restore();
4427                        return;
4428                    }
4429
4430                    js = parserInput.$re(/^[^`]*`/);
4431                    if (js) {
4432                        parserInput.forget();
4433                        return new(tree.JavaScript)(js.substr(0, js.length - 1), Boolean(escape), index, fileInfo);
4434                    }
4435                    parserInput.restore('invalid javascript definition');
4436                }
4437            },
4438
4439            //
4440            // The variable part of a variable definition. Used in the `rule` parser
4441            //
4442            //     @fink:
4443            //
4444            variable: function () {
4445                var name;
4446
4447                if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; }
4448            },
4449
4450            //
4451            // Call a variable value
4452            //
4453            //     @fink()
4454            //
4455            variableCall: function () {
4456                var name;
4457
4458                if (parserInput.currentChar() === '@'
4459                    && (name = parserInput.$re(/^(@[\w-]+)\(\s*\)/))
4460                    && parsers.end()) {
4461                    return new tree.VariableCall(name[1]);
4462                }
4463            },
4464
4465            //
4466            // extend syntax - used to extend selectors
4467            //
4468            extend: function(isRule) {
4469                var elements, e, index = parserInput.i, option, extendList, extend;
4470
4471                if (!parserInput.$str(isRule ? '&:extend(' : ':extend(')) {
4472                    return;
4473                }
4474
4475                do {
4476                    option = null;
4477                    elements = null;
4478                    while (!(option = parserInput.$re(/^(all)(?=\s*(\)|,))/))) {
4479                        e = this.element();
4480                        if (!e) {
4481                            break;
4482                        }
4483                        if (elements) {
4484                            elements.push(e);
4485                        } else {
4486                            elements = [ e ];
4487                        }
4488                    }
4489
4490                    option = option && option[1];
4491                    if (!elements) {
4492                        error('Missing target selector for :extend().');
4493                    }
4494                    extend = new(tree.Extend)(new(tree.Selector)(elements), option, index, fileInfo);
4495                    if (extendList) {
4496                        extendList.push(extend);
4497                    } else {
4498                        extendList = [ extend ];
4499                    }
4500                } while (parserInput.$char(','));
4501
4502                expect(/^\)/);
4503
4504                if (isRule) {
4505                    expect(/^;/);
4506                }
4507
4508                return extendList;
4509            },
4510
4511            //
4512            // extendRule - used in a rule to extend all the parent selectors
4513            //
4514            extendRule: function() {
4515                return this.extend(true);
4516            },
4517
4518            //
4519            // Mixins
4520            //
4521            mixin: {
4522                //
4523                // A Mixin call, with an optional argument list
4524                //
4525                //     #mixins > .square(#fff);
4526                //     .rounded(4px, black);
4527                //     .button;
4528                //
4529                // The `while` loop is there because mixins can be
4530                // namespaced, but we only support the child and desce
4530ndant
4531                // selector for now.
4532                //
4533                call: function () {
4534                    var s = parserInput.currentChar(), important = false, index = parserInput.i, elemIndex,
4535                        elements, elem, e, c, args;
4536
4537                    if (s !== '.' && s !== '#') { return; }
4538
4539                    parserInput.save(); // stop us absorbing part of an invalid selector
4540
4541                    while (true) {
4542                        elemIndex = parserInput.i;
4543                        e = parserInput.$re(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/);
4544                        if (!e) {
4545                            break;
4546                        }
4547                        elem = new(tree.Element)(c, e, elemIndex, fileInfo);
4548                        if (elements) {
4549                            elements.push(elem);
4550                        } else {
4551                            elements = [ elem ];
4552                        }
4553                        c = parserInput.$char('>');
4554                    }
4555
4556                    if (elements) {
4557                        if (parserInput.$char('(')) {
4558                            args = this.args(true).args;
4559                            expectChar(')');
4560                        }
4561
4562                        if (parsers.important()) {
4563                            important = true;
4564                        }
4565
4566                        if (parsers.end()) {
4567                            parserInput.forget();
4568                            return new(tree.mixin.Call)(elements, args, index, fileInfo, important);
4569                        }
4570                    }
4571
4572                    parserInput.restore();
4573                },
4574                args: function (isCall) {
4575                    var entities = parsers.entities,
4576                        returner = { args:null, variadic: false },
4577                        expressions = [], argsSemiColon = [], argsComma = [],
4578                        isSemiColonSeparated, expressionContainsNamed, name, nameLoop,
4579                        value, arg, expand;
4580
4581                    parserInput.save();
4582
4583                    while (true) {
4584                        if (isCall) {
4585                            arg = parsers.detachedRuleset() || parsers.expression();
4586                        } else {
4587                            parserInput.commentStore.length = 0;
4588                            if (parserInput.$str('...')) {
4589                                returner.variadic = true;
4590                                if (parserInput.$char(';') && !isSemiColonSeparated) {
4591                                    isSemiColonSeparated = true;
4592                                }
4593                                (isSemiColonSeparated ? argsSemiColon : argsComma)
4594                                    .push({ variadic: true });
4595                                break;
4596                            }
4597                            arg = entities.variable() || entities.property() || entities.literal() || entities.keyword();
4598                        }
4599
4600                        if (!arg) {
4601                            break;
4602                        }
4603
4604                        nameLoop = null;
4605                        if (arg.throwAwayComments) {
4606                            arg.throwAwayComments();
4607                        }
4608                        value = arg;
4609                        var val = null;
4610
4611                        if (isCall) {
4612                            // Variable
4613                            if (arg.value && arg.value.length == 1) {
4614                                val = arg.value[0];
4615                            }
4616                        } else {
4617                            val = arg;
4618                        }
4619
4620                        if (val && (val instanceof tree.Variable || val instanceof tree.Property)) {
4621                            if (parserInput.$char(':')) {
4622                                if (expressions.length > 0) {
4623                                    if (isSemiColonSeparated) {
4624                                        error('Cannot mix ; and , as delimiter types');
4625                                    }
4626                                    expressionContainsNamed = true;
4627                                }
4628
4629                                value = parsers.detachedRuleset() || parsers.expression();
4630
4631                                if (!value) {
4632                                    if (isCall) {
4633                                        error('could not understand value for named argument');
4634                                    } else {
4635                                        parserInput.restore();
4636                                        returner.args = [];
4637                                        return returner;
4638                                    }
4639                                }
4640                                nameLoop = (name = val.name);
4641                            } else if (parserInput.$str('...')) {
4642                                if (!isCall) {
4643                                    returner.variadic = true;
4644                                    if (parserInput.$char(';') && !isSemiColonSeparated) {
4645                                        isSemiColonSeparated = true;
4646                                    }
4647                                    (isSemiColonSeparated ? argsSemiColon : argsComma)
4648                                        .push({ name: arg.name, variadic: true });
4649                                    break;
4650                                } else {
4651                                    expand = true;
4652                                }
4653                            } else if (!isCall) {
4654                                name = nameLoop = val.name;
4655                                value = null;
4656                            }
4657                        }
4658
4659                        if (value) {
4660                            expressions.push(value);
4661                        }
4662
4663                        argsComma.push({ name:nameLoop, value:value, expand:expand });
4664
4665                        if (parserInput.$char(',')) {
4666                            continue;
4667                        }
4668
4669                        if (parserInput.$char(';') || isSemiColonSeparated) {
4670
4671                            if (expressionContainsNamed) {
4672                                error('Cannot mix ; and , as delimiter types');
4673                            }
4674
4675                            isSemiColonSeparated = true;
4676
4677                            if (expressions.length > 1) {
4678                                value = new(tree.Value)(expressions);
4679                            }
4680                            argsSemiColon.push({ name:name, value:value, expand:expand });
4681
4682                            name = null;
4683                            expressions = [];
4684                            expressionContainsNamed = false;
4685                        }
4686                    }
4687
4688                    parserInput.forget();
4689                    returner.args = isSemiColonSeparated ? argsSemiColon : argsComma;
4690                    return returner;
4691                },
4692                //
4693                // A Mixin definition, with a list of parameters
4694                //
4695                //     .rounded (@radius: 2px, @color) {
4696                //        ...
4697                //     }
4698                //
4699                // Until we have a finer grained state-machine, we have to
4700                // do a look-ahead, to make sure we don't have a mixin call.
4701                // See the `rule` function for more information.
4702                //
4703                // We start by matching `.rounded (`, and then proceed on to
4704                // the argument list, which has optional default values.
4705                // We store the parameters in `params`, with a `value` key,
4706                // if there is a value, such as in the case of `@radius`.
4707                //
4708                // Once we've got our params list, and a closing `)`, we parse
4709                // the `{...}` block.
4710                //
4711                definition: function () {
4712                    var name, params = [], match, ruleset, cond, variadic = false;
4713                    if ((parserInput.currentChar() !== '.' && parserInput.currentChar() !== '#') ||
4714                        parserInput.peek(/^[^{]*\}/)) {
4715                        return;
4716                    }
4717
4718                    parserInput.save();
4719
4720                    match = parserInput.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/);
4721                    if (match) {
4722                        name = match[1];
4723
4724                        var argInfo = this.args(false);
4725                        params = argInfo.args;
4726                        variadic = argInfo.variadic;
4727
4728                        // .mixincall("@{a}");
4729                        // looks a bit like a mixin definition..
4730                        // also
4731                        // .mixincall(@a: {rule: set;});
4732                        // so we have to be nice and restore
4733                        if (!parserInput.$char(')')) {
4734                            parserInput.restore('Missing closing \')\'');
4735                            return;
4736                        }
4737
4738                        parserInput.commentStore.length = 0;
4739
4740                        if (parserInput.$str('when')) { // Guard
4741                            cond = expect(parsers.conditions, 'expected condition');
4742                        }
4743
4744                        ruleset = parsers.block();
4745
4746                        if (ruleset) {
4747                            parserInput.forget();
4748                            return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
4749                        } else {
4750                            parserInput.restore();
4751                        }
4752                    } else {
4753                        parserInput.forget();
4754                    }
4755                }
4756            },
4757
4758            //
4759            // Entities are the smallest recognized token,
4760            // and can be found inside a rule's value.
4761            //
4762            entity: function () {
4763                var entities = this.entities;
4764
4765                return this.comment() || entities.literal() || entities.variable() || entities.url() ||
4766                       entities.property() || entities.call() || entities.keyword()  || entities.javascript();
4767            },
4768
4769            //
4770            // A Declaration terminator. Note that we use `peek()` to check for '}',
4771            // because the `block` rule will be expecting it, but we still need to make sure
4772            // it's there, if ';' was omitted.
4773            //
4774            end: function () {
4775                return parserInput.$char(';') || parserInput.peek('}');
4776            },
4777
4778            //
4779            // IE's alpha function
4780            //
4781            //     alpha(opacity=88)
4782            //
4783            ieAlpha: function () {
4784                var value;
4785
4786                // http://jsperf.com/case-insensitive-regex-vs-strtolower-then-regex/18
4787                if (!parserInput.$re(/^opacity=/i)) { return; }
4788                value = parserInput.$re(/^\d+/);
4789                if (!value) {
4790                    value = expect(parsers.entities.variable, 'Could not parse alpha');
4791                    value = '@{' + value.name.slice(1) + '}';
4792                }
4793                expectChar(')');
4794                return new tree.Quoted('', 'alpha(opacity=' + value + ')');
4795            },
4796
4797            //
4798            // A Selector Element
4799            //
4800            //     div
4801            //     + h1
4802            //     #socks
4803            //     input[type="text"]
4804            //
4805            // Elements are the building blocks for Selectors,
4806            // they are made out of a `Combinator` (see combinator rule),
4807            // and an element name, such as a tag a class, or `*`.
4808            //
4809            element: function () {
4810                var e, c, v, index = parserInput.i;
4811
4812                c = this.combinator();
4813
4814                e = parserInput.$re(/^(?:\d+\.\d+|\d+)%/) ||
4815                    parserInput.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
4816                    parserInput.$char('*') || parserInput.$char('&') || this.attribute() ||
4817                    parserInput.$re(/^\([^&()@]+\)/) ||  parserInput.$re(/^[\.#:](?=@)/) ||
4818                    this.entities.variableCurly();
4819
4820                if (!e) {
4821                    parserInput.save();
4822                    if (parserInput.$char('(')) {
4823                        if ((v = this.selector(false)) && parserInput.$char(')')) {
4824                            e = new(tree.Paren)(v);
4825                            parserInput.forget();
4826                        } else {
4827                            parserInput.restore('Missing closing \')\'');
4828                        }
4829                    } else {
4830                        parserInput.forget();
4831                    }
4832                }
4833
4834                if (e) { return new(tree.Element)(c, e, index, fileInfo); }
4835            },
4836
4837            //
4838            // Combinators combine elements together, in a Selector.
4839            //
4840            // Because our parser isn't white-space sensitive, special care
4841            // has to be taken, when parsing the descendant combinator, ` `,
4842            // as it's an empty space. We have to check the previous character
4843            // in the input, to see if it's a ` ` character. More info on how
4844            // we deal with this in *combinator.js*.
4845            //
4846            combinator: function () {
4847                var c = parserInput.currentChar();
4848
4849                if (c === '/') {
4850                    parserInput.save();
4851                    var slashedCombinator = parserInput.$re(/^\/[a-z]+\//i);
4852                    if (slashedCombinator) {
4853                        parserInput.forget();
4854                        return new(tree.Combinator)(slashedCombinator);
4855                    }
4856                    parserInput.restore();
4857                }
4858
4859                if (c === '>' || c === '+' || c === '~' || c === '|' || c === '^') {
4860                    parserInput.i++;
4861                    if (c === '^' && parserInput.currentChar() === '^') {
4862                        c = '^^';
4863                        parserInput.i++;
4864                    }
4865                    while (parserInput.isWhitespace()) { parserInput.i++; }
4866                    return new(tree.Combinator)(c);
4867                } else if (parserInput.isWhitespace(-1)) {
4868                    return new(tree.Combinator)(' ');
4869                } else {
4870                    return new(tree.Combinator)(null);
4871                }
4872            },
4873            //
4874            // A CSS Selector
4875            // with less extensions e.g. the ability to extend and guard
4876            //
4877            //     .class > div + h1
4878            //     li a:hover
4879            //
4880            // Selectors are made out of one or more Elements, see above.
4881            //
4882            selector: function (isLess) {
4883                var index = parserInput.i, elements, extendList, c, e, allExtends, when, condition;
4884                isLess = isLess !== false;
4885                while ((isLess && (extendList = this.extend())) || (isLess && (when = parserInput.$str('when'))) || (e = this.element())) {
4886                    if (when) {
4887                        condition = expect(this.conditions, 'expected condition');
4888                    } else if (condition) {
4889                        error('CSS guard can only be used at the end of selector');
4890                    } else if (extendList) {
4891                        if (allExtends) {
4892                            allExtends = allExtends.concat(extendList);
4893                        } else {
4894                            allExtends = extendList;
4895                        }
4896                    } else {
4897                        if (allExtends) { error('Extend can only be used at the end of selector'); }
4898                        c = parserInput.currentChar();
4899                        if (elements) {
4900                            elements.push(e);
4901                        } else {
4902                            elements = [ e ];
4903                        }
4904                        e = null;
4905                    }
4906                    if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
4907                        break;
4908                    }
4909                }
4910
4911                if (elements) { return new(tree.Selector)(elements, allExtends, condition, index, fileInfo); }
4912                if (allExtends) { error('Extend must be used to extend a selector, it cannot be used on its own'); }
4913            },
4914            attribute: function () {
4915                if (!parserInput.$char('[')) { return; }
4916
4917                var entities = this.entities,
4918                    key, val, op;
4919
4920                if (!(key = entities.variableCurly())) {
4921                    key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
4922                }
4923
4924                op = parserInput.$re(/^[|~*$^]?=/);
4925                if (op) {
4926                    val = entities.quoted() || parserInput.$re(/^[0-9]+%/) || parserInput.$re(/^[\w-]+/) || entities.variableCurly();
4927                }
4928
4929                expectChar(']');
4930
4931                return new(tree.Attribute)(key, op, val);
4932            },
4933
4934            //
4935            // The `block` rule is used by `ruleset` and `mixin.definition`.
4936            // It's a wrapper around the `primary` rule, with added `{}`.
4937            //
4938            block: function () {
4939                var content;
4940                if (parserInput.$char('{') && (content = this.primary()) && parserInput.$char('}')) {
4941                    return content;
4942                }
4943            },
4944
4945            blockRuleset: function() {
4946                var block = this.block();
4947
4948                if (block) {
4949                    block = new tree.Ruleset(null, block);
4950                }
4951                return block;
4952            },
4953
4954            detachedRuleset: function() {
4955                var blockRuleset = this.blockRuleset();
4956                if (blockRuleset) {
4957                    return new tree.DetachedRuleset(blockRuleset);
4958                }
4959            },
4960
4961            //
4962            // div, .class, body > p {...}
4963            //
4964            ruleset: function () {
4965                var selectors, s, rules, debugInfo;
4966
4967                parserInput.save();
4968
4969                if (context.dumpLineNumbers) {
4970                    debugInfo = getDebugInfo(parserInput.i);
4971                }
4972
4973                while (true) {
4974                    s = this.selector();
4975                    if (!s) {
4976                        break;
4977                    }
4978                    if (selectors) {
4979                        selectors.push(s);
4980                    } else {
4981                        selectors = [ s ];
4982                    }
4983                    parserInput.commentStore.length = 0;
4984                    if (s.condition && selectors.length > 1) {
4985                        error('Guards are only currently allowed on a single selector.');
4986                    }
4987                    if (!parserInput.$char(',')) { break; }
4988                    if (s.condition) {
4989                        error('Guards are only currently allowed on a single selector.');
4990                    }
4991                    parserInput.commentStore.length = 0;
4992                }
4993
4994                if (selectors && (rules = this.block())) {
4995                    parserInput.forget();
4996                    var ruleset = new(tree.Ruleset)(selectors, rules, context.strictImports);
4997                    if (context.dumpLineNumbers) {
4998                        ruleset.debugInfo = debugInfo;
4999                    }
5000                    return ruleset;
5001                } else {
5002                    parserInput.restore();
5003                }
5004            },
5005            declaration: function () {
5006                var name, value, index = parserInput.i, 
5007                    c = parserInput.currentChar(), important, merge, isVariable;
5008
5009                if (c === '.' || c === '#' || c === '&' || c === ':') { return; }
5010
5011                parserInput.save();
5012
5013                name = this.variable() || this.ruleProperty();
5014                if (name) {
5015                    isVariable = typeof name === 'string';
5016
5017                    if (isVariable) {
5018                        value = this.detachedRuleset();
5019                    }
5020
5021                    parserInput.commentStore.length = 0;
5022                    if (!value) {
5023                        // a name returned by this.ruleProperty() is always an array of the form:
5024                        // [string-1, ..., string-n, ""] or [string-1, ..., string-n, "+"]
5025                        // where each item is a tree.Keyword or tree.Variable
5026                        merge = !isVariable && name.length > 1 && name.pop().value;
5027
5028                        // Custom property values get permissive parsing
5029                        if (name[0].value && name[0].value.slice(0, 2) === '--') {
5030                            value = this.permissiveValue(';');
5031                        }
5032                        // Try to store values as anonymous
5033                        // If we need the value later we'll re-parse it in ruleset.parseValue
5034                        else {
5035                            value = this.anonymousValue();
5036                        }
5037                        if (value) {
5038                            parserInput.forget();
5039                            // anonymous values absorb the end ';' which is required for them to work
5040                            return new (tree.Declaration)(name, value, false, merge, index, fileInfo);
5041                        }
5042
5043                        if (!value) {
5044                            value = this.value();
5045                        }
5046
5047                        important = this.important();
5048
5049                        // As a last resort, let a variable try to be parsed as a permissive value
5050                        if (!value && isVariable) {
5051                            value = this.permissiveValue(';');
5052                        }
5053                    }
5054
5055                    if (value && this.end()) {
5056                        parserInput.forget();
5057                        return new (tree.Declaration)(name, value, important, merge, index, fileInfo);
5058                    }
5059                    else {
5060                        parserInput.restore();
5061                    }
5062                } else {
5063                    parserInput.restore();
5064                }
5065            },
5066            anonymousValue: function () {
5067                var index = parserInput.i;
5068                var match = parserInput.$re(/^([^@\$+\/'"*`(;{}-]*);/);
5069                if (match) {
5070                    return new(tree.Anonymous)(match[1], index);
5071                }
5072            },
5073            /**
5074             * Used for custom properties and custom at-rules
5075             * Parses almost anything inside of {} [] () "" blocks
5076             * until it reaches outer-most tokens.
5077             */
5078            permissiveValue: function (untilTokens) {
5079                var i, index = parserInput.i,
5080                    value = parserInput.$parseUntil(untilTokens);
5081
5082                if (value) {
5083                    if (typeof value === 'string') {
5084                        error('Expected \'' + value + '\'', 'Parse');
5085                    }
5086                    if (value.length === 1 && value[0] === ' ') {
5087                        return new tree.Anonymous('', index);
5088                    }
5089                    var item, args = [];
5090                    for (i = 0; i < value.length; i++) {
5091                        item = value[i];
5092                        if (Array.isArray(item)) {
5093                            // Treat actual quotes as normal quoted values
5094                            args.push(new tree.Quoted(item[0], item[1], true, index, fileInfo));
5095                        }
5096                        else {
5097                            if (i === value.length - 1) {
5098                                item = item.trim();
5099                            }
5100                            // Treat like quoted values, but replace vars like unquoted expressions
5101                            var quote = new tree.Quoted('\'', item, true, index, fileInfo);
5102                            quote.variableRegex = /@([\w-]+)/g;
5103                            quote.propRegex = /\$([\w-]+)/g;
5104                            quote.reparse = true;
5105                            args.push(quote);
5106                        }
5107                    }
5108                    return new tree.Expression(args, true);
5109                }
5110            },
5111
5112            //
5113            // An @import atrule
5114            //
5115            //     @import "lib";
5116            //
5117            // Depending on our environment, importing is done differently:
5118            // In the browser, it's an XHR request, in Node, it would be a
5119            // file-system operation. The function used for importing is
5120            // stored in `import`, which we pass to the Import constructor.
5121            //
5122            'import': function () {
5123                var path, features, index = parserInput.i;
5124
5125                var dir = parserInput.$re(/^@import?\s+/);
5126
5127                if (dir) {
5128                    var options = (dir ? this.importOptions() : null) || {};
5129
5130                    if ((path = this.entities.quoted() || this.entities.url())) {
5131                        features = this.mediaFeatures();
5132
5133                        if (!parserInput.$char(';')) {
5134                            parserInput.i = index;
5135                            error('missing semi-colon or unrecognised media features on import');
5136                        }
5137                        features = features && new(tree.Value)(features);
5138                        return new(tree.Import)(path, features, options, index, fileInfo);
5139                    }
5140                    else {
5141                        parserInput.i = index;
5142                        error('malformed import statement');
5143                    }
5144                }
5145            },
5146
5147            importOptions: function() {
5148                var o, options = {}, optionName, value;
5149
5150                // list of options, surrounded by parens
5151                if (!parserInput.$char('(')) { return null; }
5152                do {
5153                    o = this.importOption();
5154                    if (o) {
5155                        optionName = o;
5156                        value = true;
5157                        switch (optionName) {
5158                            case 'css':
5159                                optionName = 'less';
5160                                value = false;
5161                                break;
5162                            case 'once':
5163                                optionName = 'multiple';
5164                                value = false;
5165                                break;
5166                        }
5167                        options[optionName] = value;
5168                        if (!parserInput.$char(',')) { break; }
5169                    }
5170                } while (o);
5171                expectChar(')');
5172                return options;
5173            },
5174
5175            importOption: function() {
5176                var opt = parserInput.$re(/^(less|css|multiple|once|inline|reference|optional)/);
5177                if (opt) {
5178                    return opt[1];
5179                }
5180            },
5181
5182            mediaFeature: function () {
5183                var entities = this.entities, nodes = [], e, p;
5184                parserInput.save();
5185                do {
5186                    e = entities.keyword() || entities.variable();
5187                    if (e) {
5188                        nodes.push(e);
5189                    } else if (parserInput.$char('(')) {
5190                        p = this.property();
5191                        e = this.value();
5192                        if (parserInput.$char(')')) {
5193                            if (p && e) {
5194                                nodes.push(new(tree.Paren)(new(tree.Declaration)(p, e, null, null, parserInput.i, fileInfo, true)));
5195                            } else if (e) {
5196                                nodes.push(new(tree.Paren)(e));
5197                            } else {
5198                                error('badly formed media feature definition');
5199                            }
5200                        } else {
5201                            error('Missing closing \')\'', 'Parse');
5202                        }
5203                    }
5204                } while (e);
5205
5206                parserInput.forget();
5207                if (nodes.length > 0) {
5208                    return new(tree.Expression)(nodes);
5209                }
5210            },
5211
5212            mediaFeatures: function () {
5213                var entities = this.entities, features = [], e;
5214                do {
5215                    e = this.mediaFeature();
5216                    if (e) {
5217                        features.push(e);
5218                        if (!parserInput.$char(',')) { break; }
5219                    } else {
5220                        e = entities.variable();
5221                        if (e) {
5222                            features.push(e);
5223                            if (!parserInput.$char(',')) { break; }
5224                        }
5225                    }
5226                } while (e);
5227
5228                return features.length > 0 ? features : null;
5229            },
5230
5231            media: function () {
5232                var features, rules, media, debugInfo, index = parserInput.i;
5233
5234                if (context.dumpLineNumbers) {
5235                    debugInfo = getDebugInfo(index);
5236                }
5237
5238                parserInput.save();
5239
5240                if (parserInput.$str('@media')) {
5241                    features = this.mediaFeatures();
5242
5243                    rules = this.block();
5244
5245                    if (!rules) {
5246                        error('media definitions require block statements after any features');
5247                    }
5248
5249                    parserInput.forget();
5250
5251                    media = new(tree.Media)(rules, features, index, fileInfo);
5252                    if (context.dumpLineNumbers) {
5253                        media.debugInfo = debugInfo;
5254                    }
5255
5256                    return media;
5257                }
5258
5259                parserInput.restore();
5260            },
5261
5262            //
5263
5264            // A @plugin directive, used to import plugins dynamically.
5265            //
5266            //     @plugin (args) "lib";
5267            //
5268            plugin: function () {
5269                var path, args, options,
5270                    index = parserInput.i,
5271                    dir   = parserInput.$re(/^@plugin?\s+/);
5272
5273                if (dir) {
5274                    args = this.pluginArgs();
5275
5276                    if (args) {
5277                        options = {
5278                            pluginArgs: args,
5279                            isPlugin: true
5280                        };
5281                    }
5282                    else {
5283                        options = { isPlugin: true };
5284                    }
5285
5286                    if ((path = this.entities.quoted() || this.entities.url())) {
5287
5288                        if (!parserInput.$char(';')) {
5289                            parserInput.i = index;
5290                            error('missing semi-colon on @plugin');
5291                        }
5292                        return new(tree.Import)(path, null, options, index, fileInfo);
5293                    }
5294                    else {
5295                        parserInput.i = index;
5296                        error('malformed @plugin statement');
5297                    }
5298                }
5299            },
5300
5301            pluginArgs: function() {
5302                // list of options, surrounded by parens
5303                parserInput.save();
5304                if (!parserInput.$char('(')) {
5305                    parserInput.restore();
5306                    return null;
5307                }
5308                var args = parserInput.$re(/^\s*([^\);]+)\)\s*/);
5309                if (args[1]) {
5310                    parserInput.forget();
5311                    return args[1].trim();
5312                }
5313                else { 
5314                    parserInput.restore();
5315                    return null;
5316                }
5317            },
5318
5319            //
5320            // A CSS AtRule
5321            //
5322            //     @charset "utf-8";
5323            //
5324            atrule: function () {
5325                var index = parserInput.i, name, value, rules, nonVendorSpecificName,
5326                    hasIdentifier, hasExpression, hasUnknown, hasBlock = true, isRooted = true;
5327
5328                if (parserInput.currentChar() !== '@') { return; }
5329
5330                value = this['import']() || this.plugin() || this.media();
5331                if (value) {
5332                    return value;
5333                }
5334
5335                parserInput.save();
5336
5337                name = parserInput.$re(/^@[a-z-]+/);
5338
5339                if (!name) { return; }
5340
5341                nonVendorSpecificName = name;
5342                if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
5343                    nonVendorSpecificName = '@' + name.slice(name.indexOf('-', 2) + 1);
5344                }
5345
5346                switch (nonVendorSpecificName) {
5347                    case '@charset':
5348                        hasIdentifier = true;
5349                        hasBlock = false;
5350                        break;
5351                    case '@namespace':
5352                        hasExpression = true;
5353                        hasBlock = false;
5354                        break;
5355                    case '@keyframes':
5356                    case '@counter-style':
5357                        hasIdentifier = true;
5358                        break;
5359                    case '@document':
5360                    case '@supports':
5361                        hasUnknown = true;
5362                        isRooted = false;
5363                        break;
5364                    default:
5365                        hasUnknown = true;
5366                        break;
5367                }
5368
5369                parserInput.commentStore.length = 0;
5370
5371                if (hasIdentifier) {
5372                    value = this.entity();
5373                    if (!value) {
5374                        error('expected ' + name + ' identifier');
5375                    }
5376                } else if (hasExpression) {
5377                    value = this.expression();
5378                    if (!value) {
5379                        error('expected ' + name + ' expression');
5380                    }
5381                } else if (hasUnknown) {
5382                    value = this.permissiveValue(/^[{;]/);
5383                    hasBlock = (parserInput.currentChar() === '{');
5384                    if (!value) {
5385                        if (!hasBlock && parserInput.currentChar() !== ';') {
5386                            error(name + ' rule is missing block or ending semi-colon');
5387                        }
5388                    }
5389                    else if (!value.value) {
5390                        value = null;
5391                    }
5392                }
5393
5394                if (hasBlock) {
5395                    rules = this.blockRuleset();
5396                }
5397
5398                if (rules || (!hasBlock && value && parserInput.$char(';'))) {
5399                    parserInput.forget();
5400                    return new (tree.AtRule)(name, value, rules, index, fileInfo,
5401                        context.dumpLineNumbers ? getDebugInfo(index) : null,
5402                        isRooted
5403                    );
5404                }
5405
5406                parserInput.restore('at-rule options not recognised');
5407            },
5408
5409            //
5410            // A Value is a comma-delimited list of Expressions
5411            //
5412            //     font-family: Baskerville, Georgia, serif;
5413            //
5414            // In a Rule, a Value represents everything after the `:`,
5415            // and before the `;`.
5416            //
5417            value: function () {
5418                var e, expressions = [], index = parserInput.i;
5419
5420                do {
5421                    e = this.expression();
5422                    if (e) {
5423                        expressions.push(e);
5424                        if (!parserInput.$char(',')) { break; }
5425                    }
5426                } while (e);
5427
5428                if (expressions.length > 0) {
5429                    return new(tree.Value)(expressions, index);
5430                }
5431            },
5432            important: function () {
5433                if (parserInput.currentChar() === '!') {
5434                    return parserInput.$re(/^! *important/);
5435                }
5436            },
5437            sub: function () {
5438                var a, e;
5439
5440                parserInput.save();
5441                if (parserInput.$char('(')) {
5442                    a = this.addition();
5443                    if (a && parserInput.$char(')')) {
5444                        parserInput.forget();
5445                        e = new(tree.Expression)([a]);
5446                        e.parens = true;
5447                        return e;
5448                    }
5449                    parserInput.restore('Expected \')\'');
5450                    return;
5451                }
5452                parserInput.restore();
5453            },
5454            multiplication: function () {
5455                var m, a, op, operation, isSpaced;
5456                m = this.operand();
5457                if (m) {
5458                    isSpaced = parserInput.isWhitespace(-1);
5459                    while (true) {
5460                        if (parserInput.peek(/^\/[*\/]/)) {
5461                            break;
5462                        }
5463
5464                        parserInput.save();
5465
5466                        op = parserInput.$char('/') || parserInput.$char('*');
5467
5468                        if (!op) { parserInput.forget(); break; }
5469
5470                        a = this.operand();
5471
5472                        if (!a) { parserInput.restore(); break; }
5473                        parserInput.forget();
5474
5475                        m.parensInOp = true;
5476                        a.parensInOp = true;
5477                        operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
5478                        isSpaced = parserInput.isWhitespace(-1);
5479                    }
5480                    return operation || m;
5481                }
5482            },
5483            addition: function () {
5484                var m, a, op, operation, isSpaced;
5485                m = this.multiplication();
5486                if (m) {
5487                    isSpaced = parserInput.isWhitespace(-1);
5488                    while (true) {
5489                        op = parserInput.$re(/^[-+]\s+/) || (!isSpaced && (parserInput.$char('+') || parserInput.$char('-')));
5490                        if (!op) {
5491                            break;
5492                        }
5493                        a = this.multiplication();
5494                        if (!a) {
5495                            break;
5496                        }
5497
5498                        m.parensInOp = true;
5499                        a.parensInOp = true;
5500                        operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
5501                        isSpaced = parserInput.isWhitespace(-1);
5502                    }
5503                    return operation || m;
5504                }
5505            },
5506            conditions: function () {
5507                var a, b, index = parserInput.i, condition;
5508
5509                a = this.condition();
5510                if (a) {
5511                    while (true) {
5512                        if (!parserInput.peek(/^,\s*(not\s*)?\(/) || !parserInput.$char(',')) {
5513                            break;
5514                        }
5515                        b = this.condition();
5516                        if (!b) {
5517                            break;
5518                        }
5519                        condition = new(tree.Condition)('or', condition || a, b, index);
5520                    }
5521                    return condition || a;
5522                }
5523            },
5524            condition: function () {
5525                var result, logical, next;
5526                function or() {
5527                    return parserInput.$str('or');
5528                }
5529
5530                result = this.conditionAnd(this);
5531                if (!result) {
5532                    return ;
5533                }
5534                logical = or();
5535                if (logical) {
5536                    next = this.condition();
5537                    if (next) {
5538                        result = new(tree.Condition)(logical, result, next);
5539                    } else {
5540                        return ;
5541                    }
5542                }
5543                return result;
5544            },
5545            conditionAnd: function () {
5546                var result, logical, next;
5547                function insideCondition(me) {
5548                    return me.negatedCondition() || me.parenthesisCondition();
5549                }
5550                function and() {
5551                    return parserInput.$str('and');
5552                }
5553
5554                result = insideCondition(this);
5555                if (!result) {
5556                    return ;
5557                }
5558                logical = and();
5559                if (logical) {
5560                    next = this.conditionAnd();
5561                    if (next) {
5562                        result = new(tree.Condition)(logical, result, next);
5563                    } else {
5564                        return ;
5565                    }
5566                }
5567                return result;
5568            },
5569            negatedCondition: function () {
5570                if (parserInput.$str('not')) {
5571                    var result = this.parenthesisCondition();
5572                    if (result) {
5573                        result.negate = !result.negate;
5574                    }
5575                    return result;
5576                }
5577            },
5578            parenthesisCondition: function () {
5579                function tryConditionFollowedByParenthesis(me) {
5580                    var body;
5581                    parserInput.save();
5582                    body = me.condition();
5583                    if (!body) {
5584                        parserInput.restore();
5585                        return ;
5586                    }
5587                    if (!parserInput.$char(')')) {
5588                        parserInput.restore();
5589                        return ;
5590                    }
5591                    parserInput.forget();
5592                    return body;
5593                }
5594
5595                var body;
5596                parserInput.save();
5597                if (!parserInput.$str('(')) {
5598                    parserInput.restore();
5599                    return ;
5600                }
5601                body = tryConditionFollowedByParenthesis(this);
5602                if (body) {
5603                    parserInput.forget();
5604                    return body;
5605                }
5606
5607                body = this.atomicCondition();
5608                if (!body) {
5609                    parserInput.restore();
5610                    return ;
5611                }
5612                if (!parserInput.$char(')')) {
5613                    parserInput.restore('expected \')\' got \'' + parserInput.currentChar() + '\'');
5614                    return ;
5615                }
5616                parserInput.forget();
5617                return body;
5618            },
5619            atomicCondition: function () {
5620                var entities = this.entities, index = parserInput.i, a, b, c, op;
5621
5622                a = this.addition() || entities.keyword() || entities.quoted();
5623                if (a) {
5624                    if (parserInput.$char('>')) {
5625                        if (parserInput.$char('=')) {
5626                            op = '>=';
5627                        } else {
5628                            op = '>';
5629                        }
5630                    } else
5631                    if (parserInput.$char('<')) {
5632                        if (parserInput.$char('=')) {
5633                            op = '<=';
5634                        } else {
5635                            op = '<';
5636                        }
5637                    } else
5638                    if (parserInput.$char('=')) {
5639                        if (parserInput.$char('>')) {
5640                            op = '=>';
5641                        } else if (parserInput.$char('<')) {
5642                            op = '=<';
5643                        } else {
5644                            op = '=';
5645                        }
5646                    }
5647                    if (op) {
5648                        b = this.addition() || entities.keyword() || entities.quoted();
5649                        if (b) {
5650                            c = new(tree.Condition)(op, a, b, index, false);
5651                        } else {
5652                            error('expected expression');
5653                        }
5654                    } else {
5655                        c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, false);
5656                    }
5657                    return c;
5658                }
5659            },
5660
5661            //
5662            // An operand is anything that can be part of an operation,
5663            // such as a Color, or a Variable
5664            //
5665            operand: function () {
5666                var entities = this.entities, negate;
5667
5668                if (parserInput.peek(/^-[@\$\(]/)) {
5669                    negate = parserInput.$char('-');
5670                }
5671
5672                var o = this.sub() || entities.dimension() ||
5673                        entities.color() || entities.variable() ||
5674                        entities.property() || entities.call() ||
5675                        entities.colorKeyword();
5676
5677                if (negate) {
5678                    o.parensInOp = true;
5679                    o = new(tree.Negative)(o);
5680                }
5681
5682                return o;
5683            },
5684
5685            //
5686            // Expressions either represent mathematical operations,
5687            // or white-space delimited Entities.
5688            //
5689            //     1px solid black
5690            //     @var * 2
5691            //
5692            expression: function () {
5693                var entities = [], e, delim, index = parserInput.i;
5694
5695                do {
5696                    e = this.comment();
5697                    if (e) {
5698                        entities.push(e);
5699                        continue;
5700                    }
5701                    e = this.addition() || this.entity();
5702                    if (e) {
5703                        entities.push(e);
5704                        // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
5705                        if (!parserInput.peek(/^\/[\/*]/)) {
5706                            delim = parserInput.$char('/');
5707                            if (delim) {
5708                                entities.push(new(tree.Anonymous)(delim, index));
5709                            }
5710                        }
5711                    }
5712                } while (e);
5713                if (entities.length > 0) {
5714                    return new(tree.Expression)(entities);
5715                }
5716            },
5717            property: function () {
5718                var name = parserInput.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);
5719                if (name) {
5720                    return name[1];
5721                }
5722            },
5723            ruleProperty: function () {
5724                var name = [], index = [], s, k;
5725
5726                parserInput.save();
5727
5728                var simpleProperty = parserInput.$re(/^([_a-zA-Z0-9-]+)\s*:/);
5729                if (simpleProperty) {
5730                    name = [new(tree.Keyword)(simpleProperty[1])];
5731                    parserInput.forget();
5732                    return name;
5733                }
5734
5735                function match(re) {
5736                    var i = parserInput.i,
5737                        chunk = parserInput.$re(re);
5738                    if (chunk) {
5739                        index.push(i);
5740                        return name.push(chunk[1]);
5741                    }
5742                }
5743
5744                match(/^(\*?)/);
5745                while (true) {
5746                    if (!match(/^((?:[\w-]+)|(?:[@\$]\{[\w-]+\}))/)) {
5747                        break;
5748                    }
5749                }
5750
5751                if ((name.length > 1) && match(/^((?:\+_|\+)?)\s*:/)) {
5752                    parserInput.forget();
5753
5754                    // at last, we have the complete match now. move forward,
5755                    // convert name particles to tree objects and return:
5756                    if (name[0] === '') {
5757                        name.shift();
5758                        index.shift();
5759                    }
5760                    for (k = 0; k < name.length; k++) {
5761                        s = name[k];
5762                        name[k] = (s.charAt(0) !== '@' && s.charAt(0) !== '$') ?
5763                            new(tree.Keyword)(s) :
5764                            (s.charAt(0) === '@' ?
5765                                new(tree.Variable)('@' + s.slice(2, -1), index[k], fileInfo) :
5766                                new(tree.Property)('$' + s.slice(2, -1), index[k], fileInfo));
5767                    }
5768                    return name;
5769                }
5770                parserInput.restore();
5771            }
5772        }
5773    };
5774};
5775Parser.serializeVars = function(vars) {
5776    var s = '';
5777
5778    for (var name in vars) {
5779        if (Object.hasOwnProperty.call(vars, name)) {
5780            var value = vars[name];
5781            s += ((name[0] === '@') ? '' : '@') + name + ': ' + value +
5782                ((String(value).slice(-1) === ';') ? '' : ';');
5783        }
5784    }
5785
5786    return s;
5787};
5788
5789module.exports = Parser;
5790
5791},{"../functions/function-registry":26,"../less-error":36,"../tree":65,"../utils":86,"../visitors":90,"./parser-input":41}],43:[function(require,module,exports){
5792/**
5793 * Plugin Manager
5794 */
5795var PluginManager = function(less) {
5796    this.less = less;
5797    this.visitors = [];
5798    this.preProcessors = [];
5799    this.postProcessors = [];
5800    this.installedPlugins = [];
5801    this.fileManagers = [];
5802    this.iterator = -1;
5803    this.pluginCache = {};
5804    this.Loader = new less.PluginLoader(less);
5805};
5806
5807var pm, PluginManagerFactory = function(less, newFactory) {
5808        if (newFactory || !pm) {
5809            pm = new PluginManager(less);
5810        }
5811        return pm;
5812    };
5813
5814/**
5815 * Adds all the plugins in the array
5816 * @param {Array} plugins
5817 */
5818PluginManager.prototype.addPlugins = function(plugins) {
5819    if (plugins) {
5820        for (var i = 0; i < plugins.length; i++) {
5821            this.addPlugin(plugins[i]);
5822        }
5823    }
5824};
5825/**
5826 *
5827 * @param plugin
5828 * @param {String} filename
5829 */
5830PluginManager.prototype.addPlugin = function(plugin, filename, functionRegistry) {
5831    this.installedPlugins.push(plugin);
5832    if (filename) {
5833        this.pluginCache[filename] = plugin;
5834    }
5835    if (plugin.install) {
5836        plugin.install(this.less, this, functionRegistry || this.less.functions.functionRegistry);
5837    }
5838};
5839/**
5840 *
5841 * @param filename
5842 */
5843PluginManager.prototype.get = function(filename) {
5844    return this.pluginCache[filename];
5845};
5846
5847/**
5848 * Adds a visitor. The visitor object has options on itself to determine
5849 * when it should run.
5850 * @param visitor
5851 */
5852PluginManager.prototype.addVisitor = function(visitor) {
5853    this.visitors.push(visitor);
5854};
5855/**
5856 * Adds a pre processor object
5857 * @param {object} preProcessor
5858 * @param {number} priority - guidelines 1 = before import, 1000 = import, 2000 = after import
5859 */
5860PluginManager.prototype.addPreProcessor = function(preProcessor, priority) {
5861    var indexToInsertAt;
5862    for (indexToInsertAt = 0; indexToInsertAt < this.preProcessors.length; indexToInsertAt++) {
5863        if (this.preProcessors[indexToInsertAt].priority >= priority) {
5864            break;
5865        }
5866    }
5867    this.preProcessors.splice(indexToInsertAt, 0, {preProcessor: preProcessor, priority: priority});
5868};
5869/**
5870 * Adds a post processor object
5871 * @param {object} postProcessor
5872 * @param {number} priority - guidelines 1 = before compression, 1000 = compression, 2000 = after compression
5873 */
5874PluginManager.prototype.addPostProcessor = function(postProcessor, priority) {
5875    var indexToInsertAt;
5876    for (indexToInsertAt = 0; indexToInsertAt < this.postProcessors.length; indexToInsertAt++) {
5877        if (this.postProcessors[indexToInsertAt].priority >= priority) {
5878            break;
5879        }
5880    }
5881    this.postProcessors.splice(indexToInsertAt, 0, {postProcessor: postProcessor, priority: priority});
5882};
5883/**
5884 *
5885 * @param manager
5886 */
5887PluginManager.prototype.addFileManager = function(manager) {
5888    this.fileManagers.push(manager);
5889};
5890/**
5891 *
5892 * @returns {Array}
5893 * @private
5894 */
5895PluginManager.prototype.getPreProcessors = function() {
5896    var preProcessors = [];
5897    for (var i = 0; i < this.preProcessors.length; i++) {
5898        preProcessors.push(this.preProcessors[i].preProcessor);
5899    }
5900    return preProcessors;
5901};
5902/**
5903 *
5904 * @returns {Array}
5905 * @private
5906 */
5907PluginManager.prototype.getPostProcessors = function() {
5908    var postProcessors = [];
5909    for (var i = 0; i < this.postProcessors.length; i++) {
5910        postProcessors.push(this.postProcessors[i].postProcessor);
5911    }
5912    return postProcessors;
5913};
5914/**
5915 *
5916 * @returns {Array}
5917 * @private
5918 */
5919PluginManager.prototype.getVisitors = function() {
5920    return this.visitors;
5921};
5922
5923PluginManager.prototype.visitor = function() {
5924    var self = this;
5925    return {
5926        first: function() {
5927            self.iterator = -1;
5928            return self.visitors[self.iterator];
5929        },
5930        get: function() {
5931            self.iterator += 1;
5932            return self.visitors[self.iterator];
5933        }
5934    };
5935};
5936/**
5937 *
5938 * @returns {Array}
5939 * @private
5940 */
5941PluginManager.prototype.getFileManagers = function() {
5942    return this.fileManagers;
5943};
5944
5945//
5946module.exports = PluginManagerFactory;
5947
5948},{}],44:[function(require,module,exports){
5949var PromiseConstructor,
5950    utils = require('./utils');
5951
5952module.exports = function(environment, ParseTree, ImportManager) {
5953    var render = function (input, options, callback) {
5954        if (typeof options === 'function') {
5955            callback = options;
5956            options = utils.defaults(this.options, {});
5957        }
5958        else {
5959            options = utils.defaults(this.options, options || {});
5960        }
5961
5962        if (!callback) {
5963            if (!PromiseConstructor) {
5964                PromiseConstructor = typeof Promise === 'undefined' ? require('promise') : Promise;
5965            }
5966            var self = this;
5967            return new PromiseConstructor(function (resolve, reject) {
5968                render.call(self, input, options, function(err, output) {
5969                    if (err) {
5970                        reject(err);
5971                    } else {
5972                        resolve(output);
5973                    }
5974                });
5975            });
5976        } else {
5977            this.parse(input, options, function(err, root, imports, options) {
5978                if (err) { return callback(err); }
5979
5980                var result;
5981                try {
5982                    var parseTree = new ParseTree(root, imports);
5983                    result = parseTree.toCSS(options);
5984                }
5985                catch (err) { return callback(err); }
5986
5987                callback(null, result);
5988            });
5989        }
5990    };
5991
5992    return render;
5993};
5994
5995},{"./utils":86,"promise":undefined}],45:[function(require,module,exports){
5996module.exports = function (SourceMapOutput, environment) {
5997
5998    var SourceMapBuilder = function (options) {
5999        this.options = options;
6000    };
6001
6002    SourceMapBuilder.prototype.toCSS = function(rootNode, options, imports) {
6003        var sourceMapOutput = new SourceMapOutput(
6004            {
6005                contentsIgnoredCharsMap: imports.contentsIgnoredChars,
6006                rootNode: rootNode,
6007                contentsMap: imports.contents,
6008                sourceMapFilename: this.options.sourceMapFilename,
6009                sourceMapURL: this.options.sourceMapURL,
6010                outputFilename: this.options.sourceMapOutputFilename,
6011                sourceMapBasepath: this.options.sourceMapBasepath,
6012                sourceMapRootpath: this.options.sourceMapRootpath,
6013                outputSourceFiles: this.options.outputSourceFiles,
6014                sourceMapGenerator: this.options.sourceMapGenerator,
6015                sourceMapFileInline: this.options.sourceMapFileInline
6016            });
6017
6018        var css = sourceMapOutput.toCSS(options);
6019        this.sourceMap = sourceMapOutput.sourceMap;
6020        this.sourceMapURL = sourceMapOutput.sourceMapURL;
6021        if (this.options.sourceMapInputFilename) {
6022            this.sourceMapInputFilename = sourceMapOutput.normalizeFilename(this.options.sourceMapInputFilename);
6023        }
6024        if (this.options.sourceMapBasepath !== undefined && this.sourceMapURL !== undefined) {
6025            this.sourceMapURL = sourceMapOutput.removeBasepath(this.sourceMapURL);
6026        }
6027        return css + this.getCSSAppendage();
6028    };
6029
6030    SourceMapBuilder.prototype.getCSSAppendage = function() {
6031
6032        var sourceMapURL = this.sourceMapURL;
6033        if (this.options.sourceMapFileInline) {
6034            if (this.sourceMap === undefined) {
6035                return '';
6036            }
6037            sourceMapURL = 'data:application/json;base64,' + environment.encodeBase64(this.sourceMap);
6038        }
6039
6040        if (sourceMapURL) {
6041            return '/*# sourceMappingURL=' + sourceMapURL + ' */';
6042        }
6043        return '';
6044    };
6045
6046    SourceMapBuilder.prototype.getExternalSourceMap = function() {
6047        return this.sourceMap;
6048    };
6049    SourceMapBuilder.prototype.setExternalSourceMap = function(sourceMap) {
6050        this.sourceMap = sourceMap;
6051    };
6052
6053    SourceMapBuilder.prototype.isInline = function() {
6054        return this.options.sourceMapFileInline;
6055    };
6056    SourceMapBuilder.prototype.getSourceMapURL = function() {
6057        return this.sourceMapURL;
6058    };
6059    SourceMapBuilder.prototype.getOutputFilename = function() {
6060        return this.options.sourceMapOutputFilename;
6061    };
6062    SourceMapBuilder.prototype.getInputFilename = function() {
6063        return this.sourceMapInputFilename;
6064    };
6065
6066    return SourceMapBuilder;
6067};
6068
6069},{}],46:[function(require,module,exports){
6070module.exports = function (environment) {
6071
6072    var SourceMapOutput = function (options) {
6073        this._css = [];
6074        this._rootNode = options.rootNode;
6075        this._contentsMap = options.contentsMap;
6076        this._contentsIgnoredCharsMap = options.contentsIgnoredCharsMap;
6077        if (options.sourceMapFilename) {
6078            this._sourceMapFilename = options.sourceMapFilename.replace(/\\/g, '/');
6079        }
6080        this._outputFilename = options.outputFilename;
6081        this.sourceMapURL = options.sourceMapURL;
6082        if (options.sourceMapBasepath) {
6083            this._sourceMapBasepath = options.sourceMapBasepath.replace(/\\/g, '/');
6084        }
6085        if (options.sourceMapRootpath) {
6086            this._sourceMapRootpath = options.sourceMapRootpath.replace(/\\/g, '/');
6087            if (this._sourceMapRootpath.charAt(this._sourceMapRootpath.length - 1) !== '/') {
6088                this._sourceMapRootpath += '/';
6089            }
6090        } else {
6091            this._sourceMapRootpath = '';
6092        }
6093        this._outputSourceFiles = options.outputSourceFiles;
6094        this._sourceMapGeneratorConstructor = environment.getSourceMapGenerator();
6095
6096        this._lineNumber = 0;
6097        this._column = 0;
6098    };
6099
6100    SourceMapOutput.prototype.removeBasepath = function(path) {
6101        if (this._sourceMapBasepath && path.indexOf(this._sourceMapBasepath) === 0) {
6102            path = path.substring(this._sourceMapBasepath.length);
6103            if (path.charAt(0) === '\\' || path.charAt(0) === '/') {
6104                path = path.substring(1);
6105            }
6106        }
6107
6108        return path;
6109    };
6110
6111    SourceMapOutput.prototype.normalizeFilename = function(filename) {
6112        filename = filename.replace(/\\/g, '/');
6113        filename = this.removeBasepath(filename);
6114        return (this._sourceMapRootpath || '') + filename;
6115    };
6116
6117    SourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
6118
6119        // ignore adding empty strings
6120        if (!chunk) {
6121            return;
6122        }
6123
6124        var lines,
6125            sourceLines,
6126            columns,
6127            sourceColumns,
6128            i;
6129
6130        if (fileInfo) {
6131            var inputSource = this._contentsMap[fileInfo.filename];
6132
6133            // remove vars/banner added to the top of the file
6134            if (this._contentsIgnoredCharsMap[fileInfo.filename]) {
6135                // adjust the index
6136                index -= this._contentsIgnoredCharsMap[fileInfo.filename];
6137                if (index < 0) { index = 0; }
6138                // adjust the source
6139                inputSource = inputSource.slice(this._contentsIgnoredCharsMap[fileInfo.filename]);
6140            }
6141            inputSource = inputSource.substring(0, index);
6142            sourceLines = inputSource.split('\n');
6143            sourceColumns = sourceLines[sourceLines.length - 1];
6144        }
6145
6146        lines = chunk.split('\n');
6147        columns = lines[lines.length - 1];
6148
6149        if (fileInfo) {
6150            if (!mapLines) {
6151                this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
6152                    original: { line: sourceLines.length, column: sourceColumns.length},
6153                    source: this.normalizeFilename(fileInfo.filename)});
6154            } else {
6155                for (i = 0; i < lines.length; i++) {
6156                    this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
6157                        original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
6158                        source: this.normalizeFilename(fileInfo.filename)});
6159                }
6160            }
6161        }
6162
6163        if (lines.length === 1) {
6164            this._column += columns.length;
6165        } else {
6166            this._lineNumber += lines.length - 1;
6167            this._column = columns.length;
6168        }
6169
6170        this._css.push(chunk);
6171    };
6172
6173    SourceMapOutput.prototype.isEmpty = function() {
6174        return this._css.length === 0;
6175    };
6176
6177    SourceMapOutput.prototype.toCSS = function(context) {
6178        this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
6179
6180        if (this._outputSourceFiles) {
6181            for (var filename in this._contentsMap) {
6182                if (this._contentsMap.hasOwnProperty(filename)) {
6183                    var source = this._contentsMap[filename];
6184                    if (this._contentsIgnoredCharsMap[filename]) {
6185                        source = source.slice(this._contentsIgnoredCharsMap[filename]);
6186                    }
6187                    this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), source);
6188                }
6189            }
6190        }
6191
6192        this._rootNode.genCSS(context, this);
6193
6194        if (this._css.length > 0) {
6195            var sourceMapURL,
6196                sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());
6197
6198            if (this.sourceMapURL) {
6199                sourceMapURL = this.sourceMapURL;
6200            } else if (this._sourceMapFilename) {
6201                sourceMapURL = this._sourceMapFilename;
6202            }
6203            this.sourceMapURL = sourceMapURL;
6204
6205            this.sourceMap = sourceMapContent;
6206        }
6207
6208        return this._css.join('');
6209    };
6210
6211    return SourceMapOutput;
6212};
6213
6214},{}],47:[function(require,module,exports){
6215var contexts = require('./contexts'),
6216    visitor = require('./visitors'),
6217    tree = require('./tree');
6218
6219module.exports = function(root, options) {
6220    options = options || {};
6221    var evaldRoot,
6222        variables = options.variables,
6223        evalEnv = new contexts.Eval(options);
6224
6225    //
6226    // Allows setting variables with a hash, so:
6227    //
6228    //   `{ color: new tree.Color('#f01') }` will become:
6229    //
6230    //   new tree.Declaration('@color',
6231    //     new tree.Value([
6232    //       new tree.Expression([
6233    //         new tree.Color('#f01')
6234    //       ])
6235    //     ])
6236    //   )
6237    //
6238    if (typeof variables === 'object' && !Array.isArray(variables)) {
6239        variables = Object.keys(variables).map(function (k) {
6240            var value = variables[k];
6241
6242            if (!(value instanceof tree.Value)) {
6243                if (!(value instanceof tree.Expression)) {
6244                    value = new tree.Expression([value]);
6245                }
6246                value = new tree.Value([value]);
6247            }
6248            return new tree.Declaration('@' + k, value, false, null, 0);
6249        });
6250        evalEnv.frames = [new tree.Ruleset(null, variables)];
6251    }
6252
6253    var visitors = [
6254            new visitor.JoinSelectorVisitor(),
6255            new visitor.MarkVisibleSelectorsVisitor(true),
6256            new visitor.ExtendVisitor(),
6257            new visitor.ToCSSVisitor({compress: Boolean(options.compress)})
6258        ], v, visitorIterator;
6259
6260    // first() / get() allows visitors to be added while visiting
6261    if (options.pluginManager) {
6262        visitorIterator = options.pluginManager.visitor();
6263        visitorIterator.first();
6264        while ((v = visitorIterator.get())) {
6265            if (v.isPreEvalVisitor) {
6266                v.run(root);
6267            }
6268        }
6269    }
6270
6271    evaldRoot = root.eval(evalEnv);
6272
6273    for (var i = 0; i < visitors.length; i++) {
6274        visitors[i].run(evaldRoot);
6275    }
6276
6277    if (options.pluginManager) {
6278        visitorIterator.first();
6279        while ((v = visitorIterator.get())) {
6280            if (!v.isPreEvalVisitor) {
6281                v.run(evaldRoot);
6282            }
6283        }
6284    }
6285
6286    return evaldRoot;
6287};
6288
6289},{"./contexts":12,"./tree":65,"./visitors":90}],48:[function(require,module,exports){
6290var Node = require('./node');
6291
6292var Anonymous = function (value, index, currentFileInfo, mapLines, rulesetLike, visibilityInfo) {
6293    this.value = value;
6294    this._index = index;
6295    this._fileInfo = currentFileInfo;
6296    this.mapLines = mapLines;
6297    this.rulesetLike = (typeof rulesetLike === 'undefined') ? false : ruleset
6297Like;
6298    this.allowRoot = true;
6299    this.copyVisibilityInfo(visibilityInfo);
6300};
6301Anonymous.prototype = new Node();
6302Anonymous.prototype.type = 'Anonymous';
6303Anonymous.prototype.eval = function () {
6304    return new Anonymous(this.value, this._index, this._fileInfo, this.mapLines, this.rulesetLike, this.visibilityInfo());
6305};
6306Anonymous.prototype.compare = function (other) {
6307    return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;
6308};
6309Anonymous.prototype.isRulesetLike = function() {
6310    return this.rulesetLike;
6311};
6312Anonymous.prototype.genCSS = function (context, output) {
6313    this.nodeVisible = Boolean(this.value);
6314    if (this.nodeVisible) {
6315        output.add(this.value, this._fileInfo, this._index, this.mapLines);
6316    }
6317};
6318module.exports = Anonymous;
6319
6320},{"./node":73}],49:[function(require,module,exports){
6321var Node = require('./node');
6322
6323var Assignment = function (key, val) {
6324    this.key = key;
6325    this.value = val;
6326};
6327
6328Assignment.prototype = new Node();
6329Assignment.prototype.type = 'Assignment';
6330Assignment.prototype.accept = function (visitor) {
6331    this.value = visitor.visit(this.value);
6332};
6333Assignment.prototype.eval = function (context) {
6334    if (this.value.eval) {
6335        return new Assignment(this.key, this.value.eval(context));
6336    }
6337    return this;
6338};
6339Assignment.prototype.genCSS = function (context, output) {
6340    output.add(this.key + '=');
6341    if (this.value.genCSS) {
6342        this.value.genCSS(context, output);
6343    } else {
6344        output.add(this.value);
6345    }
6346};
6347module.exports = Assignment;
6348
6349},{"./node":73}],50:[function(require,module,exports){
6350var Node = require('./node'),
6351    Selector = require('./selector'),
6352    Ruleset = require('./ruleset'),
6353    Anonymous = require('./anonymous');
6354
6355var AtRule = function (name, value, rules, index, currentFileInfo, debugInfo, isRooted, visibilityInfo) {
6356    var i;
6357
6358    this.name  = name;
6359    this.value = (value instanceof Node) ? value : (value ? new Anonymous(value) : value);
6360    if (rules) {
6361        if (Array.isArray(rules)) {
6362            this.rules = rules;
6363        } else {
6364            this.rules = [rules];
6365            this.rules[0].selectors = (new Selector([], null, null, index, currentFileInfo)).createEmptySelectors();
6366        }
6367        for (i = 0; i < this.rules.length; i++) {
6368            this.rules[i].allowImports = true;
6369        }
6370        this.setParent(this.rules, this);
6371    }
6372    this._index = index;
6373    this._fileInfo = currentFileInfo;
6374    this.debugInfo = debugInfo;
6375    this.isRooted = isRooted || false;
6376    this.copyVisibilityInfo(visibilityInfo);
6377    this.allowRoot = true;
6378};
6379
6380AtRule.prototype = new Node();
6381AtRule.prototype.type = 'AtRule';
6382AtRule.prototype.accept = function (visitor) {
6383    var value = this.value, rules = this.rules;
6384    if (rules) {
6385        this.rules = visitor.visitArray(rules);
6386    }
6387    if (value) {
6388        this.value = visitor.visit(value);
6389    }
6390};
6391AtRule.prototype.isRulesetLike = function() {
6392    return this.rules || !this.isCharset();
6393};
6394AtRule.prototype.isCharset = function() {
6395    return '@charset' === this.name;
6396};
6397AtRule.prototype.genCSS = function (context, output) {
6398    var value = this.value, rules = this.rules;
6399    output.add(this.name, this.fileInfo(), this.getIndex());
6400    if (value) {
6401        output.add(' ');
6402        value.genCSS(context, output);
6403    }
6404    if (rules) {
6405        this.outputRuleset(context, output, rules);
6406    } else {
6407        output.add(';');
6408    }
6409};
6410AtRule.prototype.eval = function (context) {
6411    var mediaPathBackup, mediaBlocksBackup, value = this.value, rules = this.rules;
6412
6413    // media stored inside other atrule should not bubble over it
6414    // backpup media bubbling information
6415    mediaPathBackup = context.mediaPath;
6416    mediaBlocksBackup = context.mediaBlocks;
6417    // deleted media bubbling information
6418    context.mediaPath = [];
6419    context.mediaBlocks = [];
6420
6421    if (value) {
6422        value = value.eval(context);
6423    }
6424    if (rules) {
6425        // assuming that there is only one rule at this point - that is how parser constructs the rule
6426        rules = [rules[0].eval(context)];
6427        rules[0].root = true;
6428    }
6429    // restore media bubbling information
6430    context.mediaPath = mediaPathBackup;
6431    context.mediaBlocks = mediaBlocksBackup;
6432
6433    return new AtRule(this.name, value, rules,
6434        this.getIndex(), this.fileInfo(), this.debugInfo, this.isRooted, this.visibilityInfo());
6435};
6436AtRule.prototype.variable = function (name) {
6437    if (this.rules) {
6438        // assuming that there is only one rule at this point - that is how parser constructs the rule
6439        return Ruleset.prototype.variable.call(this.rules[0], name);
6440    }
6441};
6442AtRule.prototype.find = function () {
6443    if (this.rules) {
6444        // assuming that there is only one rule at this point - that is how parser constructs the rule
6445        return Ruleset.prototype.find.apply(this.rules[0], arguments);
6446    }
6447};
6448AtRule.prototype.rulesets = function () {
6449    if (this.rules) {
6450        // assuming that there is only one rule at this point - that is how parser constructs the rule
6451        return Ruleset.prototype.rulesets.apply(this.rules[0]);
6452    }
6453};
6454AtRule.prototype.outputRuleset = function (context, output, rules) {
6455    var ruleCnt = rules.length, i;
6456    context.tabLevel = (context.tabLevel | 0) + 1;
6457
6458    // Compressed
6459    if (context.compress) {
6460        output.add('{');
6461        for (i = 0; i < ruleCnt; i++) {
6462            rules[i].genCSS(context, output);
6463        }
6464        output.add('}');
6465        context.tabLevel--;
6466        return;
6467    }
6468
6469    // Non-compressed
6470    var tabSetStr = '\n' + Array(context.tabLevel).join('  '), tabRuleStr = tabSetStr + '  ';
6471    if (!ruleCnt) {
6472        output.add(' {' + tabSetStr + '}');
6473    } else {
6474        output.add(' {' + tabRuleStr);
6475        rules[0].genCSS(context, output);
6476        for (i = 1; i < ruleCnt; i++) {
6477            output.add(tabRuleStr);
6478            rules[i].genCSS(context, output);
6479        }
6480        output.add(tabSetStr + '}');
6481    }
6482
6483    context.tabLevel--;
6484};
6485module.exports = AtRule;
6486
6487},{"./anonymous":48,"./node":73,"./ruleset":78,"./selector":79}],51:[function(require,module,exports){
6488var Node = require('./node');
6489
6490var Attribute = function (key, op, value) {
6491    this.key = key;
6492    this.op = op;
6493    this.value = value;
6494};
6495Attribute.prototype = new Node();
6496Attribute.prototype.type = 'Attribute';
6497Attribute.prototype.eval = function (context) {
6498    return new Attribute(this.key.eval ? this.key.eval(context) : this.key,
6499        this.op, (this.value && this.value.eval) ? this.value.eval(context) : this.value);
6500};
6501Attribute.prototype.genCSS = function (context, output) {
6502    output.add(this.toCSS(context));
6503};
6504Attribute.prototype.toCSS = function (context) {
6505    var value = this.key.toCSS ? this.key.toCSS(context) : this.key;
6506
6507    if (this.op) {
6508        value += this.op;
6509        value += (this.value.toCSS ? this.value.toCSS(context) : this.value);
6510    }
6511
6512    return '[' + value + ']';
6513};
6514module.exports = Attribute;
6515
6516},{"./node":73}],52:[function(require,module,exports){
6517var Node = require('./node'),
6518    Anonymous = require('./anonymous'),
6519    FunctionCaller = require('../functions/function-caller');
6520//
6521// A function call node.
6522//
6523var Call = function (name, args, index, currentFileInfo) {
6524    this.name = name;
6525    this.args = args;
6526    this.mathOn = name === 'calc' ? false : true;
6527    this._index = index;
6528    this._fileInfo = currentFileInfo;
6529};
6530Call.prototype = new Node();
6531Call.prototype.type = 'Call';
6532Call.prototype.accept = function (visitor) {
6533    if (this.args) {
6534        this.args = visitor.visitArray(this.args);
6535    }
6536};
6537//
6538// When evaluating a function call,
6539// we either find the function in the functionRegistry,
6540// in which case we call it, passing the  evaluated arguments,
6541// if this returns null or we cannot find the function, we
6542// simply print it out as it appeared originally [2].
6543//
6544// The reason why we evaluate the arguments, is in the case where
6545// we try to pass a variable to a function, like: `saturate(@color)`.
6546// The function should receive the value, not the variable.
6547//
6548Call.prototype.eval = function (context) {
6549
6550    /**
6551     * Turn off math for calc(), and switch back on for evaluating nested functions
6552     */
6553    var currentMathContext = context.mathOn;
6554    context.mathOn = this.mathOn;
6555    var args = this.args.map(function (a) { return a.eval(context); });
6556    context.mathOn = currentMathContext;
6557
6558    var result, funcCaller = new FunctionCaller(this.name, context, this.getIndex(), this.fileInfo());
6559    
6560    if (funcCaller.isValid()) {
6561        try {
6562            result = funcCaller.call(args);
6563        } catch (e) {
6564            throw { 
6565                type: e.type || 'Runtime',
6566                message: 'error evaluating function `' + this.name + '`' +
6567                         (e.message ? ': ' + e.message : ''),
6568                index: this.getIndex(), 
6569                filename: this.fileInfo().filename,
6570                line: e.lineNumber,
6571                column: e.columnNumber
6572            };
6573        }
6574
6575        if (result !== null && result !== undefined) {
6576            // Results that that are not nodes are cast as Anonymous nodes
6577            // Falsy values or booleans are returned as empty nodes
6578            if (!(result instanceof Node)) {
6579                if (!result || result === true) {
6580                    result = new Anonymous(null); 
6581                }
6582                else {
6583                    result = new Anonymous(result.toString()); 
6584                }
6585                
6586            }
6587            result._index = this._index;
6588            result._fileInfo = this._fileInfo;
6589            return result;
6590        }
6591
6592    }
6593
6594    return new Call(this.name, args, this.getIndex(), this.fileInfo());
6595};
6596Call.prototype.genCSS = function (context, output) {
6597    output.add(this.name + '(', this.fileInfo(), this.getIndex());
6598
6599    for (var i = 0; i < this.args.length; i++) {
6600        this.args[i].genCSS(context, output);
6601        if (i + 1 < this.args.length) {
6602            output.add(', ');
6603        }
6604    }
6605
6606    output.add(')');
6607};
6608module.exports = Call;
6609
6610},{"../functions/function-caller":25,"./anonymous":48,"./node":73}],53:[function(require,module,exports){
6611var Node = require('./node'),
6612    colors = require('../data/colors');
6613
6614//
6615// RGB Colors - #ff0014, #eee
6616//
6617var Color = function (rgb, a, originalForm) {
6618    //
6619    // The end goal here, is to parse the arguments
6620    // into an integer triplet, such as `128, 255, 0`
6621    //
6622    // This facilitates operations and conversions.
6623    //
6624    if (Array.isArray(rgb)) {
6625        this.rgb = rgb;
6626    } else if (rgb.length == 6) {
6627        this.rgb = rgb.match(/.{2}/g).map(function (c) {
6628            return parseInt(c, 16);
6629        });
6630    } else {
6631        this.rgb = rgb.split('').map(function (c) {
6632            return parseInt(c + c, 16);
6633        });
6634    }
6635    this.alpha = typeof a === 'number' ? a : 1;
6636    if (typeof originalForm !== 'undefined') {
6637        this.value = originalForm;
6638    }
6639};
6640
6641Color.prototype = new Node();
6642Color.prototype.type = 'Color';
6643
6644function clamp(v, max) {
6645    return Math.min(Math.max(v, 0), max);
6646}
6647
6648function toHex(v) {
6649    return '#' + v.map(function (c) {
6650        c = clamp(Math.round(c), 255);
6651        return (c < 16 ? '0' : '') + c.toString(16);
6652    }).join('');
6653}
6654
6655Color.prototype.luma = function () {
6656    var r = this.rgb[0] / 255,
6657        g = this.rgb[1] / 255,
6658        b = this.rgb[2] / 255;
6659
6660    r = (r <= 0.03928) ? r / 12.92 : Math.pow(((r + 0.055) / 1.055), 2.4);
6661    g = (g <= 0.03928) ? g / 12.92 : Math.pow(((g + 0.055) / 1.055), 2.4);
6662    b = (b <= 0.03928) ? b / 12.92 : Math.pow(((b + 0.055) / 1.055), 2.4);
6663
6664    return 0.2126 * r + 0.7152 * g + 0.0722 * b;
6665};
6666Color.prototype.genCSS = function (context, output) {
6667    output.add(this.toCSS(context));
6668};
6669Color.prototype.toCSS = function (context, doNotCompress) {
6670    var compress = context && context.compress && !doNotCompress, color, alpha;
6671
6672    // `value` is set if this color was originally
6673    // converted from a named color string so we need
6674    // to respect this and try to output named color too.
6675    if (this.value) {
6676        return this.value;
6677    }
6678
6679    // If we have some transparency, the only way to represent it
6680    // is via `rgba`. Otherwise, we use the hex representation,
6681    // which has better compatibility with older browsers.
6682    // Values are capped between `0` and `255`, rounded and zero-padded.
6683    alpha = this.fround(context, this.alpha);
6684    if (alpha < 1) {
6685        return 'rgba(' + this.rgb.map(function (c) {
6686            return clamp(Math.round(c), 255);
6687        }).concat(clamp(alpha, 1))
6688            .join(',' + (compress ? '' : ' ')) + ')';
6689    }
6690
6691    color = this.toRGB();
6692
6693    if (compress) {
6694        var splitcolor = color.split('');
6695
6696        // Convert color to short format
6697        if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
6698            color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5];
6699        }
6700    }
6701
6702    return color;
6703};
6704
6705//
6706// Operations have to be done per-channel, if not,
6707// channels will spill onto each other. Once we have
6708// our result, in the form of an integer triplet,
6709// we create a new Color node to hold the result.
6710//
6711Color.prototype.operate = function (context, op, other) {
6712    var rgb = new Array(3);
6713    var alpha = this.alpha * (1 - other.alpha) + other.alpha;
6714    for (var c = 0; c < 3; c++) {
6715        rgb[c] = this._operate(context, op, this.rgb[c], other.rgb[c]);
6716    }
6717    return new Color(rgb, alpha);
6718};
6719Color.prototype.toRGB = function () {
6720    return toHex(this.rgb);
6721};
6722Color.prototype.toHSL = function () {
6723    var r = this.rgb[0] / 255,
6724        g = this.rgb[1] / 255,
6725        b = this.rgb[2] / 255,
6726        a = this.alpha;
6727
6728    var max = Math.max(r, g, b), min = Math.min(r, g, b);
6729    var h, s, l = (max + min) / 2, d = max - min;
6730
6731    if (max === min) {
6732        h = s = 0;
6733    } else {
6734        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
6735
6736        switch (max) {
6737            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
6738            case g: h = (b - r) / d + 2;               break;
6739            case b: h = (r - g) / d + 4;               break;
6740        }
6741        h /= 6;
6742    }
6743    return { h: h * 360, s: s, l: l, a: a };
6744};
6745// Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
6746Color.prototype.toHSV = function () {
6747    var r = this.rgb[0] / 255,
6748        g = this.rgb[1] / 255,
6749        b = this.rgb[2] / 255,
6750        a = this.alpha;
6751
6752    var max = Math.max(r, g, b), min = Math.min(r, g, b);
6753    var h, s, v = max;
6754
6755    var d = max - min;
6756    if (max === 0) {
6757        s = 0;
6758    } else {
6759        s = d / max;
6760    }
6761
6762    if (max === min) {
6763        h = 0;
6764    } else {
6765        switch (max) {
6766            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
6767            case g: h = (b - r) / d + 2; break;
6768            case b: h = (r - g) / d + 4; break;
6769        }
6770        h /= 6;
6771    }
6772    return { h: h * 360, s: s, v: v, a: a };
6773};
6774Color.prototype.toARGB = function () {
6775    return toHex([this.alpha * 255].concat(this.rgb));
6776};
6777Color.prototype.compare = function (x) {
6778    return (x.rgb &&
6779        x.rgb[0] === this.rgb[0] &&
6780        x.rgb[1] === this.rgb[1] &&
6781        x.rgb[2] === this.rgb[2] &&
6782        x.alpha  === this.alpha) ? 0 : undefined;
6783};
6784
6785Color.fromKeyword = function(keyword) {
6786    var c, key = keyword.toLowerCase();
6787    if (colors.hasOwnProperty(key)) {
6788        c = new Color(colors[key].slice(1));
6789    }
6790    else if (key === 'transparent') {
6791        c = new Color([0, 0, 0], 0);
6792    }
6793
6794    if (c) {
6795        c.value = keyword;
6796        return c;
6797    }
6798};
6799module.exports = Color;
6800
6801},{"../data/colors":13,"./node":73}],54:[function(require,module,exports){
6802var Node = require('./node');
6803
6804var Combinator = function (value) {
6805    if (value === ' ') {
6806        this.value = ' ';
6807        this.emptyOrWhitespace = true;
6808    } else {
6809        this.value = value ? value.trim() : '';
6810        this.emptyOrWhitespace = this.value === '';
6811    }
6812};
6813Combinator.prototype = new Node();
6814Combinator.prototype.type = 'Combinator';
6815var _noSpaceCombinators = {
6816    '': true,
6817    ' ': true,
6818    '|': true
6819};
6820Combinator.prototype.genCSS = function (context, output) {
6821    var spaceOrEmpty = (context.compress || _noSpaceCombinators[this.value]) ? '' : ' ';
6822    output.add(spaceOrEmpty + this.value + spaceOrEmpty);
6823};
6824module.exports = Combinator;
6825
6826},{"./node":73}],55:[function(require,module,exports){
6827var Node = require('./node'),
6828    getDebugInfo = require('./debug-info');
6829
6830var Comment = function (value, isLineComment, index, currentFileInfo) {
6831    this.value = value;
6832    this.isLineComment = isLineComment;
6833    this._index = index;
6834    this._fileInfo = currentFileInfo;
6835    this.allowRoot = true;
6836};
6837Comment.prototype = new Node();
6838Comment.prototype.type = 'Comment';
6839Comment.prototype.genCSS = function (context, output) {
6840    if (this.debugInfo) {
6841        output.add(getDebugInfo(context, this), this.fileInfo(), this.getIndex());
6842    }
6843    output.add(this.value);
6844};
6845Comment.prototype.isSilent = function(context) {
6846    var isCompressed = context.compress && this.value[2] !== '!';
6847    return this.isLineComment || isCompressed;
6848};
6849module.exports = Comment;
6850
6851},{"./debug-info":57,"./node":73}],56:[function(require,module,exports){
6852var Node = require('./node');
6853
6854var Condition = function (op, l, r, i, negate) {
6855    this.op = op.trim();
6856    this.lvalue = l;
6857    this.rvalue = r;
6858    this._index = i;
6859    this.negate = negate;
6860};
6861Condition.prototype = new Node();
6862Condition.prototype.type = 'Condition';
6863Condition.prototype.accept = function (visitor) {
6864    this.lvalue = visitor.visit(this.lvalue);
6865    this.rvalue = visitor.visit(this.rvalue);
6866};
6867Condition.prototype.eval = function (context) {
6868    var result = (function (op, a, b) {
6869        switch (op) {
6870            case 'and': return a && b;
6871            case 'or':  return a || b;
6872            default:
6873                switch (Node.compare(a, b)) {
6874                    case -1:
6875                        return op === '<' || op === '=<' || op === '<=';
6876                    case 0:
6877                        return op === '=' || op === '>=' || op === '=<' || op === '<=';
6878                    case 1:
6879                        return op === '>' || op === '>=';
6880                    default:
6881                        return false;
6882                }
6883        }
6884    })(this.op, this.lvalue.eval(context), this.rvalue.eval(context));
6885
6886    return this.negate ? !result : result;
6887};
6888module.exports = Condition;
6889
6890},{"./node":73}],57:[function(require,module,exports){
6891var debugInfo = function(context, ctx, lineSeparator) {
6892    var result = '';
6893    if (context.dumpLineNumbers && !context.compress) {
6894        switch (context.dumpLineNumbers) {
6895            case 'comments':
6896                result = debugInfo.asComment(ctx);
6897                break;
6898            case 'mediaquery':
6899                result = debugInfo.asMediaQuery(ctx);
6900                break;
6901            case 'all':
6902                result = debugInfo.asComment(ctx) + (lineSeparator || '') + debugInfo.asMediaQuery(ctx);
6903                break;
6904        }
6905    }
6906    return result;
6907};
6908
6909debugInfo.asComment = function(ctx) {
6910    return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
6911};
6912
6913debugInfo.asMediaQuery = function(ctx) {
6914    var filenameWithProtocol = ctx.debugInfo.fileName;
6915    if (!/^[a-z]+:\/\//i.test(filenameWithProtocol)) {
6916        filenameWithProtocol = 'file://' + filenameWithProtocol;
6917    }
6918    return '@media -sass-debug-info{filename{font-family:' +
6919        filenameWithProtocol.replace(/([.:\/\\])/g, function (a) {
6920            if (a == '\\') {
6921                a = '\/';
6922            }
6923            return '\\' + a;
6924        }) +
6925        '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
6926};
6927
6928module.exports = debugInfo;
6929
6930},{}],58:[function(require,module,exports){
6931var Node = require('./node'),
6932    Value = require('./value'),
6933    Keyword = require('./keyword'),
6934    Anonymous = require('./anonymous');
6935
6936var Declaration = function (name, value, important, merge, index, currentFileInfo, inline, variable) {
6937    this.name = name;
6938    this.value = (value instanceof Node) ? value : new Value([value ? new Anonymous(value) : null]);
6939    this.important = important ? ' ' + important.trim() : '';
6940    this.merge = merge;
6941    this._index = index;
6942    this._fileInfo = currentFileInfo;
6943    this.inline = inline || false;
6944    this.variable = (variable !== undefined) ? variable
6945        : (name.charAt && (name.charAt(0) === '@'));
6946    this.allowRoot = true;
6947    this.setParent(this.value, this);
6948};
6949
6950function evalName(context, name) {
6951    var value = '', i, n = name.length,
6952        output = {add: function (s) {value += s;}};
6953    for (i = 0; i < n; i++) {
6954        name[i].eval(context).genCSS(context, output);
6955    }
6956    return value;
6957}
6958
6959Declaration.prototype = new Node();
6960Declaration.prototype.type = 'Declaration';
6961Declaration.prototype.genCSS = function (context, output) {
6962    output.add(this.name + (context.compress ? ':' : ': '), this.fileInfo(), this.getIndex());
6963    try {
6964        this.value.genCSS(context, output);
6965    }
6966    catch (e) {
6967        e.index = this._index;
6968        e.filename = this._fileInfo.filename;
6969        throw e;
6970    }
6971    output.add(this.important + ((this.inline || (context.lastRule && context.compress)) ? '' : ';'), this._fileInfo, this._index);
6972};
6973Declaration.prototype.eval = function (context) {
6974    var strictMathBypass = false, name = this.name, evaldValue, variable = this.variable;
6975    if (typeof name !== 'string') {
6976        // expand 'primitive' name directly to get
6977        // things faster (~10% for benchmark.less):
6978        name = (name.length === 1) && (name[0] instanceof Keyword) ?
6979                name[0].value : evalName(context, name);
6980        variable = false; // never treat expanded interpolation as new variable name
6981    }
6982    if (name === 'font' && !context.strictMath) {
6983        strictMathBypass = true;
6984        context.strictMath = true;
6985    }
6986    try {
6987        context.importantScope.push({});
6988        evaldValue = this.value.eval(context);
6989
6990        if (!this.variable && evaldValue.type === 'DetachedRuleset') {
6991            throw { message: 'Rulesets cannot be evaluated on a property.',
6992                index: this.getIndex(), filename: this.fileInfo().filename };
6993        }
6994        var important = this.important,
6995            importantResult = context.importantScope.pop();
6996        if (!important && importantResult.important) {
6997            important = importantResult.important;
6998        }
6999
7000        return new Declaration(name,
7001                          evaldValue,
7002                          important,
7003                          this.merge,
7004                          this.getIndex(), this.fileInfo(), this.inline,
7005                              variable);
7006    }
7007    catch (e) {
7008        if (typeof e.index !== 'number') {
7009            e.index = this.getIndex();
7010            e.filename = this.fileInfo().filename;
7011        }
7012        throw e;
7013    }
7014    finally {
7015        if (strictMathBypass) {
7016            context.strictMath = false;
7017        }
7018    }
7019};
7020Declaration.prototype.makeImportant = function () {
7021    return new Declaration(this.name,
7022                          this.value,
7023                          '!important',
7024                          this.merge,
7025                          this.getIndex(), this.fileInfo(), this.inline);
7026};
7027
7028module.exports = Declaration;
7029},{"./anonymous":48,"./keyword":68,"./node":73,"./value":83}],59:[function(require,module,exports){
7030var Node = require('./node'),
7031    contexts = require('../contexts'),
7032    utils = require('../utils');
7033
7034var DetachedRuleset = function (ruleset, frames) {
7035    this.ruleset = ruleset;
7036    this.frames = frames;
7037    this.setParent(this.ruleset, this);
7038};
7039DetachedRuleset.prototype = new Node();
7040DetachedRuleset.prototype.type = 'DetachedRuleset';
7041DetachedRuleset.prototype.evalFirst = true;
7042DetachedRuleset.prototype.accept = function (visitor) {
7043    this.ruleset = visitor.visit(this.ruleset);
7044};
7045DetachedRuleset.prototype.eval = function (context) {
7046    var frames = this.frames || utils.copyArray(context.frames);
7047    return new DetachedRuleset(this.ruleset, frames);
7048};
7049DetachedRuleset.prototype.callEval = function (context) {
7050    return this.ruleset.eval(this.frames ? new contexts.Eval(context, this.frames.concat(context.frames)) : context);
7051};
7052module.exports = DetachedRuleset;
7053
7054},{"../contexts":12,"../utils":86,"./node":73}],60:[function(require,module,exports){
7055var Node = require('./node'),
7056    unitConversions = require('../data/unit-conversions'),
7057    Unit = require('./unit'),
7058    Color = require('./color');
7059
7060//
7061// A number with a unit
7062//
7063var Dimension = function (value, unit) {
7064    this.value = parseFloat(value);
7065    if (isNaN(this.value)) {
7066        throw new Error('Dimension is not a number.');
7067    }
7068    this.unit = (unit && unit instanceof Unit) ? unit :
7069      new Unit(unit ? [unit] : undefined);
7070    this.setParent(this.unit, this);
7071};
7072
7073Dimension.prototype = new Node();
7074Dimension.prototype.type = 'Dimension';
7075Dimension.prototype.accept = function (visitor) {
7076    this.unit = visitor.visit(this.unit);
7077};
7078Dimension.prototype.eval = function (context) {
7079    return this;
7080};
7081Dimension.prototype.toColor = function () {
7082    return new Color([this.value, this.value, this.value]);
7083};
7084Dimension.prototype.genCSS = function (context, output) {
7085    if ((context && context.strictUnits) && !this.unit.isSingular()) {
7086        throw new Error('Multiple units in dimension. Correct the units or use the unit function. Bad unit: ' + this.unit.toString());
7087    }
7088
7089    var value = this.fround(context, this.value),
7090        strValue = String(value);
7091
7092    if (value !== 0 && value < 0.000001 && value > -0.000001) {
7093        // would be output 1e-6 etc.
7094        strValue = value.toFixed(20).replace(/0+$/, '');
7095    }
7096
7097    if (context && context.compress) {
7098        // Zero values doesn't need a unit
7099        if (value === 0 && this.unit.isLength()) {
7100            output.add(strValue);
7101            return;
7102        }
7103
7104        // Float values doesn't need a leading zero
7105        if (value > 0 && value < 1) {
7106            strValue = (strValue).substr(1);
7107        }
7108    }
7109
7110    output.add(strValue);
7111    this.unit.genCSS(context, output);
7112};
7113
7114// In an operation between two Dimensions,
7115// we default to the first Dimension's unit,
7116// so `1px + 2` will yield `3px`.
7117Dimension.prototype.operate = function (context, op, other) {
7118    /* jshint noempty:false */
7119    var value = this._operate(context, op, this.value, other.value),
7120        unit = this.unit.clone();
7121
7122    if (op === '+' || op === '-') {
7123        if (unit.numerator.length === 0 && unit.denominator.length === 0) {
7124            unit = other.unit.clone();
7125            if (this.unit.backupUnit) {
7126                unit.backupUnit = this.unit.backupUnit;
7127            }
7128        } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
7129            // do nothing
7130        } else {
7131            other = other.convertTo(this.unit.usedUnits());
7132
7133            if (context.strictUnits && other.unit.toString() !== unit.toString()) {
7134                throw new Error('Incompatible units. Change the units or use the unit function. Bad units: \'' + unit.toString() +
7135                    '\' and \'' + other.unit.toString() + '\'.');
7136            }
7137
7138            value = this._operate(context, op, this.value, other.value);
7139        }
7140    } else if (op === '*') {
7141        unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
7142        unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
7143        unit.cancel();
7144    } else if (op === '/') {
7145        unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
7146        unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
7147        unit.cancel();
7148    }
7149    return new Dimension(value, unit);
7150};
7151Dimension.prototype.compare = function (other) {
7152    var a, b;
7153
7154    if (!(other instanceof Dimension)) {
7155        return undefined;
7156    }
7157
7158    if (this.unit.isEmpty() || other.unit.isEmpty()) {
7159        a = this;
7160        b = other;
7161    } else {
7162        a = this.unify();
7163        b = other.unify();
7164        if (a.unit.compare(b.unit) !== 0) {
7165            return undefined;
7166        }
7167    }
7168
7169    return Node.numericCompare(a.value, b.value);
7170};
7171Dimension.prototype.unify = function () {
7172    return this.convertTo({ length: 'px', duration: 's', angle: 'rad' });
7173};
7174Dimension.prototype.convertTo = function (conversions) {
7175    var value = this.value, unit = this.unit.clone(),
7176        i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
7177
7178    if (typeof conversions === 'string') {
7179        for (i in unitConversions) {
7180            if (unitConversions[i].hasOwnProperty(conversions)) {
7181                derivedConversions = {};
7182                derivedConversions[i] = conversions;
7183            }
7184        }
7185        conversions = derivedConversions;
7186    }
7187    applyUnit = function (atomicUnit, denominator) {
7188        /* jshint loopfunc:true */
7189        if (group.hasOwnProperty(atomicUnit)) {
7190            if (denominator) {
7191                value = value / (group[atomicUnit] / group[targetUnit]);
7192            } else {
7193                value = value * (group[atomicUnit] / group[targetUnit]);
7194            }
7195
7196            return targetUnit;
7197        }
7198
7199        return atomicUnit;
7200    };
7201
7202    for (groupName in conversions) {
7203        if (conversions.hasOwnProperty(groupName)) {
7204            targetUnit = conversions[groupName];
7205            group = unitConversions[groupName];
7206
7207            unit.map(applyUnit);
7208        }
7209    }
7210
7211    unit.cancel();
7212
7213    return new Dimension(value, unit);
7214};
7215module.exports = Dimension;
7216
7217},{"../data/unit-conversions":15,"./color":53,"./node":73,"./unit":81}],61:[function(require,module,exports){
7218var Node = require('./node'),
7219    Paren = require('./paren'),
7220    Combinator = require('./combinator');
7221
7222var Element = function (combinator, value, index, currentFileInfo, visibilityInfo) {
7223    this.combinator = combinator instanceof Combinator ?
7224                      combinator : new Combinator(combinator);
7225
7226    if (typeof value === 'string') {
7227        this.value = value.trim();
7228    } else if (value) {
7229        this.value = value;
7230    } else {
7231        this.value = '';
7232    }
7233    this._index = index;
7234    this._fileInfo = currentFileInfo;
7235    this.copyVisibilityInfo(visibilityInfo);
7236    this.setParent(this.combinator, this);
7237};
7238Element.prototype = new Node();
7239Element.prototype.type = 'Element';
7240Element.prototype.accept = function (visitor) {
7241    var value = this.value;
7242    this.combinator = visitor.visit(this.combinator);
7243    if (typeof value === 'object') {
7244        this.value = visitor.visit(value);
7245    }
7246};
7247Element.prototype.eval = function (context) {
7248    return new Element(this.combinator,
7249                             this.value.eval ? this.value.eval(context) : this.value,
7250                             this.getIndex(),
7251                             this.fileInfo(), this.visibilityInfo());
7252};
7253Element.prototype.clone = function () {
7254    return new Element(this.combinator,
7255        this.value,
7256        this.getIndex(),
7257        this.fileInfo(), this.visibilityInfo());
7258};
7259Element.prototype.genCSS = function (context, output) {
7260    output.add(this.toCSS(context), this.fileInfo(), this.getIndex());
7261};
7262Element.prototype.toCSS = function (context) {
7263    context = context || {};
7264    var value = this.value, firstSelector = context.firstSelector;
7265    if (value instanceof Paren) {
7266        // selector in parens should not be affected by outer selector
7267        // flags (breaks only interpolated selectors - see #1973)
7268        context.firstSelector = true;
7269    }
7270    value = value.toCSS ? value.toCSS(context) : value;
7271    context.firstSelector = firstSelector;
7272    if (value === '' && this.combinator.value.charAt(0) === '&') {
7273        return '';
7274    } else {
7275        return this.combinator.toCSS(context) + value;
7276    }
7277};
7278module.exports = Element;
7279
7280},{"./combinator":54,"./node":73,"./paren":75}],62:[function(require,module,exports){
7281var Node = require('./node'),
7282    Paren = require('./paren'),
7283    Comment = require('./comment');
7284
7285var Expression = function (value, noSpacing) {
7286    this.value = value;
7287    this.noSpacing = noSpacing;
7288    if (!value) {
7289        throw new Error('Expression requires an array parameter');
7290    }
7291};
7292Expression.prototype = new Node();
7293Expression.prototype.type = 'Expression';
7294Expression.prototype.accept = function (visitor) {
7295    this.value = visitor.visitArray(this.value);
7296};
7297Expression.prototype.eval = function (context) {
7298    var returnValue,
7299        inParenthesis = this.parens && !this.parensInOp,
7300        doubleParen = false;
7301    if (inParenthesis) {
7302        context.inParenthesis();
7303    }
7304    if (this.value.length > 1) {
7305        returnValue = new Expression(this.value.map(function (e) {
7306            return e.eval(context);
7307        }), this.noSpacing);
7308    } else if (this.value.length === 1) {
7309        if (this.value[0].parens && !this.value[0].parensInOp) {
7310            doubleParen = true;
7311        }
7312        returnValue = this.value[0].eval(context);
7313    } else {
7314        returnValue = this;
7315    }
7316    if (inParenthesis) {
7317        context.outOfParenthesis();
7318    }
7319    if (this.parens && this.parensInOp && !(context.isMathOn()) && !doubleParen) {
7320        returnValue = new Paren(returnValue);
7321    }
7322    return returnValue;
7323};
7324Expression.prototype.genCSS = function (context, output) {
7325    for (var i = 0; i < this.value.length; i++) {
7326        this.value[i].genCSS(context, output);
7327        if (!this.noSpacing && i + 1 < this.value.length) {
7328            output.add(' ');
7329        }
7330    }
7331};
7332Expression.prototype.throwAwayComments = function () {
7333    this.value = this.value.filter(function(v) {
7334        return !(v instanceof Comment);
7335    });
7336};
7337module.exports = Expression;
7338
7339},{"./comment":55,"./node":73,"./paren":75}],63:[function(require,module,exports){
7340var Node = require('./node'),
7341    Selector = require('./selector');
7342
7343var Extend = function Extend(selector, option, index, currentFileInfo, visibilityInfo) {
7344    this.selector = selector;
7345    this.option = option;
7346    this.object_id = Extend.next_id++;
7347    this.parent_ids = [this.object_id];
7348    this._index = index;
7349    this._fileInfo = currentFileInfo;
7350    this.copyVisibilityInfo(visibilityInfo);
7351    this.allowRoot = true;
7352
7353    switch (option) {
7354        case 'all':
7355            this.allowBefore = true;
7356            this.allowAfter = true;
7357            break;
7358        default:
7359            this.allowBefore = false;
7360            this.allowAfter = false;
7361            break;
7362    }
7363    this.setParent(this.selector, this);
7364};
7365Extend.next_id = 0;
7366
7367Extend.prototype = new Node();
7368Extend.prototype.type = 'Extend';
7369Extend.prototype.accept = function (visitor) {
7370    this.selector = visitor.visit(this.selector);
7371};
7372Extend.prototype.eval = function (context) {
7373    return new Extend(this.selector.eval(context), this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo());
7374};
7375Extend.prototype.clone = function (context) {
7376    return new Extend(this.selector, this.option, this.getIndex(), this.fileInfo(), this.visibilityInfo());
7377};
7378// it concatenates (joins) all selectors in selector array
7379Extend.prototype.findSelfSelectors = function (selectors) {
7380    var selfElements = [],
7381        i,
7382        selectorElements;
7383
7384    for (i = 0; i < selectors.length; i++) {
7385        selectorElements = selectors[i].elements;
7386        // duplicate the logic in genCSS function inside the selector node.
7387        // future TODO - move both logics into the selector joiner visitor
7388        if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === '') {
7389            selectorElements[0].combinator.value = ' ';
7390        }
7391        selfElements = selfElements.concat(selectors[i].elements);
7392    }
7393
7394    this.selfSelectors = [new Selector(selfElements)];
7395    this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo());
7396};
7397module.exports = Extend;
7398
7399},{"./node":73,"./selector":79}],64:[function(require,module,exports){
7400var Node = require('./node'),
7401    Media = require('./media'),
7402    URL = require('./url'),
7403    Quoted = require('./quoted'),
7404    Ruleset = require('./ruleset'),
7405    Anonymous = require('./anonymous'),
7406    utils = require('../utils'),
7407    LessError = require('../less-error');
7408
7409//
7410// CSS @import node
7411//
7412// The general strategy here is that we don't want to wait
7413// for the parsing to be completed, before we start importing
7414// the file. That's because in the context of a browser,
7415// most of the time will be spent waiting for the server to respond.
7416//
7417// On creation, we push the import path to our import queue, though
7418// `import,push`, we also pass it a callback, which it'll call once
7419// the file has been fetched, and parsed.
7420//
7421var Import = function (path, features, options, index, currentFileInfo, visibilityInfo) {
7422    this.options = options;
7423    this._index = index;
7424    this._fileInfo = currentFileInfo;
7425    this.path = path;
7426    this.features = features;
7427    this.allowRoot = true;
7428
7429    if (this.options.less !== undefined || this.options.inline) {
7430        this.css = !this.options.less || this.options.inline;
7431    } else {
7432        var pathValue = this.getPath();
7433        if (pathValue && /[#\.\&\?]css([\?;].*)?$/.test(pathValue)) {
7434            this.css = true;
7435        }
7436    }
7437    this.copyVisibilityInfo(visibilityInfo);
7438    this.setParent(this.features, this);
7439    this.setParent(this.path, this);
7440};
7441
7442//
7443// The actual import node doesn't return anything, when converted to CSS.
7444// The reason is that it's used at the evaluation stage, so that the rules
7445// it imports can be treated like any other rules.
7446//
7447// In `eval`, we make sure all Import nodes get evaluated, recursively, so
7448// we end up with a flat structure, which can easily be imported in the parent
7449// ruleset.
7450//
7451Import.prototype = new Node();
7452Import.prototype.type = 'Import';
7453Import.prototype.accept = function (visitor) {
7454    if (this.features) {
7455        this.features = visitor.visit(this.features);
7456    }
7457    this.path = visitor.visit(this.path);
7458    if (!this.options.isPlugin && !this.options.inline && this.root) {
7459        this.root = visitor.visit(this.root);
7460    }
7461};
7462Import.prototype.genCSS = function (context, output) {
7463    if (this.css && this.path._fileInfo.reference === undefined) {
7464        output.add('@import ', this._fileInfo, this._index);
7465        this.path.genCSS(context, output);
7466        if (this.features) {
7467            output.add(' ');
7468            this.features.genCSS(context, output);
7469        }
7470        output.add(';');
7471    }
7472};
7473Import.prototype.getPath = function () {
7474    return (this.path instanceof URL) ?
7475        this.path.value.value : this.path.value;
7476};
7477Import.prototype.isVariableImport = function () {
7478    var path = this.path;
7479    if (path instanceof URL) {
7480        path = path.value;
7481    }
7482    if (path instanceof Quoted) {
7483        return path.containsVariables();
7484    }
7485
7486    return true;
7487};
7488Import.prototype.evalForImport = function (context) {
7489    var path = this.path;
7490
7491    if (path instanceof URL) {
7492        path = path.value;
7493    }
7494
7495    return new Import(path.eval(context), this.features, this.options, this._index, this._fileInfo, this.visibilityInfo());
7496};
7497Import.prototype.evalPath = function (context) {
7498    var path = this.path.eval(context);
7499    var rootpath = this._fileInfo && this._fileInfo.rootpath;
7500
7501    if (!(path instanceof URL)) {
7502        if (rootpath) {
7503            var pathValue = path.value;
7504            // Add the base path if the import is relative
7505            if (pathValue && context.isPathRelative(pathValue)) {
7506                path.value = rootpath + pathValue;
7507            }
7508        }
7509        path.value = context.normalizePath(path.value);
7510    }
7511
7512    return path;
7513};
7514Import.prototype.eval = function (context) {
7515    var result = this.doEval(context);
7516    if (this.options.reference || this.blocksVisibility()) {
7517        if (result.length || result.length === 0) {
7518            result.forEach(function (node) {
7519                node.addVisibilityBlock();
7520            }
7521            );
7522        } else {
7523            result.addVisibilityBlock();
7524        }
7525    }
7526    return result;
7527};
7528Import.prototype.doEval = function (context) {
7529    var ruleset, registry,
7530        features = this.features && this.features.eval(context);
7531
7532    if (this.options.isPlugin) {
7533        if (this.root && this.root.eval) {
7534            try {
7535                this.root.eval(context);
7536            }
7537            catch (e) {
7538                e.message = 'Plugin error during evaluation';
7539                throw new LessError(e, this.root.imports, this.root.filename);
7540            }
7541        }
7542        registry = context.frames[0] && context.frames[0].functionRegistry;
7543        if ( registry && this.root && this.root.functions ) {
7544            registry.addMultiple( this.root.functions );
7545        }
7546
7547        return [];
7548    }
7549
7550    if (this.skip) {
7551        if (typeof this.skip === 'function') {
7552            this.skip = this.skip();
7553        }
7554        if (this.skip) {
7555            return [];
7556        }
7557    }
7558    if (this.options.inline) {
7559        var contents = new Anonymous(this.root, 0,
7560            {
7561                filename: this.importedFilename,
7562                reference: this.path._fileInfo && this.path._fileInfo.reference
7563            }, true, true);
7564
7565        return this.features ? new Media([contents], this.features.value) : [contents];
7566    } else if (this.css) {
7567        var newImport = new Import(this.evalPath(context), features, this.options, this._index);
7568        if (!newImport.css && this.error) {
7569            throw this.error;
7570        }
7571        return newImport;
7572    } else {
7573        ruleset = new Ruleset(null, utils.copyArray(this.root.rules));
7574        ruleset.evalImports(context);
7575
7576        return this.features ? new Media(ruleset.rules, this.features.value) : ruleset.rules;
7577    }
7578};
7579module.exports = Import;
7580
7581},{"../less-error":36,"../utils":86,"./anonymous":48,"./media":69,"./node":73,"./quoted":77,"./ruleset":78,"./url":82}],65:[function(require,module,exports){
7582var tree = Object.create(null);
7583
7584tree.Node = require('./node');
7585tree.Color = require('./color');
7586tree.AtRule = require('./atrule');
7587tree.DetachedRuleset = require('./detached-ruleset');
7588tree.Operation = require('./operation');
7589tree.Dimension = require('./dimension');
7590tree.Unit = require('./unit');
7591tree.Keyword = require('./keyword');
7592tree.Variable = require('./variable');
7593tree.Property = require('./property');
7594tree.Ruleset = require('./ruleset');
7595tree.Element = require('./element');
7596tree.Attribute = require('./attribute');
7597tree.Combinator = require('./combinator');
7598tree.Selector = require('./selector');
7599tree.Quoted = require('./quoted');
7600tree.Expression = require('./expression');
7601tree.Declaration = require('./declaration');
7602tree.Call = require('./call');
7603tree.URL = require('./url');
7604tree.Import = require('./import');
7605tree.mixin = {
7606    Call: require('./mixin-call'),
7607    Definition: require('./mixin-definition')
7608};
7609tree.Comment = require('./comment');
7610tree.Anonymous = require('./anonymous');
7611tree.Value = require('./value');
7612tree.JavaScript = require('./javascript');
7613tree.Assignment = require('./assignment');
7614tree.Condition = require('./condition');
7615tree.Paren = require('./paren');
7616tree.Media = require('./media');
7617tree.UnicodeDescriptor = require('./unicode-descriptor');
7618tree.Negative = require('./negative');
7619tree.Extend = require('./extend');
7620tree.VariableCall = require('./variable-call');
7621
7622module.exports = tree;
7623
7624},{"./anonymous":48,"./assignment":49,"./atrule":50,"./attribute":51,"./call":52,"./color":53,"./combinator":54,"./comment":55,"./condition":56,"./declaration":58,"./detached-ruleset":59,"./dimension":60,"./element":61,"./expression":62,"./extend":63,"./import":64,"./javascript":66,"./keyword":68,"./media":69,"./mixin-call":70,"./mixin-definition":71,"./negative":72,"./node":73,"./operation":74,"./paren":75,"./property":76,"./quoted":77,"./ruleset":78,"./selector":79,"./unicode-descriptor":80,"./unit":81,"./url":82,"./value":83,"./variable":85,"./variable-call":84}],66:[function(require,module,exports){
7625var JsEvalNode = require('./js-eval-node'),
7626    Dimension = require('./dimension'),
7627    Quoted = require('./quoted'),
7628    Anonymous = require('./anonymous');
7629
7630var JavaScript = function (string, escaped, index, currentFileInfo) {
7631    this.escaped = escaped;
7632    this.expression = string;
7633    this._index = index;
7634    this._fileInfo = currentFileInfo;
7635};
7636JavaScript.prototype = new JsEvalNode();
7637JavaScript.prototype.type = 'JavaScript';
7638JavaScript.prototype.eval = function(context) {
7639    var result = this.evaluateJavaScript(this.expression, context);
7640
7641    if (typeof result === 'number') {
7642        return new Dimension(result);
7643    } else if (typeof result === 'string') {
7644        return new Quoted('"' + result + '"', result, this.escaped, this._index);
7645    } else if (Array.isArray(result)) {
7646        return new Anonymous(result.join(', '));
7647    } else {
7648        return new Anonymous(result);
7649    }
7650};
7651
7652module.exports = JavaScript;
7653
7654},{"./anonymous":48,"./dimension":60,"./js-eval-node":67,"./quoted":77}],67:[function(require,module,exports){
7655var Node = require('./node'),
7656    Variable = require('./variable');
7657
7658var JsEvalNode = function() {
7659};
7660JsEvalNode.prototype = new Node();
7661
7662JsEvalNode.prototype.evaluateJavaScript = function (expression, context) {
7663    var result,
7664        that = this,
7665        evalContext = {};
7666
7667    if (!context.javascriptEnabled) {
7668        throw { message: 'Inline JavaScript is not enabled. Is it set in your options?',
7669            filename: this.fileInfo().filename,
7670            index: this.getIndex() };
7671    }
7672
7673    expression = expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
7674        return that.jsify(new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context));
7675    });
7676
7677    try {
7678        expression = new Function('return (' + expression + ')');
7679    } catch (e) {
7680        throw { message: 'JavaScript evaluation error: ' + e.message + ' from `' + expression + '`' ,
7681            filename: this.fileInfo().filename,
7682            index: this.getIndex() };
7683    }
7684
7685    var variables = context.frames[0].variables();
7686    for (var k in variables) {
7687        if (variables.hasOwnProperty(k)) {
7688            /* jshint loopfunc:true */
7689            evalContext[k.slice(1)] = {
7690                value: variables[k].value,
7691                toJS: function () {
7692                    return this.value.eval(context).toCSS();
7693                }
7694            };
7695        }
7696    }
7697
7698    try {
7699        result = expression.call(evalContext);
7700    } catch (e) {
7701        throw { message: 'JavaScript evaluation error: \'' + e.name + ': ' + e.message.replace(/["]/g, '\'') + '\'' ,
7702            filename: this.fileInfo().filename,
7703            index: this.getIndex() };
7704    }
7705    return result;
7706};
7707JsEvalNode.prototype.jsify = function (obj) {
7708    if (Array.isArray(obj.value) && (obj.value.length > 1)) {
7709        return '[' + obj.value.map(function (v) { return v.toCSS(); }).join(', ') + ']';
7710    } else {
7711        return obj.toCSS();
7712    }
7713};
7714
7715module.exports = JsEvalNode;
7716
7717},{"./node":73,"./variable":85}],68:[function(require,module,exports){
7718var Node = require('./node');
7719
7720var Keyword = function (value) { this.value = value; };
7721Keyword.prototype = new Node();
7722Keyword.prototype.type = 'Keyword';
7723Keyword.prototype.genCSS = function (context, output) {
7724    if (this.value === '%') { throw { type: 'Syntax', message: 'Invalid % without number' }; }
7725    output.add(this.value);
7726};
7727
7728Keyword.True = new Keyword('true');
7729Keyword.False = new Keyword('false');
7730
7731module.exports = Keyword;
7732
7733},{"./node":73}],69:[function(require,module,exports){
7734var Ruleset = require('./ruleset'),
7735    Value = require('./value'),
7736    Selector = require('./selector'),
7737    Anonymous = require('./anonymous'),
7738    Expression = require('./expression'),
7739    AtRule = require('./atrule'),
7740    utils = require('../utils');
7741
7742var Media = function (value, features, index, currentFileInfo, visibilityInfo) {
7743    this._index = index;
7744    this._fileInfo = currentFileInfo;
7745
7746    var selectors = (new Selector([], null, null, this._index, this._fileInfo)).createEmptySelectors();
7747
7748    this.features = new Value(features);
7749    this.rules = [new Ruleset(selectors, value)];
7750    this.rules[0].allowImports = true;
7751    this.copyVisibilityInfo(visibilityInfo);
7752    this.allowRoot = true;
7753    this.setParent(selectors, this);
7754    this.setParent(this.features, this);
7755    this.setParent(this.rules, this);
7756};
7757Media.prototype = new AtRule();
7758Media.prototype.type = 'Media';
7759Media.prototype.isRulesetLike = function() { return true; };
7760Media.prototype.accept = function (visitor) {
7761    if (this.features) {
7762        this.features = visitor.visit(this.features);
7763    }
7764    if (this.rules) {
7765        this.rules = visitor.visitArray(this.rules);
7766    }
7767};
7768Media.prototype.genCSS = function (context, output) {
7769    output.add('@media ', this._fileInfo, this._index);
7770    this.features.genCSS(context, output);
7771    this.outputRuleset(context, output, this.rules);
7772};
7773Media.prototype.eval = function (context) {
7774    if (!context.mediaBlocks) {
7775        context.mediaBlocks = [];
7776        context.mediaPath = [];
7777    }
7778
7779    var media = new Media(null, [], this._index, this._fileInfo, this.visibilityInfo());
7780    if (this.debugInfo) {
7781        this.rules[0].debugInfo = this.debugInfo;
7782        media.debugInfo = this.debugInfo;
7783    }
7784    
7785    media.features = this.features.eval(context);
7786
7787    context.mediaPath.push(media);
7788    context.mediaBlocks.push(media);
7789
7790    this.rules[0].functionRegistry = context.frames[0].functionRegistry.inherit();
7791    context.frames.unshift(this.rules[0]);
7792    media.rules = [this.rules[0].eval(context)];
7793    context.frames.shift();
7794
7795    context.mediaPath.pop();
7796
7797    return context.mediaPath.length === 0 ? media.evalTop(context) :
7798                media.evalNested(context);
7799};
7800Media.prototype.evalTop = function (context) {
7801    var result = this;
7802
7803    // Render all dependent Media blocks.
7804    if (context.mediaBlocks.length > 1) {
7805        var selectors = (new Selector([], null, null, this.getIndex(), this.fileInfo())).createEmptySelectors();
7806        result = new Ruleset(selectors, context.mediaBlocks);
7807        result.multiMedia = true;
7808        result.copyVisibilityInfo(this.visibilityInfo());
7809        this.setParent(result, this);
7810    }
7811
7812    delete context.mediaBlocks;
7813    delete context.mediaPath;
7814
7815    return result;
7816};
7817Media.prototype.evalNested = function (context) {
7818    var i, value,
7819        path = context.mediaPath.concat([this]);
7820
7821    // Extract the media-query conditions separated with `,` (OR).
7822    for (i = 0; i < path.length; i++) {
7823        value = path[i].features instanceof Value ?
7824                    path[i].features.value : path[i].features;
7825        path[i] = Array.isArray(value) ? value : [value];
7826    }
7827
7828    // Trace all permutations to generate the resulting media-query.
7829    //
7830    // (a, b and c) with nested (d, e) ->
7831    //    a and d
7832    //    a and e
7833    //    b and c and d
7834    //    b and c and e
7835    this.features = new Value(this.permute(path).map(function (path) {
7836        path = path.map(function (fragment) {
7837            return fragment.toCSS ? fragment : new Anonymous(fragment);
7838        });
7839
7840        for (i = path.length - 1; i > 0; i--) {
7841            path.splice(i, 0, new Anonymous('and'));
7842        }
7843
7844        return new Expression(path);
7845    }));
7846    this.setParent(this.features, this);
7847
7848    // Fake a tree-node that doesn't output anything.
7849    return new Ruleset([], []);
7850};
7851Media.prototype.permute = function (arr) {
7852    if (arr.length === 0) {
7853        return [];
7854    } else if (arr.length === 1) {
7855        return arr[0];
7856    } else {
7857        var result = [];
7858        var rest = this.permute(arr.slice(1));
7859        for (var i = 0; i < rest.length; i++) {
7860            for (var j = 0; j < arr[0].length; j++) {
7861                result.push([arr[0][j]].concat(rest[i]));
7862            }
7863        }
7864        return result;
7865    }
7866};
7867Media.prototype.bubbleSelectors = function (selectors) {
7868    if (!selectors) {
7869        return;
7870    }
7871    this.rules = [new Ruleset(utils.copyArray(selectors), [this.rules[0]])];
7872    this.setParent(this.rules, this);
7873};
7874module.exports = Media;
7875
7876},{"../utils":86,"./anonymous":48,"./atrule":50,"./expression":62,"./ruleset":78,"./selector":79,"./value":83}],70:[function(require,module,exports){
7877var Node = require('./node'),
7878    Selector = require('./selector'),
7879    MixinDefinition = require('./mixin-definition'),
7880    defaultFunc = require('../functions/default');
7881
7882var MixinCall = function (elements, args, index, currentFileInfo, important) {
7883    this.selector = new Selector(elements);
7884    this.arguments = args || [];
7885    this._index = index;
7886    this._fileInfo = currentFileInfo;
7887    this.important = important;
7888    this.allowRoot = true;
7889    this.setParent(this.selector, this);
7890};
7891MixinCall.prototype = new Node();
7892MixinCall.prototype.type = 'MixinCall';
7893MixinCall.prototype.accept = function (visitor) {
7894    if (this.selector) {
7895        this.selector = visitor.visit(this.selector);
7896    }
7897    if (this.arguments.length) {
7898        this.arguments = visitor.visitArray(this.arguments);
7899    }
7900};
7901MixinCall.prototype.eval = function (context) {
7902    var mixins, mixin, mixinPath, args = [], arg, argValue,
7903        rules = [], match = false, i, m, f, isRecursive, isOneFound,
7904        candidates = [], candidate, conditionResult = [], defaultResult, defFalseEitherCase = -1,
7905        defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter;
7906
7907    function calcDefGroup(mixin, mixinPath) {
7908        var f, p, namespace;
7909
7910        for (f = 0; f < 2; f++) {
7911            conditionResult[f] = true;
7912            defaultFunc.value(f);
7913            for (p = 0; p < mixinPath.length && conditionResult[f]; p++) {
7914                namespace = mixinPath[p];
7915                if (namespace.matchCondition) {
7916                    conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, context);
7917                }
7918            }
7919            if (mixin.matchCondition) {
7920                conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, context);
7921            }
7922        }
7923        if (conditionResult[0] || conditionResult[1]) {
7924            if (conditionResult[0] != conditionResult[1]) {
7925                return conditionResult[1] ?
7926                    defTrue : defFalse;
7927            }
7928
7929            return defNone;
7930        }
7931        return defFalseEitherCase;
7932    }
7933
7934    for (i = 0; i < this.arguments.length; i++) {
7935        arg = this.arguments[i];
7936        argValue = arg.value.eval(context);
7937        if (arg.expand && Array.isArray(argValue.value)) {
7938            argValue = argValue.value;
7939            for (m = 0; m < argValue.length; m++) {
7940                args.push({value: argValue[m]});
7941            }
7942        } else {
7943            args.push({name: arg.name, value: argValue});
7944        }
7945    }
7946
7947    noArgumentsFilter = function(rule) {return rule.matchArgs(null, context);};
7948
7949    for (i = 0; i < context.frames.length; i++) {
7950        if ((mixins = context.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) {
7951            isOneFound = true;
7952
7953            // To make `default()` function independent of definition order we have two "subpasses" here.
7954            // At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
7955            // and build candidate list with corresponding flags. Then, when we know all possible matches,
7956            // we make a final decision.
7957
7958            for (m = 0; m < mixins.length; m++) {
7959                mixin = mixins[m].rule;
7960                mixinPath = mixins[m].path;
7961                isRecursive = false;
7962                for (f = 0; f < context.frames.length; f++) {
7963                    if ((!(mixin instanceof MixinDefinition)) && mixin === (context.frames[f].originalRuleset || context.frames[f])) {
7964                        isRecursive = true;
7965                        break;
7966                    }
7967                }
7968                if (isRecursive) {
7969                    continue;
7970                }
7971
7972                if (mixin.matchArgs(args, context)) {
7973                    candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)};
7974
7975                    if (candidate.group !== defFalseEitherCase) {
7976                        candidates.push(candidate);
7977                    }
7978
7979                    match = true;
7980                }
7981            }
7982
7983            defaultFunc.reset();
7984
7985            count = [0, 0, 0];
7986            for (m = 0; m < candidates.length; m++) {
7987                count[candidates[m].group]++;
7988            }
7989
7990            if (count[defNone] > 0) {
7991                defaultResult = defFalse;
7992            } else {
7993                defaultResult = defTrue;
7994                if ((count[defTrue] + count[defFalse]) > 1) {
7995                    throw { type: 'Runtime',
7996                        message: 'Ambiguous use of `default()` found when matching for `' + this.format(args) + '`',
7997                        index: this.getIndex(), filename: this.fileInfo().filename };
7998                }
7999            }
8000
8001            for (m = 0; m < candidates.length; m++) {
8002                candidate = candidates[m].group;
8003                if ((candidate === defNone) || (candidate === defaultResult)) {
8004                    try {
8005                        mixin = candidates[m].mixin;
8006                        if (!(mixin instanceof MixinDefinition)) {
8007                            originalRuleset = mixin.originalRuleset || mixin;
8008                            mixin = new MixinDefinition('', [], mixin.rules, null, false, null, originalRuleset.visibilityInfo());
8009                            mixin.originalRuleset = originalRuleset;
8010                        }
8011                        var newRules = mixin.evalCall(context, args, this.important).rules;
8012                        this._setVisibilityToReplacement(newRules);
8013                        Array.prototype.push.apply(rules, newRules);
8014                    } catch (e) {
8015                        throw { message: e.message, index: this.getIndex(), filename: this.fileInfo().filename, stack: e.stack };
8016                    }
8017                }
8018            }
8019
8020            if (match) {
8021                return rules;
8022            }
8023        }
8024    }
8025    if (isOneFound) {
8026        throw { type:    'Runtime',
8027            message: 'No matching definition was found for `' + this.format(args) + '`',
8028            index:   this.getIndex(), filename: this.fileInfo().filename };
8029    } else {
8030        throw { type:    'Name',
8031            message: this.selector.toCSS().trim() + ' is undefined',
8032            index:   this.getIndex(), filename: this.fileInfo().filename };
8033    }
8034};
8035
8036MixinCall.prototype._setVisibilityToReplacement = function (replacement) {
8037    var i, rule;
8038    if (this.blocksVisibility()) {
8039        for (i = 0; i < replacement.length; i++) {
8040            rule = replacement[i];
8041            rule.addVisibilityBlock();
8042        }
8043    }
8044};
8045MixinCall.prototype.format = function (args) {
8046    return this.selector.toCSS().trim() + '(' +
8047        (args ? args.map(function (a) {
8048            var argValue = '';
8049            if (a.name) {
8050                argValue += a.name + ':';
8051            }
8052            if (a.value.toCSS) {
8053                argValue += a.value.toCSS();
8054            } else {
8055                argValue += '???';
8056            }
8057            return argValue;
8058        }).join(', ') : '') + ')';
8059};
8060module.exports = MixinCall;
8061
8062},{"../functions/default":24,"./mixin-definition":71,"./node":73,"./selector":79}],71:[function(require,module,exports){
8063var Selector = require('./selector'),
8064    Element = require('./element'),
8065    Ruleset = require('./ruleset'),
8066    Declaration = require('./declaration'),
8067    Expression = require('./expression'),
8068    contexts = require('../contexts'),
8069    utils = require('../utils');
8070
8071var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) {
8072    this.name = name;
8073    this.selectors = [new Selector([new Element(null, name, this._index, this._fileInfo)])];
8074    this.params = params;
8075    this.condition = condition;
8076    this.variadic = variadic;
8077    this.arity = params.length;
8078    this.rules = rules;
8079    this._lookups = {};
8080    var optionalParameters = [];
8081    this.required = params.reduce(function (count, p) {
8082        if (!p.name || (p.name && !p.value)) {
8083            return count + 1;
8084        }
8085        else {
8086            optionalParameters.push(p.name);
8087            return count;
8088        }
8089    }, 0);
8090    this.optionalParameters = optionalParameters;
8091    this.frames = frames;
8092    this.copyVisibilityInfo(visibilityInfo);
8093    this.allowRoot = true;
8094};
8095Definition.prototype = new Ruleset();
8096Definition.prototype.type = 'MixinDefinition';
8097Definition.prototype.evalFirst = true;
8098Definition.prototype.accept = function (visitor) {
8099    if (this.params && this.params.length) {
8100        this.params = visitor.visitArray(this.params);
8101    }
8102    this.rules = visitor.visitArray(this.rules);
8103    if (this.condition) {
8104        this.condition = visitor.visit(this.condition);
8105    }
8106};
8107Definition.prototype.evalParams = function (context, mixinEnv, args, evaldArguments) {
8108    /* jshint boss:true */
8109    var frame = new Ruleset(null, null),
8110        varargs, arg,
8111        params = utils.copyArray(this.params),
8112        i, j, val, name, isNamedFound, argIndex, argsLength = 0;
8113
8114    if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) {
8115        frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit();
8116    }
8117    mixinEnv = new contexts.Eval(mixinEnv, [frame].concat(mixinEnv.frames));
8118
8119    if (args) {
8120        args = utils.copyArray(args);
8121        argsLength = args.length;
8122
8123        for (i = 0; i < argsLength; i++) {
8124            arg = args[i];
8125            if (name = (arg && arg.name)) {
8126                isNamedFound = false;
8127                for (j = 0; j < params.length; j++) {
8128                    if (!evaldArguments[j] && name === params[j].name) {
8129                        evaldArguments[j] = arg.value.eval(context);
8130                        frame.prependRule(new Declaration(name, arg.value.eval(context)));
8131                        isNamedFound = true;
8132                        break;
8133                    }
8134                }
8135                if (isNamedFound) {
8136                    args.splice(i, 1);
8137                    i--;
8138                    continue;
8139                } else {
8140                    throw { type: 'Runtime', message: 'Named argument for ' + this.name +
8141                        ' ' + args[i].name + ' not found' };
8142                }
8143            }
8144        }
8145    }
8146    argIndex = 0;
8147    for (i = 0; i < params.length; i++) {
8148        if (evaldArguments[i]) { continue; }
8149
8150        arg = args && args[argIndex];
8151
8152        if (name = params[i].name) {
8153            if (params[i].variadic) {
8154                varargs = [];
8155                for (j = argIndex; j < argsLength; j++) {
8156                    varargs.push(args[j].value.eval(context));
8157                }
8158                frame.prependRule(new Declaration(name, new Expression(varargs).eval(context)));
8159            } else {
8160                val = arg && arg.value;
8161                if (val) {
8162                    val = val.eval(context);
8163                } else if (params[i].value) {
8164                    val = params[i].value.eval(mixinEnv);
8165                    frame.resetCache();
8166                } else {
8167                    throw { type: 'Runtime', message: 'wrong number of arguments for ' + this.name +
8168                        ' (' + argsLength + ' for ' + this.arity + ')' };
8169                }
8170
8171                frame.prependRule(new Declaration(name, val));
8172                evaldArguments[i] = val;
8173            }
8174        }
8175
8176        if (params[i].variadic && args) {
8177            for (j = argIndex; j < argsLength; j++) {
8178                evaldArguments[j] = args[j].value.eval(context);
8179            }
8180        }
8181        argIndex++;
8182    }
8183
8184    return frame;
8185};
8186Definition.prototype.makeImportant = function() {
8187    var rules = !this.rules ? this.rules : this.rules.map(function (r) {
8188        if (r.makeImportant) {
8189            return r.makeImportant(true);
8190        } else {
8191            return r;
8192        }
8193    });
8194    var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames);
8195    return result;
8196};
8197Definition.prototype.eval = function (context) {
8198    return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames));
8199};
8200Definition.prototype.evalCall = function (context, args, important) {
8201    var _arguments = [],
8202        mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames,
8203        frame = this.evalParams(context, new contexts.Eval(context, mixinFrames), args, _arguments),
8204        rules, ruleset;
8205
8206    frame.prependRule(new Declaration('@arguments', new Expression(_arguments).eval(context)));
8207
8208    rules = utils.copyArray(this.rules);
8209
8210    ruleset = new Ruleset(null, rules);
8211    ruleset.originalRuleset = this;
8212    ruleset = ruleset.eval(new contexts.Eval(context, [this, frame].concat(mixinFrames)));
8213    if (important) {
8214        ruleset = ruleset.makeImportant();
8215    }
8216    return ruleset;
8217};
8218Definition.prototype.matchCondition = function (args, context) {
8219    if (this.condition && !this.condition.eval(
8220        new contexts.Eval(context,
8221            [this.evalParams(context, /* the parameter variables */
8222                new contexts.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
8223            .concat(this.frames || []) // the parent namespace/mixin frames
8224            .concat(context.frames)))) { // the current environment frames
8225        return false;
8226    }
8227    return true;
8228};
8229Definition.prototype.matchArgs = function (args, context) {
8230    var allArgsCnt = (args && args.length) || 0, len, optionalParameters = this.optionalParameters;
8231    var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) {
8232        if (optionalParameters.indexOf(p.name) < 0) {
8233            return count + 1;
8234        } else {
8235            return count;
8236        }
8237    }, 0);
8238
8239    if (!this.variadic) {
8240        if (requiredArgsCnt < this.required) {
8241            return false;
8242        }
8243        if (allArgsCnt > this.params.length) {
8244            return false;
8245        }
8246    } else {
8247        if (requiredArgsCnt < (this.required - 1)) {
8248            return false;
8249        }
8250    }
8251
8252    // check patterns
8253    len = Math.min(requiredArgsCnt, this.arity);
8254
8255    for (var i = 0; i < len; i++) {
8256        if (!this.params[i].name && !this.params[i].variadic) {
8257            if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) {
8258                return false;
8259            }
8260        }
8261    }
8262    return true;
8263};
8264module.exports = Definition;
8265
8266},{"../contexts":12,"../utils":86,"./declaration":58,"./element":61,"./expression":62,"./ruleset":78,"./selector":79}],72:[function(require,module,exports){
8267var Node = require('./node'),
8268    Operation = require('./operation'),
8269    Dimension = require('./dimension');
8270
8271var Negative = function (node) {
8272    this.value = node;
8273};
8274Negative.prototype = new Node();
8275Negative.prototype.type = 'Negative';
8276Negative.prototype.genCSS = function (context, output) {
8277    output.add('-');
8278    this.value.genCSS(context, output);
8279};
8280Negative.prototype.eval = function (context) {
8281    if (context.isMathOn()) {
8282        return (new Operation('*', [new Dimension(-1), this.value])).eval(context);
8283    }
8284    return new Negative(this.value.eval(context));
8285};
8286module.exports = Negative;
8287
8288},{"./dimension":60,"./node":73,"./operation":74}],73:[function(require,module,exports){
8289var Node = function() {
8290    this.parent = null;
8291    this.visibilityBlocks = undefined;
8292    this.nodeVisible = undefined;
8293    this.rootNode = null;
8294    this.parsed = null;
8295
8296    var self = this;
8297    Object.defineProperty(this, 'currentFileInfo', {
8298        get: function() { return self.fileInfo(); }
8299    });
8300    Object.defineProperty(this, 'index', {
8301        get: function() { return self.getIndex(); }
8302    });
8303
8304};
8305Node.prototype.setParent = function(nodes, parent) {
8306    function set(node) {
8307        if (node && node instanceof Node) {
8308            node.parent = parent;
8309        }
8310    }
8311    if (Array.isArray(nodes)) {
8312        nodes.forEach(set);
8313    }
8314    else {
8315        set(nodes);
8316    }
8317};
8318Node.prototype.getIndex = function() {
8319    return this._index || (this.parent && this.parent.getIndex()) || 0;
8320};
8321Node.prototype.fileInfo = function() {
8322    return this._fileInfo || (this.parent && this.parent.fileInfo()) || {};
8323};
8324Node.prototype.isRulesetLike = function() { return false; };
8325Node.prototype.toCSS = function (context) {
8326    var strs = [];
8327    this.genCSS(context, {
8328        add: function(chunk, fileInfo, index) {
8329            strs.push(chunk);
8330        },
8331        isEmpty: function () {
8332            return strs.length === 0;
8333        }
8334    });
8335    return strs.join('');
8336};
8337Node.prototype.genCSS = function (context, output) {
8338    output.add(this.value);
8339};
8340Node.prototype.accept = function (visitor) {
8341    this.value = visitor.visit(this.value);
8342};
8343Node.prototype.eval = function () { return this; };
8344Node.prototype._operate = function (context, op, a, b) {
8345    switch (op) {
8346        case '+': return a + b;
8347        case '-': return a - b;
8348        case '*': return a * b;
8349        case '/': return a / b;
8350    }
8351};
8352Node.prototype.fround = function(context, value) {
8353    var precision = context && context.numPrecision;
8354    // add "epsilon" to ensure numbers like 1.000000005 (represented as 1.000000004999...) are properly rounded:
8355    return (precision) ? Number((value + 2e-16).toFixed(precision)) : value;
8356};
8357Node.compare = function (a, b) {
8358    /* returns:
8359     -1: a < b
8360     0: a = b
8361     1: a > b
8362     and *any* other value for a != b (e.g. undefined, NaN, -2 etc.) */
8363
8364    if ((a.compare) &&
8365        // for "symmetric results" force toCSS-based comparison
8366        // of Quoted or Anonymous if either value is one of those
8367        !(b.type === 'Quoted' || b.type === 'Anonymous')) {
8368        return a.compare(b);
8369    } else if (b.compare) {
8370        return -b.compare(a);
8371    } else if (a.type !== b.type) {
8372        return undefined;
8373    }
8374
8375    a = a.value;
8376    b = b.value;
8377    if (!Array.isArray(a)) {
8378        return a === b ? 0 : undefined;
8379    }
8380    if (a.length !== b.length) {
8381        return undefined;
8382    }
8383    for (var i = 0; i < a.length; i++) {
8384        if (Node.compare(a[i], b[i]) !== 0) {
8385            return undefined;
8386        }
8387    }
8388    return 0;
8389};
8390
8391Node.numericCompare = function (a, b) {
8392    return a  <  b ? -1
8393        : a === b ?  0
8394        : a  >  b ?  1 : undefined;
8395};
8396// Returns true if this node represents root of ast imported by reference
8397Node.prototype.blocksVisibility = function () {
8398    if (this.visibilityBlocks == null) {
8399        this.visibilityBlocks = 0;
8400    }
8401    return this.visibilityBlocks !== 0;
8402};
8403Node.prototype.addVisibilityBlock = function () {
8404    if (this.visibilityBlocks == null) {
8405        this.visibilityBlocks = 0;
8406    }
8407    this.visibilityBlocks = this.visibilityBlocks + 1;
8408};
8409Node.prototype.removeVisibilityBlock = function () {
8410    if (this.visibilityBlocks == null) {
8411        this.visibilityBlocks = 0;
8412    }
8413    this.visibilityBlocks = this.visibilityBlocks - 1;
8414};
8415// Turns on node visibility - if called node will be shown in output regardless
8416// of whether it comes from import by reference or not
8417Node.prototype.ensureVisibility = function () {
8418    this.nodeVisible = true;
8419};
8420// Turns off node visibility - if called node will NOT be shown in output regardless
8421// of whether it comes from import by reference or not
8422Node.prototype.ensureInvisibility = function () {
8423    this.nodeVisible = false;
8424};
8425// return values:
8426// false - the node must not be visible
8427// true - the node must be visible
8428// undefined or null - the node has the same visibility as its parent
8429Node.prototype.isVisible = function () {
8430    return this.nodeVisible;
8431};
8432Node.prototype.visibilityInfo = function() {
8433    return {
8434        visibilityBlocks: this.visibilityBlocks,
8435        nodeVisible: this.nodeVisible
8436    };
8437};
8438Node.prototype.copyVisibilityInfo = function(info) {
8439    if (!info) {
8440        return;
8441    }
8442    this.visibilityBlocks = info.visibilityBlocks;
8443    this.nodeVisible = info.nodeVisible;
8444};
8445module.exports = Node;
8446
8447},{}],74:[function(require,module,exports){
8448var Node = require('./node'),
8449    Color = require('./color'),
8450    Dimension = require('./dimension');
8451
8452var Operation = function (op, operands, isSpaced) {
8453    this.op = op.trim();
8454    this.operands = operands;
8455    this.isSpaced = isSpaced;
8456};
8457Operation.prototype = new Node();
8458Operation.prototype.type = 'Operation';
8459Operation.prototype.accept = function (visitor) {
8460    this.operands = visitor.visit(this.operands);
8461};
8462Operation.prototype.eval = function (context) {
8463    var a = this.operands[0].eval(context),
8464        b = this.operands[1].eval(context);
8465
8466    if (context.isMathOn()) {
8467        if (a instanceof Dimension && b instanceof Color) {
8468            a = a.toColor();
8469        }
8470        if (b instanceof Dimension && a instanceof Color) {
8471            b = b.toColor();
8472        }
8473        if (!a.operate) {
8474            throw { type: 'Operation',
8475                message: 'Operation on an invalid type' };
8476        }
8477
8478        return a.operate(context, this.op, b);
8479    } else {
8480        return new Operation(this.op, [a, b], this.isSpaced);
8481    }
8482};
8483Operation.prototype.genCSS = function (context, output) {
8484    this.operands[0].genCSS(context, output);
8485    if (this.isSpaced) {
8486        output.add(' ');
8487    }
8488    output.add(this.op);
8489    if (this.isSpaced) {
8490        output.add(' ');
8491    }
8492    this.operands[1].genCSS(context, output);
8493};
8494
8495module.exports = Operation;
8496
8497},{"./color":53,"./dimension":60,"./node":73}],75:[function(require,module,exports){
8498var Node = require('./node');
8499
8500var Paren = function (node) {
8501    this.value = node;
8502};
8503Paren.prototype = new Node();
8504Paren.prototype.type = 'Paren';
8505Paren.prototype.genCSS = function (context, output) {
8506    output.add('(');
8507    this.value.genCSS(context, output);
8508    output.add(')');
8509};
8510Paren.prototype.eval = function (context) {
8511    return new Paren(this.value.eval(context));
8512};
8513module.exports = Paren;
8514
8515},{"./node":73}],76:[function(require,module,exports){
8516var Node = require('./node'),
8517    Declaration = require('./declaration');
8518
8519var Property = function (name, index, currentFileInfo) {
8520    this.name = name;
8521    this._index = index;
8522    this._fileInfo = currentFileInfo;
8523};
8524Property.prototype = new Node();
8525Property.prototype.type = 'Property';
8526Property.prototype.eval = function (context) {
8527    var property, name = this.name;
8528    // TODO: shorten this reference
8529    var mergeRules = context.pluginManager.less.visitors.ToCSSVisitor.prototype._mergeRules;
8530
8531    if (this.evaluating) {
8532        throw { type: 'Name',
8533            message: 'Recursive property reference for ' + name,
8534            filename: this.fileInfo().filename,
8535            index: this.getIndex() };
8536    }
8537
8538    this.evaluating = true;
8539
8540    property = this.find(context.frames, function (frame) {
8541
8542        var v, vArr = frame.property(name);
8543        if (vArr) {
8544            for (var i = 0; i < vArr.length; i++) {
8545                v = vArr[i];
8546
8547                vArr[i] = new Declaration(v.name,
8548                    v.value,
8549                    v.important,
8550                    v.merge,
8551                    v.index,
8552                    v.currentFileInfo,
8553                    v.inline,
8554                    v.variable
8555                );
8556            }
8557            mergeRules(vArr);
8558
8559            v = vArr[vArr.length - 1];
8560            if (v.important) {
8561                var importantScope = context.importantScope[context.importantScope.length - 1];
8562                importantScope.important = v.important;
8563            }
8564            v = v.value.eval(context);
8565            return v;
8566        }
8567    });
8568    if (property) {
8569        this.evaluating = false;
8570        return property;
8571    } else {
8572        throw { type: 'Name',
8573            message: 'Property \'' + name + '\' is undefined',
8574            filename: this.currentFileInfo.filename,
8575            index: this.index };
8576    }
8577};
8578Property.prototype.find = function (obj, fun) {
8579    for (var i = 0, r; i < obj.length; i++) {
8580        r = fun.call(obj, obj[i]);
8581        if (r) { return r; }
8582    }
8583    return null;
8584};
8585module.exports = Property;
8586
8587},{"./declaration":58,"./node":73}],77:[function(require,module,exports){
8588var Node = require('./node'),
8589    Variable = require('./variable'),
8590    Property = require('./property');
8591
8592var Quoted = function (str, content, escaped, index, currentFileInfo) {
8593    this.escaped = (escaped == null) ? true : escaped;
8594    this.value = content || '';
8595    this.quote = str.charAt(0);
8596    this._index = index;
8597    this._fileInfo = currentFileInfo;
8598    this.variableRegex = /@\{([\w-]+)\}/g;
8599    this.propRegex = /\$\{([\w-]+)\}/g;
8600};
8601Quoted.prototype = new Node();
8602Quoted.prototype.type = 'Quoted';
8603Quoted.prototype.genCSS = function (context, output) {
8604    if (!this.escaped) {
8605        output.add(this.quote, this.fileInfo(), this.getIndex());
8606    }
8607    output.add(this.value);
8608    if (!this.escaped) {
8609        output.add(this.quote);
8610    }
8611};
8612Quoted.prototype.containsVariables = function() {
8613    return this.value.match(this.variableRegex);
8614};
8615Quoted.prototype.eval = function (context) {
8616    var that = this, value = this.value;
8617    var variableReplacement = function (_, name) {
8618        var v = new Variable('@' + name, that.getIndex(), that.fileInfo()).eval(context, true);
8619        return (v instanceof Quoted) ? v.value : v.toCSS();
8620    };
8621    var propertyReplacement = function (_, name) {
8622        var v = new Property('$' + name, that.getIndex(), that.fileInfo()).eval(context, true);
8623        return (v instanceof Quoted) ? v.value : v.toCSS();
8624    };
8625    function iterativeReplace(value, regexp, replacementFnc) {
8626        var evaluatedValue = value;
8627        do {
8628            value = evaluatedValue;
8629            evaluatedValue = value.replace(regexp, replacementFnc);
8630        } while (value !== evaluatedValue);
8631        return evaluatedValue;
8632    }
8633    value = iterativeReplace(value, this.variableRegex, variableReplacement);
8634    value = iterativeReplace(value, this.propRegex, propertyReplacement);
8635    return new Quoted(this.quote + value + this.quote, value, this.escaped, this.getIndex(), this.fileInfo());
8636};
8637Quoted.prototype.compare = function (other) {
8638    // when comparing quoted strings allow the quote to differ
8639    if (other.type === 'Quoted' && !this.escaped && !other.escaped) {
8640        return Node.numericCompare(this.value, other.value);
8641    } else {
8642        return other.toCSS && this.toCSS() === other.toCSS() ? 0 : undefined;
8643    }
8644};
8645module.exports = Quoted;
8646
8647},{"./node":73,"./property":76,"./variable":85}],78:[function(require,module,exports){
8648var Node = require('./node'),
8649    Declaration = require('./declaration'),
8650    Keyword = require('./keyword'),
8651    Comment = require('./comment'),
8652    Paren = require('./paren'),
8653    Selector = require('./selector'),
8654    Element = require('./element'),
8655    Anonymous = require('./anonymous'),
8656    contexts = require('../contexts'),
8657    globalFunctionRegistry = require('../functions/function-registry'),
8658    defaultFunc = require('../functions/default'),
8659    getDebugInfo = require('./debug-info'),
8660    utils = require('../utils');
8661
8662var Ruleset = function (selectors, rules, strictImports, visibilityInfo) {
8663    this.selectors = selectors;
8664    this.rules = rules;
8665    this._lookups = {};
8666    this._variables = null;
8667    this._properties = null;
8668    this.strictImports = strictImports;
8669    this.copyVisibilityInfo(visibilityInfo);
8670    this.allowRoot = true;
8671
8672    this.setParent(this.selectors, this);
8673    this.setParent(this.rules, this);
8674
8675};
8676Ruleset.prototype = new Node();
8677Ruleset.prototype.type = 'Ruleset';
8678Ruleset.prototype.isRuleset = true;
8679Ruleset.prototype.isRulesetLike = function() { return true; };
8680Ruleset.prototype.accept = function (visitor) {
8681    if (this.paths) {
8682        this.paths = visitor.visitArray(this.paths, true);
8683    } else if (this.selectors) {
8684        this.selectors = visitor.visitArray(this.selectors);
8685    }
8686    if (this.rules && this.rules.length) {
8687        this.rules = visitor.visitArray(this.rules);
8688    }
8689};
8690Ruleset.prototype.eval = function (context) {
8691    var thisSelectors = this.selectors, selectors,
8692        selCnt, selector, i, hasOnePassingSelector = false;
8693
8694    if (thisSelectors && (selCnt = thisSelectors.length)) {
8695        selectors = new Array(selCnt);
8696        defaultFunc.error({
8697            type: 'Syntax',
8698            message: 'it is currently only allowed in parametric mixin guards,'
8699        });
8700        for (i = 0; i < selCnt; i++) {
8701            selector = thisSelectors[i].eval(context);
8702            selectors[i] = selector;
8703            if (selector.evaldCondition) {
8704                hasOnePassingSelector = true;
8705            }
8706        }
8707        defaultFunc.reset();
8708    } else {
8709        hasOnePassingSelector = true;
8710    }
8711
8712    var rules = this.rules ? utils.copyArray(this.rules) : null,
8713        ruleset = new Ruleset(selectors, rules, this.strictImports, this.visibilityInfo()),
8714        rule, subRule;
8715
8716    ruleset.originalRuleset = this;
8717    ruleset.root = this.root;
8718    ruleset.firstRoot = this.firstRoot;
8719    ruleset.allowImports = this.allowImports;
8720
8721    if (this.debugInfo) {
8722        ruleset.debugInfo = this.debugInfo;
8723    }
8724
8725    if (!hasOnePassingSelector) {
8726        rules.length = 0;
8727    }
8728
8729    // inherit a function registry from the frames stack when possible;
8730    // otherwise from the global registry
8731    ruleset.functionRegistry = (function (frames) {
8732        var i = 0,
8733            n = frames.length,
8734            found;
8735        for ( ; i !== n ; ++i ) {
8736            found = frames[ i ].functionRegistry;
8737            if ( found ) { return found; }
8738        }
8739        return globalFunctionRegistry;
8740    }(context.frames)).inherit();
8741
8742    // push the current ruleset to the frames stack
8743    var ctxFrames = context.frames;
8744    ctxFrames.unshift(ruleset);
8745
8746    // currrent selectors
8747    var ctxSelectors = context.selectors;
8748    if (!ctxSelectors) {
8749        context.selectors = ctxSelectors = [];
8750    }
8751    ctxSelectors.unshift(this.selectors);
8752
8753    // Evaluate imports
8754    if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
8755        ruleset.evalImports(context);
8756    }
8757
8758    // Store the frames around mixin definitions,
8759    // so they can be evaluated like closures when the time comes.
8760    var rsRules = ruleset.rules;
8761    for (i = 0; (rule = rsRules[i]); i++) {
8762        if (rule.evalFirst) {
8763            rsRules[i] = rule.eval(context);
8764        }
8765    }
8766
8767    var mediaBlockCount = (context.mediaBlocks && context.mediaBlocks.length) || 0;
8768
8769    // Evaluate mixin calls.
8770    for (i = 0; (rule = rsRules[i]); i++) {
8771        if (rule.type === 'MixinCall') {
8772            /* jshint loopfunc:true */
8773            rules = rule.eval(context).filter(function(r) {
8774                if ((r instanceof Declaration) && r.variable) {
8775                    // do not pollute the scope if the variable is
8776                    // already there. consider returning false here
8777                    // but we need a way to "return" variable from mixins
8778                    return !(ruleset.variable(r.name));
8779                }
8780                return true;
8781            });
8782            rsRules.splice.apply(rsRules, [i, 1].concat(rules));
8783            i += rules.length - 1;
8784            ruleset.resetCache();
8785        } else if (rule.type ===  'VariableCall') {
8786            /* jshint loopfunc:true */
8787            rules = rule.eval(context).rules.filter(function(r) {
8788                if ((r instanceof Declaration) && r.variable) {
8789                    // do not pollute the scope at all
8790                    return false;
8791                }
8792                return true;
8793            });
8794            rsRules.splice.apply(rsRules, [i, 1].concat(rules));
8795            i += rules.length - 1;
8796            ruleset.resetCache();
8797        }
8798    }
8799
8800    // Evaluate everything else
8801    for (i = 0; (rule = rsRules[i]); i++) {
8802        if (!rule.evalFirst) {
8803            rsRules[i] = rule = rule.eval ? rule.eval(context) : rule;
8804        }
8805    }
8806
8807    // Evaluate everything else
8808    for (i = 0; (rule = rsRules[i]); i++) {
8809        // for rulesets, check if it is a css guard and can be removed
8810        if (rule instanceof Ruleset && rule.selectors && rule.selectors.length === 1) {
8811            // check if it can be folded in (e.g. & where)
8812            if (rule.selectors[0].isJustParentSelector()) {
8813                rsRules.splice(i--, 1);
8814
8815                for (var j = 0; (subRule = rule.rules[j]); j++) {
8816                    if (subRule instanceof Node) {
8817                        subRule.copyVisibilityInfo(rule.visibilityInfo());
8818                        if (!(subRule instanceof Declaration) || !subRule.variable) {
8819                            rsRules.splice(++i, 0, subRule);
8820                        }
8821                    }
8822                }
8823            }
8824        }
8825    }
8826
8827    // Pop the stack
8828    ctxFrames.shift();
8829    ctxSelectors.shift();
8830
8831    if (context.mediaBlocks) {
8832        for (i = mediaBlockCount; i < context.mediaBlocks.length; i++) {
8833            context.mediaBlocks[i].bubbleSelectors(selectors);
8834        }
8835    }
8836
8837    return ruleset;
8838};
8839Ruleset.prototype.evalImports = function(context) {
8840    var rules = this.rules, i, importRules;
8841    if (!rules) { return; }
8842
8843    for (i = 0; i < rules.length; i++) {
8844        if (rules[i].type === 'Import') {
8845            importRules = rules[i].eval(context);
8846            if (importRules && (importRules.length || importRules.length === 0)) {
8847                rules.splice.apply(rules, [i, 1].concat(importRules));
8848                i += importRules.length - 1;
8849            } else {
8850                rules.splice(i, 1, importRules);
8851            }
8852            this.resetCache();
8853        }
8854    }
8855};
8856Ruleset.prototype.makeImportant = function() {
8857    var result = new Ruleset(this.selectors, this.rules.map(function (r) {
8858        if (r.makeImportant) {
8859            return r.makeImportant();
8860        } else {
8861            return r;
8862        }
8863    }), this.strictImports, this.visibilityInfo());
8864
8865    return result;
8866};
8867Ruleset.prototype.matchArgs = function (args) {
8868    return !args || args.length === 0;
8869};
8870// lets you call a css selector with a guard
8871Ruleset.prototype.matchCondition = function (args, context) {
8872    var lastSelector = this.selectors[this.selectors.length - 1];
8873    if (!lastSelector.evaldCondition) {
8874        return false;
8875    }
8876    if (lastSelector.condition &&
8877        !lastSelector.condition.eval(
8878            new contexts.Eval(context,
8879                context.frames))) {
8880        return false;
8881    }
8882    return true;
8883};
8884Ruleset.prototype.resetCache = function () {
8885    this._rulesets = null;
8886    this._variables = null;
8887    this._properties = null;
8888    this._lookups = {};
8889};
8890Ruleset.prototype.variables = function () {
8891    if (!this._variables) {
8892        this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) {
8893            if (r instanceof Declaration && r.variable === true) {
8894                hash[r.name] = r;
8895            }
8896            // when evaluating variables in an import statement, imports have not been eval'd
8897            // so we need to go inside import statements.
8898            // guard against root being a string (in the case of inlined less)
8899            if (r.type === 'Import' && r.root && r.root.variables) {
8900                var vars = r.root.variables();
8901                for (var name in vars) {
8902                    if (vars.hasOwnProperty(name)) {
8903                        hash[name] = vars[name];
8904                    }
8905                }
8906            }
8907            return hash;
8908        }, {});
8909    }
8910    return this._variables;
8911};
8912Ruleset.prototype.properties = function () {
8913    if (!this._properties) {
8914        this._properties = !this.rules ? {} : this.rules.reduce(function (hash, r) {
8915            if (r instanceof Declaration && r.variable !== true) {
8916                var name = (r.name.length === 1) && (r.name[0] instanceof Keyword) ?
8917                    r.name[0].value : r.name;
8918                // Properties don't overwrite as they can merge
8919                if (!hash['$' + name]) {
8920                    hash['$' + name] = [ r ];
8921                }
8922                else {
8923                    hash['$' + name].push(r);
8924                }
8925            }
8926            return hash;
8927        }, {});
8928    }
8929    return this._properties;
8930};
8931Ruleset.prototype.variable = function (name) {
8932    var decl = this.variables()[name];
8933    if (decl) {
8934        return this.parseValue(decl);
8935    }
8936};
8937Ruleset.prototype.property = function (name) {
8938    var decl = this.properties()[name];
8939    if (decl) {
8940        return this.parseValue(decl);
8941    }
8942};
8943Ruleset.prototype.parseValue = function(toParse) {
8944    var self = this;
8945    function transformDeclaration(decl) {
8946        if (decl.value instanceof Anonymous && !decl.parsed) {
8947            if (typeof decl.value.value === 'string') {
8948                this.parse.parseNode(
8949                    decl.value.value,
8950                    ['value', 'important'], 
8951                    decl.value.getIndex(), 
8952                    decl.fileInfo(), 
8953                    function(err, result) {
8954                        if (err) {
8955                            decl.parsed = true;
8956                        }
8957                        if (result) {
8958                            decl.value = result[0];
8959                            decl.important = result[1] || '';
8960                            decl.parsed = true;
8961                        }
8962                    });
8963            } else {
8964                decl.parsed = true;
8965            }
8966
8967            return decl;
8968        }
8969        else {
8970            return decl;
8971        }
8972    }
8973    if (!Array.isArray(toParse)) {
8974        return transformDeclaration.call(self, toParse);
8975    }
8976    else {
8977        var nodes = [];
8978        toParse.forEach(function(n) {
8979            nodes.push(transformDeclaration.call(self, n));
8980        });
8981        return nodes;
8982    }
8983};
8984Ruleset.prototype.rulesets = function () {
8985    if (!this.rules) { return []; }
8986
8987    var filtRules = [], rules = this.rules,
8988        i, rule;
8989
8990    for (i = 0; (rule = rules[i]); i++) {
8991        if (rule.isRuleset) {
8992            filtRules.push(rule);
8993        }
8994    }
8995
8996    return filtRules;
8997};
8998Ruleset.prototype.prependRule = function (rule) {
8999    var rules = this.rules;
9000    if (rules) {
9001        rules.unshift(rule);
9002    } else {
9003        this.rules = [ rule ];
9004    }
9005    this.setParent(rule, this);
9006};
9007Ruleset.prototype.find = function (selector, self, filter) {
9008    self = self || this;
9009    var rules = [], match, foundMixins,
9010        key = selector.toCSS();
9011
9012    if (key in this._lookups) { return this._lookups[key]; }
9013
9014    this.rulesets().forEach(function (rule) {
9015        if (rule !== self) {
9016            for (var j = 0; j < rule.selectors.length; j++) {
9017                match = selector.match(rule.selectors[j]);
9018                if (match) {
9019                    if (selector.elements.length > match) {
9020                        if (!filter || filter(rule)) {
9021                            foundMixins = rule.find(new Selector(selector.elements.slice(match)), self, filter);
9022                            for (var i = 0; i < foundMixins.length; ++i) {
9023                                foundMixins[i].path.push(rule);
9024                            }
9025                            Array.prototype.push.apply(rules, foundMixins);
9026                        }
9027                    } else {
9028                        rules.push({ rule: rule, path: []});
9029                    }
9030                    break;
9031                }
9032            }
9033        }
9034    });
9035    this._lookups[key] = rules;
9036    return rules;
9037};
9038Ruleset.prototype.genCSS = function (context, output) {
9039    var i, j,
9040        charsetRuleNodes = [],
9041        ruleNodes = [],
9042        debugInfo,     // Line number debugging
9043        rule,
9044        path;
9045
9046    context.tabLevel = (context.tabLevel || 0);
9047
9048    if (!this.root) {
9049        context.tabLevel++;
9050    }
9051
9052    var tabRuleStr = context.compress ? '' : Array(context.tabLevel + 1).join('  '),
9053        tabSetStr = context.compress ? '' : Array(context.tabLevel).join('  '),
9054        sep;
9055
9056    var charsetNodeIndex = 0;
9057    var importNodeIndex = 0;
9058    for (i = 0; (rule = this.rules[i]); i++) {
9059        if (rule instanceof Comment) {
9060            if (importNodeIndex === i) {
9061                importNodeIndex++;
9062            }
9063            ruleNodes.push(rule);
9064        } else if (rule.isCharset && rule.isCharset()) {
9065            ruleNodes.splice(charsetNodeIndex, 0, rule);
9066            charsetNodeIndex++;
9067            importNodeIndex++;
9068        } else if (rule.type === 'Import') {
9069            ruleNodes.splice(importNodeIndex, 0, rule);
9070            importNodeIndex++;
9071        } else {
9072            ruleNodes.push(rule);
9073        }
9074    }
9075    ruleNodes = charsetRuleNodes.concat(ruleNodes);
9076
9077    // If this is the root node, we don't render
9078    // a selector, or {}.
9079    if (!this.root) {
9080        debugInfo = getDebugInfo(context, this, tabSetStr);
9081
9082        if (debugInfo) {
9083            output.add(debugInfo);
9084            output.add(tabSetStr);
9085        }
9086
9087        var paths = this.paths, pathCnt = paths.length,
9088            pathSubCnt;
9089
9090        sep = context.compress ? ',' : (',\n' + tabSetStr);
9091
9092        for (i = 0; i < pathCnt; i++) {
9093            path = paths[i];
9094            if (!(pathSubCnt = path.length)) { continue; }
9095            if (i > 0) { output.add(sep); }
9096
9097            context.firstSelector = true;
9098            path[0].genCSS(context, output);
9099
9100            context.firstSelector = false;
9101            for (j = 1; j < pathSubCnt; j++) {
9102                path[j].genCSS(context, output);
9103            }
9104        }
9105
9106        output.add((context.compress ? '{' : ' {\n') + tabRuleStr);
9107    }
9108
9109    // Compile rules and rulesets
9110    for (i = 0; (rule = ruleNodes[i]); i++) {
9111
9112        if (i + 1 === ruleNodes.length) {
9113            context.lastRule = true;
9114        }
9115
9116        var currentLastRule = context.lastRule;
9117        if (rule.isRulesetLike(rule)) {
9118            context.lastRule = false;
9119        }
9120
9121        if (rule.genCSS) {
9122            rule.genCSS(context, output);
9123        } else if (rule.value) {
9124            output.add(rule.value.toString());
9125        }
9126
9127        context.lastRule = currentLastRule;
9128
9129        if (!context.lastRule && rule.isVisible()) {
9130            output.add(context.compress ? '' : ('\n' + tabRuleStr));
9131        } else {
9132            context.lastRule = false;
9133        }
9134    }
9135
9136    if (!this.root) {
9137        output.add((context.compress ? '}' : '\n' + tabSetStr + '}'));
9138        context.tabLevel--;
9139    }
9140
9141    if (!output.isEmpty() && !context.compress && this.firstRoot) {
9142        output.add('\n');
9143    }
9144};
9145
9146Ruleset.prototype.joinSelectors = function (paths, context, selectors) {
9147    for (var s = 0; s < selectors.length; s++) {
9148        this.joinSelector(paths, context, selectors[s]);
9149    }
9150};
9151
9152Ruleset.prototype.joinSelector = function (paths, context, selector) {
9153
9154    function createParenthesis(elementsToPak, originalElement) {
9155        var replacementParen, j;
9156        if (elementsToPak.length === 0) {
9157            replacementParen = new Paren(elementsToPak[0]);
9158        } else {
9159            var insideParent = new Array(elementsToPak.length);
9160            for (j = 0; j < elementsToPak.length; j++) {
9161                insideParent[j] = new Element(null, elementsToPak[j], originalElement._index, originalElement._fileInfo);
9162            }
9163            replacementParen = new Paren(new Selector(insideParent));
9164        }
9165        return replacementParen;
9166    }
9167
9168    function createSelector(containedElement, originalElement) {
9169        var element, selector;
9170        element = new Element(null, containedElement, originalElement._index, originalElement._fileInfo);
9171        selector = new Selector([element]);
9172        return selector;
9173    }
9174
9175    // joins selector path from `beginningPath` with selector path in `addPath`
9176    // `replacedElement` contains element that is being replaced by `addPath`
9177    // returns concatenated path
9178    function addReplacementIntoPath(beginningPath, addPath, replacedElement, originalSelector) {
9179        var newSelectorPath, lastSelector, newJoinedSelector;
9180        // our new selector path
9181        newSelectorPath = [];
9182
9183        // construct the joined selector - if & is the first thing this will be empty,
9184        // if not newJoinedSelector will be the last set of elements in the selector
9185        if (beginningPath.length > 0) {
9186            newSelectorPath = utils.copyArray(beginningPath);
9187            lastSelector = newSelectorPath.pop();
9188            newJoinedSelector = originalSelector.createDerived(utils.copyArray(lastSelector.elements));
9189        }
9190        else {
9191            newJoinedSelector = originalSelector.createDerived([]);
9192        }
9193
9194        if (addPath.length > 0) {
9195            // /deep/ is a combinator that is valid without anything in front of it
9196            // so if the & does not have a combinator that is "" or " " then
9197            // and there is a combinator on the parent, then grab that.
9198            // this also allows + a { & .b { .a & { ... though not sure why you would want to do that
9199            var combinator = replacedElement.combinator, parentEl = addPath[0].elements[0];
9200            if (combinator.emptyOrWhitespace && !parentEl.combinator.emptyOrWhitespace) {
9201                combinator = parentEl.combinator;
9202            }
9203            // join the elements so far with the first part of the parent
9204            newJoinedSelector.elements.push(new Element(combinator, parentEl.value, replacedElement._index, replacedElement._fileInfo));
9205            newJoinedSelector.elements = newJoinedSelector.elements.concat(addPath[0].elements.slice(1));
9206        }
9207
9208        // now add the joined selector - but only if it is not empty
9209        if (newJoinedSelector.elements.length !== 0) {
9210            newSelectorPath.push(newJoinedSelector);
9211        }
9212
9213        // put together the parent selectors after the join (e.g. the rest of the parent)
9214        if (addPath.length > 1) {
9215            var restOfPath = addPath.slice(1);
9216            restOfPath = restOfPath.map(function (selector) {
9217                return selector.createDerived(selector.elements, []);
9218            });
9219            newSelectorPath = newSelectorPath.concat(restOfPath);
9220        }
9221        return newSelectorPath;
9222    }
9223
9224    // joins selector path from `beginningPath` with every selector path in `addPaths` array
9225    // `replacedElement` contains element that is being replaced by `addPath`
9226    // returns array with all concatenated paths
9227    function addAllReplacementsIntoPath( beginningPath, addPaths, replacedElement, originalSelector, result) {
9228        var j;
9229        for (j = 0; j < beginningPath.length; j++) {
9230            var newSelectorPath = addReplacementIntoPath(beginningPath[j], addPaths, replacedElement, originalSelector);
9231            result.push(newSelectorPath);
9232        }
9233        return result;
9234    }
9235
9236    function mergeElementsOnToSelectors(elements, selectors) {
9237        var i, sel;
9238
9239        if (elements.length === 0) {
9240            return ;
9241        }
9242        if (selectors.length === 0) {
9243            selectors.push([ new Selector(elements) ]);
9244            return;
9245        }
9246
9247        for (i = 0; (sel = selectors[i]); i++) {
9248            // if the previous thing in sel is a parent this needs to join on to it
9249            if (sel.length > 0) {
9250                sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
9251            }
9252            else {
9253                sel.push(new Selector(elements));
9254            }
9255        }
9256    }
9257
9258    // replace all parent selectors inside `inSelector` by content of `context` array
9259    // resulting selectors are returned inside `paths` array
9260    // returns true if `inSelector` contained at least one parent selector
9261    function replaceParentSelector(paths, context, inSelector) {
9262        // The paths are [[Selector]]
9263        // The first list is a list of comma separated selectors
9264        // The inner list is a list of inheritance separated selectors
9265        // e.g.
9266        // .a, .b {
9267        //   .c {
9268        //   }
9269        // }
9270        // == [[.a] [.c]] [[.b] [.c]]
9271        //
9272        var i, j, k, currentElements, newSelectors, selectorsMultiplied, sel, el, hadParentSelector = false, length, lastSelector;
9273        function findNestedSelector(element) {
9274            var maybeSelector;
9275            if (!(element.value instanceof Paren)) {
9276                return null;
9277            }
9278
9279            maybeSelector = element.value.value;
9280            if (!(maybeSelector instanceof Selector)) {
9281                return null;
9282            }
9283
9284            return maybeSelector;
9285        }
9286
9287        // the elements from the current selector so far
9288        currentElements = [];
9289        // the current list of new selectors to add to the path.
9290        // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
9291        // by the parents
9292        newSelectors = [
9293            []
9294        ];
9295
9296        for (i = 0; (el = inSelector.elements[i]); i++) {
9297            // non parent reference elements just get added
9298            if (el.value !== '&') {
9299                var nestedSelector = findNestedSelector(el);
9300                if (nestedSelector != null) {
9301                    // merge the current list of non parent selector elements
9302                    // on to the current list of selectors to add
9303                    mergeElementsOnToSelectors(currentElements, newSelectors);
9304
9305                    var nestedPaths = [], replaced, replacedNewSelectors = [];
9306                    replaced = replaceParentSelector(nestedPaths, context, nestedSelector);
9307                    hadParentSelector = hadParentSelector || replaced;
9308                    // the nestedPaths array should have only one member - replaceParentSelector does not multiply selectors
9309                    for (k = 0; k < nestedPaths.length; k++) {
9310                        var replacementSelector = createSelector(createParenthesis(nestedPaths[k], el), el);
9311                        addAllReplacementsIntoPath(newSelectors, [replacementSelector], el, inSelector, replacedNewSelectors);
9312                    }
9313                    newSelectors = replacedNewSelectors;
9314                    currentElements = [];
9315
9316                } else {
9317                    currentElements.push(el);
9318                }
9319
9320            } else {
9321                hadParentSelector = true;
9322                // the new list of selectors to add
9323                selectorsMultiplied = [];
9324
9325                // merge the current list of non parent selector elements
9326                // on to the current list of selectors to add
9327                mergeElementsOnToSelectors(currentElements, newSelectors);
9328
9329                // loop through our current selectors
9330                for (j = 0; j < newSelectors.length; j++) {
9331                    sel = newSelectors[j];
9332                    // if we don't have any parent paths, the & might be in a mixin so that it can be used
9333                    // whether there are parents or not
9334                    if (context.length === 0) {
9335                        // the combinator used on el should now be applied to the next element instead so that
9336                        // it is not lost
9337                        if (sel.length > 0) {
9338                            sel[0].elements.push(new Element(el.combinator, '', el._index, el._fileInfo));
9339                        }
9340                        selectorsMultiplied.push(sel);
9341                    }
9342                    else {
9343                        // and the parent selectors
9344                        for (k = 0; k < context.length; k++) {
9345                            // We need to put the current selectors
9346                            // then join the last selector's elements on to the parents selectors
9347                            var newSelectorPath = addReplacementIntoPath(sel, context[k], el, inSelector);
9348                            // add that to our new set of selectors
9349                            selectorsMultiplied.push(newSelectorPath);
9350                        }
9351                    }
9352                }
9353
9354                // our new selectors has been multiplied, so reset the state
9355                newSelectors = selectorsMultiplied;
9356                currentElements = [];
9357            }
9358        }
9359
9360        // if we have any elements left over (e.g. .a& .b == .b)
9361        // add them on to all the current selectors
9362        mergeElementsOnToSelectors(currentElements, newSelectors);
9363
9364        for (i = 0; i < newSelectors.length; i++) {
9365            length = newSelectors[i].length;
9366            if (length > 0) {
9367                paths.push(newSelectors[i]);
9368                lastSelector = newSelectors[i][length - 1];
9369                newSelectors[i][length - 1] = lastSelector.createDerived(lastSelector.elements, inSelector.extendList);
9370            }
9371        }
9372
9373        return hadParentSelector;
9374    }
9375
9376    function deriveSelector(visibilityInfo, deriveFrom) {
9377        var newSelector = deriveFrom.createDerived(deriveFrom.elements, deriveFrom.extendList, deriveFrom.evaldCondition);
9378        newSelector.copyVisibilityInfo(visibilityInfo);
9379        return newSelector;
9380    }
9381
9382    // joinSelector code follows
9383    var i, newPaths, hadParentSelector;
9384
9385    newPaths = [];
9386    hadParentSelector = replaceParentSelector(newPaths, context, selector);
9387
9388    if (!hadParentSelector) {
9389        if (context.length > 0) {
9390            newPaths = [];
9391            for (i = 0; i < context.length; i++) {
9392
9393                var concatenated = context[i].map(deriveSelector.bind(this, selector.visibilityInfo()));
9394
9395                concatenated.push(selector);
9396                newPaths.push(concatenated);
9397            }
9398        }
9399        else {
9400            newPaths = [[selector]];
9401        }
9402    }
9403
9404    for (i = 0; i < newPaths.length; i++) {
9405        paths.push(newPaths[i]);
9406    }
9407
9408};
9409module.exports = Ruleset;
9410
9411},{"../contexts":12,"../functions/default":24,"../functions/function-registry":26,"../utils":86,"./anonymous":48,"./comment":55,"./debug-info":57,"./declaration":58,"./element":61,"./keyword":68,"./node":73,"./paren":75,"./selector":79}],79:[function(require,module,exports){
9412var Node = require('./node'),
9413    Element = require('./element'),
9414    LessError = require('../less-error');
9415
9416var Selector = function (elements, extendList, condition, index, currentFileInfo, visibilityInfo) {
9417    this.extendList = extendList;
9418    this.condition = condition;
9419    this.evaldCondition = !condition;
9420    this._index = index;
9421    this._fileInfo = currentFileInfo;
9422    this.elements = this.getElements(elements);
9423    this.mixinElements_ = undefined;
9424    this.copyVisibilityInfo(visibilityInfo);
9425    this.setParent(this.elements, this);
9426};
9427Selector.prototype = new Node();
9428Selector.prototype.type = 'Selector';
9429Selector.prototype.accept = function (visitor) {
9430    if (this.elements) {
9431        this.elements = visitor.visitArray(this.elements);
9432    }
9433    if (this.extendList) {
9434        this.extendList = visitor.visitArray(this.extendList);
9435    }
9436    if (this.condition) {
9437        this.condition = visitor.visit(this.condition);
9438    }
9439};
9440Selector.prototype.createDerived = function(elements, extendList, evaldCondition) {
9441    elements = this.getElements(elements);
9442    var newSelector = new Selector(elements, extendList || this.extendList,
9443        null, this.getIndex(), this.fileInfo(), this.visibilityInfo());
9444    newSelector.evaldCondition = (evaldCondition != null) ? evaldCondition : this.evaldCondition;
9445    newSelector.mediaEmpty = this.mediaEmpty;
9446    return newSelector;
9447};
9448Selector.prototype.getElements = function(els) {
9449    if (typeof els === 'string') {
9450        this.parse.parseNode(
9451            els, 
9452            ['selector'],
9453            this._index, 
9454            this._fileInfo, 
9455            function(err, result) {
9456                if (err) {
9457                    throw new LessError({
9458                        index: err.index,
9459                        message: err.message
9460                    }, this.parse.imports, this._fileInfo.filename);
9461                }
9462                els = result[0].elements;
9463            });
9464    }
9465    return els;
9466};
9467Selector.prototype.createEmptySelectors = function() {
9468    var el = new Element('', '&', this._index, this._fileInfo),
9469        sels = [new Selector([el], null, null, this._index, this._fileInfo)];
9470    sels[0].mediaEmpty = true;
9471    return sels;
9472};
9473Selector.prototype.match = function (other) {
9474    var elements = this.elements,
9475        len = elements.length,
9476        olen, i;
9477
9478    other = other.mixinElements();
9479    olen = other.length;
9480    if (olen === 0 || len < olen) {
9481        return 0;
9482    } else {
9483        for (i = 0; i < olen; i++) {
9484            if (elements[i].value !== other[i]) {
9485                return 0;
9486            }
9487        }
9488    }
9489
9490    return olen; // return number of matched elements
9491};
9492Selector.prototype.mixinElements = function() {
9493    if (this.mixinElements_) {
9494        return this.mixinElements_;
9495    }
9496
9497    var elements = this.elements.map( function(v) {
9498        return v.combinator.value + (v.value.value || v.value);
9499    }).join('').match(/[,&#\*\.\w-]([\w-]|(\\.))*/g);
9500
9501    if (elements) {
9502        if (elements[0] === '&') {
9503            elements.shift();
9504        }
9505    } else {
9506        elements = [];
9507    }
9508
9509    return (this.mixinElements_ = elements);
9510};
9511Selector.prototype.isJustParentSelector = function() {
9512    return !this.mediaEmpty &&
9513        this.elements.length === 1 &&
9514        this.elements[0].value === '&' &&
9515        (this.elements[0].combinator.value === ' ' || this.elements[0].combinator.value === '');
9516};
9517Selector.prototype.eval = function (context) {
9518    var evaldCondition = this.condition && this.condition.eval(context),
9519        elements = this.elements, extendList = this.extendList;
9520
9521    elements = elements && elements.map(function (e) { return e.eval(context); });
9522    extendList = extendList && extendList.map(function(extend) { return extend.eval(context); });
9523
9524    return this.createDerived(elements, extendList, evaldCondition);
9525};
9526Selector.prototype.genCSS = function (context, output) {
9527    var i, element;
9528    if ((!context || !context.firstSelector) && this.elements[0].combinator.value === '') {
9529        output.add(' ', this.fileInfo(), this.getIndex());
9530    }
9531    for (i = 0; i < this.elements.length; i++) {
9532        element = this.elements[i];
9533        element.genCSS(context, output);
9534    }
9535};
9536Selector.prototype.getIsOutput = function() {
9537    return this.evaldCondition;
9538};
9539module.exports = Selector;
9540
9541},{"../less-error":36,"./element":61,"./node":73}],80:[function(require,module,exports){
9542var Node = require('./node');
9543
9544var UnicodeDescriptor = function (value) {
9545    this.value = value;
9546};
9547UnicodeDescriptor.prototype = new Node();
9548UnicodeDescriptor.prototype.type = 'UnicodeDescriptor';
9549
9550module.exports = UnicodeDescriptor;
9551
9552},{"./node":73}],81:[function(require,module,exports){
9553var Node = require('./node'),
9554    unitConversions = require('../data/unit-conversions'),
9555    utils = require('../utils');
9556
9557var Unit = function (numerator, denominator, backupUnit) {
9558    this.numerator = numerator ? utils.copyArray(numerator).sort() : [];
9559    this.denominator = denominator ? utils.copyArray(denominator).sort() : [];
9560    if (backupUnit) {
9561        this.backupUnit = backupUnit;
9562    } else if (numerator && numerator.length) {
9563        this.backupUnit = numerator[0];
9564    }
9565};
9566
9567Unit.prototype = new Node();
9568Unit.prototype.type = 'Unit';
9569Unit.prototype.clone = function () {
9570    return new Unit(utils.copyArray(this.numerator), utils.copyArray(this.denominator), this.backupUnit);
9571};
9572Unit.prototype.genCSS = function (context, output) {
9573    // Dimension checks the unit is singular and throws an error if in strict math mode.
9574    var strictUnits = context && context.strictUnits;
9575    if (this.numerator.length === 1) {
9576        output.add(this.numerator[0]); // the ideal situation
9577    } else if (!strictUnits && this.backupUnit) {
9578        output.add(this.backupUnit);
9579    } else if (!strictUnits && this.denominator.length) {
9580        output.add(this.denominator[0]);
9581    }
9582};
9583Unit.prototype.toString = function () {
9584    var i, returnStr = this.numerator.join('*');
9585    for (i = 0; i < this.denominator.length; i++) {
9586        returnStr += '/' + this.denominator[i];
9587    }
9588    return returnStr;
9589};
9590Unit.prototype.compare = function (other) {
9591    return this.is(other.toString()) ? 0 : undefined;
9592};
9593Unit.prototype.is = function (unitString) {
9594    return this.toString().toUpperCase() === unitString.toUpperCase();
9595};
9596Unit.prototype.isLength = function () {
9597    return RegExp('^(px|em|ex|ch|rem|in|cm|mm|pc|pt|ex|vw|vh|vmin|vmax)$', 'gi').test(this.toCSS());
9598};
9599Unit.prototype.isEmpty = function () {
9600    return this.numerator.length === 0 && this.denominator.length === 0;
9601};
9602Unit.prototype.isSingular = function() {
9603    return this.numerator.length <= 1 && this.denominator.length === 0;
9604};
9605Unit.prototype.map = function(callback) {
9606    var i;
9607
9608    for (i = 0; i < this.numerator.length; i++) {
9609        this.numerator[i] = callback(this.numerator[i], false);
9610    }
9611
9612    for (i = 0; i < this.denominator.length; i++) {
9613        this.denominator[i] = callback(this.denominator[i], true);
9614    }
9615};
9616Unit.prototype.usedUnits = function() {
9617    var group, result = {}, mapUnit, groupName;
9618
9619    mapUnit = function (atomicUnit) {
9620        /* jshint loopfunc:true */
9621        if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
9622            result[groupName] = atomicUnit;
9623        }
9624
9625        return atomicUnit;
9626    };
9627
9628    for (groupName in unitConversions) {
9629        if (unitConversions.hasOwnProperty(groupName)) {
9630            group = unitConversions[groupName];
9631
9632            this.map(mapUnit);
9633        }
9634    }
9635
9636    return result;
9637};
9638Unit.prototype.cancel = function () {
9639    var counter = {}, atomicUnit, i;
9640
9641    for (i = 0; i < this.numerator.length; i++) {
9642        atomicUnit = this.numerator[i];
9643        counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
9644    }
9645
9646    for (i = 0; i < this.denominator.length; i++) {
9647        atomicUnit = this.denominator[i];
9648        counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
9649    }
9650
9651    this.numerator = [];
9652    this.denominator = [];
9653
9654    for (atomicUnit in counter) {
9655        if (counter.hasOwnProperty(atomicUnit)) {
9656            var count = counter[atomicUnit];
9657
9658            if (count > 0) {
9659                for (i = 0; i < count; i++) {
9660                    this.numerator.push(atomicUnit);
9661                }
9662            } else if (count < 0) {
9663                for (i = 0; i < -count; i++) {
9664                    this.denominator.push(atomicUnit);
9665                }
9666            }
9667        }
9668    }
9669
9670    this.numerator.sort();
9671    this.denominator.sort();
9672};
9673module.exports = Unit;
9674
9675},{"../data/unit-conversions":15,"../utils":86,"./node":73}],82:[function(require,module,exports){
9676var Node = require('./node');
9677
9678var URL = function (val, index, currentFileInfo, isEvald) {
9679    this.value = val;
9680    this._index = index;
9681    this._fileInfo = currentFileInfo;
9682    this.isEvald = isEvald;
9683};
9684URL.prototype = new Node();
9685URL.prototype.type = 'Url';
9686URL.prototype.accept = function (visitor) {
9687    this.value = visitor.visit(this.value);
9688};
9689URL.prototype.genCSS = function (context, output) {
9690    output.add('url(');
9691    this.value.genCSS(context, output);
9692    output.add(')');
9693};
9694URL.prototype.eval = function (context) {
9695    var val = this.value.eval(context),
9696        rootpath;
9697
9698    if (!this.isEvald) {
9699        // Add the base path if the URL is relative
9700        rootpath = this.fileInfo() && this.fileInfo().rootpath;
9701        if (rootpath &&
9702            typeof val.value === 'string' &&
9703            context.isPathRelative(val.value)) {
9704
9705            if (!val.quote) {
9706                rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return '\\' + match; });
9707            }
9708            val.value = rootpath + val.value;
9709        }
9710
9711        val.value = context.normalizePath(val.value);
9712
9713        // Add url args if enabled
9714        if (context.urlArgs) {
9715            if (!val.value.match(/^\s*data:/)) {
9716                var delimiter = val.value.indexOf('?') === -1 ? '?' : '&';
9717                var urlArgs = delimiter + context.urlArgs;
9718                if (val.value.indexOf('#') !== -1) {
9719                    val.value = val.value.replace('#', urlArgs + '#');
9720                } else {
9721                    val.value += urlArgs;
9722                }
9723            }
9724        }
9725    }
9726
9727    return new URL(val, this.getIndex(), this.fileInfo(), true);
9728};
9729module.exports = URL;
9730
9731},{"./node":73}],83:[function(require,module,exports){
9732var Node = require('./node');
9733
9734var Value = function (value) {
9735    if (!value) {
9736        throw new Error('Value requires an array argument');
9737    }
9738    if (!Array.isArray(value)) {
9739        this.value = [ value ];
9740    }
9741    else {
9742        this.value = value;
9743    }
9744};
9745Value.prototype = new Node();
9746Value.prototype.type = 'Value';
9747Value.prototype.accept = function (visitor) {
9748    if (this.value) {
9749        this.value = visitor.visitArray(this.value);
9750    }
9751};
9752Value.prototype.eval = function (context) {
9753    if (this.value.length === 1) {
9754        return this.value[0].eval(context);
9755    } else {
9756        return new Value(this.value.map(function (v) {
9757            return v.eval(context);
9758        }));
9759    }
9760};
9761Value.prototype.genCSS = function (context, output) {
9762    var i;
9763    for (i = 0; i < this.value.length; i++) {
9764        this.value[i].genCSS(context, output);
9765        if (i + 1 < this.value.length) {
9766            output.add((context && context.compress) ? ',' : ', ');
9767        }
9768    }
9769};
9770module.exports = Value;
9771
9772},{"./node":73}],84:[function(require,module,exports){
9773var Node = require('./node'),
9774    Variable = require('./variable');
9775
9776var VariableCall = function (variable) {
9777    this.variable = variable;
9778    this.allowRoot = true;
9779};
9780VariableCall.prototype = new Node();
9781VariableCall.prototype.type = 'VariableCall';
9782VariableCall.prototype.eval = function (context) {
9783    var detachedRuleset = new Variable(this.variable).eval(context);
9784    return detachedRuleset.callEval(context);
9785};
9786module.exports = VariableCall;
9787
9788},{"./node":73,"./variable":85}],85:[function(require,module,exports){
9789var Node = require('./node');
9790
9791var Variable = function (name, index, currentFileInfo) {
9792    this.name = name;
9793    this._index = index;
9794    this._fileInfo = currentFileInfo;
9795};
9796Variable.prototype = new Node();
9797Variable.prototype.type = 'Variable';
9798Variable.prototype.eval = function (context) {
9799    var variable, name = this.name;
9800
9801    if (name.indexOf('@@') === 0) {
9802        name = '@' + new Variable(name.slice(1), this.getIndex(), this.fileInfo()).eval(context).value;
9803    }
9804
9805    if (this.evaluating) {
9806        throw { type: 'Name',
9807            message: 'Recursive variable definition for ' + name,
9808            filename: this.fileInfo().filename,
9809            index: this.getIndex() };
9810    }
9811
9812    this.evaluating = true;
9813
9814    variable = this.find(context.frames, function (frame) {
9815        var v = frame.variable(name);
9816        if (v) {
9817            if (v.important) {
9818                var importantScope = context.importantScope[context.importantScope.length - 1];
9819                importantScope.important = v.important;
9820            }
9821            return v.value.eval(context);
9822        }
9823    });
9824    if (variable) {
9825        this.evaluating = false;
9826        return variable;
9827    } else {
9828        throw { type: 'Name',
9829            message: 'variable ' + name + ' is undefined',
9830            filename: this.fileInfo().filename,
9831            index: this.getIndex() };
9832    }
9833};
9834Variable.prototype.find = function (obj, fun) {
9835    for (var i = 0, r; i < obj.length; i++) {
9836        r = fun.call(obj, obj[i]);
9837        if (r) { return r; }
9838    }
9839    return null;
9840};
9841module.exports = Variable;
9842
9843},{"./node":73}],86:[function(require,module,exports){
9844/* jshint proto: true */
9845module.exports = {
9846    getLocation: function(index, inputStream) {
9847        var n = index + 1,
9848            line = null,
9849            column = -1;
9850
9851        while (--n >= 0 && inputStream.charAt(n) !== '\n') {
9852            column++;
9853        }
9854
9855        if (typeof index === 'number') {
9856            line = (inputStream.slice(0, index).match(/\n/g) || '').length;
9857        }
9858
9859        return {
9860            line: line,
9861            column: column
9862        };
9863    },
9864    copyArray: function(arr) {
9865        var i, length = arr.length,
9866            copy = new Array(length);
9867        
9868        for (i = 0; i < length; i++) {
9869            copy[i] = arr[i];
9870        }
9871        return copy;
9872    },
9873    clone: function (obj) {
9874        var cloned = {};
9875        for (var prop in obj) {
9876            if (obj.hasOwnProperty(prop)) {
9877                cloned[prop] = obj[prop];
9878            }
9879        }
9880        return cloned;
9881    },
9882    defaults: function(obj1, obj2) {
9883        if (!obj2._defaults || obj2._defaults !== obj1) {
9884            for (var prop in obj1) {
9885                if (obj1.hasOwnProperty(prop)) {
9886                    if (!obj2.hasOwnProperty(prop)) {
9887                        obj2[prop] = obj1[prop];
9888                    }
9889                    else if (Array.isArray(obj1[prop])
9890                        && Array.isArray(obj2[prop])) {
9891
9892                        obj1[prop].forEach(function(p) {
9893                            if (obj2[prop].indexOf(p) === -1) {
9894                                obj2[prop].push(p);
9895                            }
9896                        });
9897                    }
9898                }
9899            }
9900        }
9901        obj2._defaults = obj1;
9902        return obj2;
9903    },
9904    merge: function(obj1, obj2) {
9905        for (var prop in obj2) {
9906            if (obj2.hasOwnProperty(prop)) {
9907                obj1[prop] = obj2[prop];
9908            }
9909        }
9910        return obj1;
9911    }
9912};
9913
9914},{}],87:[function(require,module,exports){
9915var tree = require('../tree'),
9916    Visitor = require('./visitor'),
9917    logger = require('../logger'),
9918    utils = require('../utils');
9919
9920/* jshint loopfunc:true */
9921
9922var ExtendFinderVisitor = function() {
9923    this._visitor = new Visitor(this);
9924    this.contexts = [];
9925    this.allExtendsStack = [[]];
9926};
9927
9928ExtendFinderVisitor.prototype = {
9929    run: function (root) {
9930        root = this._visitor.visit(root);
9931        root.allExtends = this.allExtendsStack[0];
9932        return root;
9933    },
9934    visitDeclaration: function (declNode, visitArgs) {
9935        visitArgs.visitDeeper = false;
9936    },
9937    visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
9938        visitArgs.visitDeeper = false;
9939    },
9940    visitRuleset: function (rulesetNode, visitArgs) {
9941        if (rulesetNode.root) {
9942            return;
9943        }
9944
9945        var i, j, extend, allSelectorsExtendList = [], extendList;
9946
9947        // get &:extend(.a); rules which apply to all selectors in this ruleset
9948        var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
9949        for (i = 0; i < ruleCnt; i++) {
9950            if (rulesetNode.rules[i] instanceof tree.Extend) {
9951                allSelectorsExtendList.push(rules[i]);
9952                rulesetNode.extendOnEveryPath = true;
9953            }
9954        }
9955
9956        // now find every selector and apply the extends that apply to all extends
9957        // and the ones which apply to an individual extend
9958        var paths = rulesetNode.paths;
9959        for (i = 0; i < paths.length; i++) {
9960            var selectorPath = paths[i],
9961                selector = selectorPath[selectorPath.length - 1],
9962                selExtendList = selector.extendList;
9963
9964            extendList = selExtendList ? utils.copyArray(selExtendList).concat(allSelectorsExtendList)
9965                                       : allSelectorsExtendList;
9966
9967            if (extendList) {
9968                extendList = extendList.map(function(allSelectorsExtend) {
9969                    return allSelectorsExtend.clone();
9970                });
9971            }
9972
9973            for (j = 0; j < extendList.length; j++) {
9974                this.foundExtends = true;
9975                extend = extendList[j];
9976                extend.findSelfSelectors(selectorPath);
9977                extend.ruleset = rulesetNode;
9978                if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
9979                this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);
9980            }
9981        }
9982
9983        this.contexts.push(rulesetNode.selectors);
9984    },
9985    visitRulesetOut: function (rulesetNode) {
9986        if (!rulesetNode.root) {
9987            this.contexts.length = this.contexts.length - 1;
9988        }
9989    },
9990    visitMedia: function (mediaNode, visitArgs) {
9991        mediaNode.allExtends = [];
9992        this.allExtendsStack.push(mediaNode.allExtends);
9993    },
9994    visitMediaOut: function (mediaNode) {
9995        this.allExtendsStack.length = this.allExtendsStack.length - 1;
9996    },
9997    visitAtRule: function (atRuleNode, visitArgs) {
9998        atRuleNode.allExtends = [];
9999        this.allExtendsStack.push(atRuleNode.allExtends);
10000    },
10001    visitAtRuleOut: function (atRuleNode) {
10002        this.allExtendsStack.length = this.allExtendsStack.length - 1;
10003    }
10004};
10005
10006var ProcessExtendsVisitor = function() {
10007    this._visitor = new Visitor(this);
10008};
10009
10010ProcessExtendsVisitor.prototype = {
10011    run: function(root) {
10012        var extendFinder = new ExtendFinderVisitor();
10013        this.extendIndices = {};
10014        extendFinder.run(root);
10015        if (!extendFinder.foundExtends) { return root; }
10016        root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
10017        this.allExtendsStack = [root.allExtends];
10018        var newRoot = this._visitor.visit(root);
10019        this.checkExtendsForNonMatched(root.allExtends);
10020        return newRoot;
10021    },
10022    checkExtendsForNonMatched: function(extendList) {
10023        var indices = this.extendIndices;
10024        extendList.filter(function(extend) {
10025            return !extend.hasFoundMatches && extend.parent_ids.length == 1;
10026        }
10026).forEach(function(extend) {
10027            var selector = '_unknown_';
10028            try {
10029                selector = extend.selector.toCSS({});
10030            }
10031            catch (_) {}
10032
10033            if (!indices[extend.index + ' ' + selector]) {
10034                indices[extend.index + ' ' + selector] = true;
10035                logger.warn('extend \'' + selector + '\' has no matches');
10036            }
10037        });
10038    },
10039    doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
10040        //
10041        // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering
10042        // and pasting the selector we would do normally, but we are also adding an extend with the same target selector
10043        // this means this new extend can then go and alter other extends
10044        //
10045        // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
10046        // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already
10047        // processed if we look at each selector at a time, as is done in visitRuleset
10048
10049        var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath,
10050            extend, targetExtend, newExtend;
10051
10052        iterationCount = iterationCount || 0;
10053
10054        // loop through comparing every extend with every target extend.
10055        // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
10056        // e.g.  .a:extend(.b) {}  and .b:extend(.c) {} then the first extend extends the second one
10057        // and the second is the target.
10058        // the separation into two lists allows us to process a subset of chains with a bigger set, as is the
10059        // case when processing media queries
10060        for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {
10061            for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {
10062
10063                extend = extendsList[extendIndex];
10064                targetExtend = extendsListTarget[targetExtendIndex];
10065
10066                // look for circular references
10067                if ( extend.parent_ids.indexOf( targetExtend.object_id ) >= 0 ) { continue; }
10068
10069                // find a match in the target extends self selector (the bit before :extend)
10070                selectorPath = [targetExtend.selfSelectors[0]];
10071                matches = extendVisitor.findMatch(extend, selectorPath);
10072
10073                if (matches.length) {
10074                    extend.hasFoundMatches = true;
10075
10076                    // we found a match, so for each self selector..
10077                    extend.selfSelectors.forEach(function(selfSelector) {
10078                        var info = targetExtend.visibilityInfo();
10079
10080                        // process the extend as usual
10081                        newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible());
10082
10083                        // but now we create a new extend from it
10084                        newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info);
10085                        newExtend.selfSelectors = newSelector;
10086
10087                        // add the extend onto the list of extends for that selector
10088                        newSelector[newSelector.length - 1].extendList = [newExtend];
10089
10090                        // record that we need to add it.
10091                        extendsToAdd.push(newExtend);
10092                        newExtend.ruleset = targetExtend.ruleset;
10093
10094                        // remember its parents for circular references
10095                        newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);
10096
10097                        // only process the selector once.. if we have :extend(.a,.b) then multiple
10098                        // extends will look at the same selector path, so when extending
10099                        // we know that any others will be duplicates in terms of what is added to the css
10100                        if (targetExtend.firstExtendOnThisSelectorPath) {
10101                            newExtend.firstExtendOnThisSelectorPath = true;
10102                            targetExtend.ruleset.paths.push(newSelector);
10103                        }
10104                    });
10105                }
10106            }
10107        }
10108
10109        if (extendsToAdd.length) {
10110            // try to detect circular references to stop a stack overflow.
10111            // may no longer be needed.
10112            this.extendChainCount++;
10113            if (iterationCount > 100) {
10114                var selectorOne = '{unable to calculate}';
10115                var selectorTwo = '{unable to calculate}';
10116                try {
10117                    selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
10118                    selectorTwo = extendsToAdd[0].selector.toCSS();
10119                }
10120                catch (e) {}
10121                throw { message: 'extend circular reference detected. One of the circular extends is currently:' +
10122                    selectorOne + ':extend(' + selectorTwo + ')'};
10123            }
10124
10125            // now process the new extends on the existing rules so that we can handle a extending b extending c extending
10126            // d extending e...
10127            return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));
10128        } else {
10129            return extendsToAdd;
10130        }
10131    },
10132    visitDeclaration: function (ruleNode, visitArgs) {
10133        visitArgs.visitDeeper = false;
10134    },
10135    visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
10136        visitArgs.visitDeeper = false;
10137    },
10138    visitSelector: function (selectorNode, visitArgs) {
10139        visitArgs.visitDeeper = false;
10140    },
10141    visitRuleset: function (rulesetNode, visitArgs) {
10142        if (rulesetNode.root) {
10143            return;
10144        }
10145        var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length - 1],
10146            selectorsToAdd = [], extendVisitor = this, selectorPath;
10147
10148        // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
10149
10150        for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
10151            for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
10152                selectorPath = rulesetNode.paths[pathIndex];
10153
10154                // extending extends happens initially, before the main pass
10155                if (rulesetNode.extendOnEveryPath) { continue; }
10156                var extendList = selectorPath[selectorPath.length - 1].extendList;
10157                if (extendList && extendList.length) { continue; }
10158
10159                matches = this.findMatch(allExtends[extendIndex], selectorPath);
10160
10161                if (matches.length) {
10162                    allExtends[extendIndex].hasFoundMatches = true;
10163
10164                    allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
10165                        var extendedSelectors;
10166                        extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible());
10167                        selectorsToAdd.push(extendedSelectors);
10168                    });
10169                }
10170            }
10171        }
10172        rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
10173    },
10174    findMatch: function (extend, haystackSelectorPath) {
10175        //
10176        // look through the haystack selector path to try and find the needle - extend.selector
10177        // returns an array of selector matches that can then be replaced
10178        //
10179        var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
10180            targetCombinator, i,
10181            extendVisitor = this,
10182            needleElements = extend.selector.elements,
10183            potentialMatches = [], potentialMatch, matches = [];
10184
10185        // loop through the haystack elements
10186        for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
10187            hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
10188
10189            for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
10190
10191                haystackElement = hackstackSelector.elements[hackstackElementIndex];
10192
10193                // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
10194                if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
10195                    potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,
10196                        initialCombinator: haystackElement.combinator});
10197                }
10198
10199                for (i = 0; i < potentialMatches.length; i++) {
10200                    potentialMatch = potentialMatches[i];
10201
10202                    // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
10203                    // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to
10204                    // work out what the resulting combinator will be
10205                    targetCombinator = haystackElement.combinator.value;
10206                    if (targetCombinator === '' && hackstackElementIndex === 0) {
10207                        targetCombinator = ' ';
10208                    }
10209
10210                    // if we don't match, null our match to indicate failure
10211                    if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
10212                        (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
10213                        potentialMatch = null;
10214                    } else {
10215                        potentialMatch.matched++;
10216                    }
10217
10218                    // if we are still valid and have finished, test whether we have elements after and whether these are allowed
10219                    if (potentialMatch) {
10220                        potentialMatch.finished = potentialMatch.matched === needleElements.length;
10221                        if (potentialMatch.finished &&
10222                            (!extend.allowAfter &&
10223                                (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) {
10224                            potentialMatch = null;
10225                        }
10226                    }
10227                    // if null we remove, if not, we are still valid, so either push as a valid match or continue
10228                    if (potentialMatch) {
10229                        if (potentialMatch.finished) {
10230                            potentialMatch.length = needleElements.length;
10231                            potentialMatch.endPathIndex = haystackSelectorIndex;
10232                            potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
10233                            potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
10234                            matches.push(potentialMatch);
10235                        }
10236                    } else {
10237                        potentialMatches.splice(i, 1);
10238                        i--;
10239                    }
10240                }
10241            }
10242        }
10243        return matches;
10244    },
10245    isElementValuesEqual: function(elementValue1, elementValue2) {
10246        if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') {
10247            return elementValue1 === elementValue2;
10248        }
10249        if (elementValue1 instanceof tree.Attribute) {
10250            if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
10251                return false;
10252            }
10253            if (!elementValue1.value || !elementValue2.value) {
10254                if (elementValue1.value || elementValue2.value) {
10255                    return false;
10256                }
10257                return true;
10258            }
10259            elementValue1 = elementValue1.value.value || elementValue1.value;
10260            elementValue2 = elementValue2.value.value || elementValue2.value;
10261            return elementValue1 === elementValue2;
10262        }
10263        elementValue1 = elementValue1.value;
10264        elementValue2 = elementValue2.value;
10265        if (elementValue1 instanceof tree.Selector) {
10266            if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
10267                return false;
10268            }
10269            for (var i = 0; i  < elementValue1.elements.length; i++) {
10270                if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
10271                    if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
10272                        return false;
10273                    }
10274                }
10275                if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
10276                    return false;
10277                }
10278            }
10279            return true;
10280        }
10281        return false;
10282    },
10283    extendSelector:function (matches, selectorPath, replacementSelector, isVisible) {
10284
10285        // for a set of matches, replace each match with the replacement selector
10286
10287        var currentSelectorPathIndex = 0,
10288            currentSelectorPathElementIndex = 0,
10289            path = [],
10290            matchIndex,
10291            selector,
10292            firstElement,
10293            match,
10294            newElements;
10295
10296        for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
10297            match = matches[matchIndex];
10298            selector = selectorPath[match.pathIndex];
10299            firstElement = new tree.Element(
10300                match.initialCombinator,
10301                replacementSelector.elements[0].value,
10302                replacementSelector.elements[0].getIndex(),
10303                replacementSelector.elements[0].fileInfo()
10304            );
10305
10306            if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
10307                path[path.length - 1].elements = path[path.length - 1]
10308                    .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
10309                currentSelectorPathElementIndex = 0;
10310                currentSelectorPathIndex++;
10311            }
10312
10313            newElements = selector.elements
10314                .slice(currentSelectorPathElementIndex, match.index)
10315                .concat([firstElement])
10316                .concat(replacementSelector.elements.slice(1));
10317
10318            if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
10319                path[path.length - 1].elements =
10320                    path[path.length - 1].elements.concat(newElements);
10321            } else {
10322                path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
10323
10324                path.push(new tree.Selector(
10325                    newElements
10326                ));
10327            }
10328            currentSelectorPathIndex = match.endPathIndex;
10329            currentSelectorPathElementIndex = match.endPathElementIndex;
10330            if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
10331                currentSelectorPathElementIndex = 0;
10332                currentSelectorPathIndex++;
10333            }
10334        }
10335
10336        if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
10337            path[path.length - 1].elements = path[path.length - 1]
10338                .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
10339            currentSelectorPathIndex++;
10340        }
10341
10342        path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
10343        path = path.map(function (currentValue) {
10344            // we can re-use elements here, because the visibility property matters only for selectors
10345            var derived = currentValue.createDerived(currentValue.elements);
10346            if (isVisible) {
10347                derived.ensureVisibility();
10348            } else {
10349                derived.ensureInvisibility();
10350            }
10351            return derived;
10352        });
10353        return path;
10354    },
10355    visitMedia: function (mediaNode, visitArgs) {
10356        var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
10357        newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
10358        this.allExtendsStack.push(newAllExtends);
10359    },
10360    visitMediaOut: function (mediaNode) {
10361        var lastIndex = this.allExtendsStack.length - 1;
10362        this.allExtendsStack.length = lastIndex;
10363    },
10364    visitAtRule: function (atRuleNode, visitArgs) {
10365        var newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
10366        newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends));
10367        this.allExtendsStack.push(newAllExtends);
10368    },
10369    visitAtRuleOut: function (atRuleNode) {
10370        var lastIndex = this.allExtendsStack.length - 1;
10371        this.allExtendsStack.length = lastIndex;
10372    }
10373};
10374
10375module.exports = ProcessExtendsVisitor;
10376
10377},{"../logger":37,"../tree":65,"../utils":86,"./visitor":94}],88:[function(require,module,exports){
10378function ImportSequencer(onSequencerEmpty) {
10379    this.imports = [];
10380    this.variableImports = [];
10381    this._onSequencerEmpty = onSequencerEmpty;
10382    this._currentDepth = 0;
10383}
10384
10385ImportSequencer.prototype.addImport = function(callback) {
10386    var importSequencer = this,
10387        importItem = {
10388            callback: callback,
10389            args: null,
10390            isReady: false
10391        };
10392    this.imports.push(importItem);
10393    return function() {
10394        importItem.args = Array.prototype.slice.call(arguments, 0);
10395        importItem.isReady = true;
10396        importSequencer.tryRun();
10397    };
10398};
10399
10400ImportSequencer.prototype.addVariableImport = function(callback) {
10401    this.variableImports.push(callback);
10402};
10403
10404ImportSequencer.prototype.tryRun = function() {
10405    this._currentDepth++;
10406    try {
10407        while (true) {
10408            while (this.imports.length > 0) {
10409                var importItem = this.imports[0];
10410                if (!importItem.isReady) {
10411                    return;
10412                }
10413                this.imports = this.imports.slice(1);
10414                importItem.callback.apply(null, importItem.args);
10415            }
10416            if (this.variableImports.length === 0) {
10417                break;
10418            }
10419            var variableImport = this.variableImports[0];
10420            this.variableImports = this.variableImports.slice(1);
10421            variableImport();
10422        }
10423    } finally {
10424        this._currentDepth--;
10425    }
10426    if (this._currentDepth === 0 && this._onSequencerEmpty) {
10427        this._onSequencerEmpty();
10428    }
10429};
10430
10431module.exports = ImportSequencer;
10432
10433},{}],89:[function(require,module,exports){
10434var contexts = require('../contexts'),
10435    Visitor = require('./visitor'),
10436    ImportSequencer = require('./import-sequencer'),
10437    utils = require('../utils');
10438
10439var ImportVisitor = function(importer, finish) {
10440
10441    this._visitor = new Visitor(this);
10442    this._importer = importer;
10443    this._finish = finish;
10444    this.context = new contexts.Eval();
10445    this.importCount = 0;
10446    this.onceFileDetectionMap = {};
10447    this.recursionDetector = {};
10448    this._sequencer = new ImportSequencer(this._onSequencerEmpty.bind(this));
10449};
10450
10451ImportVisitor.prototype = {
10452    isReplacing: false,
10453    run: function (root) {
10454        try {
10455            // process the contents
10456            this._visitor.visit(root);
10457        }
10458        catch (e) {
10459            this.error = e;
10460        }
10461
10462        this.isFinished = true;
10463        this._sequencer.tryRun();
10464    },
10465    _onSequencerEmpty: function() {
10466        if (!this.isFinished) {
10467            return;
10468        }
10469        this._finish(this.error);
10470    },
10471    visitImport: function (importNode, visitArgs) {
10472        var inlineCSS = importNode.options.inline;
10473
10474        if (!importNode.css || inlineCSS) {
10475
10476            var context = new contexts.Eval(this.context, utils.copyArray(this.context.frames));
10477            var importParent = context.frames[0];
10478
10479            this.importCount++;
10480            if (importNode.isVariableImport()) {
10481                this._sequencer.addVariableImport(this.processImportNode.bind(this, importNode, context, importParent));
10482            } else {
10483                this.processImportNode(importNode, context, importParent);
10484            }
10485        }
10486        visitArgs.visitDeeper = false;
10487    },
10488    processImportNode: function(importNode, context, importParent) {
10489        var evaldImportNode,
10490            inlineCSS = importNode.options.inline;
10491
10492        try {
10493            evaldImportNode = importNode.evalForImport(context);
10494        } catch (e) {
10495            if (!e.filename) { e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename; }
10496            // attempt to eval properly and treat as css
10497            importNode.css = true;
10498            // if that fails, this error will be thrown
10499            importNode.error = e;
10500        }
10501
10502        if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
10503
10504            if (evaldImportNode.options.multiple) {
10505                context.importMultiple = true;
10506            }
10507
10508            // try appending if we haven't determined if it is css or not
10509            var tryAppendLessExtension = evaldImportNode.css === undefined;
10510
10511            for (var i = 0; i < importParent.rules.length; i++) {
10512                if (importParent.rules[i] === importNode) {
10513                    importParent.rules[i] = evaldImportNode;
10514                    break;
10515                }
10516            }
10517
10518            var onImported = this.onImported.bind(this, evaldImportNode, context),
10519                sequencedOnImported = this._sequencer.addImport(onImported);
10520
10521            this._importer.push(evaldImportNode.getPath(), tryAppendLessExtension, evaldImportNode.fileInfo(),
10522                evaldImportNode.options, sequencedOnImported);
10523        } else {
10524            this.importCount--;
10525            if (this.isFinished) {
10526                this._sequencer.tryRun();
10527            }
10528        }
10529    },
10530    onImported: function (importNode, context, e, root, importedAtRoot, fullPath) {
10531        if (e) {
10532            if (!e.filename) {
10533                e.index = importNode.getIndex(); e.filename = importNode.fileInfo().filename;
10534            }
10535            this.error = e;
10536        }
10537
10538        var importVisitor = this,
10539            inlineCSS = importNode.options.inline,
10540            isPlugin = importNode.options.isPlugin,
10541            isOptional = importNode.options.optional,
10542            duplicateImport = importedAtRoot || fullPath in importVisitor.recursionDetector;
10543
10544        if (!context.importMultiple) {
10545            if (duplicateImport) {
10546                importNode.skip = true;
10547            } else {
10548                importNode.skip = function() {
10549                    if (fullPath in importVisitor.onceFileDetectionMap) {
10550                        return true;
10551                    }
10552                    importVisitor.onceFileDetectionMap[fullPath] = true;
10553                    return false;
10554                };
10555            }
10556        }
10557
10558        if (!fullPath && isOptional) {
10559            importNode.skip = true;
10560        }
10561
10562        if (root) {
10563            importNode.root = root;
10564            importNode.importedFilename = fullPath;
10565
10566            if (!inlineCSS && !isPlugin && (context.importMultiple || !duplicateImport)) {
10567                importVisitor.recursionDetector[fullPath] = true;
10568
10569                var oldContext = this.context;
10570                this.context = context;
10571                try {
10572                    this._visitor.visit(root);
10573                } catch (e) {
10574                    this.error = e;
10575                }
10576                this.context = oldContext;
10577            }
10578        }
10579
10580        importVisitor.importCount--;
10581
10582        if (importVisitor.isFinished) {
10583            importVisitor._sequencer.tryRun();
10584        }
10585    },
10586    visitDeclaration: function (declNode, visitArgs) {
10587        if (declNode.value.type === 'DetachedRuleset') {
10588            this.context.frames.unshift(declNode);
10589        } else {
10590            visitArgs.visitDeeper = false;
10591        }
10592    },
10593    visitDeclarationOut: function(declNode) {
10594        if (declNode.value.type === 'DetachedRuleset') {
10595            this.context.frames.shift();
10596        }
10597    },
10598    visitAtRule: function (atRuleNode, visitArgs) {
10599        this.context.frames.unshift(atRuleNode);
10600    },
10601    visitAtRuleOut: function (atRuleNode) {
10602        this.context.frames.shift();
10603    },
10604    visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
10605        this.context.frames.unshift(mixinDefinitionNode);
10606    },
10607    visitMixinDefinitionOut: function (mixinDefinitionNode) {
10608        this.context.frames.shift();
10609    },
10610    visitRuleset: function (rulesetNode, visitArgs) {
10611        this.context.frames.unshift(rulesetNode);
10612    },
10613    visitRulesetOut: function (rulesetNode) {
10614        this.context.frames.shift();
10615    },
10616    visitMedia: function (mediaNode, visitArgs) {
10617        this.context.frames.unshift(mediaNode.rules[0]);
10618    },
10619    visitMediaOut: function (mediaNode) {
10620        this.context.frames.shift();
10621    }
10622};
10623module.exports = ImportVisitor;
10624
10625},{"../contexts":12,"../utils":86,"./import-sequencer":88,"./visitor":94}],90:[function(require,module,exports){
10626var visitors = {
10627    Visitor: require('./visitor'),
10628    ImportVisitor: require('./import-visitor'),
10629    MarkVisibleSelectorsVisitor: require('./set-tree-visibility-visitor'),
10630    ExtendVisitor: require('./extend-visitor'),
10631    JoinSelectorVisitor: require('./join-selector-visitor'),
10632    ToCSSVisitor: require('./to-css-visitor')
10633};
10634
10635module.exports = visitors;
10636
10637},{"./extend-visitor":87,"./import-visitor":89,"./join-selector-visitor":91,"./set-tree-visibility-visitor":92,"./to-css-visitor":93,"./visitor":94}],91:[function(require,module,exports){
10638var Visitor = require('./visitor');
10639
10640var JoinSelectorVisitor = function() {
10641    this.contexts = [[]];
10642    this._visitor = new Visitor(this);
10643};
10644
10645JoinSelectorVisitor.prototype = {
10646    run: function (root) {
10647        return this._visitor.visit(root);
10648    },
10649    visitDeclaration: function (declNode, visitArgs) {
10650        visitArgs.visitDeeper = false;
10651    },
10652    visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
10653        visitArgs.visitDeeper = false;
10654    },
10655
10656    visitRuleset: function (rulesetNode, visitArgs) {
10657        var context = this.contexts[this.contexts.length - 1],
10658            paths = [], selectors;
10659
10660        this.contexts.push(paths);
10661
10662        if (!rulesetNode.root) {
10663            selectors = rulesetNode.selectors;
10664            if (selectors) {
10665                selectors = selectors.filter(function(selector) { return selector.getIsOutput(); });
10666                rulesetNode.selectors = selectors.length ? selectors : (selectors = null);
10667                if (selectors) { rulesetNode.joinSelectors(paths, context, selectors); }
10668            }
10669            if (!selectors) { rulesetNode.rules = null; }
10670            rulesetNode.paths = paths;
10671        }
10672    },
10673    visitRulesetOut: function (rulesetNode) {
10674        this.contexts.length = this.contexts.length - 1;
10675    },
10676    visitMedia: function (mediaNode, visitArgs) {
10677        var context = this.contexts[this.contexts.length - 1];
10678        mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
10679    },
10680    visitAtRule: function (atRuleNode, visitArgs) {
10681        var context = this.contexts[this.contexts.length - 1];
10682        if (atRuleNode.rules && atRuleNode.rules.length) {
10683            atRuleNode.rules[0].root = (atRuleNode.isRooted || context.length === 0 || null);
10684        }
10685    }
10686};
10687
10688module.exports = JoinSelectorVisitor;
10689
10690},{"./visitor":94}],92:[function(require,module,exports){
10691var SetTreeVisibilityVisitor = function(visible) {
10692    this.visible = visible;
10693};
10694SetTreeVisibilityVisitor.prototype.run = function(root) {
10695    this.visit(root);
10696};
10697SetTreeVisibilityVisitor.prototype.visitArray = function(nodes) {
10698    if (!nodes) {
10699        return nodes;
10700    }
10701
10702    var cnt = nodes.length, i;
10703    for (i = 0; i < cnt; i++) {
10704        this.visit(nodes[i]);
10705    }
10706    return nodes;
10707};
10708SetTreeVisibilityVisitor.prototype.visit = function(node) {
10709    if (!node) {
10710        return node;
10711    }
10712    if (node.constructor === Array) {
10713        return this.visitArray(node);
10714    }
10715
10716    if (!node.blocksVisibility || node.blocksVisibility()) {
10717        return node;
10718    }
10719    if (this.visible) {
10720        node.ensureVisibility();
10721    } else {
10722        node.ensureInvisibility();
10723    }
10724
10725    node.accept(this);
10726    return node;
10727};
10728module.exports = SetTreeVisibilityVisitor;
10729},{}],93:[function(require,module,exports){
10730var tree = require('../tree'),
10731    Visitor = require('./visitor');
10732
10733var CSSVisitorUtils = function(context) {
10734    this._visitor = new Visitor(this);
10735    this._context = context;
10736};
10737
10738CSSVisitorUtils.prototype = {
10739    containsSilentNonBlockedChild: function(bodyRules) {
10740        var rule;
10741        if (!bodyRules) {
10742            return false;
10743        }
10744        for (var r = 0; r < bodyRules.length; r++) {
10745            rule = bodyRules[r];
10746            if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
10747                // the atrule contains something that was referenced (likely by extend)
10748                // therefore it needs to be shown in output too
10749                return true;
10750            }
10751        }
10752        return false;
10753    },
10754
10755    keepOnlyVisibleChilds: function(owner) {
10756        if (owner && owner.rules) {
10757            owner.rules = owner.rules.filter(function(thing) {
10758                return thing.isVisible();
10759            });
10760        }
10761    },
10762
10763    isEmpty: function(owner) {
10764        return (owner && owner.rules) 
10765            ? (owner.rules.length === 0) : true;
10766    },
10767
10768    hasVisibleSelector: function(rulesetNode) {
10769        return (rulesetNode && rulesetNode.paths)
10770            ? (rulesetNode.paths.length > 0) : false;
10771    },
10772
10773    resolveVisibility: function (node, originalRules) {
10774        if (!node.blocksVisibility()) {
10775            if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) {
10776                return ;
10777            }
10778
10779            return node;
10780        }
10781
10782        var compiledRulesBody = node.rules[0];
10783        this.keepOnlyVisibleChilds(compiledRulesBody);
10784
10785        if (this.isEmpty(compiledRulesBody)) {
10786            return ;
10787        }
10788
10789        node.ensureVisibility();
10790        node.removeVisibilityBlock();
10791
10792        return node;
10793    },
10794
10795    isVisibleRuleset: function(rulesetNode) {
10796        if (rulesetNode.firstRoot) {
10797            return true;
10798        }
10799
10800        if (this.isEmpty(rulesetNode)) {
10801            return false;
10802        }
10803
10804        if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {
10805            return false;
10806        }
10807
10808        return true;
10809    }
10810
10811};
10812
10813var ToCSSVisitor = function(context) {
10814    this._visitor = new Visitor(this);
10815    this._context = context;
10816    this.utils = new CSSVisitorUtils(context);
10817};
10818
10819ToCSSVisitor.prototype = {
10820    isReplacing: true,
10821    run: function (root) {
10822        return this._visitor.visit(root);
10823    },
10824
10825    visitDeclaration: function (declNode, visitArgs) {
10826        if (declNode.blocksVisibility() || declNode.variable) {
10827            return;
10828        }
10829        return declNode;
10830    },
10831
10832    visitMixinDefinition: function (mixinNode, visitArgs) {
10833        // mixin definitions do not get eval'd - this means they keep state
10834        // so we have to clear that state here so it isn't used if toCSS is called twice
10835        mixinNode.frames = [];
10836    },
10837
10838    visitExtend: function (extendNode, visitArgs) {
10839    },
10840
10841    visitComment: function (commentNode, visitArgs) {
10842        if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {
10843            return;
10844        }
10845        return commentNode;
10846    },
10847
10848    visitMedia: function(mediaNode, visitArgs) {
10849        var originalRules = mediaNode.rules[0].rules;
10850        mediaNode.accept(this._visitor);
10851        visitArgs.visitDeeper = false;
10852
10853        return this.utils.resolveVisibility(mediaNode, originalRules);
10854    },
10855
10856    visitImport: function (importNode, visitArgs) {
10857        if (importNode.blocksVisibility()) {
10858            return ;
10859        }
10860        return importNode;
10861    },
10862
10863    visitAtRule: function(atRuleNode, visitArgs) {
10864        if (atRuleNode.rules && atRuleNode.rules.length) {
10865            return this.visitAtRuleWithBody(atRuleNode, visitArgs);
10866        } else {
10867            return this.visitAtRuleWithoutBody(atRuleNode, visitArgs);
10868        }
10869    },
10870
10871    visitAnonymous: function(anonymousNode, visitArgs) {
10872        if (!anonymousNode.blocksVisibility()) {
10873            anonymousNode.accept(this._visitor);
10874            return anonymousNode;
10875        }
10876    },
10877
10878    visitAtRuleWithBody: function(atRuleNode, visitArgs) {
10879        // if there is only one nested ruleset and that one has no path, then it is
10880        // just fake ruleset
10881        function hasFakeRuleset(atRuleNode) {
10882            var bodyRules = atRuleNode.rules;
10883            return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
10884        }
10885        function getBodyRules(atRuleNode) {
10886            var nodeRules = atRuleNode.rules;
10887            if (hasFakeRuleset(atRuleNode)) {
10888                return nodeRules[0].rules;
10889            }
10890
10891            return nodeRules;
10892        }
10893        // it is still true that it is only one ruleset in array
10894        // this is last such moment
10895        // process childs
10896        var originalRules = getBodyRules(atRuleNode);
10897        atRuleNode.accept(this._visitor);
10898        visitArgs.visitDeeper = false;
10899
10900        if (!this.utils.isEmpty(atRuleNode)) {
10901            this._mergeRules(atRuleNode.rules[0].rules);
10902        }
10903
10904        return this.utils.resolveVisibility(atRuleNode, originalRules);
10905    },
10906
10907    visitAtRuleWithoutBody: function(atRuleNode, visitArgs) {
10908        if (atRuleNode.blocksVisibility()) {
10909            return;
10910        }
10911
10912        if (atRuleNode.name === '@charset') {
10913            // Only output the debug info together with subsequent @charset definitions
10914            // a comment (or @media statement) before the actual @charset atrule would
10915            // be considered illegal css as it has to be on the first line
10916            if (this.charset) {
10917                if (atRuleNode.debugInfo) {
10918                    var comment = new tree.Comment('/* ' + atRuleNode.toCSS(this._context).replace(/\n/g, '') + ' */\n');
10919                    comment.debugInfo = atRuleNode.debugInfo;
10920                    return this._visitor.visit(comment);
10921                }
10922                return;
10923            }
10924            this.charset = true;
10925        }
10926
10927        return atRuleNode;
10928    },
10929
10930    checkValidNodes: function(rules, isRoot) {
10931        if (!rules) {
10932            return;
10933        }
10934
10935        for (var i = 0; i < rules.length; i++) {
10936            var ruleNode = rules[i];
10937            if (isRoot && ruleNode instanceof tree.Declaration && !ruleNode.variable) {
10938                throw { message: 'Properties must be inside selector blocks. They cannot be in the root',
10939                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
10940            }
10941            if (ruleNode instanceof tree.Call) {
10942                throw { message: 'Function \'' + ruleNode.name + '\' is undefined',
10943                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
10944            }
10945            if (ruleNode.type && !ruleNode.allowRoot) {
10946                throw { message: ruleNode.type + ' node returned by a function is not valid here',
10947                    index: ruleNode.getIndex(), filename: ruleNode.fileInfo() && ruleNode.fileInfo().filename};
10948            }
10949        }
10950    },
10951
10952    visitRuleset: function (rulesetNode, visitArgs) {
10953        // at this point rulesets are nested into each other
10954        var rule, rulesets = [];
10955
10956        this.checkValidNodes(rulesetNode.rules, rulesetNode.firstRoot);
10957
10958        if (!rulesetNode.root) {
10959            // remove invisible paths
10960            this._compileRulesetPaths(rulesetNode);
10961
10962            // remove rulesets from this ruleset body and compile them separately
10963            var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
10964            for (var i = 0; i < nodeRuleCnt; ) {
10965                rule = nodeRules[i];
10966                if (rule && rule.rules) {
10967                    // visit because we are moving them out from being a child
10968                    rulesets.push(this._visitor.visit(rule));
10969                    nodeRules.splice(i, 1);
10970                    nodeRuleCnt--;
10971                    continue;
10972                }
10973                i++;
10974            }
10975            // accept the visitor to remove rules and refactor itself
10976            // then we can decide nogw whether we want it or not
10977            // compile body
10978            if (nodeRuleCnt > 0) {
10979                rulesetNode.accept(this._visitor);
10980            } else {
10981                rulesetNode.rules = null;
10982            }
10983            visitArgs.visitDeeper = false;
10984
10985        } else { // if (! rulesetNode.root) {
10986            rulesetNode.accept(this._visitor);
10987            visitArgs.visitDeeper = false;
10988        }
10989
10990        if (rulesetNode.rules) {
10991            this._mergeRules(rulesetNode.rules);
10992            this._removeDuplicateRules(rulesetNode.rules);
10993        }
10994
10995        // now decide whether we keep the ruleset
10996        if (this.utils.isVisibleRuleset(rulesetNode)) {
10997            rulesetNode.ensureVisibility();
10998            rulesets.splice(0, 0, rulesetNode);
10999        }
11000
11001        if (rulesets.length === 1) {
11002            return rulesets[0];
11003        }
11004        return rulesets;
11005    },
11006
11007    _compileRulesetPaths: function(rulesetNode) {
11008        if (rulesetNode.paths) {
11009            rulesetNode.paths = rulesetNode.paths
11010                .filter(function(p) {
11011                    var i;
11012                    if (p[0].elements[0].combinator.value === ' ') {
11013                        p[0].elements[0].combinator = new(tree.Combinator)('');
11014                    }
11015                    for (i = 0; i < p.length; i++) {
11016                        if (p[i].isVisible() && p[i].getIsOutput()) {
11017                            return true;
11018                        }
11019                    }
11020                    return false;
11021                });
11022        }
11023    },
11024
11025    _removeDuplicateRules: function(rules) {
11026        if (!rules) { return; }
11027
11028        // remove duplicates
11029        var ruleCache = {},
11030            ruleList, rule, i;
11031
11032        for (i = rules.length - 1; i >= 0 ; i--) {
11033            rule = rules[i];
11034            if (rule instanceof tree.Declaration) {
11035                if (!ruleCache[rule.name]) {
11036                    ruleCache[rule.name] = rule;
11037                } else {
11038                    ruleList = ruleCache[rule.name];
11039                    if (ruleList instanceof tree.Declaration) {
11040                        ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._context)];
11041                    }
11042                    var ruleCSS = rule.toCSS(this._context);
11043                    if (ruleList.indexOf(ruleCSS) !== -1) {
11044                        rules.splice(i, 1);
11045                    } else {
11046                        ruleList.push(ruleCSS);
11047                    }
11048                }
11049            }
11050        }
11051    },
11052
11053    _mergeRules: function(rules) {
11054        if (!rules) {
11055            return; 
11056        }
11057
11058        var groups    = {},
11059            groupsArr = [];
11060        
11061        for (var i = 0; i < rules.length; i++) {
11062            var rule = rules[i];
11063            if (rule.merge) {
11064                var key = rule.name;
11065                groups[key] ? rules.splice(i--, 1) : 
11066                    groupsArr.push(groups[key] = []);
11067                groups[key].push(rule);
11068            }
11069        }
11070
11071        groupsArr.forEach(function(group) {
11072            if (group.length > 0) {
11073                var result = group[0],
11074                    space  = [],
11075                    comma  = [new tree.Expression(space)];
11076                group.forEach(function(rule) {
11077                    if ((rule.merge === '+') && (space.length > 0)) {
11078                        comma.push(new tree.Expression(space = []));
11079                    }
11080                    space.push(rule.value);
11081                    result.important = result.important || rule.important;
11082                });
11083                result.value = new tree.Value(comma);
11084            }
11085        });
11086    }
11087};
11088
11089module.exports = ToCSSVisitor;
11090
11091},{"../tree":65,"./visitor":94}],94:[function(require,module,exports){
11092var tree = require('../tree');
11093
11094var _visitArgs = { visitDeeper: true },
11095    _hasIndexed = false;
11096
11097function _noop(node) {
11098    return node;
11099}
11100
11101function indexNodeTypes(parent, ticker) {
11102    // add .typeIndex to tree node types for lookup table
11103    var key, child;
11104    for (key in parent) { 
11105        /* eslint guard-for-in: 0 */
11106        child = parent[key];
11107        switch (typeof child) {
11108            case 'function':
11109                // ignore bound functions directly on tree which do not have a prototype
11110                // or aren't nodes
11111                if (child.prototype && child.prototype.type) {
11112                    child.prototype.typeIndex = ticker++;
11113                }
11114                break;
11115            case 'object':
11116                ticker = indexNodeTypes(child, ticker);
11117                break;
11118        
11119        }
11120    }
11121    return ticker;
11122}
11123
11124var Visitor = function(implementation) {
11125    this._implementation = implementation;
11126    this._visitFnCache = [];
11127
11128    if (!_hasIndexed) {
11129        indexNodeTypes(tree, 1);
11130        _hasIndexed = true;
11131    }
11132};
11133
11134Visitor.prototype = {
11135    visit: function(node) {
11136        if (!node) {
11137            return node;
11138        }
11139
11140        var nodeTypeIndex = node.typeIndex;
11141        if (!nodeTypeIndex) {
11142            return node;
11143        }
11144
11145        var visitFnCache = this._visitFnCache,
11146            impl = this._implementation,
11147            aryIndx = nodeTypeIndex << 1,
11148            outAryIndex = aryIndx | 1,
11149            func = visitFnCache[aryIndx],
11150            funcOut = visitFnCache[outAryIndex],
11151            visitArgs = _visitArgs,
11152            fnName;
11153
11154        visitArgs.visitDeeper = true;
11155
11156        if (!func) {
11157            fnName = 'visit' + node.type;
11158            func = impl[fnName] || _noop;
11159            funcOut = impl[fnName + 'Out'] || _noop;
11160            visitFnCache[aryIndx] = func;
11161            visitFnCache[outAryIndex] = funcOut;
11162        }
11163
11164        if (func !== _noop) {
11165            var newNode = func.call(impl, node, visitArgs);
11166            if (impl.isReplacing) {
11167                node = newNode;
11168            }
11169        }
11170
11171        if (visitArgs.visitDeeper && node && node.accept) {
11172            node.accept(this);
11173        }
11174
11175        if (funcOut != _noop) {
11176            funcOut.call(impl, node);
11177        }
11178
11179        return node;
11180    },
11181    visitArray: function(nodes, nonReplacing) {
11182        if (!nodes) {
11183            return nodes;
11184        }
11185
11186        var cnt = nodes.length, i;
11187
11188        // Non-replacing
11189        if (nonReplacing || !this._implementation.isReplacing) {
11190            for (i = 0; i < cnt; i++) {
11191                this.visit(nodes[i]);
11192            }
11193            return nodes;
11194        }
11195
11196        // Replacing
11197        var out = [];
11198        for (i = 0; i < cnt; i++) {
11199            var evald = this.visit(nodes[i]);
11200            if (evald === undefined) { continue; }
11201            if (!evald.splice) {
11202                out.push(evald);
11203            } else if (evald.length) {
11204                this.flatten(evald, out);
11205            }
11206        }
11207        return out;
11208    },
11209    flatten: function(arr, out) {
11210        if (!out) {
11211            out = [];
11212        }
11213
11214        var cnt, i, item,
11215            nestedCnt, j, nestedItem;
11216
11217        for (i = 0, cnt = arr.length; i < cnt; i++) {
11218            item = arr[i];
11219            if (item === undefined) {
11220                continue;
11221            }
11222            if (!item.splice) {
11223                out.push(item);
11224                continue;
11225            }
11226
11227            for (j = 0, nestedCnt = item.length; j < nestedCnt; j++) {
11228                nestedItem = item[j];
11229                if (nestedItem === undefined) {
11230                    continue;
11231                }
11232                if (!nestedItem.splice) {
11233                    out.push(nestedItem);
11234                } else if (nestedItem.length) {
11235                    this.flatten(nestedItem, out);
11236                }
11237            }
11238        }
11239
11240        return out;
11241    }
11242};
11243module.exports = Visitor;
11244
11245},{"../tree":65}],95:[function(require,module,exports){
11246"use strict";
11247
11248// rawAsap provides everything we need except exception management.
11249var rawAsap = require("./raw");
11250// RawTasks are recycled to reduce GC churn.
11251var freeTasks = [];
11252// We queue errors to ensure they are thrown in right order (FIFO).
11253// Array-as-queue is good enough here, since we are just dealing with exceptions.
11254var pendingErrors = [];
11255var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
11256
11257function throwFirstError() {
11258    if (pendingErrors.length) {
11259        throw pendingErrors.shift();
11260    }
11261}
11262
11263/**
11264 * Calls a task as soon as possible after returning, in its own event, with priority
11265 * over other events like animation, reflow, and repaint. An error thrown from an
11266 * event will not interrupt, nor even substantially slow down the processing of
11267 * other events, but will be rather postponed to a lower priority event.
11268 * @param {{call}} task A callable object, typically a function that takes no
11269 * arguments.
11270 */
11271module.exports = asap;
11272function asap(task) {
11273    var rawTask;
11274    if (freeTasks.length) {
11275        rawTask = freeTasks.pop();
11276    } else {
11277        rawTask = new RawTask();
11278    }
11279    rawTask.task = task;
11280    rawAsap(rawTask);
11281}
11282
11283// We wrap tasks with recyclable task objects.  A task object implements
11284// `call`, just like a function.
11285function RawTask() {
11286    this.task = null;
11287}
11288
11289// The sole purpose of wrapping the task is to catch the exception and recycle
11290// the task object after its single use.
11291RawTask.prototype.call = function () {
11292    try {
11293        this.task.call();
11294    } catch (error) {
11295        if (asap.onerror) {
11296            // This hook exists purely for testing purposes.
11297            // Its name will be periodically randomized to break any code that
11298            // depends on its existence.
11299            asap.onerror(error);
11300        } else {
11301            // In a web browser, exceptions are not fatal. However, to avoid
11302            // slowing down the queue of pending tasks, we rethrow the error in a
11303            // lower priority turn.
11304            pendingErrors.push(error);
11305            requestErrorThrow();
11306        }
11307    } finally {
11308        this.task = null;
11309        freeTasks[freeTasks.length] = this;
11310    }
11311};
11312
11313},{"./raw":96}],96:[function(require,module,exports){
11314(function (global){
11315"use strict";
11316
11317// Use the fastest means possible to execute a task in its own turn, with
11318// priority over other events including IO, animation, reflow, and redraw
11319// events in browsers.
11320//
11321// An exception thrown by a task will permanently interrupt the processing of
11322// subsequent tasks. The higher level `asap` function ensures that if an
11323// exception is thrown by a task, that the task queue will continue flushing as
11324// soon as possible, but if you use `rawAsap` directly, you are responsible to
11325// either ensure that no exceptions are thrown from your task, or to manually
11326// call `rawAsap.requestFlush` if an exception is thrown.
11327module.exports = rawAsap;
11328function rawAsap(task) {
11329    if (!queue.length) {
11330        requestFlush();
11331        flushing = true;
11332    }
11333    // Equivalent to push, but avoids a function call.
11334    queue[queue.length] = task;
11335}
11336
11337var queue = [];
11338// Once a flush has been requested, no further calls to `requestFlush` are
11339// necessary until the next `flush` completes.
11340var flushing = false;
11341// `requestFlush` is an implementation-specific method that attempts to kick
11342// off a `flush` event as quickly as possible. `flush` will attempt to exhaust
11343// the event queue before yielding to the browser's own event loop.
11344var requestFlush;
11345// The position of the next task to execute in the task queue. This is
11346// preserved between calls to `flush` so that it can be resumed if
11347// a task throws an exception.
11348var index = 0;
11349// If a task schedules additional tasks recursively, the task queue can grow
11350// unbounded. To prevent memory exhaustion, the task queue will periodically
11351// truncate already-completed tasks.
11352var capacity = 1024;
11353
11354// The flush function processes all tasks that have been scheduled with
11355// `rawAsap` unless and until one of those tasks throws an exception.
11356// If a task throws an exception, `flush` ensures that its state will remain
11357// consistent and will resume where it left off when called again.
11358// However, `flush` does not make any arrangements to be called again if an
11359// exception is thrown.
11360function flush() {
11361    while (index < queue.length) {
11362        var currentIndex = index;
11363        // Advance the index before calling the task. This ensures that we will
11364        // begin flushing on the next task the task throws an error.
11365        index = index + 1;
11366        queue[currentIndex].call();
11367        // Prevent leaking memory for long chains of recursive calls to `asap`.
11368        // If we call `asap` within tasks scheduled by `asap`, the queue will
11369        // grow, but to avoid an O(n) walk for every task we execute, we don't
11370        // shift tasks off the queue after they have been executed.
11371        // Instead, we periodically shift 1024 tasks off the queue.
11372        if (index > capacity) {
11373            // Manually shift all values starting at the index back to the
11374            // beginning of the queue.
11375            for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
11376                queue[scan] = queue[scan + index];
11377            }
11378            queue.length -= index;
11379            index = 0;
11380        }
11381    }
11382    queue.length = 0;
11383    index = 0;
11384    flushing = false;
11385}
11386
11387// `requestFlush` is implemented using a strategy based on data collected from
11388// every available SauceLabs Selenium web driver worker at time of writing.
11389// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
11390
11391// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
11392// have WebKitMutationObserver but not un-prefixed MutationObserver.
11393// Must use `global` or `self` instead of `window` to work in both frames and web
11394// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
11395
11396/* globals self */
11397var scope = typeof global !== "undefined" ? global : self;
11398var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
11399
11400// MutationObservers are desirable because they have high priority and work
11401// reliably everywhere they are implemented.
11402// They are implemented in all modern browsers.
11403//
11404// - Android 4-4.3
11405// - Chrome 26-34
11406// - Firefox 14-29
11407// - Internet Explorer 11
11408// - iPad Safari 6-7.1
11409// - iPhone Safari 7-7.1
11410// - Safari 6-7
11411if (typeof BrowserMutationObserver === "function") {
11412    requestFlush = makeRequestCallFromMutationObserver(flush);
11413
11414// MessageChannels are desirable because they give direct access to the HTML
11415// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
11416// 11-12, and in web workers in many engines.
11417// Although message channels yield to any queued rendering and IO tasks, they
11418// would be better than imposing the 4ms delay of timers.
11419// However, they do not work reliably in Internet Explorer or Safari.
11420
11421// Internet Explorer 10 is the only browser that has setImmediate but does
11422// not have MutationObservers.
11423// Although setImmediate yields to the browser's renderer, it would be
11424// preferrable to falling back to setTimeout since it does not have
11425// the minimum 4ms penalty.
11426// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (
11426and
11427// Desktop to a lesser extent) that renders both setImmediate and
11428// MessageChannel useless for the purposes of ASAP.
11429// https://github.com/kriskowal/q/issues/396
11430
11431// Timers are implemented universally.
11432// We fall back to timers in workers in most engines, and in foreground
11433// contexts in the following browsers.
11434// However, note that even this simple case requires nuances to operate in a
11435// broad spectrum of browsers.
11436//
11437// - Firefox 3-13
11438// - Internet Explorer 6-9
11439// - iPad Safari 4.3
11440// - Lynx 2.8.7
11441} else {
11442    requestFlush = makeRequestCallFromTimer(flush);
11443}
11444
11445// `requestFlush` requests that the high priority event queue be flushed as
11446// soon as possible.
11447// This is useful to prevent an error thrown in a task from stalling the event
11448// queue if the exception handled by Node.js’s
11449// `process.on("uncaughtException")` or by a domain.
11450rawAsap.requestFlush = requestFlush;
11451
11452// To request a high priority event, we induce a mutation observer by toggling
11453// the text of a text node between "1" and "-1".
11454function makeRequestCallFromMutationObserver(callback) {
11455    var toggle = 1;
11456    var observer = new BrowserMutationObserver(callback);
11457    var node = document.createTextNode("");
11458    observer.observe(node, {characterData: true});
11459    return function requestCall() {
11460        toggle = -toggle;
11461        node.data = toggle;
11462    };
11463}
11464
11465// The message channel technique was discovered by Malte Ubl and was the
11466// original foundation for this library.
11467// http://www.nonblocking.io/2011/06/windownexttick.html
11468
11469// Safari 6.0.5 (at least) intermittently fails to create message ports on a
11470// page's first load. Thankfully, this version of Safari supports
11471// MutationObservers, so we don't need to fall back in that case.
11472
11473// function makeRequestCallFromMessageChannel(callback) {
11474//     var channel = new MessageChannel();
11475//     channel.port1.onmessage = callback;
11476//     return function requestCall() {
11477//         channel.port2.postMessage(0);
11478//     };
11479// }
11480
11481// For reasons explained above, we are also unable to use `setImmediate`
11482// under any circumstances.
11483// Even if we were, there is another bug in Internet Explorer 10.
11484// It is not sufficient to assign `setImmediate` to `requestFlush` because
11485// `setImmediate` must be called *by name* and therefore must be wrapped in a
11486// closure.
11487// Never forget.
11488
11489// function makeRequestCallFromSetImmediate(callback) {
11490//     return function requestCall() {
11491//         setImmediate(callback);
11492//     };
11493// }
11494
11495// Safari 6.0 has a problem where timers will get lost while the user is
11496// scrolling. This problem does not impact ASAP because Safari 6.0 supports
11497// mutation observers, so that implementation is used instead.
11498// However, if we ever elect to use timers in Safari, the prevalent work-around
11499// is to add a scroll event listener that calls for a flush.
11500
11501// `setTimeout` does not call the passed callback if the delay is less than
11502// approximately 7 in web workers in Firefox 8 through 18, and sometimes not
11503// even then.
11504
11505function makeRequestCallFromTimer(callback) {
11506    return function requestCall() {
11507        // We dispatch a timeout with a specified delay of 0 for engines that
11508        // can reliably accommodate that request. This will usually be snapped
11509        // to a 4 milisecond delay, but once we're flushing, there's no delay
11510        // between events.
11511        var timeoutHandle = setTimeout(handleTimer, 0);
11512        // However, since this timer gets frequently dropped in Firefox
11513        // workers, we enlist an interval handle that will try to fire
11514        // an event 20 times per second until it succeeds.
11515        var intervalHandle = setInterval(handleTimer, 50);
11516
11517        function handleTimer() {
11518            // Whichever timer succeeds will cancel both timers and
11519            // execute the callback.
11520            clearTimeout(timeoutHandle);
11521            clearInterval(intervalHandle);
11522            callback();
11523        }
11524    };
11525}
11526
11527// This is for `asap.js` only.
11528// Its name will be periodically randomized to break any code that depends on
11529// its existence.
11530rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
11531
11532// ASAP was originally a nextTick shim included in Q. This was factored out
11533// into this ASAP package. It was later adapted to RSVP which made further
11534// amendments. These decisions, particularly to marginalize MessageChannel and
11535// to capture the MutationObserver implementation in a closure, were integrated
11536// back into ASAP proper.
11537// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
11538
11539}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
11540},{}],97:[function(require,module,exports){
11541'use strict';
11542
11543var asap = require('asap/raw');
11544
11545function noop() {}
11546
11547// States:
11548//
11549// 0 - pending
11550// 1 - fulfilled with _value
11551// 2 - rejected with _value
11552// 3 - adopted the state of another promise, _value
11553//
11554// once the state is no longer pending (0) it is immutable
11555
11556// All `_` prefixed properties will be reduced to `_{random number}`
11557// at build time to obfuscate them and discourage their use.
11558// We don't use symbols or Object.defineProperty to fully hide them
11559// because the performance isn't good enough.
11560
11561
11562// to avoid using try/catch inside critical functions, we
11563// extract them to here.
11564var LAST_ERROR = null;
11565var IS_ERROR = {};
11566function getThen(obj) {
11567  try {
11568    return obj.then;
11569  } catch (ex) {
11570    LAST_ERROR = ex;
11571    return IS_ERROR;
11572  }
11573}
11574
11575function tryCallOne(fn, a) {
11576  try {
11577    return fn(a);
11578  } catch (ex) {
11579    LAST_ERROR = ex;
11580    return IS_ERROR;
11581  }
11582}
11583function tryCallTwo(fn, a, b) {
11584  try {
11585    fn(a, b);
11586  } catch (ex) {
11587    LAST_ERROR = ex;
11588    return IS_ERROR;
11589  }
11590}
11591
11592module.exports = Promise;
11593
11594function Promise(fn) {
11595  if (typeof this !== 'object') {
11596    throw new TypeError('Promises must be constructed via new');
11597  }
11598  if (typeof fn !== 'function') {
11599    throw new TypeError('Promise constructor\'s argument is not a function');
11600  }
11601  this._40 = 0;
11602  this._65 = 0;
11603  this._55 = null;
11604  this._72 = null;
11605  if (fn === noop) return;
11606  doResolve(fn, this);
11607}
11608Promise._37 = null;
11609Promise._87 = null;
11610Promise._61 = noop;
11611
11612Promise.prototype.then = function(onFulfilled, onRejected) {
11613  if (this.constructor !== Promise) {
11614    return safeThen(this, onFulfilled, onRejected);
11615  }
11616  var res = new Promise(noop);
11617  handle(this, new Handler(onFulfilled, onRejected, res));
11618  return res;
11619};
11620
11621function safeThen(self, onFulfilled, onRejected) {
11622  return new self.constructor(function (resolve, reject) {
11623    var res = new Promise(noop);
11624    res.then(resolve, reject);
11625    handle(self, new Handler(onFulfilled, onRejected, res));
11626  });
11627}
11628function handle(self, deferred) {
11629  while (self._65 === 3) {
11630    self = self._55;
11631  }
11632  if (Promise._37) {
11633    Promise._37(self);
11634  }
11635  if (self._65 === 0) {
11636    if (self._40 === 0) {
11637      self._40 = 1;
11638      self._72 = deferred;
11639      return;
11640    }
11641    if (self._40 === 1) {
11642      self._40 = 2;
11643      self._72 = [self._72, deferred];
11644      return;
11645    }
11646    self._72.push(deferred);
11647    return;
11648  }
11649  handleResolved(self, deferred);
11650}
11651
11652function handleResolved(self, deferred) {
11653  asap(function() {
11654    var cb = self._65 === 1 ? deferred.onFulfilled : deferred.onRejected;
11655    if (cb === null) {
11656      if (self._65 === 1) {
11657        resolve(deferred.promise, self._55);
11658      } else {
11659        reject(deferred.promise, self._55);
11660      }
11661      return;
11662    }
11663    var ret = tryCallOne(cb, self._55);
11664    if (ret === IS_ERROR) {
11665      reject(deferred.promise, LAST_ERROR);
11666    } else {
11667      resolve(deferred.promise, ret);
11668    }
11669  });
11670}
11671function resolve(self, newValue) {
11672  // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
11673  if (newValue === self) {
11674    return reject(
11675      self,
11676      new TypeError('A promise cannot be resolved with itself.')
11677    );
11678  }
11679  if (
11680    newValue &&
11681    (typeof newValue === 'object' || typeof newValue === 'function')
11682  ) {
11683    var then = getThen(newValue);
11684    if (then === IS_ERROR) {
11685      return reject(self, LAST_ERROR);
11686    }
11687    if (
11688      then === self.then &&
11689      newValue instanceof Promise
11690    ) {
11691      self._65 = 3;
11692      self._55 = newValue;
11693      finale(self);
11694      return;
11695    } else if (typeof then === 'function') {
11696      doResolve(then.bind(newValue), self);
11697      return;
11698    }
11699  }
11700  self._65 = 1;
11701  self._55 = newValue;
11702  finale(self);
11703}
11704
11705function reject(self, newValue) {
11706  self._65 = 2;
11707  self._55 = newValue;
11708  if (Promise._87) {
11709    Promise._87(self, newValue);
11710  }
11711  finale(self);
11712}
11713function finale(self) {
11714  if (self._40 === 1) {
11715    handle(self, self._72);
11716    self._72 = null;
11717  }
11718  if (self._40 === 2) {
11719    for (var i = 0; i < self._72.length; i++) {
11720      handle(self, self._72[i]);
11721    }
11722    self._72 = null;
11723  }
11724}
11725
11726function Handler(onFulfilled, onRejected, promise){
11727  this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
11728  this.onRejected = typeof onRejected === 'function' ? onRejected : null;
11729  this.promise = promise;
11730}
11731
11732/**
11733 * Take a potentially misbehaving resolver function and make sure
11734 * onFulfilled and onRejected are only called once.
11735 *
11736 * Makes no guarantees about asynchrony.
11737 */
11738function doResolve(fn, promise) {
11739  var done = false;
11740  var res = tryCallTwo(fn, function (value) {
11741    if (done) return;
11742    done = true;
11743    resolve(promise, value);
11744  }, function (reason) {
11745    if (done) return;
11746    done = true;
11747    reject(promise, reason);
11748  });
11749  if (!done && res === IS_ERROR) {
11750    done = true;
11751    reject(promise, LAST_ERROR);
11752  }
11753}
11754
11755},{"asap/raw":96}],98:[function(require,module,exports){
11756'use strict';
11757
11758//This file contains the ES6 extensions to the core Promises/A+ API
11759
11760var Promise = require('./core.js');
11761
11762module.exports = Promise;
11763
11764/* Static Functions */
11765
11766var TRUE = valuePromise(true);
11767var FALSE = valuePromise(false);
11768var NULL = valuePromise(null);
11769var UNDEFINED = valuePromise(undefined);
11770var ZERO = valuePromise(0);
11771var EMPTYSTRING = valuePromise('');
11772
11773function valuePromise(value) {
11774  var p = new Promise(Promise._61);
11775  p._65 = 1;
11776  p._55 = value;
11777  return p;
11778}
11779Promise.resolve = function (value) {
11780  if (value instanceof Promise) return value;
11781
11782  if (value === null) return NULL;
11783  if (value === undefined) return UNDEFINED;
11784  if (value === true) return TRUE;
11785  if (value === false) return FALSE;
11786  if (value === 0) return ZERO;
11787  if (value === '') return EMPTYSTRING;
11788
11789  if (typeof value === 'object' || typeof value === 'function') {
11790    try {
11791      var then = value.then;
11792      if (typeof then === 'function') {
11793        return new Promise(then.bind(value));
11794      }
11795    } catch (ex) {
11796      return new Promise(function (resolve, reject) {
11797        reject(ex);
11798      });
11799    }
11800  }
11801  return valuePromise(value);
11802};
11803
11804Promise.all = function (arr) {
11805  var args = Array.prototype.slice.call(arr);
11806
11807  return new Promise(function (resolve, reject) {
11808    if (args.length === 0) return resolve([]);
11809    var remaining = args.length;
11810    function res(i, val) {
11811      if (val && (typeof val === 'object' || typeof val === 'function')) {
11812        if (val instanceof Promise && val.then === Promise.prototype.then) {
11813          while (val._65 === 3) {
11814            val = val._55;
11815          }
11816          if (val._65 === 1) return res(i, val._55);
11817          if (val._65 === 2) reject(val._55);
11818          val.then(function (val) {
11819            res(i, val);
11820          }, reject);
11821          return;
11822        } else {
11823          var then = val.then;
11824          if (typeof then === 'function') {
11825            var p = new Promise(then.bind(val));
11826            p.then(function (val) {
11827              res(i, val);
11828            }, reject);
11829            return;
11830          }
11831        }
11832      }
11833      args[i] = val;
11834      if (--remaining === 0) {
11835        resolve(args);
11836      }
11837    }
11838    for (var i = 0; i < args.length; i++) {
11839      res(i, args[i]);
11840    }
11841  });
11842};
11843
11844Promise.reject = function (value) {
11845  return new Promise(function (resolve, reject) {
11846    reject(value);
11847  });
11848};
11849
11850Promise.race = function (values) {
11851  return new Promise(function (resolve, reject) {
11852    values.forEach(function(value){
11853      Promise.resolve(value).then(resolve, reject);
11854    });
11855  });
11856};
11857
11858/* Prototype Methods */
11859
11860Promise.prototype['catch'] = function (onRejected) {
11861  return this.then(null, onRejected);
11862};
11863
11864},{"./core.js":97}],99:[function(require,module,exports){
11865// should work in any browser without browserify
11866
11867if (typeof Promise.prototype.done !== 'function') {
11868  Promise.prototype.done = function (onFulfilled, onRejected) {
11869    var self = arguments.length ? this.then.apply(this, arguments) : this
11870    self.then(null, function (err) {
11871      setTimeout(function () {
11872        throw err
11873      }, 0)
11874    })
11875  }
11876}
11877},{}],100:[function(require,module,exports){
11878// not "use strict" so we can declare global "Promise"
11879
11880var asap = require('asap');
11881
11882if (typeof Promise === 'undefined') {
11883  Promise = require('./lib/core.js')
11884  require('./lib/es6-extensions.js')
11885}
11886
11887require('./polyfill-done.js');
11888
11889},{"./lib/core.js":97,"./lib/es6-extensions.js":98,"./polyfill-done.js":99,"asap":95}]},{},[2])(2)
11890});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.