text: /*
   * LESS - Leaner CSS v1.4.0
   * http://lesscss.org
   *
   * Copyright (c) 2009-2013, Alexis Sellier
   * Licensed under the Apache 2.0 License.
   *
   * @licence
   */
  (function (window, undefined) {
  //
  // Stub out `require` in the browser
  //
      function require(arg) {
          return window.less[arg.split('/')[1]];
      };
  
      var less, tree, charset;
  
      if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
          // Rhino
          // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
          if (typeof(window) === 'undefined') {
              less = {}
          }
          else {
              less = window.less = {}
          }
          tree = less.tree = {};
          less.mode = 'rhino';
      } else if (typeof(window) === 'undefined') {
          // Node.js
          less = exports,
              tree = require('./tree');
          less.mode = 'node';
      } else {
          // Browser
          if (typeof(window.less) === 'undefined') {
              window.less = {}
          }
          less = window.less,
              tree = window.less.tree = {};
          less.mode = 'browser';
      }
  //
  // less.js - parser
  //
  //    A relatively straight-forward predictive parser.
  //    There is no tokenization/lexing stage, the input is parsed
  //    in one sweep.
  //
  //    To make the parser fast enough to run in the browser, several
  //    optimization had to be made:
  //
  //    - Matching and slicing on a huge input is often cause of slowdowns.
  //      The solution is to chunkify the input into smaller strings.
  //      The chunks are stored in the `chunks` var,
  //      `j` holds the current chunk index, and `current` holds
  //      the index of the current chunk in relation to `input`.
  //      This gives us an almost 4x speed-up.
  //
  //    - In many cases, we don't need to match individual tokens;
  //      for example, if a value doesn't hold any variables, operations
  //      or dynamic references, the parser can effectively 'skip' it,
  //      treating it as a literal.
  //      An example would be '1px solid #000' - which evaluates to itself,
  //      we don't need to know what the individual components are.
  //      The drawback, of course is that you don't get the benefits of
  //      syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
  //      and a smaller speed-up in the code-gen.
  //
  //
  //    Token matching is done with the `$` function, which either takes
  //    a terminal string or regexp, or a non-terminal function to call.
  //    It also takes care of moving all the indices forwards.
  //
  //
      less.Parser = function Parser(env) {
          var input,       // LeSS input string
              i,           // current index in `input`
              j,           // current chunk
              temp,        // temporarily holds a chunk's state, for backtracking
              memo,        // temporarily holds `i`, when backtracking
              furthest,    // furthest index the parser has gone to
              chunks,      // chunkified input
              current,     // index of current chunk, in `input`
              parser;
  
          var that = this;
  
          // Top parser on an import tree must be sure there is one "env"
          // which will then be passed around by reference.
          if (!(env instanceof tree.parseEnv)) {
              env = new tree.parseEnv(env);
          }
  
          var imports = this.imports = {
              paths: env.paths || [],  // Search paths, when importing
              queue: [],               // Files which haven't been imported yet
              files: env.files,        // Holds the imported parse trees
              contents: env.contents,  // Holds the imported file contents
              mime: env.mime,         // MIME type of .less files
              error: null,             // Error in parsing/evaluating an import
              push: function (path, currentFileInfo, callback) {
                  var parserImporter = this;
                  this.queue.push(path);
  
                  //
                  // Import a file asynchronously
                  //
                  less.Parser.importer(path, currentFileInfo, function (e, root, fullPath) {
                      parserImporter.queue.splice(parserImporter.queue.indexOf(path), 1); // Remove the path from the queue
  
                      var imported = fullPath in parserImporter.files;
  
                      parserImporter.files[fullPath] = root;                        // Store the root
  
                      if (e && !parserImporter.error) {
                          parserImporter.error = e;
                      }
  
                      callback(e, root, imported);
                  }, env);
              }
          };
  
          function save() {
              temp = chunks[j], memo = i, current = i;
          }
  
          function restore() {
              chunks[j] = temp, i = memo, current = i;
          }
  
          function sync() {
              if (i > current) {
                  chunks[j] = chunks[j].slice(i - current);
                  current = i;
              }
          }
  
          function isWhitespace(c) {
              // Could change to \s?
              var code = c.charCodeAt(0);
              return code === 32 || code === 10 || code === 9;
          }
  
          //
          // Parse from a token, regexp or string, and move forward if match
          //
          function $(tok) {
              var match, args, length, index, k;
  
              //
              // Non-terminal
              //
              if (tok instanceof Function) {
                  return tok.call(parser.parsers);
                  //
                  // Terminal
                  //
                  //     Either match a single character in the input,
                  //     or match a regexp in the current chunk (chunk[j]).
                  //
              } else if (typeof(tok) === 'string') {
                  match = input.charAt(i) === tok ? tok : null;
                  length = 1;
                  sync();
              } else {
                  sync();
  
                  if (match = tok.exec(chunks[j])) {
                      length = match[0].length;
                  } else {
                      return null;
                  }
              }
  
              // The match is confirmed, add the match length to `i`,
              // and consume any extra white-space characters (' ' || '\n')
              // which come after that. The reason for this is that LeSS's
              // grammar is mostly white-space insensitive.
              //
              if (match) {
                  skipWhitespace(length);
  
                  if (typeof(match) === 'string') {
                      return match;
                  } else {
                      return match.length === 1 ? match[0] : match;
                  }
              }
          }
  
          function skipWhitespace(length) {
              var oldi = i, oldj = j,
                  endIndex = i + chunks[j].length,
                  mem = i += length;
  
              while (i < endIndex) {
                  if (!isWhitespace(input.charAt(i))) {
                      break
                  }
                  i++;
              }
              chunks[j] = chunks[j].slice(length + (i - mem));
              current = i;
  
              if (chunks[j].length === 0 && j < chunks.length - 1) {
                  j++
              }
  
              return oldi !== i || oldj !== j;
          }
  
          function expect(arg, msg) {
              var result = $(arg);
              if (!result) {
                  error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
                          : "unexpected token"));
              } else {
                  return result;
              }
          }
  
          function error(msg, type) {
              var e = new Error(msg);
              e.index = i;
              e.type = type || 'Syntax';
              throw e;
          }
  
          // Same as $(), but don't change the state of the parser,
          // just return the match.
          function peek(tok) {
              if (typeof(tok) === 'string') {
                  return input.charAt(i) === tok;
              } else {
                  if (tok.test(chunks[j])) {
                      return true;
                  } else {
                      return false;
                  }
              }
          }
  
          function getInput(e, env) {
              if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
                  return parser.imports.contents[e.filename];
              } else {
                  return input;
              }
          }
  
          function getLocation(index, input) {
              for (var n = index, column = -1;
                  n >= 0 && input.charAt(n) !== '\n';
                  n--) {
                  column++
              }
  
              return {
                  line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
                  column: column
              };
          }
  
          function getDebugInfo(index, inputStream, env) {
              var filename = env.currentFileInfo.filename;
              if (less.mode !== 'browser' && less.mode !== 'rhino') {
                  filename = require('path').resolve(filename);
              }
  
              return {
                  lineNumber: getLocation(index, inputStream).line + 1,
                  fileName: filename
              };
          }
  
          function LessError(e, env) {
              var input = getInput(e, env),
                  loc = getLocation(e.index, input),
                  line = loc.line,
                  col = loc.column,
                  lines = input.split('\n');
  
              this.type = e.type || 'Syntax';
              this.message = e.message;
              this.filename = e.filename || env.currentFileInfo.filename;
              this.index = e.index;
              this.line = typeof(line) === 'number' ? line + 1 : null;
              this.callLine = e.call && (getLocation(e.call, input).line + 1);
              this.callExtract = lines[getLocation(e.call, input).line];
              this.stack = e.stack;
              this.column = col;
              this.extract = [
                  lines[line - 1],
                  lines[line],
                  lines[line + 1]
              ];
          }
  
          LessError.prototype = new Error();
          LessError.prototype.constructor = LessError;
  
          this.env = env = env || {};
  
          // The optimization level dictates the thoroughness of the parser,
          // the lower the number, the less nodes it will create in the tree.
          // This could matter for debugging, or if you want to access
          // the individual nodes in the tree.
          this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
  
          //
          // The Parser
          //
          return parser = {
  
              imports: imports,
              //
              // Parse an input string into an abstract syntax tree,
              // call `callback` when done.
              //
              parse: function (str, callback) {
                  var root, start, end, zone, line, lines, buff = [], c, error = null;
  
                  i = j = current = furthest = 0;
                  input = str.replace(/\r\n/g, '\n');
  
                  // Remove potential UTF Byte Order Mark
                  input = input.replace(/^\uFEFF/, '');
  
                  // Split the input into chunks.
                  chunks = (function (chunks) {
                      var j = 0,
                          skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
                          comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
                          string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
                          level = 0,
                          match,
                          chunk = chunks[0],
                          inParam;
  
                      for (var i = 0, c, cc; i < input.length;) {
                          skip.lastIndex = i;
                          if (match = skip.exec(input)) {
                              if (match.index === i) {
                                  i += match[0].length;
                                  chunk.push(match[0]);
                              }
                          }
                          c = input.charAt(i);
                          comment.lastIndex = string.lastIndex = i;
  
                          if (match = string.exec(input)) {
                              if (match.index === i) {
                                  i += match[0].length;
                                  chunk.push(match[0]);
                                  continue;
                              }
                          }
  
                          if (!inParam && c === '/') {
                              cc = input.charAt(i + 1);
                              if (cc === '/' || cc === '*') {
                                  if (match = comment.exec(input)) {
                                      if (match.index === i) {
                                          i += match[0].length;
                                          chunk.push(match[0]);
                                          continue;
                                      }
                                  }
                              }
                          }
  
                          switch (c) {
                              case '{':
                                  if (!inParam) {
                                      level++;
                                      chunk.push(c);
                                      break
                                  }
                              case '}':
                                  if (!inParam) {
                                      level--;
                                      chunk.push(c);
                                      chunks[++j] = chunk = [];
                                      break
                                  }
                              case '(':
                                  if (!inParam) {
                                      inParam = true;
                                      chunk.push(c);
                                      break
                                  }
                              case ')':
                                  if (inParam) {
                                      inParam = false;
                                      chunk.push(c);
                                      break
                                  }
                              default:
                                  chunk.push(c);
                          }
  
                          i++;
                      }
                      if (level != 0) {
                          error = new (LessError)({
                              index: i - 1,
                              type: 'Parse',
                              message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
                              filename: env.currentFileInfo.filename
                          }, env);
                      }
  
                      return chunks.map(function (c) {
                          return c.join('')
                      });
                      ;
                  })([[]]);
  
                  if (error) {
                      return callback(new (LessError)(error, env));
                  }
  
                  // Start with the primary rule.
                  // The whole syntax tree is held under a Ruleset node,
                  // with the `root` property set to true, so no `{}` are
                  // output. The callback is called when the input is parsed.
                  try {
                      root = new (tree.Ruleset)([], $(this.parsers.primary));
                      root.root = true;
                      root.firstRoot = true;
                  } catch (e) {
                      return callback(new (LessError)(e, env));
                  }
  
                  root.toCSS = (function (evaluate) {
                      var line, lines, column;
  
                      return function (options, variables) {
                          options = options || {};
                          var importError,
                              evalEnv = new tree.evalEnv(options);
  
                          //
                          // Allows setting variables with a hash, so:
                          //
                          //   `{ color: new(tree.Color)('#f01') }` will become:
                          //
                          //   new(tree.Rule)('@color',
                          //     new(tree.Value)([
                          //       new(tree.Expression)([
                          //         new(tree.Color)('#f01')
                          //       ])
                          //     ])
                          //   )
                          //
                          if (typeof(variables) === 'object' && !Array.isArray(variables)) {
                              variables = Object.keys(variables).map(function (k) {
                                  var value = variables[k];
  
                                  if (!(value instanceof tree.Value)) {
                                      if (!(value instanceof tree.Expression)) {
                                          value = new (tree.Expression)([value]);
                                      }
                                      value = new (tree.Value)([value]);
                                  }
                                  return new (tree.Rule)('@' + k, value, false, 0);
                              });
                              evalEnv.frames = [new (tree.Ruleset)(null, variables)];
                          }
  
                          try {
                              var evaldRoot = evaluate.call(this, evalEnv);
  
                              new (tree.joinSelectorVisitor)()
                              .run(evaldRoot);
  
                              new (tree.processExtendsVisitor)()
                              .run(evaldRoot);
  
                              var css = evaldRoot.toCSS({
                                  compress: Boolean(options.compress),
                                  dumpLineNumbers: env.dumpLineNumbers,
                                  strictUnits: Boolean(options.strictUnits)
                              });
                          } catch (e) {
                              throw new (LessError)(e, env);
                          }
  
                          if (options.yuicompress && less.mode === 'node') {
                              return require('ycssmin').cssmin(css, options.maxLineLen);
                          } else if (options.compress) {
                              return css.replace(/(\s)+/g, "$1");
                          } else {
                              return css;
                          }
                      };
                  })(root.eval);
  
                  // If `i` is smaller than the `input.length - 1`,
                  // it means the parser wasn't able to parse the whole
                  // string, so we've got a parsing error.
                  //
                  // We try to extract a \n delimited string,
                  // showing the line where the parse error occured.
                  // We split it up into two parts (the part which parsed,
                  // and the part which didn't), so we can color them differently.
                  if (i < input.length - 1) {
                      i = furthest;
                      lines = input.split('\n');
                      line = (input.slice(0, i).match(/\n/g) || "").length + 1;
  
                      for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) {
                          column++
                      }
  
                      error = {
                          type: "Parse",
                          message: "Unrecognised input",
                          index: i,
                          filename: env.currentFileInfo.filename,
                          line: line,
                          column: column,
                          extract: [
                              lines[line - 2],
                              lines[line - 1],
                              lines[line]
                          ]
                      };
                  }
  
                  var finish = function (e) {
                      e = error || e || parser.imports.error;
  
                      if (e) {
                          if (!(e instanceof LessError)) {
                              e = new (LessError)(e, env);
                          }
  
                          callback(e);
                      }
                      else {
                          callback(null, root);
                      }
                  };
  
                  if (env.processImports !== false) {
                      new tree.importVisitor(this.imports, finish)
                      .run(root);
                  } else {
                      finish();
                  }
              },
  
              //
              // Here in, the parsing rules/functions
              //
              // The basic structure of the syntax tree generated is as follows:
              //
              //   Ruleset ->  Rule -> Value -> Expression -> Entity
              //
              // Here's some LESS code:
              //
              //    .class {
              //      color: #fff;
              //      border: 1px solid #000;
              //      width: @w + 4px;
              //      > .child {...}
              //    }
              //
              // And here's what the parse tree might look like:
              //
              //     Ruleset (Selector '.class', [
              //         Rule ("color",  Value ([Expression [Color #fff]]))
              //         Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
              //         Rule ("width",  Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
              //         Ruleset (Selector [Element '>', '.child'], [...])
              //     ])
              //
              //  In general, most rules will try to parse a token with the `$()` function, and if the return
              //  value is truly, will return a new node, of the relevant type. Sometimes, we need to check
              //  first, before parsing, that's when we use `peek()`.
              //
              parsers: {
                  //
                  // The `primary` rule is the *entry* and *exit* point of the parser.
                  // The rules here can appear at any level of the parse tree.
                  //
                  // The recursive nature of the grammar is an interplay between the `block`
                  // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
                  // as represented by this simplified grammar:
                  //
                  //     primary  →  (ruleset | rule)+
                  //     ruleset  →  selector+ block
                  //     block    →  '{' primary '}'
                  //
                  // Only at one point is the primary rule not called from the
                  // block rule: at the root level.
                  //
                  primary: function () {
                      var node, root = [];
  
                      while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
                          $(this.mixin.call) || $(this.comment) || $(this.directive))
                      || $(/^[\s\n]+/) || $(/^;+/)) {
                          node && root.push(node);
                      }
                      return root;
                  },
  
                  // We create a Comment node for CSS comments `/* */`,
                  // but keep the LeSS comments `//` silent, by just skipping
                  // over them.
                  comment: function () {
                      var comment;
  
                      if (input.charAt(i) !== '/') {
                          return;
                      }
  
                      if (input.charAt(i + 1) === '/') {
                          return new (tree.Comment)($(/^\/\/.*/), true);
                      } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
                          return new (tree.Comment)(comment);
                      }
                  },
  
                  //
                  // Entities are tokens which can be found inside an Expression
                  //
                  entities: {
                      //
                      // A string, which supports escaping " and '
                      //
                      //     "milky way" 'he\'s the one!'
                      //
                      quoted: function () {
                          var str, j = i, e, index = i;
  
                          if (input.charAt(j) === '~') {
                              j++, e = true
                          } // Escaped strings
                          if (input.charAt(j) !== '"' && input.charAt(j) !== "'") {
                              return;
                          }
  
                          e && $('~');
  
                          if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
                              return new (tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo);
                          }
                      },
  
                      //
                      // A catch-all word, such as:
                      //
                      //     black border-collapse
                      //
                      keyword: function () {
                          var k;
  
                          if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
                              if (tree.colors.hasOwnProperty(k)) {
                                  // detect named color
                                  return new (tree.Color)(tree.colors[k].slice(1));
                              } else {
                                  return new (tree.Keyword)(k);
                              }
                          }
                      },
  
                      //
                      // A function call
                      //
                      //     rgb(255, 0, 255)
                      //
                      // We also try to catch IE's `alpha()`, but let the `alpha` parser
                      // deal with the details.
                      //
                      // The arguments are parsed with the `entities.arguments` parser.
                      //
                      call: function () {
                          var name, nameLC, args, alpha_ret, index = i;
  
                          if (!(name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) {
                              return;
                          }
  
                          name = name[1];
                          nameLC = name.toLowerCase();
  
                          if (nameLC === 'url') {
                              return null
                          }
                          else {
                              i += name.length
                          }
  
                          if (nameLC === 'alpha') {
                              alpha_ret = $(this.alpha);
                              if (typeof alpha_ret !== 'undefined') {
                                  return alpha_ret;
                              }
                          }
  
                          $('('); // Parse the '(' and consume whitespace.
  
                          args = $(this.entities.arguments);
  
                          if (!$(')')) {
                              return;
                          }
  
                          if (name) {
                              return new (tree.Call)(name, args, index, env.currentFileInfo);
                          }
                      },
                      arguments: function () {
                          var args = [], arg;
  
                          while (arg = $(this.entities.assignment) || $(this.expression)) {
                              args.push(arg);
                              if (!$(',')) {
                                  break
                              }
                          }
                          return args;
                      },
                      literal: function () {
                          return $(this.entities.dimension) ||
                              $(this.entities.color) ||
                              $(this.entities.quoted) ||
                              $(this.entities.unicodeDescriptor);
                      },
  
                      // Assignments are argument entities for calls.
                      // They are present in ie filter properties as shown below.
                      //
                      //     filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
                      //
  
                      assignment: function () {
                          var key, value;
                          if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
                              return new (tree.Assignment)(key, value);
                          }
                      },
  
                      //
                      // Parse url() tokens
                      //
                      // We use a specific rule for urls, because they don't really behave like
                      // standard function calls. The difference is that the argument doesn't have
                      // to be enclosed within a string, so it can't be parsed as an Expression.
                      //
                      url: function () {
                          var value;
  
                          if (input.charAt(i) !== 'u' || !$(/^url\(/)) {
                              return;
                          }
                          value = $(this.entities.quoted) || $(this.entities.variable) ||
                              $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
  
                          expect(')');
  
                          return new (tree.URL)((value.value != null || value instanceof tree.Variable)
                              ? value : new (tree.Anonymous)(value), env.currentFileInfo);
                      },
  
                      //
                      // A Variable entity, such as `@fink`, in
                      //
                      //     width: @fink + 2px
                      //
                      // We use a different parser for variable definitions,
                      // see `parsers.variable`.
                      //
                      variable: function () {
                          var name, index = i;
  
                          if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
                              return new (tree.Variable)(name, index, env.currentFileInfo);
                          }
                      },
  
                      // A variable entity useing the protective {} e.g. @{var}
                      variableCurly: function () {
                          var name, curly, index = i;
  
                          if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
                              return new (tree.Variable)("@" + curly[1], index, env.currentFileInfo);
                          }
                      },
  
                      //
                      // A Hexadecimal color
                      //
                      //     #4F3C2F
                      //
                      // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
                      //
                      color: function () {
                          var rgb;
  
                          if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
                              return new (tree.Color)(rgb[1]);
                          }
                      },
  
                      //
                      // A Dimension, that is, a number and a unit
                      //
                      //     0.5em 95%
                      //
                      dimension: function () {
                          var value, c = input.charCodeAt(i);
                          //Is the first char of the dimension 0-9, '.', '+' or '-'
                          if ((c > 57 || c < 43) || c === 47 || c == 44) {
                              return;
                          }
  
                          if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) {
                              return new (tree.Dimension)(value[1], value[2]);
                          }
                      },
  
                      //
                      // A unicode descriptor, as is used in unicode-range
                      //
                      // U+0??  or U+00A1-00A9
                      //
                      unicodeDescriptor: function () {
                          var ud;
  
                          if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) {
                              return new (tree.UnicodeDescriptor)(ud[0]);
                          }
                      },
  
                      //
                      // JavaScript code to be evaluated
                      //
                      //     `window.location.href`
                      //
                      javascript: function () {
                          var str, j = i, e;
  
                          if (input.charAt(j) === '~') {
                              j++, e = true
                          } // Escaped strings
                          if (input.charAt(j) !== '`') {
                              return
                          }
  
                          e && $('~');
  
                          if (str = $(/^`([^`]*)`/)) {
                              return new (tree.JavaScript)(str[1], i, e);
                          }
                      }
                  },
  
                  //
                  // The variable part of a variable definition. Used in the `rule` parser
                  //
                  //     @fink:
                  //
                  variable: function () {
                      var name;
  
                      if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) {
                          return name[1]
                      }
                  },
  
                  //
                  // extend syntax - used to extend selectors
                  //
                  extend: function (isRule) {
                      var elements, e, index = i, option, extendList = [];
  
                      if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) {
                          return;
                      }
  
                      do {
                          option = null;
                          elements = [];
                          while (true) {
                              option = $(/^(all)(?=\s*(\)|,))/);
                              if (option) {
                                  break;
                              }
                              e = $(this.element);
                              if (!e) {
                                  break;
                              }
                              elements.push(e);
                          }
  
                          option = option && option[1];
  
                          extendList.push(new (tree.Extend)(new (tree.Selector)(elements), option, index));
  
                      } while ($(","))
  
                      expect(/^\)/);
  
                      if (isRule) {
                          expect(/^;/);
                      }
  
                      return extendList;
                  },
  
                  //
                  // extendRule - used in a rule to extend all the parent selectors
                  //
                  extendRule: function () {
                      return this.extend(true);
                  },
  
                  //
                  // Mixins
                  //
                  mixin: {
                      //
                      // A Mixin call, with an optional argument list
                      //
                      //     #mixins > .square(#fff);
                      //     .rounded(4px, black);
                      //     .button;
                      //
                      // The `while` loop is there because mixins can be
                      // namespaced, but we only support the child and descendant
                      // selector for now.
                      //
                      call: function () {
                          var elements = [], e, c, args, delim, arg, index = i, s = input.charAt(i), important = false;
  
                          if (s !== '.' && s !== '#') {
                              return
                          }
  
                          save(); // stop us absorbing part of an invalid selector
  
                          while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
                              elements.push(new (tree.Element)(c, e, i));
                              c = $('>');
                          }
                          if ($('(')) {
                              args = this.mixin.args.call(this, true).args;
                              expect(')');
                          }
  
                          args = args || [];
  
                          if ($(this.important)) {
                              important = true;
                          }
  
                          if (elements.length > 0 && ($(';') || peek('}'))) {
                              return new (tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
                          }
  
                          restore();
                      },
                      args: function (isCall) {
                          var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg,
                              returner = {args: null, variadic: false};
                          while (true) {
                              if (isCall) {
                                  arg = $(this.expression);
                              } else {
                                  $(this.comment);
                                  if (input.charAt(i) === '.' && $(/^\.{3}/)) {
                                      returner.variadic = true;
                                      if ($(";") && !isSemiColonSeperated) {
                                          isSemiColonSeperated = true;
                                      }
                                      (isSemiColonSeperated ? argsSemiColon : argsComma)
                                      .push({variadic: true});
                                      break;
                                  }
                                  arg = $(this.entities.variable) || $(this.entities.literal)
                                      || $(this.entities.keyword);
                              }
  
                              if (!arg) {
                                  break;
                              }
  
                              nameLoop = null;
                              if (arg.throwAwayComments) {
                                  arg.throwAwayComments();
                              }
                              value = arg;
                              var val = null;
  
                              if (isCall) {
                                  // Variable
                                  if (arg.value.length == 1) {
                                      var val = arg.value[0];
                                  }
                              } else {
                                  val = arg;
                              }
  
                              if (val && val instanceof tree.Variable) {
                                  if ($(':')) {
                                      if (expressions.length > 0) {
                                          if (isSemiColonSeperated) {
                                              error("Cannot mix ; and , as delimiter types");
                                          }
                                          expressionContainsNamed = true;
                                      }
                                      value = expect(this.expression);
                                      nameLoop = (name = val.name);
                                  } else if (!isCall && $(/^\.{3}/)) {
                                      returner.variadic = true;
                                      if ($(";") && !isSemiColonSeperated) {
                                          isSemiColonSeperated = true;
                                      }
                                      (isSemiColonSeperated ? argsSemiColon : argsComma)
                                      .push({name: arg.name, variadic: true});
                                      break;
                                  } else if (!isCall) {
                                      name = nameLoop = val.name;
                                      value = null;
                                  }
                              }
  
                              if (value) {
                                  expressions.push(value);
                              }
  
                              argsComma.push({name: nameLoop, value: value});
  
                              if ($(',')) {
                                  continue;
                              }
  
                              if ($(';') || isSemiColonSeperated) {
  
                                  if (expressionContainsNamed) {
                                      error("Cannot mix ; and , as delimiter types");
                                  }
  
                                  isSemiColonSeperated = true;
  
                                  if (expressions.length > 1) {
                                      value = new (tree.Value)(expressions);
                                  }
                                  argsSemiColon.push({name: name, value: value});
  
                                  name = null;
                                  expressions = [];
                                  expressionContainsNamed = false;
                              }
                          }
  
                          returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
                          return returner;
                      },
                      //
                      // A Mixin definition, with a list of parameters
                      //
                      //     .rounded (@radius: 2px, @color) {
                      //        ...
                      //     }
                      //
                      // Until we have a finer grained state-machine, we have to
                      // do a look-ahead, to make sure we don't have a mixin call.
                      // See the `rule` function for more information.
                      //
                      // We start by matching `.rounded (`, and then proceed on to
                      // the argument list, which has optional default values.
                      // We store the parameters in `params`, with a `value` key,
                      // if there is a value, such as in the case of `@radius`.
                      //
                      // Once we've got our params list, and a closing `)`, we parse
                      // the `{...}` block.
                      //
                      definition: function () {
                          var name, params = [], match, ruleset, param, value, cond, variadic = false;
                          if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
                              peek(/^[^{]*\}/)) {
                              return;
                          }
  
                          save();
  
                          if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
                              name = match[1];
  
                              var argInfo = this.mixin.args.call(this, false);
                              params = argInfo.args;
                              variadic = argInfo.variadic;
  
                              // .mixincall("@{a}");
                              // looks a bit like a mixin definition.. so we have to be nice and restore
                              if (!$(')')) {
                                  furthest = i;
                                  restore();
                              }
  
                              $(this.comment);
  
                              if ($(/^when/)) { // Guard
                                  cond = expect(this.conditions, 'expected condition');
                              }
  
                              ruleset = $(this.block);
  
                              if (ruleset) {
                                  return new (tree.mixin.Definition)(name, params, ruleset, cond, variadic);
                              } else {
                                  restore();
                              }
                          }
                      }
                  },
  
                  //
                  // Entities are the smallest recognized token,
                  // and can be found inside a rule's value.
                  //
                  entity: function () {
                      return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
                          $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) ||
                          $(this.comment);
                  },
  
                  //
                  // A Rule terminator. Note that we use `peek()` to check for '}',
                  // because the `block` rule will be expecting it, but we still need to make sure
                  // it's there, if ';' was ommitted.
                  //
                  end: function () {
                      return $(';') || peek('}');
                  },
  
                  //
                  // IE's alpha function
                  //
                  //     alpha(opacity=88)
                  //
                  alpha: function () {
                      var value;
  
                      if (!$(/^\(opacity=/i)) {
                          return;
                      }
                      if (value = $(/^\d+/) || $(this.entities.variable)) {
                          expect(')');
                          return new (tree.Alpha)(value);
                      }
                  },
  
                  //
                  // A Selector Element
                  //
                  //     div
                  //     + h1
                  //     #socks
                  //     input[type="text"]
                  //
                  // Elements are the building blocks for Selectors,
                  // they are made out of a `Combinator` (see combinator rule),
                  // and an element name, such as a tag a class, or `*`.
                  //
                  element: function () {
                      var e, t, c, v;
  
                      c = $(this.combinator);
  
                      e = $(/^(?:\d+\.\d+|\d+)%/) || $(
                              /^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
                          $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(
                              this.entities.variableCurly);
  
                      if (!e) {
                          if ($('(')) {
                              if ((v = ($(this.selector))) &&
                                  $(')')) {
                                  e = new (tree.Paren)(v);
                              }
                          }
                      }
  
                      if (e) {
                          return new (tree.Element)(c, e, i)
                      }
                  },
  
                  //
                  // Combinators combine elements together, in a Selector.
                  //
                  // Because our parser isn't white-space sensitive, special care
                  // has to be taken, when parsing the descendant combinator, ` `,
                  // as it's an empty space. We have to check the previous character
                  // in the input, to see if it's a ` ` character. More info on how
                  // we deal with this in *combinator.js*.
                  //
                  combinator: function () {
                      var match, c = input.charAt(i);
  
                      if (c === '>' || c === '+' || c === '~' || c === '|') {
                          i++;
                          while (input.charAt(i).match(/\s/)) {
                              i++
                          }
                          return new (tree.Combinator)(c);
                      } else if (input.charAt(i - 1).match(/\s/)) {
                          return new (tree.Combinator)(" ");
                      } else {
                          return new (tree.Combinator)(null);
                      }
                  },
  
                  //
                  // A CSS Selector
                  //
                  //     .class > div + h1
                  //     li a:hover
                  //
                  // Selectors are made out of one or more Elements, see above.
                  //
                  selector: function () {
                      var sel, e, elements = [], c, match, extend, extendList = [];
  
                      while ((extend = $(this.extend)) || (e = $(this.element))) {
                          if (extend) {
                              extendList.push.apply(extendList, extend);
                          } else {
                              if (extendList.length) {
                                  error("Extend can only be used at the end of selector");
                              }
                              c = input.charAt(i);
                              elements.push(e)
                              e = null;
                          }
                          if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
                              break
                          }
                      }
  
                      if (elements.length > 0) {
                          return new (tree.Selector)(elements, extendList);
                      }
                      if (extendList.length) {
                          error("Extend must be used to extend a selector, it cannot be used on its own");
                      }
                  },
                  attribute: function () {
                      var attr = '', key, val, op;
  
                      if (!$('[')) {
                          return;
                      }
  
                      if (!(key = $(this.entities.variableCurly))) {
                          key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
                      }
  
                      if ((op = $(/^[|~*$^]?=/))) {
                          val = $(this.entities.quoted) || $(/^[\w-]+/) || $(this.entities.variableCurly);
                      }
  
                      expect(']');
  
                      return new (tree.Attribute)(key, op, val);
                  },
  
                  //
                  // The `block` rule is used by `ruleset` and `mixin.definition`.
                  // It's a wrapper around the `primary` rule, with added `{}`.
                  //
                  block: function () {
                      var content;
                      if ($('{') && (content = $(this.primary)) && $('}')) {
                          return content;
                      }
                  },
  
                  //
                  // div, .class, body > p {...}
                  //
                  ruleset: function () {
                      var selectors = [], s, rules, match, debugInfo;
  
                      save();
  
                      if (env.dumpLineNumbers) {
                          debugInfo = getDebugInfo(i, input, env);
                      }
  
                      while (s = $(this.selector)) {
                          selectors.push(s);
                          $(this.comment);
                          if (!$(',')) {
                              break
                          }
                          $(this.comment);
                      }
  
                      if (selectors.length > 0 && (rules = $(this.block))) {
                          var ruleset = new (tree.Ruleset)(selectors, rules, env.strictImports);
                          if (env.dumpLineNumbers) {
                              ruleset.debugInfo = debugInfo;
                          }
                          return ruleset;
                      } else {
                          // Backtrack
                          furthest = i;
                          restore();
                      }
                  },
                  rule: function (tryAnonymous) {
                      var name, value, c = input.charAt(i), important, match;
                      save();
  
                      if (c === '.' || c === '#' || c === '&') {
                          return
                      }
  
                      if (name = $(this.variable) || $(this.property)) {
                          // prefer to try to parse first if its a variable or we are compressing
                          // but always fallback on the other one
                          value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ?
                              ($(this.value) || $(this.anonymousValue)) :
                              ($(this.anonymousValue) || $(this.value));
  
                          important = $(this.important);
  
                          if (value && $(this.end)) {
                              return new (tree.Rule)(name, value, important, memo, env.currentFileInfo);
                          } else {
                              furthest = i;
                              restore();
                              if (value && !tryAnonymous) {
                                  return this.rule(true);
                              }
                          }
                      }
                  },
                  anonymousValue: function () {
                      if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) {
                          i += match[0].length - 1;
                          return new (tree.Anonymous)(match[1]);
                      }
                  },
  
                  //
                  // An @import directive
                  //
                  //     @import "lib";
                  //
                  // Depending on our environemnt, importing is done differently:
                  // In the browser, it's an XHR request, in Node, it would be a
                  // file-system operation. The function used for importing is
                  // stored in `import`, which we pass to the Import constructor.
                  //
                  "import": function () {
                      var path, features, index = i;
  
                      save();
  
                      var dir = $(/^@import?\s+/);
  
                      var options = (dir ? $(this.importOptions) : null) || {};
  
                      if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
                          features = $(this.mediaFeatures);
                          if ($(';')) {
                              features = features && new (tree.Value)(features);
                              return new (tree.Import)(path, features, options, index, env.currentFileInfo);
                          }
                      }
  
                      restore();
                  },
  
                  importOptions: function () {
                      var o, options = {}, optionName, value;
  
                      // list of options, surrounded by parens
                      if (!$('(')) {
                          return null;
                      }
                      do {
                          if (o = $(this.importOption)) {
                              optionName = o;
                              value = true;
                              switch (optionName) {
                                  case "css":
                                      optionName = "less";
                                      value = false;
                                      break;
                                  case "once":
                                      optionName = "multiple";
                                      value = false;
                                      break;
                              }
                              options[optionName] = value;
                              if (!$(',')) {
                                  break
                              }
                          }
                      } while (o);
                      expect(')');
                      return options;
                  },
  
                  importOption: function () {
                      var opt = $(/^(less|css|multiple|once)/);
                      if (opt) {
                          return opt[1];
                      }
                  },
  
                  mediaFeature: function () {
                      var e, p, nodes = [];
  
                      do {
                          if (e = $(this.entities.keyword)) {
                              nodes.push(e);
                          } else if ($('(')) {
                              p = $(this.property);
                              e = $(this.value);
                              if ($(')')) {
                                  if (p && e) {
                                      nodes.push(
                                          new (tree.Paren)(new (tree.Rule)(p, e, null, i, env.currentFileInfo, true)));
                                  } else if (e) {
                                      nodes.push(new (tree.Paren)(e));
                                  } else {
                                      return null;
                                  }
                              } else {
                                  return null
                              }
                          }
                      } while (e);
  
                      if (nodes.length > 0) {
                          return new (tree.Expression)(nodes);
                      }
                  },
  
                  mediaFeatures: function () {
                      var e, features = [];
  
                      do {
                          if (e = $(this.mediaFeature)) {
                              features.push(e);
                              if (!$(',')) {
                                  break
                              }
                          } else if (e = $(this.entities.variable)) {
                              features.push(e);
                              if (!$(',')) {
                                  break
                              }
                          }
                      } while (e);
  
                      return features.length > 0 ? features : null;
                  },
  
                  media: function () {
                      var features, rules, media, debugInfo;
  
                      if (env.dumpLineNumbers) {
                          debugInfo = getDebugInfo(i, input, env);
                      }
  
                      if ($(/^@media/)) {
                          features = $(this.mediaFeatures);
  
                          if (rules = $(this.block)) {
                              media = new (tree.Media)(rules, features);
                              if (env.dumpLineNumbers) {
                                  media.debugInfo = debugInfo;
                              }
                              return media;
                          }
                      }
                  },
  
                  //
                  // A CSS Directive
                  //
                  //     @charset "utf-8";
                  //
                  directive: function () {
                      var name, value, rules, identifier, e, nodes, nonVendorSpecificName,
                          hasBlock, hasIdentifier, hasExpression;
  
                      if (input.charAt(i) !== '@') {
                          return;
                      }
  
                      if (value = $(this['import']) || $(this.media)) {
                          return value;
                      }
  
                      save();
  
                      name = $(/^@[a-z-]+/);
  
                      if (!name) {
                          return;
                      }
  
                      nonVendorSpecificName = name;
                      if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
                          nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
                      }
  
                      switch (nonVendorSpecificName) {
                          case "@font-face":
                              hasBlock = true;
                              break;
                          case "@viewport":
                          case "@top-left":
                          case "@top-left-corner":
                          case "@top-center":
                          case "@top-right":
                          case "@top-right-corner":
                          case "@bottom-left":
                          case "@bottom-left-corner":
                          case "@bottom-center":
                          case "@bottom-right":
                          case "@bottom-right-corner":
                          case "@left-top":
                          case "@left-middle":
                          case "@left-bottom":
                          case "@right-top":
                          case "@right-middle":
                          case "@right-bottom":
                              hasBlock = true;
                              break;
                          case "@page":
                          case "@document":
                          case "@supports":
                          case "@keyframes":
                              hasBlock = true;
                              hasIdentifier = true;
                              break;
                          case "@namespace":
                              hasExpression = true;
                              break;
                      }
  
                      if (hasIdentifier) {
                          name += " " + ($(/^[^{]+/) || '').trim();
                      }
  
                      if (hasBlock) {
                          if (rules = $(this.block)) {
                              return new (tree.Directive)(name, rules);
                          }
                      } else {
                          if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
                              var directive = new (tree.Directive)(name, value);
                              if (env.dumpLineNumbers) {
                                  directive.debugInfo = getDebugInfo(i, input, env);
                              }
                              return directive;
                          }
                      }
  
                      restore();
                  },
  
                  //
                  // A Value is a comma-delimited list of Expressions
                  //
                  //     font-family: Baskerville, Georgia, serif;
                  //
                  // In a Rule, a Value represents everything after the `:`,
                  // and before the `;`.
                  //
                  value: function () {
                      var e, expressions = [], important;
  
                      while (e = $(this.expression)) {
                          expressions.push(e);
                          if (!$(',')) {
                              break
                          }
                      }
  
                      if (expressions.length > 0) {
                          return new (tree.Value)(expressions);
                      }
                  },
                  important: function () {
                      if (input.charAt(i) === '!') {
                          return $(/^! *important/);
                      }
                  },
                  sub: function () {
                      var a, e;
  
                      if ($('(')) {
                          if (a = $(this.addition)) {
                              e = new (tree.Expression)([a]);
                              expect(')');
                              e.parens = true;
                              return e;
                          }
                      }
                  },
                  multiplication: function () {
                      var m, a, op, operation, isSpaced, expression = [];
                      if (m = $(this.operand)) {
                          isSpaced = isWhitespace(input.charAt(i - 1));
                          while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) {
                              if (a = $(this.operand)) {
                                  m.parensInOp = true;
                                  a.parensInOp = true;
                                  operation = new (tree.Operation)(op, [operation || m, a], isSpaced);
                                  isSpaced = isWhitespace(input.charAt(i - 1));
                              } else {
                                  break;
                              }
                          }
                          return operation || m;
                      }
                  },
                  addition: function () {
                      var m, a, op, operation, isSpaced;
                      if (m = $(this.multiplication)) {
                          isSpaced = isWhitespace(input.charAt(i - 1));
                          while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) &&
                          (a = $(this.multiplication))) {
                              m.parensInOp = true;
                              a.parensInOp = true;
                              operation = new (tree.Operation)(op, [operation || m, a], isSpaced);
                              isSpaced = isWhitespace(input.charAt(i - 1));
                          }
                          return operation || m;
                      }
                  },
                  conditions: function () {
                      var a, b, index = i, condition;
  
                      if (a = $(this.condition)) {
                          while ($(',') && (b = $(this.condition))) {
                              condition = new (tree.Condition)('or', condition || a, b, index);
                          }
                          return condition || a;
                      }
                  },
                  condition: function () {
                      var a, b, c, op, index = i, negate = false;
  
                      if ($(/^not/)) {
                          negate = true
                      }
                      expect('(');
                      if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
                          if (op = $(/^(?:>=|=<|[<=>])/)) {
                              if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
                                  c = new (tree.Condition)(op, a, b, index, negate);
                              } else {
                                  error('expected expression');
                              }
                          } else {
                              c = new (tree.Condition)('=', a, new (tree.Keyword)('true'), index, negate);
                          }
                          expect(')');
                          return $(/^and/) ? new (tree.Condition)('and', c, $(this.condition)) : c;
                      }
                  },
  
                  //
                  // An operand is anything that can be part of an operation,
                  // such as a Color, or a Variable
                  //
                  operand: function () {
                      var negate, p = input.charAt(i + 1);
  
                      if (input.charAt(i) === '-' && (p === '@' || p === '(')) {
                          negate = $('-')
                      }
                      var o = $(this.sub) || $(this.entities.dimension) ||
                          $(this.entities.color) || $(this.entities.variable) ||
                          $(this.entities.call);
  
                      if (negate) {
                          o.parensInOp = true;
                          o = new (tree.Negative)(o);
                      }
  
                      return o;
                  },
  
                  //
                  // Expressions either represent mathematical operations,
                  // or white-space delimited Entities.
                  //
                  //     1px solid black
                  //     @var * 2
                  //
                  expression: function () {
                      var e, delim, entities = [], d;
  
                      while (e = $(this.addition) || $(this.entity)) {
                          entities.push(e);
                          // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
                          if (!peek(/^\/[\/*]/) && (delim = $('/'))) {
                              entities.push(new (tree.Anonymous)(delim));
                          }
                      }
                      if (entities.length > 0) {
                          return new (tree.Expression)(entities);
                      }
                  },
                  property: function () {
                      var name;
  
                      if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) {
                          return name[1];
                      }
                  }
              }
          };
      };
  
      if (less.mode === 'browser' || less.mode === 'rhino') {
          //
          // Used by `@import` directives
          //
          less.Parser.importer = function (path, currentFileInfo, callback, env) {
              if (!/^([a-z-]+:)?\//.test(path) && currentFileInfo.currentDirectory) {
                  path = currentFileInfo.currentDirectory + path;
              }
              var sheetEnv = env.toSheet(path);
              sheetEnv.processImports = false;
              sheetEnv.currentFileInfo = currentFileInfo;
  
              // We pass `true` as 3rd argument, to force the reload of the import.
              // This is so we can get the syntax tree as opposed to just the CSS output,
              // as we need this to evaluate the current stylesheet.
              loadStyleSheet(sheetEnv,
                  function (e, root, data, sheet, _, path) {
                      callback.call(null, e, root, path);
                  }, true);
          };
      }
  
      (function (tree) {
  
          tree.functions = {
              rgb: function (r, g, b) {
                  return this.rgba(r, g, b, 1.0);
              },
              rgba: function (r, g, b, a) {
                  var rgb = [r, g, b].map(function (c) {
                      return scaled(c, 256);
                  });
                  a = number(a);
                  return new (tree.Color)(rgb, a);
              },
              hsl: function (h, s, l) {
                  return this.hsla(h, s, l, 1.0);
              },
              hsla: function (h, s, l, a) {
                  h = (number(h) % 360) / 360;
                  s = clamp(number(s));
                  l = clamp(number(l));
                  a = clamp(number(a));
  
                  var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
                  var m1 = l * 2 - m2;
  
                  return this.rgba(hue(h + 1 / 3) * 255,
                      hue(h) * 255,
                      hue(h - 1 / 3) * 255,
                      a);
  
                  function hue(h) {
                      h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
                      if (h * 6 < 1) {
                          return m1 + (m2 - m1) * h * 6;
                      } else if (h * 2 < 1) {
                          return m2;
                      } else if (h * 3 < 2) {
                          return m1 + (m2 - m1) * (2 / 3 - h) * 6;
                      } else {
                          return m1;
                      }
                  }
              },
  
              hsv: function (h, s, v) {
                  return this.hsva(h, s, v, 1.0);
              },
  
              hsva: function (h, s, v, a) {
                  h = ((number(h) % 360) / 360) * 360;
                  s = number(s);
                  v = number(v);
                  a = number(a);
  
                  var i, f;
                  i = Math.floor((h / 60) % 6);
                  f = (h / 60) - i;
  
                  var vs = [v,
                      v * (1 - s),
                      v * (1 - f * s),
                      v * (1 - (1 - f) * s)];
                  var perm = [[0, 3, 1],
                      [2, 0, 1],
                      [1, 0, 3],
                      [1, 2, 0],
                      [3, 1, 0],
                      [0, 1, 2]];
  
                  return this.rgba(vs[perm[i][0]] * 255,
                      vs[perm[i][1]] * 255,
                      vs[perm[i][2]] * 255,
                      a);
              },
  
              hue: function (color) {
                  return new (tree.Dimension)(Math.round(color.toHSL().h));
              },
              saturation: function (color) {
                  return new (tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
              },
              lightness: function (color) {
                  return new (tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
              },
              hsvhue: function (color) {
                  return new (tree.Dimension)(Math.round(color.toHSV().h));
              },
              hsvsaturation: function (color) {
                  return new (tree.Dimension)(Math.round(color.toHSV().s * 100), '%');
              },
              hsvvalue: function (color) {
                  return new (tree.Dimension)(Math.round(color.toHSV().v * 100), '%');
              },
              red: function (color) {
                  return new (tree.Dimension)(color.rgb[0]);
              },
              green: function (color) {
                  return new (tree.Dimension)(color.rgb[1]);
              },
              blue: function (color) {
                  return new (tree.Dimension)(color.rgb[2]);
              },
              alpha: function (color) {
                  return new (tree.Dimension)(color.toHSL().a);
              },
              luma: function (color) {
                  return new (tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%');
              },
              saturate: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.s += amount.value / 100;
                  hsl.s = clamp(hsl.s);
                  return hsla(hsl);
              },
              desaturate: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.s -= amount.value / 100;
                  hsl.s = clamp(hsl.s);
                  return hsla(hsl);
              },
              lighten: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.l += amount.value / 100;
                  hsl.l = clamp(hsl.l);
                  return hsla(hsl);
              },
              darken: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.l -= amount.value / 100;
                  hsl.l = clamp(hsl.l);
                  return hsla(hsl);
              },
              fadein: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.a += amount.value / 100;
                  hsl.a = clamp(hsl.a);
                  return hsla(hsl);
              },
              fadeout: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.a -= amount.value / 100;
                  hsl.a = clamp(hsl.a);
                  return hsla(hsl);
              },
              fade: function (color, amount) {
                  var hsl = color.toHSL();
  
                  hsl.a = amount.value / 100;
                  hsl.a = clamp(hsl.a);
                  return hsla(hsl);
              },
              spin: function (color, amount) {
                  var hsl = color.toHSL();
                  var hue = (hsl.h + amount.value) % 360;
  
                  hsl.h = hue < 0 ? 360 + hue : hue;
  
                  return hsla(hsl);
              },
              //
              // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
              // http://sass-lang.com
              //
              mix: function (color1, color2, weight) {
                  if (!weight) {
                      weight = new (tree.Dimension)(50);
                  }
                  var p = weight.value / 100.0;
                  var w = p * 2 - 1;
                  var a = color1.toHSL().a - color2.toHSL().a;
  
                  var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
                  var w2 = 1 - w1;
  
                  var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
                      color1.rgb[1] * w1 + color2.rgb[1] * w2,
                      color1.rgb[2] * w1 + color2.rgb[2] * w2];
  
                  var alpha = color1.alpha * p + color2.alpha * (1 - p);
  
                  return new (tree.Color)(rgb, alpha);
              },
              greyscale: function (color) {
                  return this.desaturate(color, new (tree.Dimension)(100));
              },
              contrast: function (color, dark, light, threshold) {
                  // filter: contrast(3.2);
                  // should be kept as is, so check for color
                  if (!color.rgb) {
                      return null;
                  }
                  if (typeof light === 'undefined') {
                      light = this.rgba(255, 255, 255, 1.0);
                  }
                  if (typeof dark === 'undefined') {
                      dark = this.rgba(0, 0, 0, 1.0);
                  }
                  //Figure out which is actually light and dark!
                  if (dark.luma() > light.luma()) {
                      var t = light;
                      light = dark;
                      dark = t;
                  }
                  if (typeof threshold === 'undefined') {
                      threshold = 0.43;
                  } else {
                      threshold = number(threshold);
                  }
                  if ((color.luma() * color.alpha) < threshold) {
                      return light;
                  } else {
                      return dark;
                  }
              },
              e: function (str) {
                  return new (tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
              },
              escape: function (str) {
                  return new (tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g,
                      "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
              },
              '%': function (quoted /* arg, arg, ...*/) {
                  var args = Array.prototype.slice.call(arguments, 1),
                      str = quoted.value;
  
                  for (var i = 0; i < args.length; i++) {
                      str = str.replace(/%[sda]/i, function (token) {
                          var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
                          return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
                      });
                  }
                  str = str.replace(/%%/g, '%');
                  return new (tree.Quoted)('"' + str + '"', str);
              },
              unit: function (val, unit) {
                  return new (tree.Dimension)(val.value, unit ? unit.toCSS() : "");
              },
              convert: function (val, unit) {
                  return val.convertTo(unit.value);
              },
              round: function (n, f) {
                  var fraction = typeof(f) === "undefined" ? 0 : f.value;
                  return this._math(function (num) {
                      return num.toFixed(fraction);
                  }, null, n);
              },
              pi: function () {
                  return new (tree.Dimension)(Math.PI);
              },
              mod: function (a, b) {
                  return new (tree.Dimension)(a.value % b.value, a.unit);
              },
              pow: function (x, y) {
                  if (typeof x === "number" && typeof y === "number") {
                      x = new (tree.Dimension)(x);
                      y = new (tree.Dimension)(y);
                  } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) {
                      throw {type: "Argument", message: "arguments must be numbers"};
                  }
  
                  return new (tree.Dimension)(Math.pow(x.value, y.value), x.unit);
              },
              _math: function (fn, unit, n) {
                  if (n instanceof tree.Dimension) {
                      return new (tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit);
                  } else if (typeof(n) === 'number') {
                      return fn(n);
                  } else {
                      throw {type: "Argument", message: "argument must be a number"};
                  }
              },
              argb: function (color) {
                  return new (tree.Anonymous)(color.toARGB());
  
              },
              percentage: function (n) {
                  return new (tree.Dimension)(n.value * 100, '%');
              },
              color: function (n) {
                  if (n instanceof tree.Quoted) {
                      return new (tree.Color)(n.value.slice(1));
                  } else {
                      throw {type: "Argument", message: "argument must be a string"};
                  }
              },
              iscolor: function (n) {
                  return this._isa(n, tree.Color);
              },
              isnumber: function (n) {
                  return this._isa(n, tree.Dimension);
              },
              isstring: function (n) {
                  return this._isa(n, tree.Quoted);
              },
              iskeyword: function (n) {
                  return this._isa(n, tree.Keyword);
              },
              isurl: function (n) {
                  return this._isa(n, tree.URL);
              },
              ispixel: function (n) {
                  return this.isunit(n, 'px');
              },
              ispercentage: function (n) {
                  return this.isunit(n, '%');
              },
              isem: function (n) {
                  return this.isunit(n, 'em');
              },
              isunit: function (n, unit) {
                  return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False;
              },
              _isa: function (n, Type) {
                  return (n instanceof Type) ? tree.True : tree.False;
              },
  
              /* Blending modes */
  
              multiply: function (color1, color2) {
                  var r = color1.rgb[0] * color2.rgb[0] / 255;
                  var g = color1.rgb[1] * color2.rgb[1] / 255;
                  var b = color1.rgb[2] * color2.rgb[2] / 255;
                  return this.rgb(r, g, b);
              },
              screen: function (color1, color2) {
                  var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
                  var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
                  var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
                  return this.rgb(r, g, b);
              },
              overlay: function (color1, color2) {
                  var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0])
                      * (255 - color2.rgb[0]) / 255;
                  var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1])
                      * (255 - color2.rgb[1]) / 255;
                  var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2])
                      * (255 - color2.rgb[2]) / 255;
                  return this.rgb(r, g, b);
              },
              softlight: function (color1, color2) {
                  var t = color2.rgb[0] * color1.rgb[0] / 255;
                  var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255;
                  t = color2.rgb[1] * color1.rgb[1] / 255;
                  var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255;
                  t = color2.rgb[2] * color1.rgb[2] / 255;
                  var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255;
                  return this.rgb(r, g, b);
              },
              hardlight: function (color1, color2) {
                  var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0])
                      * (255 - color1.rgb[0]) / 255;
                  var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1])
                      * (255 - color1.rgb[1]) / 255;
                  var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2])
                      * (255 - color1.rgb[2]) / 255;
                  return this.rgb(r, g, b);
              },
              difference: function (color1, color2) {
                  var r = Math.abs(color1.rgb[0] - color2.rgb[0]);
                  var g = Math.abs(color1.rgb[1] - color2.rgb[1]);
                  var b = Math.abs(color1.rgb[2] - color2.rgb[2]);
                  return this.rgb(r, g, b);
              },
              exclusion: function (color1, color2) {
                  var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255;
                  var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255;
                  var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255;
                  return this.rgb(r, g, b);
              },
              average: function (color1, color2) {
                  var r = (color1.rgb[0] + color2.rgb[0]) / 2;
                  var g = (color1.rgb[1] + color2.rgb[1]) / 2;
                  var b = (color1.rgb[2] + color2.rgb[2]) / 2;
                  return this.rgb(r, g, b);
              },
              negation: function (color1, color2) {
                  var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]);
                  var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]);
                  var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]);
                  return this.rgb(r, g, b);
              },
              tint: function (color, amount) {
                  return this.mix(this.rgb(255, 255, 255), color, amount);
              },
              shade: function (color, amount) {
                  return this.mix(this.rgb(0, 0, 0), color, amount);
              },
              extract: function (values, index) {
                  index = index.value - 1; // (1-based index)
                  return values.value[index];
              },
  
              "data-uri": function (mimetypeNode, filePathNode) {
  
                  if (typeof window !== 'undefined') {
                      return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
                  }
  
                  var mimetype = mimetypeNode.value;
                  var filePath = (filePathNode && filePathNode.value);
  
                  var fs = require("fs"),
                      path = require("path"),
                      useBase64 = false;
  
                  if (arguments.length < 2) {
                      filePath = mimetype;
                  }
  
                  if (this.env.isPathRelative(filePath)) {
                      if (this.currentFileInfo.relativeUrls) {
                          filePath = path.join(this.currentFileInfo.currentDirectory, filePath);
                      } else {
                          filePath = path.join(this.currentFileInfo.entryPath, filePath);
                      }
                  }
  
                  // detect the mimetype if not given
                  if (arguments.length < 2) {
                      var mime;
                      try {
                          mime = require('mime');
                      } catch (ex) {
                          mime = tree._mime;
                      }
  
                      mimetype = mime.lookup(filePath);
  
                      // use base 64 unless it's an ASCII or UTF-8 format
                      var charset = mime.charsets.lookup(mimetype);
                      useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
                      if (useBase64) {
                          mimetype += ';base64';
                      }
                  }
                  else {
                      useBase64 = /;base64$/.test(mimetype)
                  }
  
                  var buf = fs.readFileSync(filePath);
  
                  // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
                  // and the --ieCompat flag is enabled, return a normal url() instead.
                  var DATA_URI_MAX_KB = 32,
                      fileSizeInKB = parseInt((buf.length / 1024), 10);
                  if (fileSizeInKB >= DATA_URI_MAX_KB) {
  
                      if (this.env.ieCompat !== false) {
                          if (!this.env.silent) {
                              console.warn(
                                  "Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!",
                                  filePath, fileSizeInKB, DATA_URI_MAX_KB);
                          }
  
                          return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
                      } else if (!this.env.silent) {
                          // if explicitly disabled (via --no-ie-compat on CLI, or env.ieCompat === false), merely warn
                          console.warn("WARNING: Embedding %s (%dKB) exceeds IE8's data-uri size limit of %dKB!",
                              filePath, fileSizeInKB, DATA_URI_MAX_KB);
                      }
                  }
  
                  buf = useBase64 ? buf.toString('base64')
                      : encodeURIComponent(buf);
  
                  var uri = "'data:" + mimetype + ',' + buf + "'";
                  return new (tree.URL)(new (tree.Anonymous)(uri));
              }
          };
  
  // these static methods are used as a fallback when the optional 'mime' dependency is missing
          tree._mime = {
              // this map is intentionally incomplete
              // if you want more, install 'mime' dep
              _types: {
                  '.htm': 'text/html',
                  '.html': 'text/html',
                  '.gif': 'image/gif',
                  '.jpg': 'image/jpeg',
                  '.jpeg': 'image/jpeg',
                  '.png': 'image/png'
              },
              lookup: function (filepath) {
                  var ext = require('path').extname(filepath),
                      type = tree._mime._types[ext];
                  if (type === undefined) {
                      throw new Error('Optional dependency "mime" is required for ' + ext);
                  }
                  return type;
              },
              charsets: {
                  lookup: function (type) {
                      // assumes all text types are UTF-8
                      return type && (/^text\//).test(type) ? 'UTF-8' : '';
                  }
              }
          };
  
          var mathFunctions = [{name: "ceil"}, {name: "floor"}, {name: "sqrt"}, {name: "abs"},
                  {name: "tan", unit: ""}, {name: "sin", unit: ""}, {name: "cos", unit: ""},
                  {name: "atan", unit: "rad"}, {name: "asin", unit: "rad"}, {name: "acos", unit: "rad"}],
              createMathFunction = function (name, unit) {
                  return function (n) {
                      if (unit != null) {
                          n = n.unify();
                      }
                      return this._math(Math[name], unit, n);
                  };
              };
  
          for (var i = 0; i < mathFunctions.length; i++) {
              tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit);
          }
  
          function hsla(color) {
              return tree.functions.hsla(color.h, color.s, color.l, color.a);
          }
  
          function scaled(n, size) {
              if (n instanceof tree.Dimension && n.unit.is('%')) {
                  return parseFloat(n.value * size / 100);
              } else {
                  return number(n);
              }
          }
  
          function number(n) {
              if (n instanceof tree.Dimension) {
                  return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
              } else if (typeof(n) === 'number') {
                  return n;
              } else {
                  throw {
                      error: "RuntimeError",
                      message: "color functions take numbers as parameters"
                  };
              }
          }
  
          function clamp(val) {
              return Math.min(1, Math.max(0, val));
          }
  
          tree.functionCall = function (env, currentFileInfo) {
              this.env = env;
              this.currentFileInfo = currentFileInfo;
          };
  
          tree.functionCall.prototype = tree.functions;
  
      })(require('./tree'));
      (function (tree) {
          tree.colors = {
              'aliceblue': '#f0f8ff',
              'antiquewhite': '#faebd7',
              'aqua': '#00ffff',
              'aquamarine': '#7fffd4',
              'azure': '#f0ffff',
              'beige': '#f5f5dc',
              'bisque': '#ffe4c4',
              'black': '#000000',
              'blanchedalmond': '#ffebcd',
              'blue': '#0000ff',
              'blueviolet': '#8a2be2',
              'brown': '#a52a2a',
              'burlywood': '#deb887',
              'cadetblue': '#5f9ea0',
              'chartreuse': '#7fff00',
              'chocolate': '#d2691e',
              'coral': '#ff7f50',
              'cornflowerblue': '#6495ed',
              'cornsilk': '#fff8dc',
              'crimson': '#dc143c',
              'cyan': '#00ffff',
              'darkblue': '#00008b',
              'darkcyan': '#008b8b',
              'darkgoldenrod': '#b8860b',
              'darkgray': '#a9a9a9',
              'darkgrey': '#a9a9a9',
              'darkgreen': '#006400',
              'darkkhaki': '#bdb76b',
              'darkmagenta': '#8b008b',
              'darkolivegreen': '#556b2f',
              'darkorange': '#ff8c00',
              'darkorchid': '#9932cc',
              'darkred': '#8b0000',
              'darksalmon': '#e9967a',
              'darkseagreen': '#8fbc8f',
              'darkslateblue': '#483d8b',
              'darkslategray': '#2f4f4f',
              'darkslategrey': '#2f4f4f',
              'darkturquoise': '#00ced1',
              'darkviolet': '#9400d3',
              'deeppink': '#ff1493',
              'deepskyblue': '#00bfff',
              'dimgray': '#696969',
              'dimgrey': '#696969',
              'dodgerblue': '#1e90ff',
              'firebrick': '#b22222',
              'floralwhite': '#fffaf0',
              'forestgreen': '#228b22',
              'fuchsia': '#ff00ff',
              'gainsboro': '#dcdcdc',
              'ghostwhite': '#f8f8ff',
              'gold': '#ffd700',
              'goldenrod': '#daa520',
              'gray': '#808080',
              'grey': '#808080',
              'green': '#008000',
              'greenyellow': '#adff2f',
              'honeydew': '#f0fff0',
              'hotpink': '#ff69b4',
              'indianred': '#cd5c5c',
              'indigo': '#4b0082',
              'ivory': '#fffff0',
              'khaki': '#f0e68c',
              'lavender': '#e6e6fa',
              'lavenderblush': '#fff0f5',
              'lawngreen': '#7cfc00',
              'lemonchiffon': '#fffacd',
              'lightblue': '#add8e6',
              'lightcoral': '#f08080',
              'lightcyan': '#e0ffff',
              'lightgoldenrodyellow': '#fafad2',
              'lightgray': '#d3d3d3',
              'lightgrey': '#d3d3d3',
              'lightgreen': '#90ee90',
              'lightpink': '#ffb6c1',
              'lightsalmon': '#ffa07a',
              'lightseagreen': '#20b2aa',
              'lightskyblue': '#87cefa',
              'lightslategray': '#778899',
              'lightslategrey': '#778899',
              'lightsteelblue': '#b0c4de',
              'lightyellow': '#ffffe0',
              'lime': '#00ff00',
              'limegreen': '#32cd32',
              'linen': '#faf0e6',
              'magenta': '#ff00ff',
              'maroon': '#800000',
              'mediumaquamarine': '#66cdaa',
              'mediumblue': '#0000cd',
              'mediumorchid': '#ba55d3',
              'mediumpurple': '#9370d8',
              'mediumseagreen': '#3cb371',
              'mediumslateblue': '#7b68ee',
              'mediumspringgreen': '#00fa9a',
              'mediumturquoise': '#48d1cc',
              'mediumvioletred': '#c71585',
              'midnightblue': '#191970',
              'mintcream': '#f5fffa',
              'mistyrose': '#ffe4e1',
              'moccasin': '#ffe4b5',
              'navajowhite': '#ffdead',
              'navy': '#000080',
              'oldlace': '#fdf5e6',
              'olive': '#808000',
              'olivedrab': '#6b8e23',
              'orange': '#ffa500',
              'orangered': '#ff4500',
              'orchid': '#da70d6',
              'palegoldenrod': '#eee8aa',
              'palegreen': '#98fb98',
              'paleturquoise': '#afeeee',
              'palevioletred': '#d87093',
              'papayawhip': '#ffefd5',
              'peachpuff': '#ffdab9',
              'peru': '#cd853f',
              'pink': '#ffc0cb',
              'plum': '#dda0dd',
              'powderblue': '#b0e0e6',
              'purple': '#800080',
              'red': '#ff0000',
              'rosybrown': '#bc8f8f',
              'royalblue': '#4169e1',
              'saddlebrown': '#8b4513',
              'salmon': '#fa8072',
              'sandybrown': '#f4a460',
              'seagreen': '#2e8b57',
              'seashell': '#fff5ee',
              'sienna': '#a0522d',
              'silver': '#c0c0c0',
              'skyblue': '#87ceeb',
              'slateblue': '#6a5acd',
              'slategray': '#708090',
              'slategrey': '#708090',
              'snow': '#fffafa',
              'springgreen': '#00ff7f',
              'steelblue': '#4682b4',
              'tan': '#d2b48c',
              'teal': '#008080',
              'thistle': '#d8bfd8',
              'tomato': '#ff6347',
              // 'transparent':'rgba(0,0,0,0)',
              'turquoise': '#40e0d0',
              'violet': '#ee82ee',
              'wheat': '#f5deb3',
              'white': '#ffffff',
              'whitesmoke': '#f5f5f5',
              'yellow': '#ffff00',
              'yellowgreen': '#9acd32'
          };
      })(require('./tree'));
      (function (tree) {
  
          tree.Alpha = function (val) {
              this.value = val;
          };
          tree.Alpha.prototype = {
              type: "Alpha",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              eval: function (env) {
                  if (this.value.eval) {
                      this.value = this.value.eval(env)
                  }
                  return this;
              },
              toCSS: function () {
                  return "alpha(opacity=" +
                      (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Anonymous = function (string) {
              this.value = string.value || string;
          };
          tree.Anonymous.prototype = {
              type: "Anonymous",
              toCSS: function () {
                  return this.value;
              },
              eval: function () {
                  return this
              },
              compare: function (x) {
                  if (!x.toCSS) {
                      return -1;
                  }
  
                  var left = this.toCSS(),
                      right = x.toCSS();
  
                  if (left === right) {
                      return 0;
                  }
  
                  return left < right ? -1 : 1;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Assignment = function (key, val) {
              this.key = key;
              this.value = val;
          };
          tree.Assignment.prototype = {
              type: "Assignment",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              toCSS: function () {
                  return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
              },
              eval: function (env) {
                  if (this.value.eval) {
                      return new (tree.Assignment)(this.key, this.value.eval(env));
                  }
                  return this;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
  //
  // A function call node.
  //
          tree.Call = function (name, args, index, currentFileInfo) {
              this.name = name;
              this.args = args;
              this.index = index;
              this.currentFileInfo = currentFileInfo;
          };
          tree.Call.prototype = {
              type: "Call",
              accept: function (visitor) {
                  this.args = visitor.visit(this.args);
              },
              //
              // When evaluating a function call,
              // we either find the function in `tree.functions` [1],
              // in which case we call it, passing the  evaluated arguments,
              // if this returns null or we cannot find the function, we
              // simply print it out as it appeared originally [2].
              //
              // The *functions.js* file contains the built-in functions.
              //
              // The reason why we evaluate the arguments, is in the case where
              // we try to pass a variable to a function, like: `saturate(@color)`.
              // The function should receive the value, not the variable.
              //
              eval: function (env) {
                  var args = this.args.map(function (a) {
                          return a.eval(env);
                      }),
                      nameLC = this.name.toLowerCase(),
                      result, func;
  
                  if (nameLC in tree.functions) { // 1.
                      try {
                          func = new tree.functionCall(env, this.currentFileInfo);
                          result = func[nameLC].apply(func, args);
                          if (result != null) {
                              return result;
                          }
                      } catch (e) {
                          throw {
                              type: e.type || "Runtime",
                              message: "error evaluating function `" + this.name + "`" +
                              (e.message ? ': ' + e.message : ''),
                              index: this.index, filename: this.currentFileInfo.filename
                          };
                      }
                  }
  
                  // 2.
                  return new (tree.Anonymous)(this.name +
                      "(" + args.map(function (a) {
                          return a.toCSS(env);
                      }).join(', ') + ")");
              },
  
              toCSS: function (env) {
                  return this.eval(env).toCSS();
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  //
  // RGB Colors - #ff0014, #eee
  //
          tree.Color = function (rgb, a) {
              //
              // The end goal here, is to parse the arguments
              // into an integer triplet, such as `128, 255, 0`
              //
              // This facilitates operations and conversions.
              //
              if (Array.isArray(rgb)) {
                  this.rgb = rgb;
              } else if (rgb.length == 6) {
                  this.rgb = rgb.match(/.{2}/g).map(function (c) {
                      return parseInt(c, 16);
                  });
              } else {
                  this.rgb = rgb.split('').map(function (c) {
                      return parseInt(c + c, 16);
                  });
              }
              this.alpha = typeof(a) === 'number' ? a : 1;
          };
          tree.Color.prototype = {
              type: "Color",
              eval: function () {
                  return this
              },
              luma: function () {
                  return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255);
              },
  
              //
              // If we have some transparency, the only way to represent it
              // is via `rgba`. Otherwise, we use the hex representation,
              // which has better compatibility with older browsers.
              // Values are capped between `0` and `255`, rounded and zero-padded.
              //
              toCSS: function (env, doNotCompress) {
                  var compress = env && env.compress && !doNotCompress;
                  if (this.alpha < 1.0) {
                      return "rgba(" + this.rgb.map(function (c) {
                              return Math.round(c);
                          }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")";
                  } else {
                      var color = this.rgb.map(function (i) {
                          i = Math.round(i);
                          i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
                          return i.length === 1 ? '0' + i : i;
                      }).join('');
  
                      if (compress) {
                          color = color.split('');
  
                          // Convert color to short format
                          if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) {
                              color = color[0] + color[2] + color[4];
                          } else {
                              color = color.join('');
                          }
                      }
  
                      return '#' + color;
                  }
              },
  
              //
              // Operations have to be done per-channel, if not,
              // channels will spill onto each other. Once we have
              // our result, in the form of an integer triplet,
              // we create a new Color node to hold the result.
              //
              operate: function (env, op, other) {
                  var result = [];
  
                  if (!(other instanceof tree.Color)) {
                      other = other.toColor();
                  }
  
                  for (var c = 0; c < 3; c++) {
                      result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]);
                  }
                  return new (tree.Color)(result, this.alpha + other.alpha);
              },
  
              toHSL: function () {
                  var r = this.rgb[0] / 255,
                      g = this.rgb[1] / 255,
                      b = this.rgb[2] / 255,
                      a = this.alpha;
  
                  var max = Math.max(r, g, b), min = Math.min(r, g, b);
                  var h, s, l = (max + min) / 2, d = max - min;
  
                  if (max === min) {
                      h = s = 0;
                  } else {
                      s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  
                      switch (max) {
                          case r:
                              h = (g - b) / d + (g < b ? 6 : 0);
                              break;
                          case g:
                              h = (b - r) / d + 2;
                              break;
                          case b:
                              h = (r - g) / d + 4;
                              break;
                      }
                      h /= 6;
                  }
                  return {h: h * 360, s: s, l: l, a: a};
              },
              //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
              toHSV: function () {
                  var r = this.rgb[0] / 255,
                      g = this.rgb[1] / 255,
                      b = this.rgb[2] / 255,
                      a = this.alpha;
  
                  var max = Math.max(r, g, b), min = Math.min(r, g, b);
                  var h, s, v = max;
  
                  var d = max - min;
                  if (max === 0) {
                      s = 0;
                  } else {
                      s = d / max;
                  }
  
                  if (max === min) {
                      h = 0;
                  } else {
                      switch (max) {
                          case r:
                              h = (g - b) / d + (g < b ? 6 : 0);
                              break;
                          case g:
                              h = (b - r) / d + 2;
                              break;
                          case b:
                              h = (r - g) / d + 4;
                              break;
                      }
                      h /= 6;
                  }
                  return {h: h * 360, s: s, v: v, a: a};
              },
              toARGB: function () {
                  var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
                  return '#' + argb.map(function (i) {
                          i = Math.round(i);
                          i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
                          return i.length === 1 ? '0' + i : i;
                      }).join('');
              },
              compare: function (x) {
                  if (!x.rgb) {
                      return -1;
                  }
  
                  return (x.rgb[0] === this.rgb[0] &&
                  x.rgb[1] === this.rgb[1] &&
                  x.rgb[2] === this.rgb[2] &&
                  x.alpha === this.alpha) ? 0 : -1;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Comment = function (value, silent) {
              this.value = value;
              this.silent = !!silent;
          };
          tree.Comment.prototype = {
              type: "Comment",
              toCSS: function (env) {
                  return env.compress ? '' : this.value;
              },
              eval: function () {
                  return this
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Condition = function (op, l, r, i, negate) {
              this.op = op.trim();
              this.lvalue = l;
              this.rvalue = r;
              this.index = i;
              this.negate = negate;
          };
          tree.Condition.prototype = {
              type: "Condition",
              accept: function (visitor) {
                  this.lvalue = visitor.visit(this.lvalue);
                  this.rvalue = visitor.visit(this.rvalue);
              },
              eval: function (env) {
                  var a = this.lvalue.eval(env),
                      b = this.rvalue.eval(env);
  
                  var i = this.index, result;
  
                  var result = (function (op) {
                      switch (op) {
                          case 'and':
                              return a && b;
                          case 'or':
                              return a || b;
                          default:
                              if (a.compare) {
                                  result = a.compare(b);
                              } else if (b.compare) {
                                  result = b.compare(a);
                              } else {
                                  throw {
                                      type: "Type",
                                      message: "Unable to perform comparison",
                                      index: i
                                  };
                              }
                              switch (result) {
                                  case -1:
                                      return op === '<' || op === '=<';
                                  case  0:
                                      return op === '=' || op === '>=' || op === '=<';
                                  case  1:
                                      return op === '>' || op === '>=';
                              }
                      }
                  })(this.op);
                  return this.negate ? !result : result;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
  //
  // A number with a unit
  //
          tree.Dimension = function (value, unit) {
              this.value = parseFloat(value);
              this.unit = (unit && unit instanceof tree.Unit) ? unit :
                  new (tree.Unit)(unit ? [unit] : undefined);
          };
  
          tree.Dimension.prototype = {
              type: "Dimension",
              accept: function (visitor) {
                  this.unit = visitor.visit(this.unit);
              },
              eval: function (env) {
                  return this;
              },
              toColor: function () {
                  return new (tree.Color)([this.value, this.value, this.value]);
              },
              toCSS: function (env) {
                  if ((env && env.strictUnits) && !this.unit.isSingular()) {
                      throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "
                          + this.unit.toString());
                  }
  
                  var value = this.value,
                      strValue = String(value);
  
                  if (value !== 0 && value < 0.000001 && value > -0.000001) {
                      // would be output 1e-6 etc.
                      strValue = value.toFixed(20).replace(/0+$/, "");
                  }
  
                  if (env && env.compress) {
                      // Zero values doesn't need a unit
                      if (value === 0 && !this.unit.isAngle()) {
                          return strValue;
                      }
  
                      // Float values doesn't need a leading zero
                      if (value > 0 && value < 1) {
                          strValue = (strValue).substr(1);
                      }
                  }
  
                  return strValue + this.unit.toCSS(env);
              },
  
              // In an operation between two Dimensions,
              // we default to the first Dimension's unit,
              // so `1px + 2` will yield `3px`.
              operate: function (env, op, other) {
                  var value = tree.operate(env, op, this.value, other.value),
                      unit = this.unit.clone();
  
                  if (op === '+' || op === '-') {
                      if (unit.numerator.length === 0 && unit.denominator.length === 0) {
                          unit.numerator = other.unit.numerator.slice(0);
                          unit.denominator = other.unit.denominator.slice(0);
                      } else if (other.unit.numerator.length == 0 && unit.denominator.length == 0) {
                          // do nothing
                      } else {
                          other = other.convertTo(this.unit.usedUnits());
  
                          if (env.strictUnits && other.unit.toString() !== unit.toString()) {
                              throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"
                                  + unit.toString() +
                                  "' and '" + other.unit.toString() + "'.");
                          }
  
                          value = tree.operate(env, op, this.value, other.value);
                      }
                  } else if (op === '*') {
                      unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
                      unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
                      unit.cancel();
                  } else if (op === '/') {
                      unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
                      unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
                      unit.cancel();
                  }
                  return new (tree.Dimension)(value, unit);
              },
  
              compare: function (other) {
                  if (other instanceof tree.Dimension) {
                      var a = this.unify(), b = other.unify(),
                          aValue = a.value, bValue = b.value;
  
                      if (bValue > aValue) {
                          return -1;
                      } else if (bValue < aValue) {
                          return 1;
                      } else {
                          if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) {
                              return -1;
                          }
                          return 0;
                      }
                  } else {
                      return -1;
                  }
              },
  
              unify: function () {
                  return this.convertTo({length: 'm', duration: 's', angle: 'rad'});
              },
  
              convertTo: function (conversions) {
                  var value = this.value, unit = this.unit.clone(),
                      i, groupName, group, conversion, targetUnit, derivedConversions = {};
  
                  if (typeof conversions === 'string') {
                      for (i in tree.UnitConversions) {
                          if (tree.UnitConversions[i].hasOwnProperty(conversions)) {
                              derivedConversions = {};
                              derivedConversions[i] = conversions;
                          }
                      }
                      conversions = derivedConversions;
                  }
  
                  for (groupName in conversions) {
                      if (conversions.hasOwnProperty(groupName)) {
                          targetUnit = conversions[groupName];
                          group = tree.UnitConversions[groupName];
  
                          unit.map(function (atomicUnit, denominator) {
                              if (group.hasOwnProperty(atomicUnit)) {
                                  if (denominator) {
                                      value = value / (group[atomicUnit] / group[targetUnit]);
                                  } else {
                                      value = value * (group[atomicUnit] / group[targetUnit]);
                                  }
  
                                  return targetUnit;
                              }
  
                              return atomicUnit;
                          });
                      }
                  }
  
                  unit.cancel();
  
                  return new (tree.Dimension)(value, unit);
              }
          };
  
  // http://www.w3.org/TR/css3-values/#absolute-lengths
          tree.UnitConversions = {
              length: {
                  'm': 1,
                  'cm': 0.01,
                  'mm': 0.001,
                  'in': 0.0254,
                  'pt': 0.0254 / 72,
                  'pc': 0.0254 / 72 * 12
              },
              duration: {
                  's': 1,
                  'ms': 0.001
              },
              angle: {
                  'rad': 1 / (2 * Math.PI),
                  'deg': 1 / 360,
                  'grad': 1 / 400,
                  'turn': 1
              }
          };
  
          tree.Unit = function (numerator, denominator, backupUnit) {
              this.numerator = numerator ? numerator.slice(0).sort() : [];
              this.denominator = denominator ? denominator.slice(0).sort() : [];
              this.backupUnit = backupUnit;
          };
  
          tree.Unit.prototype = {
              type: "Unit",
              clone: function () {
                  return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
              },
  
              toCSS: function (env) {
                  if (this.numerator.length >= 1) {
                      return this.numerator[0];
                  }
                  if (this.denominator.length >= 1) {
                      return this.denominator[0];
                  }
                  if ((!env || !env.strictUnits) && this.backupUnit) {
                      return this.backupUnit;
                  }
                  return "";
              },
  
              toString: function () {
                  var i, returnStr = this.numerator.join("*");
                  for (i = 0; i < this.denominator.length; i++) {
                      returnStr += "/" + this.denominator[i];
                  }
                  return returnStr;
              },
  
              compare: function (other) {
                  return this.is(other.toString()) ? 0 : -1;
              },
  
              is: function (unitString) {
                  return this.toString() === unitString;
              },
  
              isAngle: function () {
                  return tree.UnitConversions.angle.hasOwnProperty(this.toCSS());
              },
  
              isEmpty: function () {
                  return this.numerator.length == 0 && this.denominator.length == 0;
              },
  
              isSingular: function () {
                  return this.numerator.length <= 1 && this.denominator.length == 0;
              },
  
              map: function (callback) {
                  var i;
  
                  for (i = 0; i < this.numerator.length; i++) {
                      this.numerator[i] = callback(this.numerator[i], false);
                  }
  
                  for (i = 0; i < this.denominator.length; i++) {
                      this.denominator[i] = callback(this.denominator[i], true);
                  }
              },
  
              usedUnits: function () {
                  var group, groupName, result = {};
  
                  for (groupName in tree.UnitConversions) {
                      if (tree.UnitConversions.hasOwnProperty(groupName)) {
                          group = tree.UnitConversions[groupName];
  
                          this.map(function (atomicUnit) {
                              if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
                                  result[groupName] = atomicUnit;
                              }
  
                              return atomicUnit;
                          });
                      }
                  }
  
                  return result;
              },
  
              cancel: function () {
                  var counter = {}, atomicUnit, i, backup;
  
                  for (i = 0; i < this.numerator.length; i++) {
                      atomicUnit = this.numerator[i];
                      if (!backup) {
                          backup = atomicUnit;
                      }
                      counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
                  }
  
                  for (i = 0; i < this.denominator.length; i++) {
                      atomicUnit = this.denominator[i];
                      if (!backup) {
                          backup = atomicUnit;
                      }
                      counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
                  }
  
                  this.numerator = [];
                  this.denominator = [];
  
                  for (atomicUnit in counter) {
                      if (counter.hasOwnProperty(atomicUnit)) {
                          var count = counter[atomicUnit];
  
                          if (count > 0) {
                              for (i = 0; i < count; i++) {
                                  this.numerator.push(atomicUnit);
                              }
                          } else if (count < 0) {
                              for (i = 0; i < -count; i++) {
                                  this.denominator.push(atomicUnit);
                              }
                          }
                      }
                  }
  
                  if (this.numerator.length === 0 && this.denominator.length === 0 && backup) {
                      this.backupUnit = backup;
                  }
  
                  this.numerator.sort();
                  this.denominator.sort();
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Directive = function (name, value) {
              this.name = name;
  
              if (Array.isArray(value)) {
                  this.ruleset = new (tree.Ruleset)([], value);
                  this.ruleset.allowImports = true;
              } else {
                  this.value = value;
              }
          };
          tree.Directive.prototype = {
              type: "Directive",
              accept: function (visitor) {
                  this.ruleset = visitor.visit(this.ruleset);
                  this.value = visitor.visit(this.value);
              },
              toCSS: function (env) {
                  if (this.ruleset) {
                      this.ruleset.root = true;
                      return this.name + (env.compress ? '{' : ' {\n  ') +
                          this.ruleset.toCSS(env).trim().replace(/\n/g, '\n  ') +
                          (env.compress ? '}' : '\n}\n');
                  } else {
                      return this.name + ' ' + this.value.toCSS() + ';\n';
                  }
              },
              eval: function (env) {
                  var evaldDirective = this;
                  if (this.ruleset) {
                      env.frames.unshift(this);
                      evaldDirective = new (tree.Directive)(this.name);
                      evaldDirective.ruleset = this.ruleset.eval(env);
                      env.frames.shift();
                  }
                  return evaldDirective;
              },
              variable: function (name) {
                  return tree.Ruleset.prototype.variable.call(this.ruleset, name)
              },
              find: function () {
                  return tree.Ruleset.prototype.find.apply(this.ruleset, arguments)
              },
              rulesets: function () {
                  return tree.Ruleset.prototype.rulesets.apply(this.ruleset)
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Element = function (combinator, value, index) {
              this.combinator = combinator instanceof tree.Combinator ?
                  combinator : new (tree.Combinator)(combinator);
  
              if (typeof(value) === 'string') {
                  this.value = value.trim();
              } else if (value) {
                  this.value = value;
              } else {
                  this.value = "";
              }
              this.index = index;
          };
          tree.Element.prototype = {
              type: "Element",
              accept: function (visitor) {
                  this.combinator = visitor.visit(this.combinator);
                  this.value = visitor.visit(this.value);
              },
              eval: function (env) {
                  return new (tree.Element)(this.combinator,
                      this.value.eval ? this.value.eval(env) : this.value,
                      this.index);
              },
              toCSS: function (env) {
                  var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
                  if (value == '' && this.combinator.value.charAt(0) == '&') {
                      return '';
                  } else {
                      return this.combinator.toCSS(env || {}) + value;
                  }
              }
          };
  
          tree.Attribute = function (key, op, value) {
              this.key = key;
              this.op = op;
              this.value = value;
          };
          tree.Attribute.prototype = {
              type: "Attribute",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              eval: function (env) {
                  return new (tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key,
                      this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value);
              },
              toCSS: function (env) {
                  var value = this.key.toCSS ? this.key.toCSS(env) : this.key;
  
                  if (this.op) {
                      value += this.op;
                      value += (this.value.toCSS ? this.value.toCSS(env) : this.value);
                  }
  
                  return '[' + value + ']';
              }
          };
  
          tree.Combinator = function (value) {
              if (value === ' ') {
                  this.value = ' ';
              } else {
                  this.value = value ? value.trim() : "";
              }
          };
          tree.Combinator.prototype = {
              type: "Combinator",
              toCSS: function (env) {
                  return {
                      '': '',
                      ' ': ' ',
                      ':': ' :',
                      '+': env.compress ? '+' : ' + ',
                      '~': env.compress ? '~' : ' ~ ',
                      '>': env.compress ? '>' : ' > ',
                      '|': env.compress ? '|' : ' | '
                  }[this.value];
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Expression = function (value) {
              this.value = value;
          };
          tree.Expression.prototype = {
              type: "Expression",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              eval: function (env) {
                  var returnValue,
                      inParenthesis = this.parens && !this.parensInOp,
                      doubleParen = false;
                  if (inParenthesis) {
                      env.inParenthesis();
                  }
                  if (this.value.length > 1) {
                      returnValue = new (tree.Expression)(this.value.map(function (e) {
                          return e.eval(env);
                      }));
                  } else if (this.value.length === 1) {
                      if (this.value[0].parens && !this.value[0].parensInOp) {
                          doubleParen = true;
                      }
                      returnValue = this.value[0].eval(env);
                  } else {
                      returnValue = this;
                  }
                  if (inParenthesis) {
                      env.outOfParenthesis();
                  }
                  if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) {
                      returnValue = new (tree.Paren)(returnValue);
                  }
                  return returnValue;
              },
              toCSS: function (env) {
                  return this.value.map(function (e) {
                      return e.toCSS ? e.toCSS(env) : '';
                  }).join(' ');
              },
              throwAwayComments: function () {
                  this.value = this.value.filter(function (v) {
                      return !(v instanceof tree.Comment);
                  });
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Extend = function Extend(selector, option, index) {
              this.selector = selector;
              this.option = option;
              this.index = index;
  
              switch (option) {
                  case "all":
                      this.allowBefore = true;
                      this.allowAfter = true;
                      break;
                  default:
                      this.allowBefore = false;
                      this.allowAfter = false;
                      break;
              }
          };
  
          tree.Extend.prototype = {
              type: "Extend",
              accept: function (visitor) {
                  this.selector = visitor.visit(this.selector);
              },
              eval: function (env) {
                  return new (tree.Extend)(this.selector.eval(env), this.option, this.index);
              },
              clone: function (env) {
                  return new (tree.Extend)(this.selector, this.option, this.index);
              },
              findSelfSelectors: function (selectors) {
                  var selfElements = [];
  
                  for (i = 0; i < selectors.length; i++) {
                      selfElements = selfElements.concat(selectors[i].elements);
                  }
  
                  this.selfSelectors = [{elements: selfElements}];
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  //
  // CSS @import node
  //
  // The general strategy here is that we don't want to wait
  // for the parsing to be completed, before we start importing
  // the file. That's because in the context of a browser,
  // most of the time will be spent waiting for the server to respond.
  //
  // On creation, we push the import path to our import queue, though
  // `import,push`, we also pass it a callback, which it'll call once
  // the file has been fetched, and parsed.
  //
          tree.Import = function (path, features, options, index, currentFileInfo) {
              var that = this;
  
              this.options = options;
              this.index = index;
              this.path = path;
              this.features = features;
              this.currentFileInfo = currentFileInfo;
  
              if (this.options.less !== undefined) {
                  this.css = !this.options.less;
              } else {
                  var pathValue = this.getPath();
                  if (pathValue && /css([\?;].*)?$/.test(pathValue)) {
                      this.css = true;
                  }
              }
          };
  
  //
  // The actual import node doesn't return anything, when converted to CSS.
  // The reason is that it's used at the evaluation stage, so that the rules
  // it imports can be treated like any other rules.
  //
  // In `eval`, we make sure all Import nodes get evaluated, recursively, so
  // we end up with a flat structure, which can easily be imported in the parent
  // ruleset.
  //
          tree.Import.prototype = {
              type: "Import",
              accept: function (visitor) {
                  this.features = visitor.visit(this.features);
                  this.path = visitor.visit(this.path);
                  this.root = visitor.visit(this.root);
              },
              toCSS: function (env) {
                  var features = this.features ? ' ' + this.features.toCSS(env) : '';
  
                  if (this.css) {
                      return "@import " + this.path.toCSS() + features + ';\n';
                  } else {
                      return "";
                  }
              },
              getPath: function () {
                  if (this.path instanceof tree.Quoted) {
                      var path = this.path.value;
                      return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
                  } else if (this.path instanceof tree.URL) {
                      return this.path.value.value;
                  }
                  return null;
              },
              evalForImport: function (env) {
                  return new (tree.Import)(this.path.eval(
                      env), this.features, this.options, this.index, this.currentFileInfo);
              },
              evalPath: function (env) {
                  var path = this.path.eval(env);
                  var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
                  if (rootpath && !(path instanceof tree.URL)) {
                      var pathValue = path.value;
                      // Add the base path if the import is relative
                      if (pathValue && env.isPathRelative(pathValue)) {
                          path.value = rootpath + pathValue;
                      }
                  }
                  return path;
              },
              eval: function (env) {
                  var ruleset, features = this.features && this.features.eval(env);
  
                  if (this.skip) {
                      return [];
                  }
  
                  if (this.css) {
                      var newImport = new (tree.Import)(this.evalPath(env), features, this.options, this.index);
                      if (!newImport.css && this.error) {
                          throw this.error;
                      }
                      return newImport;
                  } else {
                      ruleset = new (tree.Ruleset)([], this.root.rules.slice(0));
  
                      ruleset.evalImports(env);
  
                      return this.features ? new (tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
                  }
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.JavaScript = function (string, index, escaped) {
              this.escaped = escaped;
              this.expression = string;
              this.index = index;
          };
          tree.JavaScript.prototype = {
              type: "JavaScript",
              eval: function (env) {
                  var result,
                      that = this,
                      context = {};
  
                  var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
                      return tree.jsify(new (tree.Variable)('@' + name, that.index).eval(env));
                  });
  
                  try {
                      expression = new (Function)('return (' + expression + ')');
                  } catch (e) {
                      throw {
                          message: "JavaScript evaluation error: `" + expression + "`",
                          index: this.index
                      };
                  }
  
                  for (var k in env.frames[0].variables()) {
                      context[k.slice(1)] = {
                          value: env.frames[0].variables()[k].value,
                          toJS: function () {
                              return this.value.eval(env).toCSS();
                          }
                      };
                  }
  
                  try {
                      result = expression.call(context);
                  } catch (e) {
                      throw {
                          message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'",
                          index: this.index
                      };
                  }
                  if (typeof(result) === 'string') {
                      return new (tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
                  } else if (Array.isArray(result)) {
                      return new (tree.Anonymous)(result.join(', '));
                  } else {
                      return new (tree.Anonymous)(result);
                  }
              }
          };
  
      })(require('../tree'));
  
      (function (tree) {
  
          tree.Keyword = function (value) {
              this.value = value
          };
          tree.Keyword.prototype = {
              type: "Keyword",
              eval: function () {
                  return this;
              },
              toCSS: function () {
                  return this.value;
              },
              compare: function (other) {
                  if (other instanceof tree.Keyword) {
                      return other.value === this.value ? 0 : 1;
                  } else {
                      return -1;
                  }
              }
          };
  
          tree.True = new (tree.Keyword)('true');
          tree.False = new (tree.Keyword)('false');
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Media = function (value, features) {
              var selectors = this.emptySelectors();
  
              this.features = new (tree.Value)(features);
              this.ruleset = new (tree.Ruleset)(selectors, value);
              this.ruleset.allowImports = true;
          };
          tree.Media.prototype = {
              type: "Media",
              accept: function (visitor) {
                  this.features = visitor.visit(this.features);
                  this.ruleset = visitor.visit(this.ruleset);
              },
              toCSS: function (env) {
                  var features = this.features.toCSS(env);
  
                  return '@media ' + features + (env.compress ? '{' : ' {\n  ') +
                      this.ruleset.toCSS(env).trim().replace(/\n/g, '\n  ') +
                      (env.compress ? '}' : '\n}\n');
              },
              eval: function (env) {
                  if (!env.mediaBlocks) {
                      env.mediaBlocks = [];
                      env.mediaPath = [];
                  }
  
                  var media = new (tree.Media)([], []);
                  if (this.debugInfo) {
                      this.ruleset.debugInfo = this.debugInfo;
                      media.debugInfo = this.debugInfo;
                  }
                  var strictMathBypass = false;
                  if (!env.strictMath) {
                      strictMathBypass = true;
                      env.strictMath = true;
                  }
                  try {
                      media.features = this.features.eval(env);
                  }
                  finally {
                      if (strictMathBypass) {
                          env.strictMath = false;
                      }
                  }
  
                  env.mediaPath.push(media);
                  env.mediaBlocks.push(media);
  
                  env.frames.unshift(this.ruleset);
                  media.ruleset = this.ruleset.eval(env);
                  env.frames.shift();
  
                  env.mediaPath.pop();
  
                  return env.mediaPath.length === 0 ? media.evalTop(env) :
                      media.evalNested(env)
              },
              variable: function (name) {
                  return tree.Ruleset.prototype.variable.call(this.ruleset, name)
              },
              find: function () {
                  return tree.Ruleset.prototype.find.apply(this.ruleset, arguments)
              },
              rulesets: function () {
                  return tree.Ruleset.prototype.rulesets.apply(this.ruleset)
              },
              emptySelectors: function () {
                  var el = new (tree.Element)('', '&', 0);
                  return [new (tree.Selector)([el])];
              },
  
              evalTop: function (env) {
                  var result = this;
  
                  // Render all dependent Media blocks.
                  if (env.mediaBlocks.length > 1) {
                      var selectors = this.emptySelectors();
                      result = new (tree.Ruleset)(selectors, env.mediaBlocks);
                      result.multiMedia = true;
                  }
  
                  delete env.mediaBlocks;
                  delete env.mediaPath;
  
                  return result;
              },
              evalNested: function (env) {
                  var i, value,
                      path = env.mediaPath.concat([this]);
  
                  // Extract the media-query conditions separated with `,` (OR).
                  for (i = 0; i < path.length; i++) {
                      value = path[i].features instanceof tree.Value ?
                          path[i].features.value : path[i].features;
                      path[i] = Array.isArray(value) ? value : [value];
                  }
  
                  // Trace all permutations to generate the resulting media-query.
                  //
                  // (a, b and c) with nested (d, e) ->
                  //    a and d
                  //    a and e
                  //    b and c and d
                  //    b and c and e
                  this.features = new (tree.Value)(this.permute(path).map(function (path) {
                      path = path.map(function (fragment) {
                          return fragment.toCSS ? fragment : new (tree.Anonymous)(fragment);
                      });
  
                      for (i = path.length - 1; i > 0; i--) {
                          path.splice(i, 0, new (tree.Anonymous)("and"));
                      }
  
                      return new (tree.Expression)(path);
                  }));
  
                  // Fake a tree-node that doesn't output anything.
                  return new (tree.Ruleset)([], []);
              },
              permute: function (arr) {
                  if (arr.length === 0) {
                      return [];
                  } else if (arr.length === 1) {
                      return arr[0];
                  } else {
                      var result = [];
                      var rest = this.permute(arr.slice(1));
                      for (var i = 0; i < rest.length; i++) {
                          for (var j = 0; j < arr[0].length; j++) {
                              result.push([arr[0][j]].concat(rest[i]));
                          }
                      }
                      return result;
                  }
              },
              bubbleSelectors: function (selectors) {
                  this.ruleset = new (tree.Ruleset)(selectors.slice(0), [this.ruleset]);
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.mixin = {};
          tree.mixin.Call = function (elements, args, index, currentFileInfo, important) {
              this.selector = new (tree.Selector)(elements);
              this.arguments = args;
              this.index = index;
              this.currentFileInfo = currentFileInfo;
              this.important = important;
          };
          tree.mixin.Call.prototype = {
              type: "MixinCall",
              accept: function (visitor) {
                  this.selector = visitor.visit(this.selector);
                  this.arguments = visitor.visit(this.arguments);
              },
              eval: function (env) {
                  var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound;
  
                  args = this.arguments && this.arguments.map(function (a) {
                          return {name: a.name, value: a.value.eval(env)};
                      });
  
                  for (i = 0; i < env.frames.length; i++) {
                      if ((mixins = env.frames[i].find(this.selector)).length > 0) {
                          isOneFound = true;
                          for (m = 0; m < mixins.length; m++) {
                              mixin = mixins[m];
                              isRecursive = false;
                              for (f = 0; f < env.frames.length; f++) {
                                  if ((!(mixin instanceof tree.mixin.Definition)) && mixin
                                      === (env.frames[f].originalRuleset || env.frames[f])) {
                                      isRecursive = true;
                                      break;
                                  }
                              }
                              if (isRecursive) {
                                  continue;
                              }
                              if (mixin.matchArgs(args, env)) {
                                  if (!mixin.matchCondition || mixin.matchCondition(args, env)) {
                                      try {
                                          Array.prototype.push.apply(
                                              rules, mixin.eval(env, args, this.important).rules);
                                      } catch (e) {
                                          throw {
                                              message: e.message,
                                              index: this.index,
                                              filename: this.currentFileInfo.filename,
                                              stack: e.stack
                                          };
                                      }
                                  }
                                  match = true;
                              }
                          }
                          if (match) {
                              return rules;
                          }
                      }
                  }
                  if (isOneFound) {
                      throw {
                          type: 'Runtime',
                          message: 'No matching definition was found for `' +
                          this.selector.toCSS().trim() + '(' +
                          (args ? args.map(function (a) {
                                  var argValue = "";
                                  if (a.name) {
                                      argValue += a.name + ":";
                                  }
                                  if (a.value.toCSS) {
                                      argValue += a.value.toCSS();
                                  } else {
                                      argValue += "???";
                                  }
                                  return argValue;
                              }).join(', ') : "") + ")`",
                          index: this.index, filename: this.currentFileInfo.filename
                      };
                  } else {
                      throw {
                          type: 'Name',
                          message: this.selector.toCSS().trim() + " is undefined",
                          index: this.index, filename: this.currentFileInfo.filename
                      };
                  }
              }
          };
  
          tree.mixin.Definition = function (name, params, rules, condition, variadic) {
              this.name = name;
              this.selectors = [new (tree.Selector)([new (tree.Element)(null, name)])];
              this.params = params;
              this.condition = condition;
              this.variadic = variadic;
              this.arity = params.length;
              this.rules = rules;
              this._lookups = {};
              this.required = params.reduce(function (count, p) {
                  if (!p.name || (p.name && !p.value)) {
                      return count + 1
                  }
                  else {
                      return count
                  }
              }, 0);
              this.parent = tree.Ruleset.prototype;
              this.frames = [];
          };
          tree.mixin.Definition.prototype = {
              type: "MixinDefinition",
              accept: function (visitor) {
                  this.params = visitor.visit(this.params);
                  this.rules = visitor.visit(this.rules);
                  this.condition = visitor.visit(this.condition);
              },
              toCSS: function () {
                  return "";
              },
              variable: function (name) {
                  return this.parent.variable.call(this, name);
              },
              variables: function () {
                  return this.parent.variables.call(this);
              },
              find: function () {
                  return this.parent.find.apply(this, arguments);
              },
              rulesets: function () {
                  return this.parent.rulesets.apply(this);
              },
  
              evalParams: function (env, mixinEnv, args, evaldArguments) {
                  var frame = new (tree.Ruleset)(null, []),
                      varargs, arg,
                      params = this.params.slice(0),
                      i, j, val, name, isNamedFound, argIndex;
  
                  mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
  
                  if (args) {
                      args = args.slice(0);
  
                      for (i = 0; i < args.length; i++) {
                          arg = args[i];
                          if (name = (arg && arg.name)) {
                              isNamedFound = false;
                              for (j = 0; j < params.length; j++) {
                                  if (!evaldArguments[j] && name === params[j].name) {
                                      evaldArguments[j] = arg.value.eval(env);
                                      frame.rules.unshift(new (tree.Rule)(name, arg.value.eval(env)));
                                      isNamedFound = true;
                                      break;
                                  }
                              }
                              if (isNamedFound) {
                                  args.splice(i, 1);
                                  i--;
                                  continue;
                              } else {
                                  throw {
                                      type: 'Runtime', message: "Named argument for " + this.name +
                                      ' ' + args[i].name + ' not found'
                                  };
                              }
                          }
                      }
                  }
                  argIndex = 0;
                  for (i = 0; i < params.length; i++) {
                      if (evaldArguments[i]) {
                          continue;
                      }
  
                      arg = args && args[argIndex];
  
                      if (name = params[i].name) {
                          if (params[i].variadic && args) {
                              varargs = [];
                              for (j = argIndex; j < args.length; j++) {
                                  varargs.push(args[j].value.eval(env));
                              }
                              frame.rules.unshift(new (tree.Rule)(name, new (tree.Expression)(varargs).eval(env)));
                          } else {
                              val = arg && arg.value;
                              if (val) {
                                  val = val.eval(env);
                              } else if (params[i].value) {
                                  val = params[i].value.eval(mixinEnv);
                                  frame.resetCache();
                              } else {
                                  throw {
                                      type: 'Runtime', message: "wrong number of arguments for " + this.name +
                                      ' (' + args.length + ' for ' + this.arity + ')'
                                  };
                              }
  
                              frame.rules.unshift(new (tree.Rule)(name, val));
                              evaldArguments[i] = val;
                          }
                      }
  
                      if (params[i].variadic && args) {
                          for (j = argIndex; j < args.length; j++) {
                              evaldArguments[j] = args[j].value.eval(env);
                          }
                      }
                      argIndex++;
                  }
  
                  return frame;
              },
              eval: function (env, args, important) {
                  var _arguments = [],
                      mixinFrames = this.frames.concat(env.frames),
                      frame = this.evalParams(env, new (tree.evalEnv)(env, mixinFrames), args, _arguments),
                      context, rules, start, ruleset;
  
                  frame.rules.unshift(new (tree.Rule)('@arguments', new (tree.Expression)(_arguments).eval(env)));
  
                  rules = important ?
                      this.parent.makeImportant.apply(this).rules : this.rules.slice(0);
  
                  ruleset = new (tree.Ruleset)(null, rules).eval(new (tree.evalEnv)(env,
                      [this, frame].concat(mixinFrames)));
                  ruleset.originalRuleset = this;
                  return ruleset;
              },
              matchCondition: function (args, env) {
  
                  if (this.condition && !this.condition.eval(
                          new (tree.evalEnv)(env,
                              [this.evalParams(env, new (tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])]
                              .concat(env.frames)))) {
                      return false;
                  }
                  return true;
              },
              matchArgs: function (args, env) {
                  var argsLength = (args && args.length) || 0, len, frame;
  
                  if (!this.variadic) {
                      if (argsLength < this.required) {
                          return false
                      }
                      if (argsLength > this.params.length) {
                          return false
                      }
                      if ((this.required > 0) && (argsLength > this.params.length)) {
                          return false
                      }
                  }
  
                  len = Math.min(argsLength, this.arity);
  
                  for (var i = 0; i < len; i++) {
                      if (!this.params[i].name && !this.params[i].variadic) {
                          if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
                              return false;
                          }
                      }
                  }
                  return true;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Negative = function (node) {
              this.value = node;
          };
          tree.Negative.prototype = {
              type: "Negative",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              toCSS: function (env) {
                  return '-' + this.value.toCSS(env);
              },
              eval: function (env) {
                  if (env.isMathOn()) {
                      return (new (tree.Operation)('*', [new (tree.Dimension)(-1), this.value])).eval(env);
                  }
                  return new (tree.Negative)(this.value.eval(env));
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Operation = function (op, operands, isSpaced) {
              this.op = op.trim();
              this.operands = operands;
              this.isSpaced = isSpaced;
          };
          tree.Operation.prototype = {
              type: "Operation",
              accept: function (visitor) {
                  this.operands = visitor.visit(this.operands);
              },
              eval: function (env) {
                  var a = this.operands[0].eval(env),
                      b = this.operands[1].eval(env),
                      temp;
  
                  if (env.isMathOn()) {
                      if (a instanceof tree.Dimension && b instanceof tree.Color) {
                          if (this.op === '*' || this.op === '+') {
                              temp = b, b = a, a = temp;
                          } else {
                              throw {
                                  type: "Operation",
                                  message: "Can't substract or divide a color from a number"
                              };
                          }
                      }
                      if (!a.operate) {
                          throw {
                              type: "Operation",
                              message: "Operation on an invalid type"
                          };
                      }
  
                      return a.operate(env, this.op, b);
                  } else {
                      return new (tree.Operation)(this.op, [a, b], this.isSpaced);
                  }
              },
              toCSS: function (env) {
                  var separator = this.isSpaced ? " " : "";
                  return this.operands[0].toCSS() + separator + this.op + separator + this.operands[1].toCSS();
              }
          };
  
          tree.operate = function (env, op, a, b) {
              switch (op) {
                  case '+':
                      return a + b;
                  case '-':
                      return a - b;
                  case '*':
                      return a * b;
                  case '/':
                      return a / b;
              }
          };
  
      })(require('../tree'));
  
      (function (tree) {
  
          tree.Paren = function (node) {
              this.value = node;
          };
          tree.Paren.prototype = {
              type: "Paren",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              toCSS: function (env) {
                  return '(' + this.value.toCSS(env).trim() + ')';
              },
              eval: function (env) {
                  return new (tree.Paren)(this.value.eval(env));
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Quoted = function (str, content, escaped, index, currentFileInfo) {
              this.escaped = escaped;
              this.value = content || '';
              this.quote = str.charAt(0);
              this.index = index;
              this.currentFileInfo = currentFileInfo;
          };
          tree.Quoted.prototype = {
              type: "Quoted",
              toCSS: function () {
                  if (this.escaped) {
                      return this.value;
                  } else {
                      return this.quote + this.value + this.quote;
                  }
              },
              eval: function (env) {
                  var that = this;
                  var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
                      return new (tree.JavaScript)(exp, that.index, true).eval(env).value;
                  }).replace(/@\{([\w-]+)\}/g, function (_, name) {
                      var v = new (tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true);
                      return (v instanceof tree.Quoted) ? v.value : v.toCSS();
                  });
                  return new (tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
              },
              compare: function (x) {
                  if (!x.toCSS) {
                      return -1;
                  }
  
                  var left = this.toCSS(),
                      right = x.toCSS();
  
                  if (left === right) {
                      return 0;
                  }
  
                  return left < right ? -1 : 1;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Rule = function (name, value, important, index, currentFileInfo, inline) {
              this.name = name;
              this.value = (value instanceof tree.Value) ? value : new (tree.Value)([value]);
              this.important = important ? ' ' + important.trim() : '';
              this.index = index;
              this.currentFileInfo = currentFileInfo;
              this.inline = inline || false;
  
              if (name.charAt(0) === '@') {
                  this.variable = true;
              } else {
                  this.variable = false
              }
          };
  
          tree.Rule.prototype = {
              type: "Rule",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              toCSS: function (env) {
                  if (this.variable) {
                      return ""
                  }
                  else {
                      try {
                          return this.name + (env.compress ? ':' : ': ') +
                              this.value.toCSS(env) +
                              this.important + (this.inline ? "" : ";");
                      }
                      catch (e) {
                          e.index = this.index;
                          e.filename = this.currentFileInfo.filename;
                          throw e;
                      }
                  }
              },
              eval: function (env) {
                  var strictMathBypass = false;
                  if (this.name === "font" && env.strictMath === false) {
                      strictMathBypass = true;
                      env.strictMath = true;
                  }
                  try {
                      return new (tree.Rule)(this.name,
                          this.value.eval(env),
                          this.important,
                          this.index, this.currentFileInfo, this.inline);
                  }
                  finally {
                      if (strictMathBypass) {
                          env.strictMath = false;
                      }
                  }
              },
              makeImportant: function () {
                  return new (tree.Rule)(this.name,
                      this.value,
                      "!important",
                      this.index, this.currentFileInfo, this.inline);
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Ruleset = function (selectors, rules, strictImports) {
              this.selectors = selectors;
              this.rules = rules;
              this._lookups = {};
              this.strictImports = strictImports;
          };
          tree.Ruleset.prototype = {
              type: "Ruleset",
              accept: function (visitor) {
                  this.selectors = visitor.visit(this.selectors);
                  this.rules = visitor.visit(this.rules);
              },
              eval: function (env) {
                  var selectors = this.selectors && this.selectors.map(function (s) {
                          return s.eval(env)
                      });
                  var ruleset = new (tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
                  var rules;
  
                  ruleset.originalRuleset = this;
                  ruleset.root = this.root;
                  ruleset.firstRoot = this.firstRoot;
                  ruleset.allowImports = this.allowImports;
  
                  if (this.debugInfo) {
                      ruleset.debugInfo = this.debugInfo;
                  }
  
                  // push the current ruleset to the frames stack
                  env.frames.unshift(ruleset);
  
                  // currrent selectors
                  if (!env.selectors) {
                      env.selectors = [];
                  }
                  env.selectors.unshift(this.selectors);
  
                  // Evaluate imports
                  if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
                      ruleset.evalImports(env);
                  }
  
                  // Store the frames around mixin definitions,
                  // so they can be evaluated like closures when the time comes.
                  for (var i = 0; i < ruleset.rules.length; i++) {
                      if (ruleset.rules[i] instanceof tree.mixin.Definition) {
                          ruleset.rules[i].frames = env.frames.slice(0);
                      }
                  }
  
                  var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
  
                  // Evaluate mixin calls.
                  for (var i = 0; i < ruleset.rules.length; i++) {
                      if (ruleset.rules[i] instanceof tree.mixin.Call) {
                          rules = ruleset.rules[i].eval(env).filter(function (r) {
                              if ((r instanceof tree.Rule) && r.variable) {
                                  // do not pollute the scope if the variable is
                                  // already there. consider returning false here
                                  // but we need a way to "return" variable from mixins
                                  return !(ruleset.variable(r.name));
                              }
                              return true;
                          });
                          ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
                          i += rules.length - 1;
                          ruleset.resetCache();
                      }
                  }
  
                  // Evaluate everything else
                  for (var i = 0, rule; i < ruleset.rules.length; i++) {
                      rule = ruleset.rules[i];
  
                      if (!(rule instanceof tree.mixin.Definition)) {
                          ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
                      }
                  }
  
                  // Pop the stack
                  env.frames.shift();
                  env.selectors.shift();
  
                  if (env.mediaBlocks) {
                      for (var i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
                          env.mediaBlocks[i].bubbleSelectors(selectors);
                      }
                  }
  
                  return ruleset;
              },
              evalImports: function (env) {
                  var i, rules;
                  for (i = 0; i < this.rules.length; i++) {
                      if (this.rules[i] instanceof tree.Import) {
                          rules = this.rules[i].eval(env);
                          if (typeof rules.length === "number") {
                              this.rules.splice.apply(this.rules, [i, 1].concat(rules));
                              i += rules.length - 1;
                          } else {
                              this.rules.splice(i, 1, rules);
                          }
                          this.resetCache();
                      }
                  }
              },
              makeImportant: function () {
                  return new tree.Ruleset(this.selectors, this.rules.map(function (r) {
                      if (r.makeImportant) {
                          return r.makeImportant();
                      } else {
                          return r;
                      }
                  }), this.strictImports);
              },
              matchArgs: function (args) {
                  return !args || args.length === 0;
              },
              resetCache: function () {
                  this._rulesets = null;
                  this._variables = null;
                  this._lookups = {};
              },
              variables: function () {
                  if (this._variables) {
                      return this._variables
                  }
                  else {
                      return this._variables = this.rules.reduce(function (hash, r) {
                          if (r instanceof tree.Rule && r.variable === true) {
                              hash[r.name] = r;
                          }
                          return hash;
                      }, {});
                  }
              },
              variable: function (name) {
                  return this.variables()[name];
              },
              rulesets: function () {
                  return this.rules.filter(function (r) {
                      return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
                  });
              },
              find: function (selector, self) {
                  self = self || this;
                  var rules = [], rule, match,
                      key = selector.toCSS();
  
                  if (key in this._lookups) {
                      return this._lookups[key]
                  }
  
                  this.rulesets().forEach(function (rule) {
                      if (rule !== self) {
                          for (var j = 0; j < rule.selectors.length; j++) {
                              if (match = selector.match(rule.selectors[j])) {
                                  if (selector.elements.length > rule.selectors[j].elements.length) {
                                      Array.prototype.push.apply(rules, rule.find(
                                          new (tree.Selector)(selector.elements.slice(1)), self));
                                  } else {
                                      rules.push(rule);
                                  }
                                  break;
                              }
                          }
                      }
                  });
                  return this._lookups[key] = rules;
              },
              //
              // Entry point for code generation
              //
              //     `context` holds an array of arrays.
              //
              toCSS: function (env) {
                  var css = [],      // The CSS output
                      rules = [],    // node.Rule instances
                      _rules = [],    //
                      rulesets = [], // node.Ruleset instances
                      selector,      // The fully rendered selector
                      debugInfo,     // Line number debugging
                      rule;
  
                  // Compile rules and rulesets
                  for (var i = 0; i < this.rules.length; i++) {
                      rule = this.rules[i];
  
                      if (rule.rules || (rule instanceof tree.Media)) {
                          rulesets.push(rule.toCSS(env));
                      } else if (rule instanceof tree.Directive) {
                          var cssValue = rule.toCSS(env);
                          // Output only the first @charset definition as such - convert the others
                          // to comments in case debug is enabled
                          if (rule.name === "@charset") {
                              // Only output the debug info together with subsequent @charset definitions
                              // a comment (or @media statement) before the actual @charset directive would
                              // be considered illegal css as it has to be on the first line
                              if (env.charset) {
                                  if (rule.debugInfo) {
                                      rulesets.push(tree.debugInfo(env, rule));
                                      rulesets.push(
                                          new tree.Comment("/* " + cssValue.replace(/\n/g, "") + " */\n").toCSS(env));
                                  }
                                  continue;
                              }
                              env.charset = true;
                          }
                          rulesets.push(cssValue);
                      } else if (rule instanceof tree.Comment) {
                          if (!rule.silent) {
                              if (this.root) {
                                  rulesets.push(rule.toCSS(env));
                              } else {
                                  rules.push(rule.toCSS(env));
                              }
                          }
                      } else {
                          if (rule.toCSS && !rule.variable) {
                              if (this.firstRoot && rule instanceof tree.Rule) {
                                  throw {
                                      message: "properties must be inside selector blocks, they cannot be in the root.",
                                      index: rule.index,
                                      filename: rule.currentFileInfo ? rule.currentFileInfo.filename : null
                                  };
                              }
                              rules.push(rule.toCSS(env));
                          } else if (rule.value && !rule.variable) {
                              rules.push(rule.value.toString());
                          }
                      }
                  }
  
                  // Remove last semicolon
                  if (env.compress && rules.length) {
                      rule = rules[rules.length - 1];
                      if (rule.charAt(rule.length - 1) === ';') {
                          rules[rules.length - 1] = rule.substring(0, rule.length - 1);
                      }
                  }
  
                  rulesets = rulesets.join('');
  
                  // If this is the root node, we don't render
                  // a selector, or {}.
                  // Otherwise, only output if this ruleset has rules.
                  if (this.root) {
                      css.push(rules.join(env.compress ? '' : '\n'));
                  } else {
                      if (rules.length > 0) {
                          debugInfo = tree.debugInfo(env, this);
                          selector = this.paths.map(function (p) {
                              return p.map(function (s) {
                                  return s.toCSS(env);
                              }).join('').trim();
                          }).join(env.compress ? ',' : ',\n');
  
                          // Remove duplicates
                          for (var i = rules.length - 1; i >= 0; i--) {
                              if (rules[i].slice(0, 2) === "/*" || _rules.indexOf(rules[i]) === -1) {
                                  _rules.unshift(rules[i]);
                              }
                          }
                          rules = _rules;
  
                          css.push(debugInfo + selector +
                              (env.compress ? '{' : ' {\n  ') +
                              rules.join(env.compress ? '' : '\n  ') +
                              (env.compress ? '}' : '\n}\n'));
                      }
                  }
                  css.push(rulesets);
  
                  return css.join('') + (env.compress ? '\n' : '');
              },
  
              joinSelectors: function (paths, context, selectors) {
                  for (var s = 0; s < selectors.length; s++) {
                      this.joinSelector(paths, context, selectors[s]);
                  }
              },
  
              joinSelector: function (paths, context, selector) {
  
                  var i, j, k,
                      hasParentSelector, newSelectors, el, sel, parentSel,
                      newSelectorPath, afterParentJoin, newJoinedSelector,
                      newJoinedSelectorEmpty, lastSelector, currentElements,
                      selectorsMultiplied;
  
                  for (i = 0; i < selector.elements.length; i++) {
                      el = selector.elements[i];
                      if (el.value === '&') {
                          hasParentSelector = true;
                      }
                  }
  
                  if (!hasParentSelector) {
                      if (context.length > 0) {
                          for (i = 0; i < context.length; i++) {
                              paths.push(context[i].concat(selector));
                          }
                      }
                      else {
                          paths.push([selector]);
                      }
                      return;
                  }
  
                  // The paths are [[Selector]]
                  // The first list is a list of comma seperated selectors
                  // The inner list is a list of inheritance seperated selectors
                  // e.g.
                  // .a, .b {
                  //   .c {
                  //   }
                  // }
                  // == [[.a] [.c]] [[.b] [.c]]
                  //
  
                  // the elements from the current selector so far
                  currentElements = [];
                  // the current list of new selectors to add to the path.
                  // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
                  // by the parents
                  newSelectors = [[]];
  
                  for (i = 0; i < selector.elements.length; i++) {
                      el = selector.elements[i];
                      // non parent reference elements just get added
                      if (el.value !== "&") {
                          currentElements.push(el);
                      } else {
                          // the new list of selectors to add
                          selectorsMultiplied = [];
  
                          // merge the current list of non parent selector elements
                          // on to the current list of selectors to add
                          if (currentElements.length > 0) {
                              this.mergeElementsOnToSelectors(currentElements, newSelectors);
                          }
  
                          // loop through our current selectors
                          for (j = 0; j < newSelectors.length; j++) {
                              sel = newSelectors[j];
                              // if we don't have any parent paths, the & might be in a mixin so that it can be used
                              // whether there are parents or not
                              if (context.length == 0) {
                                  // the combinator used on el should now be applied to the next element instead so that
                                  // it is not lost
                                  if (sel.length > 0) {
                                      sel[0].elements = sel[0].elements.slice(0);
                                      sel[0].elements.push(new (tree.Element)(el.combinator, '', 0)); //new Element(el.Combinator,  ""));
                                  }
                                  selectorsMultiplied.push(sel);
                              }
                              else {
                                  // and the parent selectors
                                  for (k = 0; k < context.length; k++) {
                                      parentSel = context[k];
                                      // We need to put the current selectors
                                      // then join the last selector's elements on to the parents selectors
  
                                      // our new selector path
                                      newSelectorPath = [];
                                      // selectors from the parent after the join
                                      afterParentJoin = [];
                                      newJoinedSelectorEmpty = true;
  
                                      //construct the joined selector - if & is the first thing this will be empty,
                                      // if not newJoinedSelector will be the last set of elements in the selector
                                      if (sel.length > 0) {
                                          newSelectorPath = sel.slice(0);
                                          lastSelector = newSelectorPath.pop();
                                          newJoinedSelector = new (tree.Selector)(lastSelector.elements.slice(
                                              0), selector.extendList);
                                          newJoinedSelectorEmpty = false;
                                      }
                                      else {
                                          newJoinedSelector = new (tree.Selector)([], selector.extendList);
                                      }
  
                                      //put together the parent selectors after the join
                                      if (parentSel.length > 1) {
                                          afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
                                      }
  
                                      if (parentSel.length > 0) {
                                          newJoinedSelectorEmpty = false;
  
                                          // join the elements so far with the first part of the parent
                                          newJoinedSelector.elements.push(
                                              new (tree.Element)(el.combinator, parentSel[0].elements[0].value, 0));
                                          newJoinedSelector.elements = newJoinedSelector.elements.concat(
                                              parentSel[0].elements.slice(1));
                                      }
  
                                      if (!newJoinedSelectorEmpty) {
                                          // now add the joined selector
                                          newSelectorPath.push(newJoinedSelector);
                                      }
  
                                      // and the rest of the parent
                                      newSelectorPath = newSelectorPath.concat(afterParentJoin);
  
                                      // add that to our new set of selectors
                                      selectorsMultiplied.push(newSelectorPath);
                                  }
                              }
                          }
  
                          // our new selectors has been multiplied, so reset the state
                          newSelectors = selectorsMultiplied;
                          currentElements = [];
                      }
                  }
  
                  // if we have any elements left over (e.g. .a& .b == .b)
                  // add them on to all the current selectors
                  if (currentElements.length > 0) {
                      this.mergeElementsOnToSelectors(currentElements, newSelectors);
                  }
  
                  for (i = 0; i < newSelectors.length; i++) {
                      if (newSelectors[i].length > 0) {
                          paths.push(newSelectors[i]);
                      }
                  }
              },
  
              mergeElementsOnToSelectors: function (elements, selectors) {
                  var i, sel, extendList;
  
                  if (selectors.length == 0) {
                      selectors.push([new (tree.Selector)(elements)]);
                      return;
                  }
  
                  for (i = 0; i < selectors.length; i++) {
                      sel = selectors[i];
  
                      // if the previous thing in sel is a parent this needs to join on to it
                      if (sel.length > 0) {
                          sel[sel.length - 1] = new (tree.Selector)(sel[sel.length - 1].elements.concat(
                              elements), sel[sel.length - 1].extendList);
                      }
                      else {
                          sel.push(new (tree.Selector)(elements));
                      }
                  }
              }
          };
      })(require('../tree'));
      (function (tree) {
  
          tree.Selector = function (elements, extendList) {
              this.elements = elements;
              this.extendList = extendList || [];
          };
          tree.Selector.prototype = {
              type: "Selector",
              accept: function (visitor) {
                  this.elements = visitor.visit(this.elements);
                  this.extendList = visitor.visit(this.extendList)
              },
              match: function (other) {
                  var elements = this.elements,
                      len = elements.length,
                      oelements, olen, max, i;
  
                  oelements = other.elements.slice(
                      (other.elements.length && other.elements[0].value === "&") ? 1 : 0);
                  olen = oelements.length;
                  max = Math.min(len, olen);
  
                  if (olen === 0 || len < olen) {
                      return false;
                  } else {
                      for (i = 0; i < max; i++) {
                          if (elements[i].value !== oelements[i].value) {
                              return false;
                          }
                      }
                  }
                  return true;
              },
              eval: function (env) {
                  return new (tree.Selector)(this.elements.map(function (e) {
                      return e.eval(env);
                  }), this.extendList.map(function (extend) {
                      return extend.eval(env);
                  }));
              },
              toCSS: function (env) {
                  if (this._css) {
                      return this._css
                  }
  
                  if (this.elements[0].combinator.value === "") {
                      this._css = ' ';
                  } else {
                      this._css = '';
                  }
  
                  this._css += this.elements.map(function (e) {
                      if (typeof(e) === 'string') {
                          return ' ' + e.trim();
                      } else {
                          return e.toCSS(env);
                      }
                  }).join('');
  
                  return this._css;
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.UnicodeDescriptor = function (value) {
              this.value = value;
          };
          tree.UnicodeDescriptor.prototype = {
              type: "UnicodeDescriptor",
              toCSS: function (env) {
                  return this.value;
              },
              eval: function () {
                  return this
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.URL = function (val, currentFileInfo) {
              this.value = val;
              this.currentFileInfo = currentFileInfo;
          };
          tree.URL.prototype = {
              type: "Url",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              toCSS: function () {
                  return "url(" + this.value.toCSS() + ")";
              },
              eval: function (ctx) {
                  var val = this.value.eval(ctx), rootpath;
  
                  // Add the base path if the URL is relative
                  rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
                  if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) {
                      if (!val.quote) {
                          rootpath = rootpath.replace(/[\(\)'"\s]/g, function (match) {
                              return "\\" + match;
                          });
                      }
                      val.value = rootpath + val.value;
                  }
  
                  return new (tree.URL)(val, null);
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Value = function (value) {
              this.value = value;
          };
          tree.Value.prototype = {
              type: "Value",
              accept: function (visitor) {
                  this.value = visitor.visit(this.value);
              },
              eval: function (env) {
                  if (this.value.length === 1) {
                      return this.value[0].eval(env);
                  } else {
                      return new (tree.Value)(this.value.map(function (v) {
                          return v.eval(env);
                      }));
                  }
              },
              toCSS: function (env) {
                  return this.value.map(function (e) {
                      return e.toCSS(env);
                  }).join(env.compress ? ',' : ', ');
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.Variable = function (name, index, currentFileInfo) {
              this.name = name, this.index = index, this.currentFileInfo = currentFileInfo
          };
          tree.Variable.prototype = {
              type: "Variable",
              eval: function (env) {
                  var variable, v, name = this.name;
  
                  if (name.indexOf('@@') == 0) {
                      name = '@' + new (tree.Variable)(name.slice(1)).eval(env).value;
                  }
  
                  if (this.evaluating) {
                      throw {
                          type: 'Name',
                          message: "Recursive variable definition for " + name,
                          filename: this.currentFileInfo.file,
                          index: this.index
                      };
                  }
  
                  this.evaluating = true;
  
                  if (variable = tree.find(env.frames, function (frame) {
                          if (v = frame.variable(name)) {
                              return v.value.eval(env);
                          }
                      })) {
                      this.evaluating = false;
                      return variable;
                  }
                  else {
                      throw {
                          type: 'Name',
                          message: "variable " + name + " is undefined",
                          filename: this.currentFileInfo.filename,
                          index: this.index
                      };
                  }
              }
          };
  
      })(require('../tree'));
      (function (tree) {
  
          tree.debugInfo = function (env, ctx) {
              var result = "";
              if (env.dumpLineNumbers && !env.compress) {
                  switch (env.dumpLineNumbers) {
                      case 'comments':
                          result = tree.debugInfo.asComment(ctx);
                          break;
                      case 'mediaquery':
                          result = tree.debugInfo.asMediaQuery(ctx);
                          break;
                      case 'all':
                          result = tree.debugInfo.asComment(ctx) + tree.debugInfo.asMediaQuery(ctx);
                          break;
                  }
              }
              return result;
          };
  
          tree.debugInfo.asComment = function (ctx) {
              return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
          };
  
          tree.debugInfo.asMediaQuery = function (ctx) {
              return '@media -sass-debug-info{filename{font-family:' +
                  ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function (a) {
                      if (a == '\\') {
                          a = '\/';
                      }
                      return '\\' + a
                  }) +
                  '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
          };
  
          tree.find = function (obj, fun) {
              for (var i = 0, r; i < obj.length; i++) {
                  if (r = fun.call(obj, obj[i])) {
                      return r
                  }
              }
              return null;
          };
          tree.jsify = function (obj) {
              if (Array.isArray(obj.value) && (obj.value.length > 1)) {
                  return '[' + obj.value.map(function (v) {
                          return v.toCSS(false)
                      }).join(', ') + ']';
              } else {
                  return obj.toCSS(false);
              }
          };
  
      })(require('./tree'));
      (function (tree) {
  
          var parseCopyProperties = [
              'paths',            // option - unmodified - paths to search for imports on
              'optimization',     // option - optimization level (for the chunker)
              'files',            // list of files that have been imported, used for import-once
              'contents',         // browser-only, contents of all the files
              'relativeUrls',     // option - whether to adjust URL's to be relative
              'strictImports',    // option -
              'dumpLineNumbers',  // option - whether to dump line numbers
              'compress',         // option - whether to compress
              'processImports',   // option - whether to process imports. if false then imports will not be imported
              'mime',             // browser only - mime type for sheet import
              'currentFileInfo'   // information about the current file - for error reporting and importing and making urls relative etc.
          ];
  
          //currentFileInfo = {
          //  'relativeUrls' - option - whether to adjust URL's to be relative
          //  'filename' - full resolved filename of current file
          //  'rootpath' - path to append to normal URLs for this node
          //  'currentDirectory' - path to the current file, absolute
          //  'rootFilename' - filename of the base file
          //  'entryPath' = absolute path to the entry file
  
          tree.parseEnv = function (options) {
              copyFromOriginal(options, this, parseCopyProperties);
  
              if (!this.contents) {
                  this.contents = {};
              }
              if (!this.files) {
                  this.files = {};
              }
  
              if (!this.currentFileInfo) {
                  var filename = options.filename || "input";
                  options.filename = null;
                  var entryPath = filename.replace(/[^\/\\]*$/, "");
                  this.currentFileInfo = {
                      filename: filename,
                      relativeUrls: this.relativeUrls,
                      rootpath: options.rootpath || "",
                      currentDirectory: entryPath,
                      entryPath: entryPath,
                      rootFilename: filename
                  };
              }
          };
  
          tree.parseEnv.prototype.toSheet = function (path) {
              var env = new tree.parseEnv(this);
              env.href = path;
              //env.title = path;
              env.type = this.mime;
              return env;
          };
  
          var evalCopyProperties = [
              'silent',      // whether to swallow errors and warnings
              'verbose',     // whether to log more activity
              'compress',    // whether to compress
              'ieCompat',    // whether to enforce IE compatibility (IE8 data-uri)
              'strictMath',  // whether math has to be within parenthesis
              'strictUnits'  // whether units need to evaluate correctly
          ];
  
          tree.evalEnv = function (options, frames) {
              copyFromOriginal(options, this, evalCopyProperties);
  
              this.frames = frames || [];
          };
  
          tree.evalEnv.prototype.inParenthesis = function () {
              if (!this.parensStack) {
                  this.parensStack = [];
              }
              this.parensStack.push(true);
          };
  
          tree.evalEnv.prototype.outOfParenthesis = function () {
              this.parensStack.pop();
          };
  
          tree.evalEnv.prototype.isMathOn = function () {
              return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
          };
  
          tree.evalEnv.prototype.isPathRelative = function (path) {
              return !/^(?:[a-z-]+:|\/)/.test(path);
          };
  
          //todo - do the same for the toCSS env
          //tree.toCSSEnv = function (options) {
          //};
  
          var copyFromOriginal = function (original, destination, propertiesToCopy) {
              if (!original) {
                  return;
              }
  
              for (var i = 0; i < propertiesToCopy.length; i++) {
                  if (original.hasOwnProperty(propertiesToCopy[i])) {
                      destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
                  }
              }
          }
      })(require('./tree'));
      (function (tree) {
  
          tree.visitor = function (implementation) {
              this._implementation = implementation;
          };
  
          tree.visitor.prototype = {
              visit: function (node) {
  
                  if (node instanceof Array) {
                      return this.visitArray(node);
                  }
  
                  if (!node || !node.type) {
                      return node;
                  }
  
                  var funcName = "visit" + node.type,
                      func = this._implementation[funcName],
                      visitArgs, newNode;
                  if (func) {
                      visitArgs = {visitDeeper: true};
                      newNode = func.call(this._implementation, node, visitArgs);
                      if (this._implementation.isReplacing) {
                          node = newNode;
                      }
                  }
                  if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) {
                      node.accept(this);
                  }
                  funcName = funcName + "Out";
                  if (this._implementation[funcName]) {
                      this._implementation[funcName](node);
                  }
                  return node;
              },
              visitArray: function (nodes) {
                  var i, newNodes = [];
                  for (i = 0; i < nodes.length; i++) {
                      var evald = this.visit(nodes[i]);
                      if (evald instanceof Array) {
                          newNodes = newNodes.concat(evald);
                      } else {
                          newNodes.push(evald);
                      }
                  }
                  if (this._implementation.isReplacing) {
                      return newNodes;
                  }
                  return nodes;
              }
          };
  
      })(require('./tree'));
      (function (tree) {
          tree.importVisitor = function (importer, finish, evalEnv) {
              this._visitor = new tree.visitor(this);
              this._importer = importer;
              this._finish = finish;
              this.env = evalEnv || new tree.evalEnv();
              this.importCount = 0;
          };
  
          tree.importVisitor.prototype = {
              isReplacing: true,
              run: function (root) {
                  var error;
                  try {
                      // process the contents
                      this._visitor.visit(root);
                  }
                  catch (e) {
                      error = e;
                  }
  
                  this.isFinished = true;
  
                  if (this.importCount === 0) {
                      this._finish(error);
                  }
              },
              visitImport: function (importNode, visitArgs) {
                  var importVisitor = this,
                      evaldImportNode;
  
                  if (!importNode.css) {
  
                      try {
                          evaldImportNode = importNode.evalForImport(this.env);
                      } catch (e) {
                          if (!e.filename) {
                              e.index = importNode.index;
                              e.filename = importNode.currentFileInfo.filename;
                          }
                          // attempt to eval properly and treat as css
                          importNode.css = true;
                          // if that fails, this error will be thrown
                          importNode.error = e;
                      }
  
                      if (evaldImportNode && !evaldImportNode.css) {
                          importNode = evaldImportNode;
                          this.importCount++;
                          var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
                          this._importer.push(importNode.getPath(), importNode.currentFileInfo,
                              function (e, root, imported) {
                                  if (e && !e.filename) {
                                      e.index = importNode.index;
                                      e.filename = importNode.currentFileInfo.filename;
                                  }
                                  if (imported && !importNode.options.multiple) {
                                      importNode.skip = imported;
                                  }
  
                                  var subFinish = function (e) {
                                      importVisitor.importCount--;
  
                                      if (importVisitor.importCount === 0 && importVisitor.isFinished) {
                                          importVisitor._finish(e);
                                      }
                                  };
  
                                  if (root) {
                                      importNode.root = root;
                                      new (tree.importVisitor)(importVisitor._importer, subFinish, env)
                                      .run(root);
                                  } else {
                                      subFinish();
                                  }
                              });
                      }
                  }
                  visitArgs.visitDeeper = false;
                  return importNode;
              },
              visitRule: function (ruleNode, visitArgs) {
                  visitArgs.visitDeeper = false;
                  return ruleNode;
              },
              visitDirective: function (directiveNode, visitArgs) {
                  this.env.frames.unshift(directiveNode);
                  return directiveNode;
              },
              visitDirectiveOut: function (directiveNode) {
                  this.env.frames.shift();
              },
              visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
                  this.env.frames.unshift(mixinDefinitionNode);
                  return mixinDefinitionNode;
              },
              visitMixinDefinitionOut: function (mixinDefinitionNode) {
                  this.env.frames.shift();
              },
              visitRuleset: function (rulesetNode, visitArgs) {
                  this.env.frames.unshift(rulesetNode);
                  return rulesetNode;
              },
              visitRulesetOut: function (rulesetNode) {
                  this.env.frames.shift();
              },
              visitMedia: function (mediaNode, visitArgs) {
                  this.env.frames.unshift(mediaNode.ruleset);
                  return mediaNode;
              },
              visitMediaOut: function (mediaNode) {
                  this.env.frames.shift();
              }
          };
  
      })(require('./tree'));
      (function (tree) {
          tree.joinSelectorVisitor = function () {
              this.contexts = [[]];
              this._visitor = new tree.visitor(this);
          };
  
          tree.joinSelectorVisitor.prototype = {
              run: function (root) {
                  return this._visitor.visit(root);
              },
              visitRule: function (ruleNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
              visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
  
              visitRuleset: function (rulesetNode, visitArgs) {
                  var context = this.contexts[this.contexts.length - 1];
                  var paths = [];
                  this.contexts.push(paths);
  
                  if (!rulesetNode.root) {
                      rulesetNode.joinSelectors(paths, context, rulesetNode.selectors);
                      rulesetNode.paths = paths;
                  }
              },
              visitRulesetOut: function (rulesetNode) {
                  this.contexts.length = this.contexts.length - 1;
              },
              visitMedia: function (mediaNode, visitArgs) {
                  var context = this.contexts[this.contexts.length - 1];
                  mediaNode.ruleset.root = (context.length === 0 || context[0].multiMedia);
              }
          };
  
      })(require('./tree'));
      (function (tree) {
          tree.extendFinderVisitor = function () {
              this._visitor = new tree.visitor(this);
              this.contexts = [];
              this.allExtendsStack = [[]];
          };
  
          tree.extendFinderVisitor.prototype = {
              run: function (root) {
                  root = this._visitor.visit(root);
                  root.allExtends = this.allExtendsStack[0];
                  return root;
              },
              visitRule: function (ruleNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
              visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
              visitRuleset: function (rulesetNode, visitArgs) {
  
                  if (rulesetNode.root) {
                      return;
                  }
  
                  var i, j, extend, allSelectorsExtendList = [], extendList;
  
                  // get &:extend(.a); rules which apply to all selectors in this ruleset
                  for (i = 0; i < rulesetNode.rules.length; i++) {
                      if (rulesetNode.rules[i] instanceof tree.Extend) {
                          allSelectorsExtendList.push(rulesetNode.rules[i]);
                      }
                  }
  
                  // now find every selector and apply the extends that apply to all extends
                  // and the ones which apply to an individual extend
                  for (i = 0; i < rulesetNode.paths.length; i++) {
                      var selectorPath = rulesetNode.paths[i],
                          selector = selectorPath[selectorPath.length - 1];
                      extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(
                          function (allSelectorsExtend) {
                              return allSelectorsExtend.clone();
                          });
                      for (j = 0; j < extendList.length; j++) {
                          this.foundExtends = true;
                          extend = extendList[j];
                          extend.findSelfSelectors(selectorPath);
                          extend.ruleset = rulesetNode;
                          if (j === 0) {
                              extend.firstExtendOnThisSelectorPath = true;
                          }
                          this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);
                      }
                  }
  
                  this.contexts.push(rulesetNode.selectors);
              },
              visitRulesetOut: function (rulesetNode) {
                  if (!rulesetNode.root) {
                      this.contexts.length = this.contexts.length - 1;
                  }
              },
              visitMedia: function (mediaNode, visitArgs) {
                  mediaNode.allExtends = [];
                  this.allExtendsStack.push(mediaNode.allExtends);
              },
              visitMediaOut: function (mediaNode) {
                  this.allExtendsStack.length = this.allExtendsStack.length - 1;
              },
              visitDirective: function (directiveNode, visitArgs) {
                  directiveNode.allExtends = [];
                  this.allExtendsStack.push(directiveNode.allExtends);
              },
              visitDirectiveOut: function (directiveNode) {
                  this.allExtendsStack.length = this.allExtendsStack.length - 1;
              }
          };
  
          tree.processExtendsVisitor = function () {
              this._visitor = new tree.visitor(this);
          };
  
          tree.processExtendsVisitor.prototype = {
              run: function (root) {
                  var extendFinder = new tree.extendFinderVisitor();
                  extendFinder.run(root);
                  if (!extendFinder.foundExtends) {
                      return root;
                  }
                  root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
                  this.allExtendsStack = [root.allExtends];
                  return this._visitor.visit(root);
              },
              doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
                  //
                  // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
                  // the selector we would do normally, but we are also adding an extend with the same target selector
                  // this means this new extend can then go and alter other extends
                  //
                  // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
                  // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
                  // we look at each selector at a time, as is done in visitRuleset
  
                  var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend;
  
                  iterationCount = iterationCount || 0;
  
                  //loop through comparing every extend with every target extend.
                  // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
                  // e.g.  .a:extend(.b) {}  and .b:extend(.c) {} then the first extend extends the second one
                  // and the second is the target.
                  // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
                  // case when processing media queries
                  for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {
                      for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {
  
                          extend = extendsList[extendIndex];
                          targetExtend = extendsListTarget[targetExtendIndex];
  
                          // look for circular references
                          if (this.inInheritanceChain(targetExtend, extend)) {
                              continue;
                          }
  
                          // find a match in the target extends self selector (the bit before :extend)
                          selectorPath = [targetExtend.selfSelectors[0]];
                          matches = extendVisitor.findMatch(extend, selectorPath);
  
                          if (matches.length) {
  
                              // we found a match, so for each self selector..
                              extend.selfSelectors.forEach(function (selfSelector) {
  
                                  // process the extend as usual
                                  newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
  
                                  // but now we create a new extend from it
                                  newExtend = new (tree.Extend)(targetExtend.selector, targetExtend.option, 0);
                                  newExtend.selfSelectors = newSelector;
  
                                  // add the extend onto the list of extends for that selector
                                  newSelector[newSelector.length - 1].extendList = [newExtend];
  
                                  // record that we need to add it.
                                  extendsToAdd.push(newExtend);
                                  newExtend.ruleset = targetExtend.ruleset;
  
                                  //remember its parents for circular references
                                  newExtend.parents = [targetExtend, extend];
  
                                  // only process the selector once.. if we have :extend(.a,.b) then multiple
                                  // extends will look at the same selector path, so when extending
                                  // we know that any others will be duplicates in terms of what is added to the css
                                  if (targetExtend.firstExtendOnThisSelectorPath) {
                                      newExtend.firstExtendOnThisSelectorPath = true;
                                      targetExtend.ruleset.paths.push(newSelector);
                                  }
                              });
                          }
                      }
                  }
  
                  if (extendsToAdd.length) {
                      // try to detect circular references to stop a stack overflow.
                      // may no longer be needed.
                      this.extendChainCount++;
                      if (iterationCount > 100) {
                          var selectorOne = "{unable to calculate}";
                          var selectorTwo = "{unable to calculate}";
                          try {
                              selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
                              selectorTwo = extendsToAdd[0].selector.toCSS();
                          }
                          catch (e) {
                          }
                          throw {
                              message: "extend circular reference detected. One of the circular extends is currently:"
                              + selectorOne + ":extend(" + selectorTwo + ")"
                          };
                      }
  
                      // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
                      return extendsToAdd.concat(
                          extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));
                  } else {
                      return extendsToAdd;
                  }
              },
              inInheritanceChain: function (possibleParent, possibleChild) {
                  if (possibleParent === possibleChild) {
                      return true;
                  }
                  if (possibleChild.parents) {
                      if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) {
                          return true;
                      }
                      if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) {
                          return true;
                      }
                  }
                  return false;
              },
              visitRule: function (ruleNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
              visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
              visitSelector: function (selectorNode, visitArgs) {
                  visitArgs.visitDeeper = false;
              },
              visitRuleset: function (rulesetNode, visitArgs) {
                  if (rulesetNode.root) {
                      return;
                  }
                  var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length
                  - 1], selectorsToAdd = [], extendVisitor = this;
  
                  // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
  
                  for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
                      for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
  
                          selectorPath = rulesetNode.paths[pathIndex];
  
                          // extending extends happens initially, before the main pass
                          if (selectorPath[selectorPath.length - 1].extendList.length) {
                              continue;
                          }
  
                          matches = this.findMatch(allExtends[extendIndex], selectorPath);
  
                          if (matches.length) {
  
                              allExtends[extendIndex].selfSelectors.forEach(function (selfSelector) {
                                  selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
                              });
                          }
                      }
                  }
                  rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
              },
              findMatch: function (extend, haystackSelectorPath) {
                  //
                  // look through the haystack selector path to try and find the needle - extend.selector
                  // returns an array of selector matches that can then be replaced
                  //
                  var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
                      targetCombinator, i,
                      extendVisitor = this,
                      needleElements = extend.selector.elements,
                      potentialMatches = [], potentialMatch, matches = [];
  
                  // loop through the haystack elements
                  for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length;
                      haystackSelectorIndex++) {
                      hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
  
                      for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length;
                          hackstackElementIndex++) {
  
                          haystackElement = hackstackSelector.elements[hackstackElementIndex];
  
                          // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
                          if (extend.allowBefore || (haystackSelectorIndex == 0 && hackstackElementIndex == 0)) {
                              potentialMatches.push({
                                  pathIndex: haystackSelectorIndex,
                                  index: hackstackElementIndex,
                                  matched: 0,
                                  initialCombinator: haystackElement.combinator
                              });
                          }
  
                          for (i = 0; i < potentialMatches.length; i++) {
                              potentialMatch = potentialMatches[i];
  
                              // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
                              // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
                              // what the resulting combinator will be
                              targetCombinator = haystackElement.combinator.value;
                              if (targetCombinator == '' && hackstackElementIndex === 0) {
                                  targetCombinator = ' ';
                              }
  
                              // if we don't match, null our match to indicate failure
                              if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value,
                                      haystackElement.value) ||
                                  (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value
                                  !== targetCombinator)) {
                                  potentialMatch = null;
                              } else {
                                  potentialMatch.matched++;
                              }
  
                              // if we are still valid and have finished, test whether we have elements after and whether these are allowed
                              if (potentialMatch) {
                                  potentialMatch.finished = potentialMatch.matched === needleElements.length;
                                  if (potentialMatch.finished &&
                                      (!extend.allowAfter && (hackstackElementIndex + 1
                                      < hackstackSelector.elements.length || haystackSelectorIndex + 1
                                      < haystackSelectorPath.length))) {
                                      potentialMatch = null;
                                  }
                              }
                              // if null we remove, if not, we are still valid, so either push as a valid match or continue
                              if (potentialMatch) {
                                  if (potentialMatch.finished) {
                                      potentialMatch.length = needleElements.length;
                                      potentialMatch.endPathIndex = haystackSelectorIndex;
                                      potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
                                      potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
                                      matches.push(potentialMatch);
                                  }
                              } else {
                                  potentialMatches.splice(i, 1);
                                  i--;
                              }
                          }
                      }
                  }
                  return matches;
              },
              isElementValuesEqual: function (elementValue1, elementValue2) {
                  if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
                      return elementValue1 === elementValue2;
                  }
                  if (elementValue1 instanceof tree.Attribute) {
                      if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
                          return false;
                      }
                      if (!elementValue1.value || !elementValue2.value) {
                          if (elementValue1.value || elementValue2.value) {
                              return false;
                          }
                          return true;
                      }
                      elementValue1 = elementValue1.value.value || elementValue1.value;
                      elementValue2 = elementValue2.value.value || elementValue2.value;
                      return elementValue1 === elementValue2;
                  }
                  return false;
              },
              extendSelector: function (matches, selectorPath, replacementSelector) {
  
                  //for a set of matches, replace each match with the replacement selector
  
                  var currentSelectorPathIndex = 0,
                      currentSelectorPathElementIndex = 0,
                      path = [],
                      matchIndex,
                      selector,
                      firstElement;
  
                  for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
                      match = matches[matchIndex];
                      selector = selectorPath[match.pathIndex];
                      firstElement = new tree.Element(
                          match.initialCombinator,
                          replacementSelector.elements[0].value,
                          replacementSelector.elements[0].index
                      );
  
                      if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
                          path[path.length - 1].elements = path[path.length - 1].elements.concat(
                              selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
                          currentSelectorPathElementIndex = 0;
                          currentSelectorPathIndex++;
                      }
  
                      path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
  
                      path.push(new tree.Selector(
                          selector.elements
                          .slice(currentSelectorPathElementIndex, match.index)
                          .concat([firstElement])
                          .concat(replacementSelector.elements.slice(1))
                      ));
                      currentSelectorPathIndex = match.endPathIndex;
                      currentSelectorPathElementIndex = match.endPathElementIndex;
                      if (currentSelectorPathElementIndex >= selector.elements.length) {
                          currentSelectorPathElementIndex = 0;
                          currentSelectorPathIndex++;
                      }
                  }
  
                  if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
                      path[path.length - 1].elements = path[path.length - 1].elements.concat(
                          selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
                      currentSelectorPathElementIndex = 0;
                      currentSelectorPathIndex++;
                  }
  
                  path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
  
                  return path;
              },
              visitRulesetOut: function (rulesetNode) {
              },
              visitMedia: function (mediaNode, visitArgs) {
                  var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
                  newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
                  this.allExtendsStack.push(newAllExtends);
              },
              visitMediaOut: function (mediaNode) {
                  this.allExtendsStack.length = this.allExtendsStack.length - 1;
              },
              visitDirective: function (directiveNode, visitArgs) {
                  var newAllExtends = directiveNode.allExtends.concat(
                      this.allExtendsStack[this.allExtendsStack.length - 1]);
                  newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
                  this.allExtendsStack.push(newAllExtends);
              },
              visitDirectiveOut: function (directiveNode) {
                  this.allExtendsStack.length = this.allExtendsStack.length - 1;
              }
          };
  
      })(require('./tree'));//
  // browser.js - client-side engine
  //
  
      var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);
  
      less.env = less.env || (location.hostname == '127.0.0.1' ||
          location.hostname == '0.0.0.0' ||
          location.hostname == 'localhost' ||
          location.port.length > 0 ||
          isFileProtocol ? 'development'
              : 'production');
  
  // Load styles asynchronously (default: false)
  //
  // This is set to `false` by default, so that the body
  // doesn't start loading before the stylesheets are parsed.
  // Setting this to `true` can result in flickering.
  //
      less.async = less.async || false;
      less.fileAsync = less.fileAsync || false;
  
  // Interval between watch polls
      less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
  
  //Setup user functions
      if (less.functions) {
          for (var func in less.functions) {
              less.tree.functions[func] = less.functions[func];
          }
      }
  
      var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);
      if (dumpLineNumbers) {
          less.dumpLineNumbers = dumpLineNumbers[1];
      }
  
  //
  // Watch mode
  //
      less.watch = function () {
          if (!less.watchMode) {
              less.env = 'development';
              initRunningMode();
          }
          return this.watchMode = true
      };
  
      less.unwatch = function () {
          clearInterval(less.watchTimer);
          return this.watchMode = false;
      };
  
      function initRunningMode() {
          if (less.env === 'development') {
              less.optimization = 0;
              less.watchTimer = setInterval(function () {
                  if (less.watchMode) {
                      loadStyleSheets(function (e, root, _, sheet, env) {
                          if (e) {
                              error(e, sheet.href);
                          } else if (root) {
                              createCSS(root.toCSS(less), sheet, env.lastModified);
                          }
                      });
                  }
              }, less.poll);
          } else {
              less.optimization = 3;
          }
      }
  
      if (/!watch/.test(location.hash)) {
          less.watch();
      }
  
      var cache = null;
  
      if (less.env != 'development') {
          try {
              cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
          } catch (_) {
          }
      }
  
  //
  // Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
  //
      var links = document.getElementsByTagName('link');
      var typePattern = /^text\/(x-)?less$/;
  
      less.sheets = [];
  
      for (var i = 0; i < links.length; i++) {
          if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
              (links[i].type.match(typePattern)))) {
              less.sheets.push(links[i]);
          }
      }
  
  //
  // With this function, it's possible to alter variables and re-render
  // CSS without reloading less-files
  //
      var session_cache = '';
      less.modifyVars = function (record) {
          var str = session_cache;
          for (name in record) {
              str += ((name.slice(0, 1) === '@') ? '' : '@') + name + ': ' +
                  ((record[name].slice(-1) === ';') ? record[name] : record[name] + ';');
          }
          new (less.Parser)(new less.tree.parseEnv(less)).parse(str, function (e, root) {
              if (e) {
                  error(e, "session_cache");
              } else {
                  createCSS(root.toCSS(less), less.sheets[less.sheets.length - 1]);
              }
          });
      };
  
      less.refresh = function (reload) {
          var startTime, endTime;
          startTime = endTime = new (Date);
  
          loadStyleSheets(function (e, root, _, sheet, env) {
              if (e) {
                  return error(e, sheet.href);
              }
              if (env.local) {
                  log("loading " + sheet.href + " from cache.");
              } else {
                  log("parsed " + sheet.href + " successfully.");
                  createCSS(root.toCSS(less), sheet, env.lastModified);
              }
              log("css for " + sheet.href + " generated in " + (new (Date) - endTime) + 'ms');
              (env.remaining === 0) && log("css generated in " + (new (Date) - startTime) + 'ms');
              endTime = new (Date);
          }, reload);
  
          loadStyles();
      };
      less.refreshStyles = loadStyles;
  
      less.refresh(less.env === 'development');
  
      function loadStyles() {
          var styles = document.getElementsByTagName('style');
          for (var i = 0; i < styles.length; i++) {
              if (styles[i].type.match(typePattern)) {
                  var env = new less.tree.parseEnv(less);
                  env.filename = document.location.href.replace(/#.*$/, '');
  
                  new (less.Parser)(env).parse(styles[i].innerHTML || '', function (e, cssAST) {
                      if (e) {
                          return error(e, "inline");
                      }
                      var css = cssAST.toCSS(less);
                      var style = styles[i];
                      style.type = 'text/css';
                      if (style.styleSheet) {
                          style.styleSheet.cssText = css;
                      } else {
                          style.innerHTML = css;
                      }
                  });
              }
          }
      }
  
      function loadStyleSheets(callback, reload) {
          for (var i = 0; i < less.sheets.length; i++) {
              loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
          }
      }
  
      function pathDiff(url, baseUrl) {
          // diff between two paths to create a relative path
  
          var urlParts = extractUrlParts(url),
              baseUrlParts = extractUrlParts(baseUrl),
              i, max, urlDirectories, baseUrlDirectories, diff = "";
          if (urlParts.hostPart !== baseUrlParts.hostPart) {
              return "";
          }
          max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
          for (i = 0; i < max; i++) {
              if (baseUrlParts.directories[i] !== urlParts.directories[i]) {
                  break;
              }
          }
          baseUrlDirectories = baseUrlParts.directories.slice(i);
          urlDirectories = urlParts.directories.slice(i);
          for (i = 0; i < baseUrlDirectories.length - 1; i++) {
              diff += "../";
          }
          for (i = 0; i < urlDirectories.length - 1; i++) {
              diff += urlDirectories[i] + "/";
          }
          return diff;
      }
  
      function extractUrlParts(url, baseUrl) {
          // urlParts[1] = protocol&hostname || /
          // urlParts[2] = / if path relative to host base
          // urlParts[3] = directories
          // urlParts[4] = filename
          // urlParts[5] = parameters
  
          var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/,
              urlParts = url.match(urlPartsRegex),
              returner = {}, directories = [], i, baseUrlParts;
  
          if (!urlParts) {
              throw new Error("Could not parse sheet href - '" + url + "'");
          }
  
          // Stylesheets in IE don't always return the full path
          if (!urlParts[1] || urlParts[2]) {
              baseUrlParts = baseUrl.match(urlPartsRegex);
              if (!baseUrlParts) {
                  throw new Error("Could not parse page url - '" + baseUrl + "'");
              }
              urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
              if (!urlParts[2]) {
                  urlParts[3] = baseUrlParts[3] + urlParts[3];
              }
          }
  
          if (urlParts[3]) {
              directories = urlParts[3].replace("\\", "/").split("/");
  
              // extract out . before .. so .. doesn't absorb a non-directory
              for (i = 0; i < directories.length; i++) {
                  if (directories[i] === ".") {
                      directories.splice(i, 1);
                      i -= 1;
                  }
              }
  
              for (i = 0; i < directories.length; i++) {
                  if (directories[i] === ".." && i > 0) {
                      directories.splice(i - 1, 2);
                      i -= 2;
                  }
              }
          }
  
          returner.hostPart = urlParts[1];
          returner.directories = directories;
          returner.path = urlParts[1] + directories.join("/");
          returner.fileUrl = returner.path + (urlParts[4] || "");
          returner.url = returner.fileUrl + (urlParts[5] || "");
          return returner;
      }
  
      function loadStyleSheet(sheet, callback, reload, remaining) {
  
          // sheet may be set to the stylesheet for the initial load or a collection of properties including
          // some env variables for imports
          var hrefParts = extractUrlParts(sheet.href, window.location.href);
          var href = hrefParts.url;
          var css = cache && cache.getItem(href);
          var timestamp = cache && cache.getItem(href + ':timestamp');
          var styles = {css: css, timestamp: timestamp};
          var env;
          var newFileInfo = {
              relativeUrls: less.relativeUrls,
              currentDirectory: hrefParts.path,
              filename: href
          };
  
          if (sheet instanceof less.tree.parseEnv) {
              env = new less.tree.parseEnv(sheet);
              newFileInfo.entryPath = env.currentFileInfo.entryPath;
              newFileInfo.rootpath = env.currentFileInfo.rootpath;
              newFileInfo.rootFilename = env.currentFileInfo.rootFilename;
          } else {
              env = new less.tree.parseEnv(less);
              env.mime = sheet.type;
              newFileInfo.entryPath = hrefParts.path;
              newFileInfo.rootpath = less.rootpath || hrefParts.path;
              newFileInfo.rootFilename = href;
          }
  
          if (env.relativeUrls) {
              //todo - this relies on option being set on less object rather than being passed in as an option
              //     - need an originalRootpath
              if (less.rootpath) {
                  newFileInfo.rootpath = extractUrlParts(
                      less.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path;
              } else {
                  newFileInfo.rootpath = hrefParts.path;
              }
          }
  
          xhr(href, sheet.type, function (data, lastModified) {
              // Store data this session
              session_cache += data.replace(/@import .+?;/ig, '');
  
              if (!reload && styles && lastModified &&
                  (new (Date)(lastModified).valueOf() ===
                  new (Date)(styles.timestamp).valueOf())) {
                  // Use local copy
                  createCSS(styles.css, sheet);
                  callback(null, null, data, sheet, {local: true, remaining: remaining}, href);
              } else {
                  // Use remote copy (re-parse)
                  try {
                      env.contents[href] = data;  // Updating content cache
                      env.paths = [hrefParts.path];
                      env.currentFileInfo = newFileInfo;
  
                      new (less.Parser)(env).parse(data, function (e, root) {
                          if (e) {
                              return callback(e, null, null, sheet);
                          }
                          try {
                              callback(e, root, data, sheet,
                                  {local: false, lastModified: lastModified, remaining: remaining}, href);
                              //TODO - there must be a better way? A generic less-to-css function that can both call error
                              //and removeNode where appropriate
                              //should also add tests
                              if (env.currentFileInfo.rootFilename === href) {
                                  removeNode(document.getElementById('less-error-message:' + extractId(href)));
                              }
                          } catch (e) {
                              callback(e, null, null, sheet);
                          }
                      });
                  } catch (e) {
                      callback(e, null, null, sheet);
                  }
              }
          }, function (status, url) {
              callback({type: 'File', message: "'" + url + "' wasn't found (" + status + ")"}, null, null, sheet);
          });
      }
  
      function extractId(href) {
          return href.replace(/^[a-z-]+:\/+?[^\/]+/, '')  // Remove protocol & domain
          .replace(/^\//, '')  // Remove root /
          .replace(/\.[a-zA-Z]+$/, '')  // Remove simple extension
          .replace(/[^\.\w-]+/g, '-')  // Replace illegal characters
          .replace(/\./g, ':'); // Replace dots with colons(for valid id)
      }
  
      function createCSS(styles, sheet, lastModified) {
          // Strip the query-string
          var href = sheet.href || '';
  
          // If there is no title set, use the filename, minus the extension
          var id = 'less:' + (sheet.title || extractId(href));
  
          // If this has already been inserted into the DOM, we may need to replace it
          var oldCss = document.getElementById(id);
          var keepOldCss = false;
  
          // Create a new stylesheet node for insertion or (if necessary) replacement
          var css = document.createElement('style');
          css.setAttribute('type', 'text/css');
          if (sheet.media) {
              css.setAttribute('media', sheet.media);
          }
          css.id = id;
  
          if (css.styleSheet) { // IE
              try {
                  css.styleSheet.cssText = styles;
              } catch (e) {
                  throw new (Error)("Couldn't reassign styleSheet.cssText.");
              }
          } else {
              css.appendChild(document.createTextNode(styles));
  
              // If new contents match contents of oldCss, don't replace oldCss
              keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 &&
              oldCss.firstChild.nodeValue === css.firstChild.nodeValue);
          }
  
          var head = document.getElementsByTagName('head')[0];
  
          // If there is no oldCss, just append; otherwise, only append if we need
          // to replace oldCss with an updated stylesheet
          if (oldCss == null || keepOldCss === false) {
              var nextEl = sheet && sheet.nextSibling || null;
              (nextEl || document.getElementsByTagName('head')[0]).parentNode.insertBefore(css, nextEl);
          }
          if (oldCss && keepOldCss === false) {
              head.removeChild(oldCss);
          }
  
          // Don't update the local store if the file wasn't modified
          if (lastModified && cache) {
              log('saving ' + href + ' to cache.');
              try {
                  cache.setItem(href, styles);
                  cache.setItem(href + ':timestamp', lastModified);
              } catch (e) {
                  //TODO - could do with adding more robust error handling
                  log('failed to save');
              }
          }
      }
  
      function xhr(url, type, callback, errback) {
          var xhr = getXMLHttpRequest();
          var async = isFileProtocol ? less.fileAsync : less.async;
  
          if (typeof(xhr.overrideMimeType) === 'function') {
              xhr.overrideMimeType('text/css');
          }
          xhr.open('GET', url, async);
          xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
          xhr.send(null);
  
          if (isFileProtocol && !less.fileAsync) {
              if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
                  callback(xhr.responseText);
              } else {
                  errback(xhr.status, url);
              }
          } else if (async) {
              xhr.onreadystatechange = function () {
                  if (xhr.readyState == 4) {
                      handleResponse(xhr, callback, errback);
                  }
              };
          } else {
              handleResponse(xhr, callback, errback);
          }
  
          function handleResponse(xhr, callback, errback) {
              if (xhr.status >= 200 && xhr.status < 300) {
                  callback(xhr.responseText,
                      xhr.getResponseHeader("Last-Modified"));
              } else if (typeof(errback) === 'function') {
                  errback(xhr.status, url);
              }
          }
      }
  
      function getXMLHttpRequest() {
          if (window.XMLHttpRequest) {
              return new (XMLHttpRequest);
          } else {
              try {
                  return new (ActiveXObject)("MSXML2.XMLHTTP.3.0");
              } catch (e) {
                  log("browser doesn't support AJAX.");
                  return null;
              }
          }
      }
  
      function removeNode(node) {
          return node && node.parentNode.removeChild(node);
      }
  
      function log(str) {
          if (less.env == 'development' && typeof(console) !== "undefined") {
              console.log('less: ' + str)
          }
      }
  
      function error(e, rootHref) {
          var id = 'less-error-message:' + extractId(rootHref || "");
          var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
          var elem = document.createElement('div'), timer, content, error = [];
          var filename = e.filename || rootHref;
          var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
  
          elem.id = id;
          elem.className = "less-error-message";
  
          content = '<h3>' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
              '</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + "</a> ";
  
          var errorline = function (e, i, classname) {
              if (e.extract[i] != undefined) {
                  error.push(template.replace(/\{line\}/, (parseInt(e.line) || 0) + (i - 1))
                  .replace(/\{class\}/, classname)
                  .replace(/\{content\}/, e.extract[i]));
              }
          };
  
          if (e.extract) {
              errorline(e, 0, '');
              errorline(e, 1, 'line');
              errorline(e, 2, '');
              content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
                  '<ul>' + error.join('') + '</ul>';
          } else if (e.stack) {
              content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
          }
          elem.innerHTML = content;
  
          // CSS for error messages
          createCSS([
              '.less-error-message ul, .less-error-message li {',
              'list-style-type: none;',
              'margin-right: 15px;',
              'padding: 4px 0;',
              'margin: 0;',
              '}',
              '.less-error-message label {',
              'font-size: 12px;',
              'margin-right: 15px;',
              'padding: 4px 0;',
              'color: #cc7777;',
              '}',
              '.less-error-message pre {',
              'color: #dd6666;',
              'padding: 4px 0;',
              'margin: 0;',
              'display: inline-block;',
              '}',
              '.less-error-message pre.line {',
              'color: #ff0000;',
              '}',
              '.less-error-message h3 {',
              'font-size: 20px;',
              'font-weight: bold;',
              'padding: 15px 0 5px 0;',
              'margin: 0;',
              '}',
              '.less-error-message a {',
              'color: #10a',
              '}',
              '.less-error-message .error {',
              'color: red;',
              'font-weight: bold;',
              'padding-bottom: 2px;',
              'border-bottom: 1px dashed red;',
              '}'
          ].join('\n'), {title: 'error-message'});
  
          elem.style.cssText = [
              "font-family: Arial, sans-serif",
              "border: 1px solid #e00",
              "background-color: #eee",
              "border-radius: 5px",
              "-webkit-border-radius: 5px",
              "-moz-border-radius: 5px",
              "color: #e00",
              "padding: 15px",
              "margin-bottom: 15px"
          ].join(';');
  
          if (less.env == 'development') {
              timer = setInterval(function () {
                  if (document.body) {
                      if (document.getElementById(id)) {
                          document.body.replaceChild(elem, document.getElementById(id));
                      } else {
                          document.body.insertBefore(elem, document.body.firstChild);
                      }
                      clearInterval(timer);
                  }
              }, 10);
          }
      }
  
  // amd.js
  //
  // Define Less as an AMD module.
      if (typeof define === "function" && define.amd) {
          define(function () {
              return less;
          });
      }
  })(window);
  