text: //
  // 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 (var 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);
      }
  }
  