2 Commits 06fba3e2e7 ... 0f2eef04fa

Author SHA1 Message Date
  Stephan Fuchs 0f2eef04fa get `clean-css-cli` working 2 months ago
  Stephan Fuchs beaa35a25d add `clean-css-cli` 2 months ago
100 changed files with 15178 additions and 2 deletions
  1. 2 0
      .gitignore
  2. 23 2
      .vscode/tasks.json
  3. 15 0
      node_modules/anymatch/LICENSE
  4. 87 0
      node_modules/anymatch/README.md
  5. 20 0
      node_modules/anymatch/index.d.ts
  6. 104 0
      node_modules/anymatch/index.js
  7. 48 0
      node_modules/anymatch/package.json
  8. 21 0
      node_modules/balanced-match/LICENSE.md
  9. 97 0
      node_modules/balanced-match/README.md
  10. 62 0
      node_modules/balanced-match/index.js
  11. 48 0
      node_modules/balanced-match/package.json
  12. 263 0
      node_modules/binary-extensions/binary-extensions.json
  13. 3 0
      node_modules/binary-extensions/binary-extensions.json.d.ts
  14. 14 0
      node_modules/binary-extensions/index.d.ts
  15. 1 0
      node_modules/binary-extensions/index.js
  16. 10 0
      node_modules/binary-extensions/license
  17. 40 0
      node_modules/binary-extensions/package.json
  18. 25 0
      node_modules/binary-extensions/readme.md
  19. 21 0
      node_modules/brace-expansion/LICENSE
  20. 129 0
      node_modules/brace-expansion/README.md
  21. 201 0
      node_modules/brace-expansion/index.js
  22. 47 0
      node_modules/brace-expansion/package.json
  23. 184 0
      node_modules/braces/CHANGELOG.md
  24. 21 0
      node_modules/braces/LICENSE
  25. 593 0
      node_modules/braces/README.md
  26. 170 0
      node_modules/braces/index.js
  27. 57 0
      node_modules/braces/lib/compile.js
  28. 57 0
      node_modules/braces/lib/constants.js
  29. 113 0
      node_modules/braces/lib/expand.js
  30. 333 0
      node_modules/braces/lib/parse.js
  31. 32 0
      node_modules/braces/lib/stringify.js
  32. 112 0
      node_modules/braces/lib/utils.js
  33. 77 0
      node_modules/braces/package.json
  34. 21 0
      node_modules/chokidar/LICENSE
  35. 308 0
      node_modules/chokidar/README.md
  36. 973 0
      node_modules/chokidar/index.js
  37. 66 0
      node_modules/chokidar/lib/constants.js
  38. 526 0
      node_modules/chokidar/lib/fsevents-handler.js
  39. 654 0
      node_modules/chokidar/lib/nodefs-handler.js
  40. 70 0
      node_modules/chokidar/package.json
  41. 192 0
      node_modules/chokidar/types/index.d.ts
  42. 246 0
      node_modules/clean-css-cli/History.md
  43. 21 0
      node_modules/clean-css-cli/LICENSE
  44. 480 0
      node_modules/clean-css-cli/README.md
  45. 4 0
      node_modules/clean-css-cli/bin/cleancss
  46. 376 0
      node_modules/clean-css-cli/index.js
  47. 51 0
      node_modules/clean-css-cli/package.json
  48. 1504 0
      node_modules/clean-css/History.md
  49. 19 0
      node_modules/clean-css/LICENSE
  50. 987 0
      node_modules/clean-css/README.md
  51. 1 0
      node_modules/clean-css/index.js
  52. 241 0
      node_modules/clean-css/lib/clean.js
  53. 33 0
      node_modules/clean-css/lib/optimizer/clone.js
  54. 1640 0
      node_modules/clean-css/lib/optimizer/configuration.js
  55. 656 0
      node_modules/clean-css/lib/optimizer/configuration/break-up.js
  56. 314 0
      node_modules/clean-css/lib/optimizer/configuration/can-override.js
  57. 15 0
      node_modules/clean-css/lib/optimizer/configuration/properties/understandable.js
  58. 294 0
      node_modules/clean-css/lib/optimizer/configuration/restore.js
  59. 8 0
      node_modules/clean-css/lib/optimizer/hack.js
  60. 10 0
      node_modules/clean-css/lib/optimizer/invalid-property-error.js
  61. 6 0
      node_modules/clean-css/lib/optimizer/level-0/optimize.js
  62. 325 0
      node_modules/clean-css/lib/optimizer/level-1/optimize.js
  63. 10 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers.js
  64. 23 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/background.js
  65. 29 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/border-radius.js
  66. 15 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/box-shadow.js
  67. 34 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/filter.js
  68. 23 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/font-weight.js
  69. 21 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/margin.js
  70. 19 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/outline.js
  71. 32 0
      node_modules/clean-css/lib/optimizer/level-1/property-optimizers/padding.js
  72. 23 0
      node_modules/clean-css/lib/optimizer/level-1/sort-selectors.js
  73. 9 0
      node_modules/clean-css/lib/optimizer/level-1/tidy-at-rule.js
  74. 34 0
      node_modules/clean-css/lib/optimizer/level-1/tidy-block.js
  75. 265 0
      node_modules/clean-css/lib/optimizer/level-1/tidy-rules.js
  76. 14 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers.js
  77. 89 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color.js
  78. 189 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color/shorten-hex.js
  79. 54 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color/shorten-hsl.js
  80. 10 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color/shorten-rgb.js
  81. 19 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/degrees.js
  82. 72 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/fraction.js
  83. 22 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/precision.js
  84. 7 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/starts-as-url.js
  85. 31 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/text-quotes.js
  86. 31 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/time.js
  87. 46 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/unit.js
  88. 23 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/url-prefix.js
  89. 22 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/url-quotes.js
  90. 22 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/url-whitespace.js
  91. 48 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/whitespace.js
  92. 49 0
      node_modules/clean-css/lib/optimizer/level-1/value-optimizers/zero.js
  93. 61 0
      node_modules/clean-css/lib/optimizer/level-2/extract-properties.js
  94. 273 0
      node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js
  95. 55 0
      node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js
  96. 105 0
      node_modules/clean-css/lib/optimizer/level-2/merge-media-queries.js
  97. 88 0
      node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js
  98. 73 0
      node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-selector.js
  99. 139 0
      node_modules/clean-css/lib/optimizer/level-2/optimize.js
  100. 28 0
      node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js

+ 2 - 0
.gitignore

@@ -60,3 +60,5 @@ sugarcube/temp/
 
 sugarcube/src/less.css
 sugarcube/src/main.less
+sugarcube/src/less_preCleaned.txt
+sugarcube/src/less.min.css

+ 23 - 2
.vscode/tasks.json

@@ -22,7 +22,7 @@
 			"problemMatcher": [],
 			"dependsOn": [
 				"esbuild",
-				"less"
+				"cleanCSS"
 			]
 		},
 		{
@@ -120,7 +120,7 @@
 		{
 			"label": "less",
 			"type": "shell",
-			"command": "lessc sugarcube/src/main.less sugarcube/src/less.css",
+			"command": "lessc sugarcube/src/main.less sugarcube/src/less_preCleaned.txt",
 			"presentation": {
 				"echo": true,
 				"reveal": "always",
@@ -135,5 +135,26 @@
 			"problemMatcher": [],
 			"dependsOn": ["lessPrecompile"]
 		},
+
+		{
+			"label": "cleanCSS",
+			"type": "shell",
+			"command": "./node_modules/.bin/cleancss -o sugarcube/src/less.min.css sugarcube/src/less_preCleaned.txt -O 2",
+			"presentation": {
+				"echo": true,
+				"reveal": "always",
+				"focus": false,
+				"panel": "dedicated",
+				"showReuseMessage": false,
+				"clear": true
+			},
+			"group": {
+				"kind": "build"
+			},
+			"problemMatcher": [],
+			"dependsOn": [
+				"less"
+			]
+		},
 	]
 }

+ 15 - 0
node_modules/anymatch/LICENSE

@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) 2019 Elan Shanker, Paul Miller (https://paulmillr.com)
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

+ 87 - 0
node_modules/anymatch/README.md

@@ -0,0 +1,87 @@
+anymatch [![Build Status](https://travis-ci.org/micromatch/anymatch.svg?branch=master)](https://travis-ci.org/micromatch/anymatch) [![Coverage Status](https://img.shields.io/coveralls/micromatch/anymatch.svg?branch=master)](https://coveralls.io/r/micromatch/anymatch?branch=master)
+======
+Javascript module to match a string against a regular expression, glob, string,
+or function that takes the string as an argument and returns a truthy or falsy
+value. The matcher can also be an array of any or all of these. Useful for
+allowing a very flexible user-defined config to define things like file paths.
+
+__Note: This module has Bash-parity, please be aware that Windows-style backslashes are not supported as separators. See https://github.com/micromatch/micromatch#backslashes for more information.__
+
+
+Usage
+-----
+```sh
+npm install anymatch
+```
+
+#### anymatch(matchers, testString, [returnIndex], [options])
+* __matchers__: (_Array|String|RegExp|Function_)
+String to be directly matched, string with glob patterns, regular expression
+test, function that takes the testString as an argument and returns a truthy
+value if it should be matched, or an array of any number and mix of these types.
+* __testString__: (_String|Array_) The string to test against the matchers. If
+passed as an array, the first element of the array will be used as the
+`testString` for non-function matchers, while the entire array will be applied
+as the arguments for function matchers.
+* __options__: (_Object_ [optional]_) Any of the [picomatch](https://github.com/micromatch/picomatch#options) options.
+    * __returnIndex__: (_Boolean [optional]_) If true, return the array index of
+the first matcher that that testString matched, or -1 if no match, instead of a
+boolean result.
+
+```js
+const anymatch = require('anymatch');
+
+const matchers = [ 'path/to/file.js', 'path/anyjs/**/*.js', /foo.js$/, string => string.includes('bar') && string.length > 10 ] ;
+
+anymatch(matchers, 'path/to/file.js'); // true
+anymatch(matchers, 'path/anyjs/baz.js'); // true
+anymatch(matchers, 'path/to/foo.js'); // true
+anymatch(matchers, 'path/to/bar.js'); // true
+anymatch(matchers, 'bar.js'); // false
+
+// returnIndex = true
+anymatch(matchers, 'foo.js', {returnIndex: true}); // 2
+anymatch(matchers, 'path/anyjs/foo.js', {returnIndex: true}); // 1
+
+// any picomatc
+
+// using globs to match directories and their children
+anymatch('node_modules', 'node_modules'); // true
+anymatch('node_modules', 'node_modules/somelib/index.js'); // false
+anymatch('node_modules/**', 'node_modules/somelib/index.js'); // true
+anymatch('node_modules/**', '/absolute/path/to/node_modules/somelib/index.js'); // false
+anymatch('**/node_modules/**', '/absolute/path/to/node_modules/somelib/index.js'); // true
+
+const matcher = anymatch(matchers);
+['foo.js', 'bar.js'].filter(matcher);  // [ 'foo.js' ]
+anymatch master* ❯
+
+```
+
+#### anymatch(matchers)
+You can also pass in only your matcher(s) to get a curried function that has
+already been bound to the provided matching criteria. This can be used as an
+`Array#filter` callback.
+
+```js
+var matcher = anymatch(matchers);
+
+matcher('path/to/file.js'); // true
+matcher('path/anyjs/baz.js', true); // 1
+
+['foo.js', 'bar.js'].filter(matcher); // ['foo.js']
+```
+
+Changelog
+----------
+[See release notes page on GitHub](https://github.com/micromatch/anymatch/releases)
+
+- **v3.0:** Removed `startIndex` and `endIndex` arguments. Node 8.x-only.
+- **v2.0:** [micromatch](https://github.com/jonschlinkert/micromatch) moves away from minimatch-parity and inline with Bash. This includes handling backslashes differently (see https://github.com/micromatch/micromatch#backslashes for more information).
+- **v1.2:** anymatch uses [micromatch](https://github.com/jonschlinkert/micromatch)
+for glob pattern matching. Issues with glob pattern matching should be
+reported directly to the [micromatch issue tracker](https://github.com/jonschlinkert/micromatch/issues).
+
+License
+-------
+[ISC](https://raw.github.com/micromatch/anymatch/master/LICENSE)

+ 20 - 0
node_modules/anymatch/index.d.ts

@@ -0,0 +1,20 @@
+type AnymatchFn = (testString: string) => boolean;
+type AnymatchPattern = string|RegExp|AnymatchFn;
+type AnymatchMatcher = AnymatchPattern|AnymatchPattern[]
+type AnymatchTester = {
+  (testString: string|any[], returnIndex: true): number;
+  (testString: string|any[]): boolean;
+}
+
+type PicomatchOptions = {dot: boolean};
+
+declare const anymatch: {
+  (matchers: AnymatchMatcher): AnymatchTester;
+  (matchers: AnymatchMatcher, testString: null, returnIndex: true | PicomatchOptions): AnymatchTester;
+  (matchers: AnymatchMatcher, testString: string|any[], returnIndex: true | PicomatchOptions): number;
+  (matchers: AnymatchMatcher, testString: string|any[]): boolean;
+}
+
+export {AnymatchMatcher as Matcher}
+export {AnymatchTester as Tester}
+export default anymatch

+ 104 - 0
node_modules/anymatch/index.js

@@ -0,0 +1,104 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", { value: true });
+
+const picomatch = require('picomatch');
+const normalizePath = require('normalize-path');
+
+/**
+ * @typedef {(testString: string) => boolean} AnymatchFn
+ * @typedef {string|RegExp|AnymatchFn} AnymatchPattern
+ * @typedef {AnymatchPattern|AnymatchPattern[]} AnymatchMatcher
+ */
+const BANG = '!';
+const DEFAULT_OPTIONS = {returnIndex: false};
+const arrify = (item) => Array.isArray(item) ? item : [item];
+
+/**
+ * @param {AnymatchPattern} matcher
+ * @param {object} options
+ * @returns {AnymatchFn}
+ */
+const createPattern = (matcher, options) => {
+  if (typeof matcher === 'function') {
+    return matcher;
+  }
+  if (typeof matcher === 'string') {
+    const glob = picomatch(matcher, options);
+    return (string) => matcher === string || glob(string);
+  }
+  if (matcher instanceof RegExp) {
+    return (string) => matcher.test(string);
+  }
+  return (string) => false;
+};
+
+/**
+ * @param {Array<Function>} patterns
+ * @param {Array<Function>} negPatterns
+ * @param {String|Array} args
+ * @param {Boolean} returnIndex
+ * @returns {boolean|number}
+ */
+const matchPatterns = (patterns, negPatterns, args, returnIndex) => {
+  const isList = Array.isArray(args);
+  const _path = isList ? args[0] : args;
+  if (!isList && typeof _path !== 'string') {
+    throw new TypeError('anymatch: second argument must be a string: got ' +
+      Object.prototype.toString.call(_path))
+  }
+  const path = normalizePath(_path, false);
+
+  for (let index = 0; index < negPatterns.length; index++) {
+    const nglob = negPatterns[index];
+    if (nglob(path)) {
+      return returnIndex ? -1 : false;
+    }
+  }
+
+  const applied = isList && [path].concat(args.slice(1));
+  for (let index = 0; index < patterns.length; index++) {
+    const pattern = patterns[index];
+    if (isList ? pattern(...applied) : pattern(path)) {
+      return returnIndex ? index : true;
+    }
+  }
+
+  return returnIndex ? -1 : false;
+};
+
+/**
+ * @param {AnymatchMatcher} matchers
+ * @param {Array|string} testString
+ * @param {object} options
+ * @returns {boolean|number|Function}
+ */
+const anymatch = (matchers, testString, options = DEFAULT_OPTIONS) => {
+  if (matchers == null) {
+    throw new TypeError('anymatch: specify first argument');
+  }
+  const opts = typeof options === 'boolean' ? {returnIndex: options} : options;
+  const returnIndex = opts.returnIndex || false;
+
+  // Early cache for matchers.
+  const mtchers = arrify(matchers);
+  const negatedGlobs = mtchers
+    .filter(item => typeof item === 'string' && item.charAt(0) === BANG)
+    .map(item => item.slice(1))
+    .map(item => picomatch(item, opts));
+  const patterns = mtchers
+    .filter(item => typeof item !== 'string' || (typeof item === 'string' && item.charAt(0) !== BANG))
+    .map(matcher => createPattern(matcher, opts));
+
+  if (testString == null) {
+    return (testString, ri = false) => {
+      const returnIndex = typeof ri === 'boolean' ? ri : false;
+      return matchPatterns(patterns, negatedGlobs, testString, returnIndex);
+    }
+  }
+
+  return matchPatterns(patterns, negatedGlobs, testString, returnIndex);
+};
+
+anymatch.default = anymatch;
+module.exports = anymatch;

+ 48 - 0
node_modules/anymatch/package.json

@@ -0,0 +1,48 @@
+{
+  "name": "anymatch",
+  "version": "3.1.3",
+  "description": "Matches strings against configurable strings, globs, regular expressions, and/or functions",
+  "files": [
+    "index.js",
+    "index.d.ts"
+  ],
+  "dependencies": {
+    "normalize-path": "^3.0.0",
+    "picomatch": "^2.0.4"
+  },
+  "author": {
+    "name": "Elan Shanker",
+    "url": "https://github.com/es128"
+  },
+  "license": "ISC",
+  "homepage": "https://github.com/micromatch/anymatch",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/micromatch/anymatch"
+  },
+  "keywords": [
+    "match",
+    "any",
+    "string",
+    "file",
+    "fs",
+    "list",
+    "glob",
+    "regex",
+    "regexp",
+    "regular",
+    "expression",
+    "function"
+  ],
+  "scripts": {
+    "test": "nyc mocha",
+    "mocha": "mocha"
+  },
+  "devDependencies": {
+    "mocha": "^6.1.3",
+    "nyc": "^14.0.0"
+  },
+  "engines": {
+    "node": ">= 8"
+  }
+}

+ 21 - 0
node_modules/balanced-match/LICENSE.md

@@ -0,0 +1,21 @@
+(MIT)
+
+Copyright (c) 2013 Julian Gruber &lt;[email protected]&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 97 - 0
node_modules/balanced-match/README.md

@@ -0,0 +1,97 @@
+# balanced-match
+
+Match balanced string pairs, like `{` and `}` or `<b>` and `</b>`. Supports regular expressions as well!
+
+[![build status](https://secure.travis-ci.org/juliangruber/balanced-match.svg)](http://travis-ci.org/juliangruber/balanced-match)
+[![downloads](https://img.shields.io/npm/dm/balanced-match.svg)](https://www.npmjs.org/package/balanced-match)
+
+[![testling badge](https://ci.testling.com/juliangruber/balanced-match.png)](https://ci.testling.com/juliangruber/balanced-match)
+
+## Example
+
+Get the first matching pair of braces:
+
+```js
+var balanced = require('balanced-match');
+
+console.log(balanced('{', '}', 'pre{in{nested}}post'));
+console.log(balanced('{', '}', 'pre{first}between{second}post'));
+console.log(balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre  {   in{nest}   }  post'));
+```
+
+The matches are:
+
+```bash
+$ node example.js
+{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' }
+{ start: 3,
+  end: 9,
+  pre: 'pre',
+  body: 'first',
+  post: 'between{second}post' }
+{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' }
+```
+
+## API
+
+### var m = balanced(a, b, str)
+
+For the first non-nested matching pair of `a` and `b` in `str`, return an
+object with those keys:
+
+* **start** the index of the first match of `a`
+* **end** the index of the matching `b`
+* **pre** the preamble, `a` and `b` not included
+* **body** the match, `a` and `b` not included
+* **post** the postscript, `a` and `b` not included
+
+If there's no match, `undefined` will be returned.
+
+If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`.
+
+### var r = balanced.range(a, b, str)
+
+For the first non-nested matching pair of `a` and `b` in `str`, return an
+array with indexes: `[ <a index>, <b index> ]`.
+
+If there's no match, `undefined` will be returned.
+
+If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`.
+
+## Installation
+
+With [npm](https://npmjs.org) do:
+
+```bash
+npm install balanced-match
+```
+
+## Security contact information
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.
+
+## License
+
+(MIT)
+
+Copyright (c) 2013 Julian Gruber &lt;[email protected]&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 62 - 0
node_modules/balanced-match/index.js

@@ -0,0 +1,62 @@
+'use strict';
+module.exports = balanced;
+function balanced(a, b, str) {
+  if (a instanceof RegExp) a = maybeMatch(a, str);
+  if (b instanceof RegExp) b = maybeMatch(b, str);
+
+  var r = range(a, b, str);
+
+  return r && {
+    start: r[0],
+    end: r[1],
+    pre: str.slice(0, r[0]),
+    body: str.slice(r[0] + a.length, r[1]),
+    post: str.slice(r[1] + b.length)
+  };
+}
+
+function maybeMatch(reg, str) {
+  var m = str.match(reg);
+  return m ? m[0] : null;
+}
+
+balanced.range = range;
+function range(a, b, str) {
+  var begs, beg, left, right, result;
+  var ai = str.indexOf(a);
+  var bi = str.indexOf(b, ai + 1);
+  var i = ai;
+
+  if (ai >= 0 && bi > 0) {
+    if(a===b) {
+      return [ai, bi];
+    }
+    begs = [];
+    left = str.length;
+
+    while (i >= 0 && !result) {
+      if (i == ai) {
+        begs.push(i);
+        ai = str.indexOf(a, i + 1);
+      } else if (begs.length == 1) {
+        result = [ begs.pop(), bi ];
+      } else {
+        beg = begs.pop();
+        if (beg < left) {
+          left = beg;
+          right = bi;
+        }
+
+        bi = str.indexOf(b, i + 1);
+      }
+
+      i = ai < bi && ai >= 0 ? ai : bi;
+    }
+
+    if (begs.length) {
+      result = [ left, right ];
+    }
+  }
+
+  return result;
+}

+ 48 - 0
node_modules/balanced-match/package.json

@@ -0,0 +1,48 @@
+{
+  "name": "balanced-match",
+  "description": "Match balanced character pairs, like \"{\" and \"}\"",
+  "version": "1.0.2",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/juliangruber/balanced-match.git"
+  },
+  "homepage": "https://github.com/juliangruber/balanced-match",
+  "main": "index.js",
+  "scripts": {
+    "test": "tape test/test.js",
+    "bench": "matcha test/bench.js"
+  },
+  "devDependencies": {
+    "matcha": "^0.7.0",
+    "tape": "^4.6.0"
+  },
+  "keywords": [
+    "match",
+    "regexp",
+    "test",
+    "balanced",
+    "parse"
+  ],
+  "author": {
+    "name": "Julian Gruber",
+    "email": "[email protected]",
+    "url": "http://juliangruber.com"
+  },
+  "license": "MIT",
+  "testling": {
+    "files": "test/*.js",
+    "browsers": [
+      "ie/8..latest",
+      "firefox/20..latest",
+      "firefox/nightly",
+      "chrome/25..latest",
+      "chrome/canary",
+      "opera/12..latest",
+      "opera/next",
+      "safari/5.1..latest",
+      "ipad/6.0..latest",
+      "iphone/6.0..latest",
+      "android-browser/4.2..latest"
+    ]
+  }
+}

+ 263 - 0
node_modules/binary-extensions/binary-extensions.json

@@ -0,0 +1,263 @@
+[
+	"3dm",
+	"3ds",
+	"3g2",
+	"3gp",
+	"7z",
+	"a",
+	"aac",
+	"adp",
+	"afdesign",
+	"afphoto",
+	"afpub",
+	"ai",
+	"aif",
+	"aiff",
+	"alz",
+	"ape",
+	"apk",
+	"appimage",
+	"ar",
+	"arj",
+	"asf",
+	"au",
+	"avi",
+	"bak",
+	"baml",
+	"bh",
+	"bin",
+	"bk",
+	"bmp",
+	"btif",
+	"bz2",
+	"bzip2",
+	"cab",
+	"caf",
+	"cgm",
+	"class",
+	"cmx",
+	"cpio",
+	"cr2",
+	"cur",
+	"dat",
+	"dcm",
+	"deb",
+	"dex",
+	"djvu",
+	"dll",
+	"dmg",
+	"dng",
+	"doc",
+	"docm",
+	"docx",
+	"dot",
+	"dotm",
+	"dra",
+	"DS_Store",
+	"dsk",
+	"dts",
+	"dtshd",
+	"dvb",
+	"dwg",
+	"dxf",
+	"ecelp4800",
+	"ecelp7470",
+	"ecelp9600",
+	"egg",
+	"eol",
+	"eot",
+	"epub",
+	"exe",
+	"f4v",
+	"fbs",
+	"fh",
+	"fla",
+	"flac",
+	"flatpak",
+	"fli",
+	"flv",
+	"fpx",
+	"fst",
+	"fvt",
+	"g3",
+	"gh",
+	"gif",
+	"graffle",
+	"gz",
+	"gzip",
+	"h261",
+	"h263",
+	"h264",
+	"icns",
+	"ico",
+	"ief",
+	"img",
+	"ipa",
+	"iso",
+	"jar",
+	"jpeg",
+	"jpg",
+	"jpgv",
+	"jpm",
+	"jxr",
+	"key",
+	"ktx",
+	"lha",
+	"lib",
+	"lvp",
+	"lz",
+	"lzh",
+	"lzma",
+	"lzo",
+	"m3u",
+	"m4a",
+	"m4v",
+	"mar",
+	"mdi",
+	"mht",
+	"mid",
+	"midi",
+	"mj2",
+	"mka",
+	"mkv",
+	"mmr",
+	"mng",
+	"mobi",
+	"mov",
+	"movie",
+	"mp3",
+	"mp4",
+	"mp4a",
+	"mpeg",
+	"mpg",
+	"mpga",
+	"mxu",
+	"nef",
+	"npx",
+	"numbers",
+	"nupkg",
+	"o",
+	"odp",
+	"ods",
+	"odt",
+	"oga",
+	"ogg",
+	"ogv",
+	"otf",
+	"ott",
+	"pages",
+	"pbm",
+	"pcx",
+	"pdb",
+	"pdf",
+	"pea",
+	"pgm",
+	"pic",
+	"png",
+	"pnm",
+	"pot",
+	"potm",
+	"potx",
+	"ppa",
+	"ppam",
+	"ppm",
+	"pps",
+	"ppsm",
+	"ppsx",
+	"ppt",
+	"pptm",
+	"pptx",
+	"psd",
+	"pya",
+	"pyc",
+	"pyo",
+	"pyv",
+	"qt",
+	"rar",
+	"ras",
+	"raw",
+	"resources",
+	"rgb",
+	"rip",
+	"rlc",
+	"rmf",
+	"rmvb",
+	"rpm",
+	"rtf",
+	"rz",
+	"s3m",
+	"s7z",
+	"scpt",
+	"sgi",
+	"shar",
+	"snap",
+	"sil",
+	"sketch",
+	"slk",
+	"smv",
+	"snk",
+	"so",
+	"stl",
+	"suo",
+	"sub",
+	"swf",
+	"tar",
+	"tbz",
+	"tbz2",
+	"tga",
+	"tgz",
+	"thmx",
+	"tif",
+	"tiff",
+	"tlz",
+	"ttc",
+	"ttf",
+	"txz",
+	"udf",
+	"uvh",
+	"uvi",
+	"uvm",
+	"uvp",
+	"uvs",
+	"uvu",
+	"viv",
+	"vob",
+	"war",
+	"wav",
+	"wax",
+	"wbmp",
+	"wdp",
+	"weba",
+	"webm",
+	"webp",
+	"whl",
+	"wim",
+	"wm",
+	"wma",
+	"wmv",
+	"wmx",
+	"woff",
+	"woff2",
+	"wrm",
+	"wvx",
+	"xbm",
+	"xif",
+	"xla",
+	"xlam",
+	"xls",
+	"xlsb",
+	"xlsm",
+	"xlsx",
+	"xlt",
+	"xltm",
+	"xltx",
+	"xm",
+	"xmind",
+	"xpi",
+	"xpm",
+	"xwd",
+	"xz",
+	"z",
+	"zip",
+	"zipx"
+]

+ 3 - 0
node_modules/binary-extensions/binary-extensions.json.d.ts

@@ -0,0 +1,3 @@
+declare const binaryExtensionsJson: readonly string[];
+
+export = binaryExtensionsJson;

+ 14 - 0
node_modules/binary-extensions/index.d.ts

@@ -0,0 +1,14 @@
+/**
+List of binary file extensions.
+
+@example
+```
+import binaryExtensions = require('binary-extensions');
+
+console.log(binaryExtensions);
+//=> ['3ds', '3g2', …]
+```
+*/
+declare const binaryExtensions: readonly string[];
+
+export = binaryExtensions;

+ 1 - 0
node_modules/binary-extensions/index.js

@@ -0,0 +1 @@
+module.exports = require('./binary-extensions.json');

+ 10 - 0
node_modules/binary-extensions/license

@@ -0,0 +1,10 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <[email protected]> (https://sindresorhus.com)
+Copyright (c) Paul Miller (https://paulmillr.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 40 - 0
node_modules/binary-extensions/package.json

@@ -0,0 +1,40 @@
+{
+	"name": "binary-extensions",
+	"version": "2.3.0",
+	"description": "List of binary file extensions",
+	"license": "MIT",
+	"repository": "sindresorhus/binary-extensions",
+	"funding": "https://github.com/sponsors/sindresorhus",
+	"author": {
+		"name": "Sindre Sorhus",
+		"email": "[email protected]",
+		"url": "https://sindresorhus.com"
+	},
+	"sideEffects": false,
+	"engines": {
+		"node": ">=8"
+	},
+	"scripts": {
+		"test": "xo && ava && tsd"
+	},
+	"files": [
+		"index.js",
+		"index.d.ts",
+		"binary-extensions.json",
+		"binary-extensions.json.d.ts"
+	],
+	"keywords": [
+		"binary",
+		"extensions",
+		"extension",
+		"file",
+		"json",
+		"list",
+		"array"
+	],
+	"devDependencies": {
+		"ava": "^1.4.1",
+		"tsd": "^0.7.2",
+		"xo": "^0.24.0"
+	}
+}

+ 25 - 0
node_modules/binary-extensions/readme.md

@@ -0,0 +1,25 @@
+# binary-extensions
+
+> List of binary file extensions
+
+The list is just a [JSON file](binary-extensions.json) and can be used anywhere.
+
+## Install
+
+```sh
+npm install binary-extensions
+```
+
+## Usage
+
+```js
+const binaryExtensions = require('binary-extensions');
+
+console.log(binaryExtensions);
+//=> ['3ds', '3g2', …]
+```
+
+## Related
+
+- [is-binary-path](https://github.com/sindresorhus/is-binary-path) - Check if a filepath is a binary file
+- [text-extensions](https://github.com/sindresorhus/text-extensions) - List of text file extensions

+ 21 - 0
node_modules/brace-expansion/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2013 Julian Gruber <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 129 - 0
node_modules/brace-expansion/README.md

@@ -0,0 +1,129 @@
+# brace-expansion
+
+[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html), 
+as known from sh/bash, in JavaScript.
+
+[![build status](https://secure.travis-ci.org/juliangruber/brace-expansion.svg)](http://travis-ci.org/juliangruber/brace-expansion)
+[![downloads](https://img.shields.io/npm/dm/brace-expansion.svg)](https://www.npmjs.org/package/brace-expansion)
+[![Greenkeeper badge](https://badges.greenkeeper.io/juliangruber/brace-expansion.svg)](https://greenkeeper.io/)
+
+[![testling badge](https://ci.testling.com/juliangruber/brace-expansion.png)](https://ci.testling.com/juliangruber/brace-expansion)
+
+## Example
+
+```js
+var expand = require('brace-expansion');
+
+expand('file-{a,b,c}.jpg')
+// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
+
+expand('-v{,,}')
+// => ['-v', '-v', '-v']
+
+expand('file{0..2}.jpg')
+// => ['file0.jpg', 'file1.jpg', 'file2.jpg']
+
+expand('file-{a..c}.jpg')
+// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
+
+expand('file{2..0}.jpg')
+// => ['file2.jpg', 'file1.jpg', 'file0.jpg']
+
+expand('file{0..4..2}.jpg')
+// => ['file0.jpg', 'file2.jpg', 'file4.jpg']
+
+expand('file-{a..e..2}.jpg')
+// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg']
+
+expand('file{00..10..5}.jpg')
+// => ['file00.jpg', 'file05.jpg', 'file10.jpg']
+
+expand('{{A..C},{a..c}}')
+// => ['A', 'B', 'C', 'a', 'b', 'c']
+
+expand('ppp{,config,oe{,conf}}')
+// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']
+```
+
+## API
+
+```js
+var expand = require('brace-expansion');
+```
+
+### var expanded = expand(str)
+
+Return an array of all possible and valid expansions of `str`. If none are
+found, `[str]` is returned.
+
+Valid expansions are:
+
+```js
+/^(.*,)+(.+)?$/
+// {a,b,...}
+```
+
+A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`.
+
+```js
+/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
+// {x..y[..incr]}
+```
+
+A numeric sequence from `x` to `y` inclusive, with optional increment.
+If `x` or `y` start with a leading `0`, all the numbers will be padded
+to have equal length. Negative numbers and backwards iteration work too.
+
+```js
+/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
+// {x..y[..incr]}
+```
+
+An alphabetic sequence from `x` to `y` inclusive, with optional increment.
+`x` and `y` must be exactly one character, and if given, `incr` must be a
+number.
+
+For compatibility reasons, the string `${` is not eligible for brace expansion.
+
+## Installation
+
+With [npm](https://npmjs.org) do:
+
+```bash
+npm install brace-expansion
+```
+
+## Contributors
+
+- [Julian Gruber](https://github.com/juliangruber)
+- [Isaac Z. Schlueter](https://github.com/isaacs)
+
+## Sponsors
+
+This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!
+
+Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!
+
+## License
+
+(MIT)
+
+Copyright (c) 2013 Julian Gruber &lt;[email protected]&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 201 - 0
node_modules/brace-expansion/index.js

@@ -0,0 +1,201 @@
+var concatMap = require('concat-map');
+var balanced = require('balanced-match');
+
+module.exports = expandTop;
+
+var escSlash = '\0SLASH'+Math.random()+'\0';
+var escOpen = '\0OPEN'+Math.random()+'\0';
+var escClose = '\0CLOSE'+Math.random()+'\0';
+var escComma = '\0COMMA'+Math.random()+'\0';
+var escPeriod = '\0PERIOD'+Math.random()+'\0';
+
+function numeric(str) {
+  return parseInt(str, 10) == str
+    ? parseInt(str, 10)
+    : str.charCodeAt(0);
+}
+
+function escapeBraces(str) {
+  return str.split('\\\\').join(escSlash)
+            .split('\\{').join(escOpen)
+            .split('\\}').join(escClose)
+            .split('\\,').join(escComma)
+            .split('\\.').join(escPeriod);
+}
+
+function unescapeBraces(str) {
+  return str.split(escSlash).join('\\')
+            .split(escOpen).join('{')
+            .split(escClose).join('}')
+            .split(escComma).join(',')
+            .split(escPeriod).join('.');
+}
+
+
+// Basically just str.split(","), but handling cases
+// where we have nested braced sections, which should be
+// treated as individual members, like {a,{b,c},d}
+function parseCommaParts(str) {
+  if (!str)
+    return [''];
+
+  var parts = [];
+  var m = balanced('{', '}', str);
+
+  if (!m)
+    return str.split(',');
+
+  var pre = m.pre;
+  var body = m.body;
+  var post = m.post;
+  var p = pre.split(',');
+
+  p[p.length-1] += '{' + body + '}';
+  var postParts = parseCommaParts(post);
+  if (post.length) {
+    p[p.length-1] += postParts.shift();
+    p.push.apply(p, postParts);
+  }
+
+  parts.push.apply(parts, p);
+
+  return parts;
+}
+
+function expandTop(str) {
+  if (!str)
+    return [];
+
+  // I don't know why Bash 4.3 does this, but it does.
+  // Anything starting with {} will have the first two bytes preserved
+  // but *only* at the top level, so {},a}b will not expand to anything,
+  // but a{},b}c will be expanded to [a}c,abc].
+  // One could argue that this is a bug in Bash, but since the goal of
+  // this module is to match Bash's rules, we escape a leading {}
+  if (str.substr(0, 2) === '{}') {
+    str = '\\{\\}' + str.substr(2);
+  }
+
+  return expand(escapeBraces(str), true).map(unescapeBraces);
+}
+
+function identity(e) {
+  return e;
+}
+
+function embrace(str) {
+  return '{' + str + '}';
+}
+function isPadded(el) {
+  return /^-?0\d/.test(el);
+}
+
+function lte(i, y) {
+  return i <= y;
+}
+function gte(i, y) {
+  return i >= y;
+}
+
+function expand(str, isTop) {
+  var expansions = [];
+
+  var m = balanced('{', '}', str);
+  if (!m || /\$$/.test(m.pre)) return [str];
+
+  var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
+  var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
+  var isSequence = isNumericSequence || isAlphaSequence;
+  var isOptions = m.body.indexOf(',') >= 0;
+  if (!isSequence && !isOptions) {
+    // {a},b}
+    if (m.post.match(/,.*\}/)) {
+      str = m.pre + '{' + m.body + escClose + m.post;
+      return expand(str);
+    }
+    return [str];
+  }
+
+  var n;
+  if (isSequence) {
+    n = m.body.split(/\.\./);
+  } else {
+    n = parseCommaParts(m.body);
+    if (n.length === 1) {
+      // x{{a,b}}y ==> x{a}y x{b}y
+      n = expand(n[0], false).map(embrace);
+      if (n.length === 1) {
+        var post = m.post.length
+          ? expand(m.post, false)
+          : [''];
+        return post.map(function(p) {
+          return m.pre + n[0] + p;
+        });
+      }
+    }
+  }
+
+  // at this point, n is the parts, and we know it's not a comma set
+  // with a single entry.
+
+  // no need to expand pre, since it is guaranteed to be free of brace-sets
+  var pre = m.pre;
+  var post = m.post.length
+    ? expand(m.post, false)
+    : [''];
+
+  var N;
+
+  if (isSequence) {
+    var x = numeric(n[0]);
+    var y = numeric(n[1]);
+    var width = Math.max(n[0].length, n[1].length)
+    var incr = n.length == 3
+      ? Math.abs(numeric(n[2]))
+      : 1;
+    var test = lte;
+    var reverse = y < x;
+    if (reverse) {
+      incr *= -1;
+      test = gte;
+    }
+    var pad = n.some(isPadded);
+
+    N = [];
+
+    for (var i = x; test(i, y); i += incr) {
+      var c;
+      if (isAlphaSequence) {
+        c = String.fromCharCode(i);
+        if (c === '\\')
+          c = '';
+      } else {
+        c = String(i);
+        if (pad) {
+          var need = width - c.length;
+          if (need > 0) {
+            var z = new Array(need + 1).join('0');
+            if (i < 0)
+              c = '-' + z + c.slice(1);
+            else
+              c = z + c;
+          }
+        }
+      }
+      N.push(c);
+    }
+  } else {
+    N = concatMap(n, function(el) { return expand(el, false) });
+  }
+
+  for (var j = 0; j < N.length; j++) {
+    for (var k = 0; k < post.length; k++) {
+      var expansion = pre + N[j] + post[k];
+      if (!isTop || isSequence || expansion)
+        expansions.push(expansion);
+    }
+  }
+
+  return expansions;
+}
+

+ 47 - 0
node_modules/brace-expansion/package.json

@@ -0,0 +1,47 @@
+{
+  "name": "brace-expansion",
+  "description": "Brace expansion as known from sh/bash",
+  "version": "1.1.11",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/juliangruber/brace-expansion.git"
+  },
+  "homepage": "https://github.com/juliangruber/brace-expansion",
+  "main": "index.js",
+  "scripts": {
+    "test": "tape test/*.js",
+    "gentest": "bash test/generate.sh",
+    "bench": "matcha test/perf/bench.js"
+  },
+  "dependencies": {
+    "balanced-match": "^1.0.0",
+    "concat-map": "0.0.1"
+  },
+  "devDependencies": {
+    "matcha": "^0.7.0",
+    "tape": "^4.6.0"
+  },
+  "keywords": [],
+  "author": {
+    "name": "Julian Gruber",
+    "email": "[email protected]",
+    "url": "http://juliangruber.com"
+  },
+  "license": "MIT",
+  "testling": {
+    "files": "test/*.js",
+    "browsers": [
+      "ie/8..latest",
+      "firefox/20..latest",
+      "firefox/nightly",
+      "chrome/25..latest",
+      "chrome/canary",
+      "opera/12..latest",
+      "opera/next",
+      "safari/5.1..latest",
+      "ipad/6.0..latest",
+      "iphone/6.0..latest",
+      "android-browser/4.2..latest"
+    ]
+  }
+}

+ 184 - 0
node_modules/braces/CHANGELOG.md

@@ -0,0 +1,184 @@
+# Release history
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+<details>
+  <summary><strong>Guiding Principles</strong></summary>
+
+- Changelogs are for humans, not machines.
+- There should be an entry for every single version.
+- The same types of changes should be grouped.
+- Versions and sections should be linkable.
+- The latest version comes first.
+- The release date of each versions is displayed.
+- Mention whether you follow Semantic Versioning.
+
+</details>
+
+<details>
+  <summary><strong>Types of changes</strong></summary>
+
+Changelog entries are classified using the following labels _(from [keep-a-changelog](http://keepachangelog.com/)_):
+
+- `Added` for new features.
+- `Changed` for changes in existing functionality.
+- `Deprecated` for soon-to-be removed features.
+- `Removed` for now removed features.
+- `Fixed` for any bug fixes.
+- `Security` in case of vulnerabilities.
+
+</details>
+
+## [3.0.0] - 2018-04-08
+
+v3.0 is a complete refactor, resulting in a faster, smaller codebase, with fewer deps, and a more accurate parser and compiler. 
+
+**Breaking Changes**
+
+- The undocumented `.makeRe` method was removed
+
+**Non-breaking changes**
+
+- Caching was removed
+
+## [2.3.2] - 2018-04-08
+
+- start refactoring
+- cover sets
+- better range handling
+
+## [2.3.1] - 2018-02-17
+
+- Remove unnecessary escape in Regex. (#14)
+
+## [2.3.0] - 2017-10-19
+
+- minor code reorganization
+- optimize regex
+- expose `maxLength` option
+
+## [2.2.1] - 2017-05-30
+
+- don't condense when braces contain extglobs
+
+## [2.2.0] - 2017-05-28
+
+- ensure word boundaries are preserved
+- fixes edge case where extglob characters precede a brace pattern
+
+## [2.1.1] - 2017-04-27
+
+- use snapdragon-node
+- handle edge case
+- optimizations, lint
+
+## [2.0.4] - 2017-04-11
+
+- pass opts to compiler
+- minor optimization in create method
+- re-write parser handlers to remove negation regex
+
+## [2.0.3] - 2016-12-10
+
+- use split-string
+- clear queue at the end
+- adds sequences example
+- add unit tests
+
+## [2.0.2] - 2016-10-21
+
+- fix comma handling in nested extglobs
+
+## [2.0.1] - 2016-10-20
+
+- add comments
+- more tests, ensure quotes are stripped
+
+## [2.0.0] - 2016-10-19
+
+- don't expand braces inside character classes
+- add quantifier pattern
+
+## [1.8.5] - 2016-05-21
+
+- Refactor (#10)
+
+## [1.8.4] - 2016-04-20
+
+- fixes https://github.com/jonschlinkert/micromatch/issues/66
+
+## [1.8.0] - 2015-03-18
+
+- adds exponent examples, tests
+- fixes the first example in https://github.com/jonschlinkert/micromatch/issues/38
+
+## [1.6.0] - 2015-01-30
+
+- optimizations, `bash` mode:
+- improve path escaping
+
+## [1.5.0] - 2015-01-28
+
+- Merge pull request #5 from eush77/lib-files
+
+## [1.4.0] - 2015-01-24
+
+- add extglob tests
+- externalize exponent function
+- better whitespace handling
+
+## [1.3.0] - 2015-01-24
+
+- make regex patterns explicity
+
+## [1.1.0] - 2015-01-11
+
+- don't create a match group with `makeRe`
+
+## [1.0.0] - 2014-12-23
+
+- Merge commit '97b05f5544f8348736a8efaecf5c32bbe3e2ad6e'
+- support empty brace syntax
+- better bash coverage
+- better support for regex strings
+
+## [0.1.4] - 2014-11-14
+
+- improve recognition of bad args, recognize mismatched argument types
+- support escaping
+- remove pathname-expansion
+- support whitespace in patterns
+
+## [0.1.0]
+
+- first commit
+
+[2.3.2]: https://github.com/micromatch/braces/compare/2.3.1...2.3.2
+[2.3.1]: https://github.com/micromatch/braces/compare/2.3.0...2.3.1
+[2.3.0]: https://github.com/micromatch/braces/compare/2.2.1...2.3.0
+[2.2.1]: https://github.com/micromatch/braces/compare/2.2.0...2.2.1
+[2.2.0]: https://github.com/micromatch/braces/compare/2.1.1...2.2.0
+[2.1.1]: https://github.com/micromatch/braces/compare/2.1.0...2.1.1
+[2.1.0]: https://github.com/micromatch/braces/compare/2.0.4...2.1.0
+[2.0.4]: https://github.com/micromatch/braces/compare/2.0.3...2.0.4
+[2.0.3]: https://github.com/micromatch/braces/compare/2.0.2...2.0.3
+[2.0.2]: https://github.com/micromatch/braces/compare/2.0.1...2.0.2
+[2.0.1]: https://github.com/micromatch/braces/compare/2.0.0...2.0.1
+[2.0.0]: https://github.com/micromatch/braces/compare/1.8.5...2.0.0
+[1.8.5]: https://github.com/micromatch/braces/compare/1.8.4...1.8.5
+[1.8.4]: https://github.com/micromatch/braces/compare/1.8.0...1.8.4
+[1.8.0]: https://github.com/micromatch/braces/compare/1.6.0...1.8.0
+[1.6.0]: https://github.com/micromatch/braces/compare/1.5.0...1.6.0
+[1.5.0]: https://github.com/micromatch/braces/compare/1.4.0...1.5.0
+[1.4.0]: https://github.com/micromatch/braces/compare/1.3.0...1.4.0
+[1.3.0]: https://github.com/micromatch/braces/compare/1.2.0...1.3.0
+[1.2.0]: https://github.com/micromatch/braces/compare/1.1.0...1.2.0
+[1.1.0]: https://github.com/micromatch/braces/compare/1.0.0...1.1.0
+[1.0.0]: https://github.com/micromatch/braces/compare/0.1.4...1.0.0
+[0.1.4]: https://github.com/micromatch/braces/compare/0.1.0...0.1.4
+
+[Unreleased]: https://github.com/micromatch/braces/compare/0.1.0...HEAD
+[keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog

+ 21 - 0
node_modules/braces/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2018, Jon Schlinkert.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 593 - 0
node_modules/braces/README.md

@@ -0,0 +1,593 @@
+# braces [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W8YFZ425KND68) [![NPM version](https://img.shields.io/npm/v/braces.svg?style=flat)](https://www.npmjs.com/package/braces) [![NPM monthly downloads](https://img.shields.io/npm/dm/braces.svg?style=flat)](https://npmjs.org/package/braces) [![NPM total downloads](https://img.shields.io/npm/dt/braces.svg?style=flat)](https://npmjs.org/package/braces) [![Linux Build Status](https://img.shields.io/travis/micromatch/braces.svg?style=flat&label=Travis)](https://travis-ci.org/micromatch/braces)
+
+> Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support for the Bash 4.3 braces specification, without sacrificing speed.
+
+Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
+
+## Install
+
+Install with [npm](https://www.npmjs.com/):
+
+```sh
+$ npm install --save braces
+```
+
+## v3.0.0 Released!!
+
+See the [changelog](CHANGELOG.md) for details.
+
+## Why use braces?
+
+Brace patterns make globs more powerful by adding the ability to match specific ranges and sequences of characters.
+
+* **Accurate** - complete support for the [Bash 4.3 Brace Expansion](www.gnu.org/software/bash/) specification (passes all of the Bash braces tests)
+* **[fast and performant](#benchmarks)** - Starts fast, runs fast and [scales well](#performance) as patterns increase in complexity.
+* **Organized code base** - The parser and compiler are easy to maintain and update when edge cases crop up.
+* **Well-tested** - Thousands of test assertions, and passes all of the Bash, minimatch, and [brace-expansion](https://github.com/juliangruber/brace-expansion) unit tests (as of the date this was written).
+* **Safer** - You shouldn't have to worry about users defining aggressive or malicious brace patterns that can break your application. Braces takes measures to prevent malicious regex that can be used for DDoS attacks (see [catastrophic backtracking](https://www.regular-expressions.info/catastrophic.html)).
+* [Supports lists](#lists) - (aka "sets") `a/{b,c}/d` => `['a/b/d', 'a/c/d']`
+* [Supports sequences](#sequences) - (aka "ranges") `{01..03}` => `['01', '02', '03']`
+* [Supports steps](#steps) - (aka "increments") `{2..10..2}` => `['2', '4', '6', '8', '10']`
+* [Supports escaping](#escaping) - To prevent evaluation of special characters.
+
+## Usage
+
+The main export is a function that takes one or more brace `patterns` and `options`.
+
+```js
+const braces = require('braces');
+// braces(patterns[, options]);
+
+console.log(braces(['{01..05}', '{a..e}']));
+//=> ['(0[1-5])', '([a-e])']
+
+console.log(braces(['{01..05}', '{a..e}'], { expand: true }));
+//=> ['01', '02', '03', '04', '05', 'a', 'b', 'c', 'd', 'e']
+```
+
+### Brace Expansion vs. Compilation
+
+By default, brace patterns are compiled into strings that are optimized for creating regular expressions and matching.
+
+**Compiled**
+
+```js
+console.log(braces('a/{x,y,z}/b')); 
+//=> ['a/(x|y|z)/b']
+console.log(braces(['a/{01..20}/b', 'a/{1..5}/b'])); 
+//=> [ 'a/(0[1-9]|1[0-9]|20)/b', 'a/([1-5])/b' ]
+```
+
+**Expanded**
+
+Enable brace expansion by setting the `expand` option to true, or by using [braces.expand()](#expand) (returns an array similar to what you'd expect from Bash, or `echo {1..5}`, or [minimatch](https://github.com/isaacs/minimatch)):
+
+```js
+console.log(braces('a/{x,y,z}/b', { expand: true }));
+//=> ['a/x/b', 'a/y/b', 'a/z/b']
+
+console.log(braces.expand('{01..10}'));
+//=> ['01','02','03','04','05','06','07','08','09','10']
+```
+
+### Lists
+
+Expand lists (like Bash "sets"):
+
+```js
+console.log(braces('a/{foo,bar,baz}/*.js'));
+//=> ['a/(foo|bar|baz)/*.js']
+
+console.log(braces.expand('a/{foo,bar,baz}/*.js'));
+//=> ['a/foo/*.js', 'a/bar/*.js', 'a/baz/*.js']
+```
+
+### Sequences
+
+Expand ranges of characters (like Bash "sequences"):
+
+```js
+console.log(braces.expand('{1..3}'));                // ['1', '2', '3']
+console.log(braces.expand('a/{1..3}/b'));            // ['a/1/b', 'a/2/b', 'a/3/b']
+console.log(braces('{a..c}', { expand: true }));     // ['a', 'b', 'c']
+console.log(braces('foo/{a..c}', { expand: true })); // ['foo/a', 'foo/b', 'foo/c']
+
+// supports zero-padded ranges
+console.log(braces('a/{01..03}/b'));   //=> ['a/(0[1-3])/b']
+console.log(braces('a/{001..300}/b')); //=> ['a/(0{2}[1-9]|0[1-9][0-9]|[12][0-9]{2}|300)/b']
+```
+
+See [fill-range](https://github.com/jonschlinkert/fill-range) for all available range-expansion options.
+
+### Steppped ranges
+
+Steps, or increments, may be used with ranges:
+
+```js
+console.log(braces.expand('{2..10..2}'));
+//=> ['2', '4', '6', '8', '10']
+
+console.log(braces('{2..10..2}'));
+//=> ['(2|4|6|8|10)']
+```
+
+When the [.optimize](#optimize) method is used, or [options.optimize](#optionsoptimize) is set to true, sequences are passed to [to-regex-range](https://github.com/jonschlinkert/to-regex-range) for expansion.
+
+### Nesting
+
+Brace patterns may be nested. The results of each expanded string are not sorted, and left to right order is preserved.
+
+**"Expanded" braces**
+
+```js
+console.log(braces.expand('a{b,c,/{x,y}}/e'));
+//=> ['ab/e', 'ac/e', 'a/x/e', 'a/y/e']
+
+console.log(braces.expand('a/{x,{1..5},y}/c'));
+//=> ['a/x/c', 'a/1/c', 'a/2/c', 'a/3/c', 'a/4/c', 'a/5/c', 'a/y/c']
+```
+
+**"Optimized" braces**
+
+```js
+console.log(braces('a{b,c,/{x,y}}/e'));
+//=> ['a(b|c|/(x|y))/e']
+
+console.log(braces('a/{x,{1..5},y}/c'));
+//=> ['a/(x|([1-5])|y)/c']
+```
+
+### Escaping
+
+**Escaping braces**
+
+A brace pattern will not be expanded or evaluted if _either the opening or closing brace is escaped_:
+
+```js
+console.log(braces.expand('a\\{d,c,b}e'));
+//=> ['a{d,c,b}e']
+
+console.log(braces.expand('a{d,c,b\\}e'));
+//=> ['a{d,c,b}e']
+```
+
+**Escaping commas**
+
+Commas inside braces may also be escaped:
+
+```js
+console.log(braces.expand('a{b\\,c}d'));
+//=> ['a{b,c}d']
+
+console.log(braces.expand('a{d\\,c,b}e'));
+//=> ['ad,ce', 'abe']
+```
+
+**Single items**
+
+Following bash conventions, a brace pattern is also not expanded when it contains a single character:
+
+```js
+console.log(braces.expand('a{b}c'));
+//=> ['a{b}c']
+```
+
+## Options
+
+### options.maxLength
+
+**Type**: `Number`
+
+**Default**: `65,536`
+
+**Description**: Limit the length of the input string. Useful when the input string is generated or your application allows users to pass a string, et cetera.
+
+```js
+console.log(braces('a/{b,c}/d', { maxLength: 3 }));  //=> throws an error
+```
+
+### options.expand
+
+**Type**: `Boolean`
+
+**Default**: `undefined`
+
+**Description**: Generate an "expanded" brace pattern (alternatively you can use the `braces.expand()` method, which does the same thing).
+
+```js
+console.log(braces('a/{b,c}/d', { expand: true }));
+//=> [ 'a/b/d', 'a/c/d' ]
+```
+
+### options.nodupes
+
+**Type**: `Boolean`
+
+**Default**: `undefined`
+
+**Description**: Remove duplicates from the returned array.
+
+### options.rangeLimit
+
+**Type**: `Number`
+
+**Default**: `1000`
+
+**Description**: To prevent malicious patterns from being passed by users, an error is thrown when `braces.expand()` is used or `options.expand` is true and the generated range will exceed the `rangeLimit`.
+
+You can customize `options.rangeLimit` or set it to `Inifinity` to disable this altogether.
+
+**Examples**
+
+```js
+// pattern exceeds the "rangeLimit", so it's optimized automatically
+console.log(braces.expand('{1..1000}'));
+//=> ['([1-9]|[1-9][0-9]{1,2}|1000)']
+
+// pattern does not exceed "rangeLimit", so it's NOT optimized
+console.log(braces.expand('{1..100}'));
+//=> ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '100']
+```
+
+### options.transform
+
+**Type**: `Function`
+
+**Default**: `undefined`
+
+**Description**: Customize range expansion.
+
+**Example: Transforming non-numeric values**
+
+```js
+const alpha = braces.expand('x/{a..e}/y', {
+  transform(value, index) {
+    // When non-numeric values are passed, "value" is a character code.
+    return 'foo/' + String.fromCharCode(value) + '-' + index;
+  }
+});
+console.log(alpha);
+//=> [ 'x/foo/a-0/y', 'x/foo/b-1/y', 'x/foo/c-2/y', 'x/foo/d-3/y', 'x/foo/e-4/y' ]
+```
+
+**Example: Transforming numeric values**
+
+```js
+const numeric = braces.expand('{1..5}', {
+  transform(value) {
+    // when numeric values are passed, "value" is a number
+    return 'foo/' + value * 2;
+  }
+});
+console.log(numeric); 
+//=> [ 'foo/2', 'foo/4', 'foo/6', 'foo/8', 'foo/10' ]
+```
+
+### options.quantifiers
+
+**Type**: `Boolean`
+
+**Default**: `undefined`
+
+**Description**: In regular expressions, quanitifiers can be used to specify how many times a token can be repeated. For example, `a{1,3}` will match the letter `a` one to three times.
+
+Unfortunately, regex quantifiers happen to share the same syntax as [Bash lists](#lists)
+
+The `quantifiers` option tells braces to detect when [regex quantifiers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#quantifiers) are defined in the given pattern, and not to try to expand them as lists.
+
+**Examples**
+
+```js
+const braces = require('braces');
+console.log(braces('a/b{1,3}/{x,y,z}'));
+//=> [ 'a/b(1|3)/(x|y|z)' ]
+console.log(braces('a/b{1,3}/{x,y,z}', {quantifiers: true}));
+//=> [ 'a/b{1,3}/(x|y|z)' ]
+console.log(braces('a/b{1,3}/{x,y,z}', {quantifiers: true, expand: true}));
+//=> [ 'a/b{1,3}/x', 'a/b{1,3}/y', 'a/b{1,3}/z' ]
+```
+
+### options.unescape
+
+**Type**: `Boolean`
+
+**Default**: `undefined`
+
+**Description**: Strip backslashes that were used for escaping from the result.
+
+## What is "brace expansion"?
+
+Brace expansion is a type of parameter expansion that was made popular by unix shells for generating lists of strings, as well as regex-like matching when used alongside wildcards (globs).
+
+In addition to "expansion", braces are also used for matching. In other words:
+
+* [brace expansion](#brace-expansion) is for generating new lists
+* [brace matching](#brace-matching) is for filtering existing lists
+
+<details>
+<summary><strong>More about brace expansion</strong> (click to expand)</summary>
+
+There are two main types of brace expansion:
+
+1. **lists**: which are defined using comma-separated values inside curly braces: `{a,b,c}`
+2. **sequences**: which are defined using a starting value and an ending value, separated by two dots: `a{1..3}b`. Optionally, a third argument may be passed to define a "step" or increment to use: `a{1..100..10}b`. These are also sometimes referred to as "ranges".
+
+Here are some example brace patterns to illustrate how they work:
+
+**Sets**
+
+```
+{a,b,c}       => a b c
+{a,b,c}{1,2}  => a1 a2 b1 b2 c1 c2
+```
+
+**Sequences**
+
+```
+{1..9}        => 1 2 3 4 5 6 7 8 9
+{4..-4}       => 4 3 2 1 0 -1 -2 -3 -4
+{1..20..3}    => 1 4 7 10 13 16 19
+{a..j}        => a b c d e f g h i j
+{j..a}        => j i h g f e d c b a
+{a..z..3}     => a d g j m p s v y
+```
+
+**Combination**
+
+Sets and sequences can be mixed together or used along with any other strings.
+
+```
+{a,b,c}{1..3}   => a1 a2 a3 b1 b2 b3 c1 c2 c3
+foo/{a,b,c}/bar => foo/a/bar foo/b/bar foo/c/bar
+```
+
+The fact that braces can be "expanded" from relatively simple patterns makes them ideal for quickly generating test fixtures, file paths, and similar use cases.
+
+## Brace matching
+
+In addition to _expansion_, brace patterns are also useful for performing regular-expression-like matching.
+
+For example, the pattern `foo/{1..3}/bar` would match any of following strings:
+
+```
+foo/1/bar
+foo/2/bar
+foo/3/bar
+```
+
+But not:
+
+```
+baz/1/qux
+baz/2/qux
+baz/3/qux
+```
+
+Braces can also be combined with [glob patterns](https://github.com/jonschlinkert/micromatch) to perform more advanced wildcard matching. For example, the pattern `*/{1..3}/*` would match any of following strings:
+
+```
+foo/1/bar
+foo/2/bar
+foo/3/bar
+baz/1/qux
+baz/2/qux
+baz/3/qux
+```
+
+## Brace matching pitfalls
+
+Although brace patterns offer a user-friendly way of matching ranges or sets of strings, there are also some major disadvantages and potential risks you should be aware of.
+
+### tldr
+
+**"brace bombs"**
+
+* brace expansion can eat up a huge amount of processing resources
+* as brace patterns increase _linearly in size_, the system resources required to expand the pattern increase exponentially
+* users can accidentally (or intentially) exhaust your system's resources resulting in the equivalent of a DoS attack (bonus: no programming knowledge is required!)
+
+For a more detailed explanation with examples, see the [geometric complexity](#geometric-complexity) section.
+
+### The solution
+
+Jump to the [performance section](#performance) to see how Braces solves this problem in comparison to other libraries.
+
+### Geometric complexity
+
+At minimum, brace patterns with sets limited to two elements have quadradic or `O(n^2)` complexity. But the complexity of the algorithm increases exponentially as the number of sets, _and elements per set_, increases, which is `O(n^c)`.
+
+For example, the following sets demonstrate quadratic (`O(n^2)`) complexity:
+
+```
+{1,2}{3,4}      => (2X2)    => 13 14 23 24
+{1,2}{3,4}{5,6} => (2X2X2)  => 135 136 145 146 235 236 245 246
+```
+
+But add an element to a set, and we get a n-fold Cartesian product with `O(n^c)` complexity:
+
+```
+{1,2,3}{4,5,6}{7,8,9} => (3X3X3) => 147 148 149 157 158 159 167 168 169 247 248 
+                                    249 257 258 259 267 268 269 347 348 349 357 
+                                    358 359 367 368 369
+```
+
+Now, imagine how this complexity grows given that each element is a n-tuple:
+
+```
+{1..100}{1..100}         => (100X100)     => 10,000 elements (38.4 kB)
+{1..100}{1..100}{1..100} => (100X100X100) => 1,000,000 elements (5.76 MB)
+```
+
+Although these examples are clearly contrived, they demonstrate how brace patterns can quickly grow out of control.
+
+**More information**
+
+Interested in learning more about brace expansion?
+
+* [linuxjournal/bash-brace-expansion](http://www.linuxjournal.com/content/bash-brace-expansion)
+* [rosettacode/Brace_expansion](https://rosettacode.org/wiki/Brace_expansion)
+* [cartesian product](https://en.wikipedia.org/wiki/Cartesian_product)
+
+</details>
+
+## Performance
+
+Braces is not only screaming fast, it's also more accurate the other brace expansion libraries.
+
+### Better algorithms
+
+Fortunately there is a solution to the ["brace bomb" problem](#brace-matching-pitfalls): _don't expand brace patterns into an array when they're used for matching_.
+
+Instead, convert the pattern into an optimized regular expression. This is easier said than done, and braces is the only library that does this currently.
+
+**The proof is in the numbers**
+
+Minimatch gets exponentially slower as patterns increase in complexity, braces does not. The following results were generated using `braces()` and `minimatch.braceExpand()`, respectively.
+
+| **Pattern**                 | **braces**         | **[minimatch][]**            |
+| ---                         | ---                | ---                          |
+| `{1..9007199254740991}`[^1] | `298 B` (5ms 459μs)|  N/A (freezes)               |
+| `{1..1000000000000000}`     | `41 B` (1ms 15μs)  |  N/A (freezes)               |
+| `{1..100000000000000}`      | `40 B` (890μs)     |  N/A (freezes)               |
+| `{1..10000000000000}`       | `39 B` (2ms 49μs)  |  N/A (freezes)               |
+| `{1..1000000000000}`        | `38 B` (608μs)     |  N/A (freezes)               |
+| `{1..100000000000}`         | `37 B` (397μs)     |  N/A (freezes)               |
+| `{1..10000000000}`          | `35 B` (983μs)     |  N/A (freezes)               |
+| `{1..1000000000}`           | `34 B` (798μs)     |  N/A (freezes)               |
+| `{1..100000000}`            | `33 B` (733μs)     |  N/A (freezes)               |
+| `{1..10000000}`             | `32 B` (5ms 632μs) | `78.89 MB` (16s 388ms 569μs) |
+| `{1..1000000}`              | `31 B` (1ms 381μs) | `6.89 MB` (1s 496ms 887μs)   |
+| `{1..100000}`               | `30 B` (950μs)     | `588.89 kB` (146ms 921μs)    |
+| `{1..10000}`                | `29 B` (1ms 114μs) | `48.89 kB` (14ms 187μs)      |
+| `{1..1000}`                 | `28 B` (760μs)     | `3.89 kB` (1ms 453μs)        |
+| `{1..100}`                  | `22 B` (345μs)     | `291 B` (196μs)              |
+| `{1..10}`                   | `10 B` (533μs)     | `20 B` (37μs)                |
+| `{1..3}`                    | `7 B` (190μs)      | `5 B` (27μs)                 |
+
+### Faster algorithms
+
+When you need expansion, braces is still much faster.
+
+_(the following results were generated using `braces.expand()` and `minimatch.braceExpand()`, respectively)_
+
+| **Pattern**     | **braces**                  | **[minimatch][]**            |
+| ---             | ---                         | ---                          |
+| `{1..10000000}` | `78.89 MB` (2s 698ms 642μs) | `78.89 MB` (18s 601ms 974μs) |
+| `{1..1000000}`  | `6.89 MB` (458ms 576μs)     | `6.89 MB` (1s 491ms 621μs)   |
+| `{1..100000}`   | `588.89 kB` (20ms 728μs)    | `588.89 kB` (156ms 919μs)    |
+| `{1..10000}`    | `48.89 kB` (2ms 202μs)      | `48.89 kB` (13ms 641μs)      |
+| `{1..1000}`     | `3.89 kB` (1ms 796μs)       | `3.89 kB` (1ms 958μs)        |
+| `{1..100}`      | `291 B` (424μs)             | `291 B` (211μs)              |
+| `{1..10}`       | `20 B` (487μs)              | `20 B` (72μs)                |
+| `{1..3}`        | `5 B` (166μs)               | `5 B` (27μs)                 |
+
+If you'd like to run these comparisons yourself, see [test/support/generate.js](test/support/generate.js).
+
+## Benchmarks
+
+### Running benchmarks
+
+Install dev dependencies:
+
+```bash
+npm i -d && npm benchmark
+```
+
+### Latest results
+
+Braces is more accurate, without sacrificing performance.
+
+```bash
+# range (expanded)
+  braces x 29,040 ops/sec ±3.69% (91 runs sampled))
+  minimatch x 4,735 ops/sec ±1.28% (90 runs sampled)
+
+# range (optimized for regex)
+  braces x 382,878 ops/sec ±0.56% (94 runs sampled)
+  minimatch x 1,040 ops/sec ±0.44% (93 runs sampled)
+
+# nested ranges (expanded)
+  braces x 19,744 ops/sec ±2.27% (92 runs sampled))
+  minimatch x 4,579 ops/sec ±0.50% (93 runs sampled)
+
+# nested ranges (optimized for regex)
+  braces x 246,019 ops/sec ±2.02% (93 runs sampled)
+  minimatch x 1,028 ops/sec ±0.39% (94 runs sampled)
+
+# set (expanded) 
+  braces x 138,641 ops/sec ±0.53% (95 runs sampled)
+  minimatch x 219,582 ops/sec ±0.98% (94 runs sampled)
+
+# set (optimized for regex)
+  braces x 388,408 ops/sec ±0.41% (95 runs sampled)
+  minimatch x 44,724 ops/sec ±0.91% (89 runs sampled)
+
+# nested sets (expanded)
+  braces x 84,966 ops/sec ±0.48% (94 runs sampled)
+  minimatch x 140,720 ops/sec ±0.37% (95 runs sampled)
+
+# nested sets (optimized for regex)
+  braces x 263,340 ops/sec ±2.06% (92 runs sampled)
+  minimatch x 28,714 ops/sec ±0.40% (90 runs sampled)
+```
+
+## About
+
+<details>
+<summary><strong>Contributing</strong></summary>
+
+Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
+
+</details>
+
+<details>
+<summary><strong>Running Tests</strong></summary>
+
+Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
+
+```sh
+$ npm install && npm test
+```
+
+</details>
+
+<details>
+<summary><strong>Building docs</strong></summary>
+
+_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
+
+To generate the readme, run the following command:
+
+```sh
+$ npm install -g verbose/verb#dev verb-generate-readme && verb
+```
+
+</details>
+
+### Contributors
+
+| **Commits** | **Contributor** |  
+| --- | --- |  
+| 197 | [jonschlinkert](https://github.com/jonschlinkert) |  
+| 4   | [doowb](https://github.com/doowb) |  
+| 1   | [es128](https://github.com/es128) |  
+| 1   | [eush77](https://github.com/eush77) |  
+| 1   | [hemanth](https://github.com/hemanth) |  
+| 1   | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) |  
+
+### Author
+
+**Jon Schlinkert**
+
+* [GitHub Profile](https://github.com/jonschlinkert)
+* [Twitter Profile](https://twitter.com/jonschlinkert)
+* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
+
+### License
+
+Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
+Released under the [MIT License](LICENSE).
+
+***
+
+_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 08, 2019._

+ 170 - 0
node_modules/braces/index.js

@@ -0,0 +1,170 @@
+'use strict';
+
+const stringify = require('./lib/stringify');
+const compile = require('./lib/compile');
+const expand = require('./lib/expand');
+const parse = require('./lib/parse');
+
+/**
+ * Expand the given pattern or create a regex-compatible string.
+ *
+ * ```js
+ * const braces = require('braces');
+ * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)']
+ * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c']
+ * ```
+ * @param {String} `str`
+ * @param {Object} `options`
+ * @return {String}
+ * @api public
+ */
+
+const braces = (input, options = {}) => {
+  let output = [];
+
+  if (Array.isArray(input)) {
+    for (let pattern of input) {
+      let result = braces.create(pattern, options);
+      if (Array.isArray(result)) {
+        output.push(...result);
+      } else {
+        output.push(result);
+      }
+    }
+  } else {
+    output = [].concat(braces.create(input, options));
+  }
+
+  if (options && options.expand === true && options.nodupes === true) {
+    output = [...new Set(output)];
+  }
+  return output;
+};
+
+/**
+ * Parse the given `str` with the given `options`.
+ *
+ * ```js
+ * // braces.parse(pattern, [, options]);
+ * const ast = braces.parse('a/{b,c}/d');
+ * console.log(ast);
+ * ```
+ * @param {String} pattern Brace pattern to parse
+ * @param {Object} options
+ * @return {Object} Returns an AST
+ * @api public
+ */
+
+braces.parse = (input, options = {}) => parse(input, options);
+
+/**
+ * Creates a braces string from an AST, or an AST node.
+ *
+ * ```js
+ * const braces = require('braces');
+ * let ast = braces.parse('foo/{a,b}/bar');
+ * console.log(stringify(ast.nodes[2])); //=> '{a,b}'
+ * ```
+ * @param {String} `input` Brace pattern or AST.
+ * @param {Object} `options`
+ * @return {Array} Returns an array of expanded values.
+ * @api public
+ */
+
+braces.stringify = (input, options = {}) => {
+  if (typeof input === 'string') {
+    return stringify(braces.parse(input, options), options);
+  }
+  return stringify(input, options);
+};
+
+/**
+ * Compiles a brace pattern into a regex-compatible, optimized string.
+ * This method is called by the main [braces](#braces) function by default.
+ *
+ * ```js
+ * const braces = require('braces');
+ * console.log(braces.compile('a/{b,c}/d'));
+ * //=> ['a/(b|c)/d']
+ * ```
+ * @param {String} `input` Brace pattern or AST.
+ * @param {Object} `options`
+ * @return {Array} Returns an array of expanded values.
+ * @api public
+ */
+
+braces.compile = (input, options = {}) => {
+  if (typeof input === 'string') {
+    input = braces.parse(input, options);
+  }
+  return compile(input, options);
+};
+
+/**
+ * Expands a brace pattern into an array. This method is called by the
+ * main [braces](#braces) function when `options.expand` is true. Before
+ * using this method it's recommended that you read the [performance notes](#performance))
+ * and advantages of using [.compile](#compile) instead.
+ *
+ * ```js
+ * const braces = require('braces');
+ * console.log(braces.expand('a/{b,c}/d'));
+ * //=> ['a/b/d', 'a/c/d'];
+ * ```
+ * @param {String} `pattern` Brace pattern
+ * @param {Object} `options`
+ * @return {Array} Returns an array of expanded values.
+ * @api public
+ */
+
+braces.expand = (input, options = {}) => {
+  if (typeof input === 'string') {
+    input = braces.parse(input, options);
+  }
+
+  let result = expand(input, options);
+
+  // filter out empty strings if specified
+  if (options.noempty === true) {
+    result = result.filter(Boolean);
+  }
+
+  // filter out duplicates if specified
+  if (options.nodupes === true) {
+    result = [...new Set(result)];
+  }
+
+  return result;
+};
+
+/**
+ * Processes a brace pattern and returns either an expanded array
+ * (if `options.expand` is true), a highly optimized regex-compatible string.
+ * This method is called by the main [braces](#braces) function.
+ *
+ * ```js
+ * const braces = require('braces');
+ * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}'))
+ * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)'
+ * ```
+ * @param {String} `pattern` Brace pattern
+ * @param {Object} `options`
+ * @return {Array} Returns an array of expanded values.
+ * @api public
+ */
+
+braces.create = (input, options = {}) => {
+  if (input === '' || input.length < 3) {
+    return [input];
+  }
+
+ return options.expand !== true
+    ? braces.compile(input, options)
+    : braces.expand(input, options);
+};
+
+/**
+ * Expose "braces"
+ */
+
+module.exports = braces;

+ 57 - 0
node_modules/braces/lib/compile.js

@@ -0,0 +1,57 @@
+'use strict';
+
+const fill = require('fill-range');
+const utils = require('./utils');
+
+const compile = (ast, options = {}) => {
+  let walk = (node, parent = {}) => {
+    let invalidBlock = utils.isInvalidBrace(parent);
+    let invalidNode = node.invalid === true && options.escapeInvalid === true;
+    let invalid = invalidBlock === true || invalidNode === true;
+    let prefix = options.escapeInvalid === true ? '\\' : '';
+    let output = '';
+
+    if (node.isOpen === true) {
+      return prefix + node.value;
+    }
+    if (node.isClose === true) {
+      return prefix + node.value;
+    }
+
+    if (node.type === 'open') {
+      return invalid ? (prefix + node.value) : '(';
+    }
+
+    if (node.type === 'close') {
+      return invalid ? (prefix + node.value) : ')';
+    }
+
+    if (node.type === 'comma') {
+      return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|');
+    }
+
+    if (node.value) {
+      return node.value;
+    }
+
+    if (node.nodes && node.ranges > 0) {
+      let args = utils.reduce(node.nodes);
+      let range = fill(...args, { ...options, wrap: false, toRegex: true });
+
+      if (range.length !== 0) {
+        return args.length > 1 && range.length > 1 ? `(${range})` : range;
+      }
+    }
+
+    if (node.nodes) {
+      for (let child of node.nodes) {
+        output += walk(child, node);
+      }
+    }
+    return output;
+  };
+
+  return walk(ast);
+};
+
+module.exports = compile;

+ 57 - 0
node_modules/braces/lib/constants.js

@@ -0,0 +1,57 @@
+'use strict';
+
+module.exports = {
+  MAX_LENGTH: 1024 * 64,
+
+  // Digits
+  CHAR_0: '0', /* 0 */
+  CHAR_9: '9', /* 9 */
+
+  // Alphabet chars.
+  CHAR_UPPERCASE_A: 'A', /* A */
+  CHAR_LOWERCASE_A: 'a', /* a */
+  CHAR_UPPERCASE_Z: 'Z', /* Z */
+  CHAR_LOWERCASE_Z: 'z', /* z */
+
+  CHAR_LEFT_PARENTHESES: '(', /* ( */
+  CHAR_RIGHT_PARENTHESES: ')', /* ) */
+
+  CHAR_ASTERISK: '*', /* * */
+
+  // Non-alphabetic chars.
+  CHAR_AMPERSAND: '&', /* & */
+  CHAR_AT: '@', /* @ */
+  CHAR_BACKSLASH: '\\', /* \ */
+  CHAR_BACKTICK: '`', /* ` */
+  CHAR_CARRIAGE_RETURN: '\r', /* \r */
+  CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */
+  CHAR_COLON: ':', /* : */
+  CHAR_COMMA: ',', /* , */
+  CHAR_DOLLAR: '$', /* . */
+  CHAR_DOT: '.', /* . */
+  CHAR_DOUBLE_QUOTE: '"', /* " */
+  CHAR_EQUAL: '=', /* = */
+  CHAR_EXCLAMATION_MARK: '!', /* ! */
+  CHAR_FORM_FEED: '\f', /* \f */
+  CHAR_FORWARD_SLASH: '/', /* / */
+  CHAR_HASH: '#', /* # */
+  CHAR_HYPHEN_MINUS: '-', /* - */
+  CHAR_LEFT_ANGLE_BRACKET: '<', /* < */
+  CHAR_LEFT_CURLY_BRACE: '{', /* { */
+  CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */
+  CHAR_LINE_FEED: '\n', /* \n */
+  CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */
+  CHAR_PERCENT: '%', /* % */
+  CHAR_PLUS: '+', /* + */
+  CHAR_QUESTION_MARK: '?', /* ? */
+  CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */
+  CHAR_RIGHT_CURLY_BRACE: '}', /* } */
+  CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */
+  CHAR_SEMICOLON: ';', /* ; */
+  CHAR_SINGLE_QUOTE: '\'', /* ' */
+  CHAR_SPACE: ' ', /*   */
+  CHAR_TAB: '\t', /* \t */
+  CHAR_UNDERSCORE: '_', /* _ */
+  CHAR_VERTICAL_LINE: '|', /* | */
+  CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */
+};

+ 113 - 0
node_modules/braces/lib/expand.js

@@ -0,0 +1,113 @@
+'use strict';
+
+const fill = require('fill-range');
+const stringify = require('./stringify');
+const utils = require('./utils');
+
+const append = (queue = '', stash = '', enclose = false) => {
+  let result = [];
+
+  queue = [].concat(queue);
+  stash = [].concat(stash);
+
+  if (!stash.length) return queue;
+  if (!queue.length) {
+    return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash;
+  }
+
+  for (let item of queue) {
+    if (Array.isArray(item)) {
+      for (let value of item) {
+        result.push(append(value, stash, enclose));
+      }
+    } else {
+      for (let ele of stash) {
+        if (enclose === true && typeof ele === 'string') ele = `{${ele}}`;
+        result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele));
+      }
+    }
+  }
+  return utils.flatten(result);
+};
+
+const expand = (ast, options = {}) => {
+  let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit;
+
+  let walk = (node, parent = {}) => {
+    node.queue = [];
+
+    let p = parent;
+    let q = parent.queue;
+
+    while (p.type !== 'brace' && p.type !== 'root' && p.parent) {
+      p = p.parent;
+      q = p.queue;
+    }
+
+    if (node.invalid || node.dollar) {
+      q.push(append(q.pop(), stringify(node, options)));
+      return;
+    }
+
+    if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) {
+      q.push(append(q.pop(), ['{}']));
+      return;
+    }
+
+    if (node.nodes && node.ranges > 0) {
+      let args = utils.reduce(node.nodes);
+
+      if (utils.exceedsLimit(...args, options.step, rangeLimit)) {
+        throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.');
+      }
+
+      let range = fill(...args, options);
+      if (range.length === 0) {
+        range = stringify(node, options);
+      }
+
+      q.push(append(q.pop(), range));
+      node.nodes = [];
+      return;
+    }
+
+    let enclose = utils.encloseBrace(node);
+    let queue = node.queue;
+    let block = node;
+
+    while (block.type !== 'brace' && block.type !== 'root' && block.parent) {
+      block = block.parent;
+      queue = block.queue;
+    }
+
+    for (let i = 0; i < node.nodes.length; i++) {
+      let child = node.nodes[i];
+
+      if (child.type === 'comma' && node.type === 'brace') {
+        if (i === 1) queue.push('');
+        queue.push('');
+        continue;
+      }
+
+      if (child.type === 'close') {
+        q.push(append(q.pop(), queue, enclose));
+        continue;
+      }
+
+      if (child.value && child.type !== 'open') {
+        queue.push(append(queue.pop(), child.value));
+        continue;
+      }
+
+      if (child.nodes) {
+        walk(child, node);
+      }
+    }
+
+    return queue;
+  };
+
+  return utils.flatten(walk(ast));
+};
+
+module.exports = expand;

+ 333 - 0
node_modules/braces/lib/parse.js

@@ -0,0 +1,333 @@
+'use strict';
+
+const stringify = require('./stringify');
+
+/**
+ * Constants
+ */
+
+const {
+  MAX_LENGTH,
+  CHAR_BACKSLASH, /* \ */
+  CHAR_BACKTICK, /* ` */
+  CHAR_COMMA, /* , */
+  CHAR_DOT, /* . */
+  CHAR_LEFT_PARENTHESES, /* ( */
+  CHAR_RIGHT_PARENTHESES, /* ) */
+  CHAR_LEFT_CURLY_BRACE, /* { */
+  CHAR_RIGHT_CURLY_BRACE, /* } */
+  CHAR_LEFT_SQUARE_BRACKET, /* [ */
+  CHAR_RIGHT_SQUARE_BRACKET, /* ] */
+  CHAR_DOUBLE_QUOTE, /* " */
+  CHAR_SINGLE_QUOTE, /* ' */
+  CHAR_NO_BREAK_SPACE,
+  CHAR_ZERO_WIDTH_NOBREAK_SPACE
+} = require('./constants');
+
+/**
+ * parse
+ */
+
+const parse = (input, options = {}) => {
+  if (typeof input !== 'string') {
+    throw new TypeError('Expected a string');
+  }
+
+  let opts = options || {};
+  let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH;
+  if (input.length > max) {
+    throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`);
+  }
+
+  let ast = { type: 'root', input, nodes: [] };
+  let stack = [ast];
+  let block = ast;
+  let prev = ast;
+  let brackets = 0;
+  let length = input.length;
+  let index = 0;
+  let depth = 0;
+  let value;
+  let memo = {};
+
+  /**
+   * Helpers
+   */
+
+  const advance = () => input[index++];
+  const push = node => {
+    if (node.type === 'text' && prev.type === 'dot') {
+      prev.type = 'text';
+    }
+
+    if (prev && prev.type === 'text' && node.type === 'text') {
+      prev.value += node.value;
+      return;
+    }
+
+    block.nodes.push(node);
+    node.parent = block;
+    node.prev = prev;
+    prev = node;
+    return node;
+  };
+
+  push({ type: 'bos' });
+
+  while (index < length) {
+    block = stack[stack.length - 1];
+    value = advance();
+
+    /**
+     * Invalid chars
+     */
+
+    if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) {
+      continue;
+    }
+
+    /**
+     * Escaped chars
+     */
+
+    if (value === CHAR_BACKSLASH) {
+      push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() });
+      continue;
+    }
+
+    /**
+     * Right square bracket (literal): ']'
+     */
+
+    if (value === CHAR_RIGHT_SQUARE_BRACKET) {
+      push({ type: 'text', value: '\\' + value });
+      continue;
+    }
+
+    /**
+     * Left square bracket: '['
+     */
+
+    if (value === CHAR_LEFT_SQUARE_BRACKET) {
+      brackets++;
+
+      let closed = true;
+      let next;
+
+      while (index < length && (next = advance())) {
+        value += next;
+
+        if (next === CHAR_LEFT_SQUARE_BRACKET) {
+          brackets++;
+          continue;
+        }
+
+        if (next === CHAR_BACKSLASH) {
+          value += advance();
+          continue;
+        }
+
+        if (next === CHAR_RIGHT_SQUARE_BRACKET) {
+          brackets--;
+
+          if (brackets === 0) {
+            break;
+          }
+        }
+      }
+
+      push({ type: 'text', value });
+      continue;
+    }
+
+    /**
+     * Parentheses
+     */
+
+    if (value === CHAR_LEFT_PARENTHESES) {
+      block = push({ type: 'paren', nodes: [] });
+      stack.push(block);
+      push({ type: 'text', value });
+      continue;
+    }
+
+    if (value === CHAR_RIGHT_PARENTHESES) {
+      if (block.type !== 'paren') {
+        push({ type: 'text', value });
+        continue;
+      }
+      block = stack.pop();
+      push({ type: 'text', value });
+      block = stack[stack.length - 1];
+      continue;
+    }
+
+    /**
+     * Quotes: '|"|`
+     */
+
+    if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) {
+      let open = value;
+      let next;
+
+      if (options.keepQuotes !== true) {
+        value = '';
+      }
+
+      while (index < length && (next = advance())) {
+        if (next === CHAR_BACKSLASH) {
+          value += next + advance();
+          continue;
+        }
+
+        if (next === open) {
+          if (options.keepQuotes === true) value += next;
+          break;
+        }
+
+        value += next;
+      }
+
+      push({ type: 'text', value });
+      continue;
+    }
+
+    /**
+     * Left curly brace: '{'
+     */
+
+    if (value === CHAR_LEFT_CURLY_BRACE) {
+      depth++;
+
+      let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true;
+      let brace = {
+        type: 'brace',
+        open: true,
+        close: false,
+        dollar,
+        depth,
+        commas: 0,
+        ranges: 0,
+        nodes: []
+      };
+
+      block = push(brace);
+      stack.push(block);
+      push({ type: 'open', value });
+      continue;
+    }
+
+    /**
+     * Right curly brace: '}'
+     */
+
+    if (value === CHAR_RIGHT_CURLY_BRACE) {
+      if (block.type !== 'brace') {
+        push({ type: 'text', value });
+        continue;
+      }
+
+      let type = 'close';
+      block = stack.pop();
+      block.close = true;
+
+      push({ type, value });
+      depth--;
+
+      block = stack[stack.length - 1];
+      continue;
+    }
+
+    /**
+     * Comma: ','
+     */
+
+    if (value === CHAR_COMMA && depth > 0) {
+      if (block.ranges > 0) {
+        block.ranges = 0;
+        let open = block.nodes.shift();
+        block.nodes = [open, { type: 'text', value: stringify(block) }];
+      }
+
+      push({ type: 'comma', value });
+      block.commas++;
+      continue;
+    }
+
+    /**
+     * Dot: '.'
+     */
+
+    if (value === CHAR_DOT && depth > 0 && block.commas === 0) {
+      let siblings = block.nodes;
+
+      if (depth === 0 || siblings.length === 0) {
+        push({ type: 'text', value });
+        continue;
+      }
+
+      if (prev.type === 'dot') {
+        block.range = [];
+        prev.value += value;
+        prev.type = 'range';
+
+        if (block.nodes.length !== 3 && block.nodes.length !== 5) {
+          block.invalid = true;
+          block.ranges = 0;
+          prev.type = 'text';
+          continue;
+        }
+
+        block.ranges++;
+        block.args = [];
+        continue;
+      }
+
+      if (prev.type === 'range') {
+        siblings.pop();
+
+        let before = siblings[siblings.length - 1];
+        before.value += prev.value + value;
+        prev = before;
+        block.ranges--;
+        continue;
+      }
+
+      push({ type: 'dot', value });
+      continue;
+    }
+
+    /**
+     * Text
+     */
+
+    push({ type: 'text', value });
+  }
+
+  // Mark imbalanced braces and brackets as invalid
+  do {
+    block = stack.pop();
+
+    if (block.type !== 'root') {
+      block.nodes.forEach(node => {
+        if (!node.nodes) {
+          if (node.type === 'open') node.isOpen = true;
+          if (node.type === 'close') node.isClose = true;
+          if (!node.nodes) node.type = 'text';
+          node.invalid = true;
+        }
+      });
+
+      // get the location of the block on parent.nodes (block's siblings)
+      let parent = stack[stack.length - 1];
+      let index = parent.nodes.indexOf(block);
+      // replace the (invalid) block with it's nodes
+      parent.nodes.splice(index, 1, ...block.nodes);
+    }
+  } while (stack.length > 0);
+
+  push({ type: 'eos' });
+  return ast;
+};
+
+module.exports = parse;

+ 32 - 0
node_modules/braces/lib/stringify.js

@@ -0,0 +1,32 @@
+'use strict';
+
+const utils = require('./utils');
+
+module.exports = (ast, options = {}) => {
+  let stringify = (node, parent = {}) => {
+    let invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent);
+    let invalidNode = node.invalid === true && options.escapeInvalid === true;
+    let output = '';
+
+    if (node.value) {
+      if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) {
+        return '\\' + node.value;
+      }
+      return node.value;
+    }
+
+    if (node.value) {
+      return node.value;
+    }
+
+    if (node.nodes) {
+      for (let child of node.nodes) {
+        output += stringify(child);
+      }
+    }
+    return output;
+  };
+
+  return stringify(ast);
+};
+

+ 112 - 0
node_modules/braces/lib/utils.js

@@ -0,0 +1,112 @@
+'use strict';
+
+exports.isInteger = num => {
+  if (typeof num === 'number') {
+    return Number.isInteger(num);
+  }
+  if (typeof num === 'string' && num.trim() !== '') {
+    return Number.isInteger(Number(num));
+  }
+  return false;
+};
+
+/**
+ * Find a node of the given type
+ */
+
+exports.find = (node, type) => node.nodes.find(node => node.type === type);
+
+/**
+ * Find a node of the given type
+ */
+
+exports.exceedsLimit = (min, max, step = 1, limit) => {
+  if (limit === false) return false;
+  if (!exports.isInteger(min) || !exports.isInteger(max)) return false;
+  return ((Number(max) - Number(min)) / Number(step)) >= limit;
+};
+
+/**
+ * Escape the given node with '\\' before node.value
+ */
+
+exports.escapeNode = (block, n = 0, type) => {
+  let node = block.nodes[n];
+  if (!node) return;
+
+  if ((type && node.type === type) || node.type === 'open' || node.type === 'close') {
+    if (node.escaped !== true) {
+      node.value = '\\' + node.value;
+      node.escaped = true;
+    }
+  }
+};
+
+/**
+ * Returns true if the given brace node should be enclosed in literal braces
+ */
+
+exports.encloseBrace = node => {
+  if (node.type !== 'brace') return false;
+  if ((node.commas >> 0 + node.ranges >> 0) === 0) {
+    node.invalid = true;
+    return true;
+  }
+  return false;
+};
+
+/**
+ * Returns true if a brace node is invalid.
+ */
+
+exports.isInvalidBrace = block => {
+  if (block.type !== 'brace') return false;
+  if (block.invalid === true || block.dollar) return true;
+  if ((block.commas >> 0 + block.ranges >> 0) === 0) {
+    block.invalid = true;
+    return true;
+  }
+  if (block.open !== true || block.close !== true) {
+    block.invalid = true;
+    return true;
+  }
+  return false;
+};
+
+/**
+ * Returns true if a node is an open or close node
+ */
+
+exports.isOpenOrClose = node => {
+  if (node.type === 'open' || node.type === 'close') {
+    return true;
+  }
+  return node.open === true || node.close === true;
+};
+
+/**
+ * Reduce an array of text nodes.
+ */
+
+exports.reduce = nodes => nodes.reduce((acc, node) => {
+  if (node.type === 'text') acc.push(node.value);
+  if (node.type === 'range') node.type = 'text';
+  return acc;
+}, []);
+
+/**
+ * Flatten an array
+ */
+
+exports.flatten = (...args) => {
+  const result = [];
+  const flat = arr => {
+    for (let i = 0; i < arr.length; i++) {
+      let ele = arr[i];
+      Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele);
+    }
+    return result;
+  };
+  flat(args);
+  return result;
+};

+ 77 - 0
node_modules/braces/package.json

@@ -0,0 +1,77 @@
+{
+  "name": "braces",
+  "description": "Bash-like brace expansion, implemented in JavaScript. Safer than other brace expansion libs, with complete support for the Bash 4.3 braces specification, without sacrificing speed.",
+  "version": "3.0.2",
+  "homepage": "https://github.com/micromatch/braces",
+  "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
+  "contributors": [
+    "Brian Woodward (https://twitter.com/doowb)",
+    "Elan Shanker (https://github.com/es128)",
+    "Eugene Sharygin (https://github.com/eush77)",
+    "hemanth.hm (http://h3manth.com)",
+    "Jon Schlinkert (http://twitter.com/jonschlinkert)"
+  ],
+  "repository": "micromatch/braces",
+  "bugs": {
+    "url": "https://github.com/micromatch/braces/issues"
+  },
+  "license": "MIT",
+  "files": [
+    "index.js",
+    "lib"
+  ],
+  "main": "index.js",
+  "engines": {
+    "node": ">=8"
+  },
+  "scripts": {
+    "test": "mocha",
+    "benchmark": "node benchmark"
+  },
+  "dependencies": {
+    "fill-range": "^7.0.1"
+  },
+  "devDependencies": {
+    "ansi-colors": "^3.2.4",
+    "bash-path": "^2.0.1",
+    "gulp-format-md": "^2.0.0",
+    "mocha": "^6.1.1"
+  },
+  "keywords": [
+    "alpha",
+    "alphabetical",
+    "bash",
+    "brace",
+    "braces",
+    "expand",
+    "expansion",
+    "filepath",
+    "fill",
+    "fs",
+    "glob",
+    "globbing",
+    "letter",
+    "match",
+    "matches",
+    "matching",
+    "number",
+    "numerical",
+    "path",
+    "range",
+    "ranges",
+    "sh"
+  ],
+  "verb": {
+    "toc": false,
+    "layout": "default",
+    "tasks": [
+      "readme"
+    ],
+    "lint": {
+      "reflinks": true
+    },
+    "plugins": [
+      "gulp-format-md"
+    ]
+  }
+}

+ 21 - 0
node_modules/chokidar/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012-2019 Paul Miller (https://paulmillr.com), Elan Shanker
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 308 - 0
node_modules/chokidar/README.md

@@ -0,0 +1,308 @@
+# Chokidar [![Weekly downloads](https://img.shields.io/npm/dw/chokidar.svg)](https://github.com/paulmillr/chokidar) [![Yearly downloads](https://img.shields.io/npm/dy/chokidar.svg)](https://github.com/paulmillr/chokidar)
+
+> Minimal and efficient cross-platform file watching library
+
+[![NPM](https://nodei.co/npm/chokidar.png)](https://www.npmjs.com/package/chokidar)
+
+## Why?
+
+Node.js `fs.watch`:
+
+* Doesn't report filenames on MacOS.
+* Doesn't report events at all when using editors like Sublime on MacOS.
+* Often reports events twice.
+* Emits most changes as `rename`.
+* Does not provide an easy way to recursively watch file trees.
+* Does not support recursive watching on Linux.
+
+Node.js `fs.watchFile`:
+
+* Almost as bad at event handling.
+* Also does not provide any recursive watching.
+* Results in high CPU utilization.
+
+Chokidar resolves these problems.
+
+Initially made for **[Brunch](https://brunch.io/)** (an ultra-swift web app build tool), it is now used in
+[Microsoft's Visual Studio Code](https://github.com/microsoft/vscode),
+[gulp](https://github.com/gulpjs/gulp/),
+[karma](https://karma-runner.github.io/),
+[PM2](https://github.com/Unitech/PM2),
+[browserify](http://browserify.org/),
+[webpack](https://webpack.github.io/),
+[BrowserSync](https://www.browsersync.io/),
+and [many others](https://www.npmjs.com/browse/depended/chokidar).
+It has proven itself in production environments.
+
+Version 3 is out! Check out our blog post about it: [Chokidar 3: How to save 32TB of traffic every week](https://paulmillr.com/posts/chokidar-3-save-32tb-of-traffic/)
+
+## How?
+
+Chokidar does still rely on the Node.js core `fs` module, but when using
+`fs.watch` and `fs.watchFile` for watching, it normalizes the events it
+receives, often checking for truth by getting file stats and/or dir contents.
+
+On MacOS, chokidar by default uses a native extension exposing the Darwin
+`FSEvents` API. This provides very efficient recursive watching compared with
+implementations like `kqueue` available on most \*nix platforms. Chokidar still
+does have to do some work to normalize the events received that way as well.
+
+On most other platforms, the `fs.watch`-based implementation is the default, which
+avoids polling and keeps CPU usage down. Be advised that chokidar will initiate
+watchers recursively for everything within scope of the paths that have been
+specified, so be judicious about not wasting system resources by watching much
+more than needed.
+
+## Getting started
+
+Install with npm:
+
+```sh
+npm install chokidar
+```
+
+Then `require` and use it in your code:
+
+```javascript
+const chokidar = require('chokidar');
+
+// One-liner for current directory
+chokidar.watch('.').on('all', (event, path) => {
+  console.log(event, path);
+});
+```
+
+## API
+
+```javascript
+// Example of a more typical implementation structure
+
+// Initialize watcher.
+const watcher = chokidar.watch('file, dir, glob, or array', {
+  ignored: /(^|[\/\\])\../, // ignore dotfiles
+  persistent: true
+});
+
+// Something to use when events are received.
+const log = console.log.bind(console);
+// Add event listeners.
+watcher
+  .on('add', path => log(`File ${path} has been added`))
+  .on('change', path => log(`File ${path} has been changed`))
+  .on('unlink', path => log(`File ${path} has been removed`));
+
+// More possible events.
+watcher
+  .on('addDir', path => log(`Directory ${path} has been added`))
+  .on('unlinkDir', path => log(`Directory ${path} has been removed`))
+  .on('error', error => log(`Watcher error: ${error}`))
+  .on('ready', () => log('Initial scan complete. Ready for changes'))
+  .on('raw', (event, path, details) => { // internal
+    log('Raw event info:', event, path, details);
+  });
+
+// 'add', 'addDir' and 'change' events also receive stat() results as second
+// argument when available: https://nodejs.org/api/fs.html#fs_class_fs_stats
+watcher.on('change', (path, stats) => {
+  if (stats) console.log(`File ${path} changed size to ${stats.size}`);
+});
+
+// Watch new files.
+watcher.add('new-file');
+watcher.add(['new-file-2', 'new-file-3', '**/other-file*']);
+
+// Get list of actual paths being watched on the filesystem
+var watchedPaths = watcher.getWatched();
+
+// Un-watch some files.
+await watcher.unwatch('new-file*');
+
+// Stop watching.
+// The method is async!
+watcher.close().then(() => console.log('closed'));
+
+// Full list of options. See below for descriptions.
+// Do not use this example!
+chokidar.watch('file', {
+  persistent: true,
+
+  ignored: '*.txt',
+  ignoreInitial: false,
+  followSymlinks: true,
+  cwd: '.',
+  disableGlobbing: false,
+
+  usePolling: false,
+  interval: 100,
+  binaryInterval: 300,
+  alwaysStat: false,
+  depth: 99,
+  awaitWriteFinish: {
+    stabilityThreshold: 2000,
+    pollInterval: 100
+  },
+
+  ignorePermissionErrors: false,
+  atomic: true // or a custom 'atomicity delay', in milliseconds (default 100)
+});
+
+```
+
+`chokidar.watch(paths, [options])`
+
+* `paths` (string or array of strings). Paths to files, dirs to be watched
+recursively, or glob patterns.
+    - Note: globs must not contain windows separators (`\`),
+    because that's how they work by the standard —
+    you'll need to replace them with forward slashes (`/`).
+    - Note 2: for additional glob documentation, check out low-level
+    library: [picomatch](https://github.com/micromatch/picomatch).
+* `options` (object) Options object as defined below:
+
+#### Persistence
+
+* `persistent` (default: `true`). Indicates whether the process
+should continue to run as long as files are being watched. If set to
+`false` when using `fsevents` to watch, no more events will be emitted
+after `ready`, even if the process continues to run.
+
+#### Path filtering
+
+* `ignored` ([anymatch](https://github.com/es128/anymatch)-compatible definition)
+Defines files/paths to be ignored. The whole relative or absolute path is
+tested, not just filename. If a function with two arguments is provided, it
+gets called twice per path - once with a single argument (the path), second
+time with two arguments (the path and the
+[`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
+object of that path).
+* `ignoreInitial` (default: `false`). If set to `false` then `add`/`addDir` events are also emitted for matching paths while
+instantiating the watching as chokidar discovers these file paths (before the `ready` event).
+* `followSymlinks` (default: `true`). When `false`, only the
+symlinks themselves will be watched for changes instead of following
+the link references and bubbling events through the link's path.
+* `cwd` (no default). The base directory from which watch `paths` are to be
+derived. Paths emitted with events will be relative to this.
+* `disableGlobbing` (default: `false`). If set to `true` then the strings passed to `.watch()` and `.add()` are treated as
+literal path names, even if they look like globs.
+
+#### Performance
+
+* `usePolling` (default: `false`).
+Whether to use fs.watchFile (backed by polling), or fs.watch. If polling
+leads to high CPU utilization, consider setting this to `false`. It is
+typically necessary to **set this to `true` to successfully watch files over
+a network**, and it may be necessary to successfully watch files in other
+non-standard situations. Setting to `true` explicitly on MacOS overrides the
+`useFsEvents` default. You may also set the CHOKIDAR_USEPOLLING env variable
+to true (1) or false (0) in order to override this option.
+* _Polling-specific settings_ (effective when `usePolling: true`)
+  * `interval` (default: `100`). Interval of file system polling, in milliseconds. You may also
+    set the CHOKIDAR_INTERVAL env variable to override this option.
+  * `binaryInterval` (default: `300`). Interval of file system
+  polling for binary files.
+  ([see list of binary extensions](https://github.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json))
+* `useFsEvents` (default: `true` on MacOS). Whether to use the
+`fsevents` watching interface if available. When set to `true` explicitly
+and `fsevents` is available this supercedes the `usePolling` setting. When
+set to `false` on MacOS, `usePolling: true` becomes the default.
+* `alwaysStat` (default: `false`). If relying upon the
+[`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
+object that may get passed with `add`, `addDir`, and `change` events, set
+this to `true` to ensure it is provided even in cases where it wasn't
+already available from the underlying watch events.
+* `depth` (default: `undefined`). If set, limits how many levels of
+subdirectories will be traversed.
+* `awaitWriteFinish` (default: `false`).
+By default, the `add` event will fire when a file first appears on disk, before
+the entire file has been written. Furthermore, in some cases some `change`
+events will be emitted while the file is being written. In some cases,
+especially when watching for large files there will be a need to wait for the
+write operation to finish before responding to a file creation or modification.
+Setting `awaitWriteFinish` to `true` (or a truthy value) will poll file size,
+holding its `add` and `change` events until the size does not change for a
+configurable amount of time. The appropriate duration setting is heavily
+dependent on the OS and hardware. For accurate detection this parameter should
+be relatively high, making file watching much less responsive.
+Use with caution.
+  * *`options.awaitWriteFinish` can be set to an object in order to adjust
+  timing params:*
+  * `awaitWriteFinish.stabilityThreshold` (default: 2000). Amount of time in
+  milliseconds for a file size to remain constant before emitting its event.
+  * `awaitWriteFinish.pollInterval` (default: 100). File size polling interval, in milliseconds.
+
+#### Errors
+
+* `ignorePermissionErrors` (default: `false`). Indicates whether to watch files
+that don't have read permissions if possible. If watching fails due to `EPERM`
+or `EACCES` with this set to `true`, the errors will be suppressed silently.
+* `atomic` (default: `true` if `useFsEvents` and `usePolling` are `false`).
+Automatically filters out artifacts that occur when using editors that use
+"atomic writes" instead of writing directly to the source file. If a file is
+re-added within 100 ms of being deleted, Chokidar emits a `change` event
+rather than `unlink` then `add`. If the default of 100 ms does not work well
+for you, you can override it by setting `atomic` to a custom value, in
+milliseconds.
+
+### Methods & Events
+
+`chokidar.watch()` produces an instance of `FSWatcher`. Methods of `FSWatcher`:
+
+* `.add(path / paths)`: Add files, directories, or glob patterns for tracking.
+Takes an array of strings or just one string.
+* `.on(event, callback)`: Listen for an FS event.
+Available events: `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `ready`,
+`raw`, `error`.
+Additionally `all` is available which gets emitted with the underlying event
+name and path for every event other than `ready`, `raw`, and `error`.  `raw` is internal, use it carefully.
+* `.unwatch(path / paths)`: Stop watching files, directories, or glob patterns.
+Takes an array of strings or just one string.
+* `.close()`: **async** Removes all listeners from watched files. Asynchronous, returns Promise. Use with `await` to ensure bugs don't happen.
+* `.getWatched()`: Returns an object representing all the paths on the file
+system being watched by this `FSWatcher` instance. The object's keys are all the
+directories (using absolute paths unless the `cwd` option was used), and the
+values are arrays of the names of the items contained in each directory.
+
+## CLI
+
+If you need a CLI interface for your file watching, check out
+[chokidar-cli](https://github.com/open-cli-tools/chokidar-cli), allowing you to
+execute a command on each change, or get a stdio stream of change events.
+
+## Install Troubleshooting
+
+* `npm WARN optional dep failed, continuing [email protected]`
+  * This message is normal part of how `npm` handles optional dependencies and is
+    not indicative of a problem. Even if accompanied by other related error messages,
+    Chokidar should function properly.
+
+* `TypeError: fsevents is not a constructor`
+  * Update chokidar by doing `rm -rf node_modules package-lock.json yarn.lock && npm install`, or update your dependency that uses chokidar.
+
+* Chokidar is producing `ENOSP` error on Linux, like this:
+  * `bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell`
+  `Error: watch /home/ ENOSPC`
+  * This means Chokidar ran out of file handles and you'll need to increase their count by executing the following command in Terminal:
+  `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`
+
+## Changelog
+
+For more detailed changelog, see [`full_changelog.md`](.github/full_changelog.md).
+- **v3.5 (Jan 6, 2021):** Support for ARM Macs with Apple Silicon. Fixes for deleted symlinks.
+- **v3.4 (Apr 26, 2020):** Support for directory-based symlinks. Fixes for macos file replacement.
+- **v3.3 (Nov 2, 2019):** `FSWatcher#close()` method became async. That fixes IO race conditions related to close method.
+- **v3.2 (Oct 1, 2019):** Improve Linux RAM usage by 50%. Race condition fixes. Windows glob fixes. Improve stability by using tight range of dependency versions.
+- **v3.1 (Sep 16, 2019):** dotfiles are no longer filtered out by default. Use `ignored` option if needed. Improve initial Linux scan time by 50%.
+- **v3 (Apr 30, 2019):** massive CPU & RAM consumption improvements; reduces deps / package size by a factor of 17x and bumps Node.js requirement to v8.16 and higher.
+- **v2 (Dec 29, 2017):** Globs are now posix-style-only; without windows support. Tons of bugfixes.
+- **v1 (Apr 7, 2015):** Glob support, symlink support, tons of bugfixes. Node 0.8+ is supported
+- **v0.1 (Apr 20, 2012):** Initial release, extracted from [Brunch](https://github.com/brunch/brunch/blob/9847a065aea300da99bd0753f90354cde9de1261/src/helpers.coffee#L66)
+
+## Also
+
+Why was chokidar named this way? What's the meaning behind it?
+
+>Chowkidar is a transliteration of a Hindi word meaning 'watchman, gatekeeper', चौकीदार. This ultimately comes from Sanskrit _ चतुष्क_ (crossway, quadrangle, consisting-of-four). This word is also used in other languages like Urdu as (چوکیدار) which is widely used in Pakistan and India. 
+
+## License
+
+MIT (c) Paul Miller (<https://paulmillr.com>), see [LICENSE](LICENSE) file.

+ 973 - 0
node_modules/chokidar/index.js

@@ -0,0 +1,973 @@
+'use strict';
+
+const { EventEmitter } = require('events');
+const fs = require('fs');
+const sysPath = require('path');
+const { promisify } = require('util');
+const readdirp = require('readdirp');
+const anymatch = require('anymatch').default;
+const globParent = require('glob-parent');
+const isGlob = require('is-glob');
+const braces = require('braces');
+const normalizePath = require('normalize-path');
+
+const NodeFsHandler = require('./lib/nodefs-handler');
+const FsEventsHandler = require('./lib/fsevents-handler');
+const {
+  EV_ALL,
+  EV_READY,
+  EV_ADD,
+  EV_CHANGE,
+  EV_UNLINK,
+  EV_ADD_DIR,
+  EV_UNLINK_DIR,
+  EV_RAW,
+  EV_ERROR,
+
+  STR_CLOSE,
+  STR_END,
+
+  BACK_SLASH_RE,
+  DOUBLE_SLASH_RE,
+  SLASH_OR_BACK_SLASH_RE,
+  DOT_RE,
+  REPLACER_RE,
+
+  SLASH,
+  SLASH_SLASH,
+  BRACE_START,
+  BANG,
+  ONE_DOT,
+  TWO_DOTS,
+  GLOBSTAR,
+  SLASH_GLOBSTAR,
+  ANYMATCH_OPTS,
+  STRING_TYPE,
+  FUNCTION_TYPE,
+  EMPTY_STR,
+  EMPTY_FN,
+
+  isWindows,
+  isMacos,
+  isIBMi
+} = require('./lib/constants');
+
+const stat = promisify(fs.stat);
+const readdir = promisify(fs.readdir);
+
+/**
+ * @typedef {String} Path
+ * @typedef {'all'|'add'|'addDir'|'change'|'unlink'|'unlinkDir'|'raw'|'error'|'ready'} EventName
+ * @typedef {'readdir'|'watch'|'add'|'remove'|'change'} ThrottleType
+ */
+
+/**
+ *
+ * @typedef {Object} WatchHelpers
+ * @property {Boolean} followSymlinks
+ * @property {'stat'|'lstat'} statMethod
+ * @property {Path} path
+ * @property {Path} watchPath
+ * @property {Function} entryPath
+ * @property {Boolean} hasGlob
+ * @property {Object} globFilter
+ * @property {Function} filterPath
+ * @property {Function} filterDir
+ */
+
+const arrify = (value = []) => Array.isArray(value) ? value : [value];
+const flatten = (list, result = []) => {
+  list.forEach(item => {
+    if (Array.isArray(item)) {
+      flatten(item, result);
+    } else {
+      result.push(item);
+    }
+  });
+  return result;
+};
+
+const unifyPaths = (paths_) => {
+  /**
+   * @type {Array<String>}
+   */
+  const paths = flatten(arrify(paths_));
+  if (!paths.every(p => typeof p === STRING_TYPE)) {
+    throw new TypeError(`Non-string provided as watch path: ${paths}`);
+  }
+  return paths.map(normalizePathToUnix);
+};
+
+// If SLASH_SLASH occurs at the beginning of path, it is not replaced
+//     because "//StoragePC/DrivePool/Movies" is a valid network path
+const toUnix = (string) => {
+  let str = string.replace(BACK_SLASH_RE, SLASH);
+  let prepend = false;
+  if (str.startsWith(SLASH_SLASH)) {
+    prepend = true;
+  }
+  while (str.match(DOUBLE_SLASH_RE)) {
+    str = str.replace(DOUBLE_SLASH_RE, SLASH);
+  }
+  if (prepend) {
+    str = SLASH + str;
+  }
+  return str;
+};
+
+// Our version of upath.normalize
+// TODO: this is not equal to path-normalize module - investigate why
+const normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));
+
+const normalizeIgnored = (cwd = EMPTY_STR) => (path) => {
+  if (typeof path !== STRING_TYPE) return path;
+  return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));
+};
+
+const getAbsolutePath = (path, cwd) => {
+  if (sysPath.isAbsolute(path)) {
+    return path;
+  }
+  if (path.startsWith(BANG)) {
+    return BANG + sysPath.join(cwd, path.slice(1));
+  }
+  return sysPath.join(cwd, path);
+};
+
+const undef = (opts, key) => opts[key] === undefined;
+
+/**
+ * Directory entry.
+ * @property {Path} path
+ * @property {Set<Path>} items
+ */
+class DirEntry {
+  /**
+   * @param {Path} dir
+   * @param {Function} removeWatcher
+   */
+  constructor(dir, removeWatcher) {
+    this.path = dir;
+    this._removeWatcher = removeWatcher;
+    /** @type {Set<Path>} */
+    this.items = new Set();
+  }
+
+  add(item) {
+    const {items} = this;
+    if (!items) return;
+    if (item !== ONE_DOT && item !== TWO_DOTS) items.add(item);
+  }
+
+  async remove(item) {
+    const {items} = this;
+    if (!items) return;
+    items.delete(item);
+    if (items.size > 0) return;
+
+    const dir = this.path;
+    try {
+      await readdir(dir);
+    } catch (err) {
+      if (this._removeWatcher) {
+        this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));
+      }
+    }
+  }
+
+  has(item) {
+    const {items} = this;
+    if (!items) return;
+    return items.has(item);
+  }
+
+  /**
+   * @returns {Array<String>}
+   */
+  getChildren() {
+    const {items} = this;
+    if (!items) return;
+    return [...items.values()];
+  }
+
+  dispose() {
+    this.items.clear();
+    delete this.path;
+    delete this._removeWatcher;
+    delete this.items;
+    Object.freeze(this);
+  }
+}
+
+const STAT_METHOD_F = 'stat';
+const STAT_METHOD_L = 'lstat';
+class WatchHelper {
+  constructor(path, watchPath, follow, fsw) {
+    this.fsw = fsw;
+    this.path = path = path.replace(REPLACER_RE, EMPTY_STR);
+    this.watchPath = watchPath;
+    this.fullWatchPath = sysPath.resolve(watchPath);
+    this.hasGlob = watchPath !== path;
+    /** @type {object|boolean} */
+    if (path === EMPTY_STR) this.hasGlob = false;
+    this.globSymlink = this.hasGlob && follow ? undefined : false;
+    this.globFilter = this.hasGlob ? anymatch(path, undefined, ANYMATCH_OPTS) : false;
+    this.dirParts = this.getDirParts(path);
+    this.dirParts.forEach((parts) => {
+      if (parts.length > 1) parts.pop();
+    });
+    this.followSymlinks = follow;
+    this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
+  }
+
+  checkGlobSymlink(entry) {
+    // only need to resolve once
+    // first entry should always have entry.parentDir === EMPTY_STR
+    if (this.globSymlink === undefined) {
+      this.globSymlink = entry.fullParentDir === this.fullWatchPath ?
+        false : {realPath: entry.fullParentDir, linkPath: this.fullWatchPath};
+    }
+
+    if (this.globSymlink) {
+      return entry.fullPath.replace(this.globSymlink.realPath, this.globSymlink.linkPath);
+    }
+
+    return entry.fullPath;
+  }
+
+  entryPath(entry) {
+    return sysPath.join(this.watchPath,
+      sysPath.relative(this.watchPath, this.checkGlobSymlink(entry))
+    );
+  }
+
+  filterPath(entry) {
+    const {stats} = entry;
+    if (stats && stats.isSymbolicLink()) return this.filterDir(entry);
+    const resolvedPath = this.entryPath(entry);
+    const matchesGlob = this.hasGlob && typeof this.globFilter === FUNCTION_TYPE ?
+      this.globFilter(resolvedPath) : true;
+    return matchesGlob &&
+      this.fsw._isntIgnored(resolvedPath, stats) &&
+      this.fsw._hasReadPermissions(stats);
+  }
+
+  getDirParts(path) {
+    if (!this.hasGlob) return [];
+    const parts = [];
+    const expandedPath = path.includes(BRACE_START) ? braces.expand(path) : [path];
+    expandedPath.forEach((path) => {
+      parts.push(sysPath.relative(this.watchPath, path).split(SLASH_OR_BACK_SLASH_RE));
+    });
+    return parts;
+  }
+
+  filterDir(entry) {
+    if (this.hasGlob) {
+      const entryParts = this.getDirParts(this.checkGlobSymlink(entry));
+      let globstar = false;
+      this.unmatchedGlob = !this.dirParts.some((parts) => {
+        return parts.every((part, i) => {
+          if (part === GLOBSTAR) globstar = true;
+          return globstar || !entryParts[0][i] || anymatch(part, entryParts[0][i], ANYMATCH_OPTS);
+        });
+      });
+    }
+    return !this.unmatchedGlob && this.fsw._isntIgnored(this.entryPath(entry), entry.stats);
+  }
+}
+
+/**
+ * Watches files & directories for changes. Emitted events:
+ * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`
+ *
+ *     new FSWatcher()
+ *       .add(directories)
+ *       .on('add', path => log('File', path, 'was added'))
+ */
+class FSWatcher extends EventEmitter {
+// Not indenting methods for history sake; for now.
+constructor(_opts) {
+  super();
+
+  const opts = {};
+  if (_opts) Object.assign(opts, _opts); // for frozen objects
+
+  /** @type {Map<String, DirEntry>} */
+  this._watched = new Map();
+  /** @type {Map<String, Array>} */
+  this._closers = new Map();
+  /** @type {Set<String>} */
+  this._ignoredPaths = new Set();
+
+  /** @type {Map<ThrottleType, Map>} */
+  this._throttled = new Map();
+
+  /** @type {Map<Path, String|Boolean>} */
+  this._symlinkPaths = new Map();
+
+  this._streams = new Set();
+  this.closed = false;
+
+  // Set up default options.
+  if (undef(opts, 'persistent')) opts.persistent = true;
+  if (undef(opts, 'ignoreInitial')) opts.ignoreInitial = false;
+  if (undef(opts, 'ignorePermissionErrors')) opts.ignorePermissionErrors = false;
+  if (undef(opts, 'interval')) opts.interval = 100;
+  if (undef(opts, 'binaryInterval')) opts.binaryInterval = 300;
+  if (undef(opts, 'disableGlobbing')) opts.disableGlobbing = false;
+  opts.enableBinaryInterval = opts.binaryInterval !== opts.interval;
+
+  // Enable fsevents on OS X when polling isn't explicitly enabled.
+  if (undef(opts, 'useFsEvents')) opts.useFsEvents = !opts.usePolling;
+
+  // If we can't use fsevents, ensure the options reflect it's disabled.
+  const canUseFsEvents = FsEventsHandler.canUse();
+  if (!canUseFsEvents) opts.useFsEvents = false;
+
+  // Use polling on Mac if not using fsevents.
+  // Other platforms use non-polling fs_watch.
+  if (undef(opts, 'usePolling') && !opts.useFsEvents) {
+    opts.usePolling = isMacos;
+  }
+
+  // Always default to polling on IBM i because fs.watch() is not available on IBM i.
+  if(isIBMi) {
+    opts.usePolling = true;
+  }
+
+  // Global override (useful for end-developers that need to force polling for all
+  // instances of chokidar, regardless of usage/dependency depth)
+  const envPoll = process.env.CHOKIDAR_USEPOLLING;
+  if (envPoll !== undefined) {
+    const envLower = envPoll.toLowerCase();
+
+    if (envLower === 'false' || envLower === '0') {
+      opts.usePolling = false;
+    } else if (envLower === 'true' || envLower === '1') {
+      opts.usePolling = true;
+    } else {
+      opts.usePolling = !!envLower;
+    }
+  }
+  const envInterval = process.env.CHOKIDAR_INTERVAL;
+  if (envInterval) {
+    opts.interval = Number.parseInt(envInterval, 10);
+  }
+
+  // Editor atomic write normalization enabled by default with fs.watch
+  if (undef(opts, 'atomic')) opts.atomic = !opts.usePolling && !opts.useFsEvents;
+  if (opts.atomic) this._pendingUnlinks = new Map();
+
+  if (undef(opts, 'followSymlinks')) opts.followSymlinks = true;
+
+  if (undef(opts, 'awaitWriteFinish')) opts.awaitWriteFinish = false;
+  if (opts.awaitWriteFinish === true) opts.awaitWriteFinish = {};
+  const awf = opts.awaitWriteFinish;
+  if (awf) {
+    if (!awf.stabilityThreshold) awf.stabilityThreshold = 2000;
+    if (!awf.pollInterval) awf.pollInterval = 100;
+    this._pendingWrites = new Map();
+  }
+  if (opts.ignored) opts.ignored = arrify(opts.ignored);
+
+  let readyCalls = 0;
+  this._emitReady = () => {
+    readyCalls++;
+    if (readyCalls >= this._readyCount) {
+      this._emitReady = EMPTY_FN;
+      this._readyEmitted = true;
+      // use process.nextTick to allow time for listener to be bound
+      process.nextTick(() => this.emit(EV_READY));
+    }
+  };
+  this._emitRaw = (...args) => this.emit(EV_RAW, ...args);
+  this._readyEmitted = false;
+  this.options = opts;
+
+  // Initialize with proper watcher.
+  if (opts.useFsEvents) {
+    this._fsEventsHandler = new FsEventsHandler(this);
+  } else {
+    this._nodeFsHandler = new NodeFsHandler(this);
+  }
+
+  // You’re frozen when your heart’s not open.
+  Object.freeze(opts);
+}
+
+// Public methods
+
+/**
+ * Adds paths to be watched on an existing FSWatcher instance
+ * @param {Path|Array<Path>} paths_
+ * @param {String=} _origAdd private; for handling non-existent paths to be watched
+ * @param {Boolean=} _internal private; indicates a non-user add
+ * @returns {FSWatcher} for chaining
+ */
+add(paths_, _origAdd, _internal) {
+  const {cwd, disableGlobbing} = this.options;
+  this.closed = false;
+  let paths = unifyPaths(paths_);
+  if (cwd) {
+    paths = paths.map((path) => {
+      const absPath = getAbsolutePath(path, cwd);
+
+      // Check `path` instead of `absPath` because the cwd portion can't be a glob
+      if (disableGlobbing || !isGlob(path)) {
+        return absPath;
+      }
+      return normalizePath(absPath);
+    });
+  }
+
+  // set aside negated glob strings
+  paths = paths.filter((path) => {
+    if (path.startsWith(BANG)) {
+      this._ignoredPaths.add(path.slice(1));
+      return false;
+    }
+
+    // if a path is being added that was previously ignored, stop ignoring it
+    this._ignoredPaths.delete(path);
+    this._ignoredPaths.delete(path + SLASH_GLOBSTAR);
+
+    // reset the cached userIgnored anymatch fn
+    // to make ignoredPaths changes effective
+    this._userIgnored = undefined;
+
+    return true;
+  });
+
+  if (this.options.useFsEvents && this._fsEventsHandler) {
+    if (!this._readyCount) this._readyCount = paths.length;
+    if (this.options.persistent) this._readyCount += paths.length;
+    paths.forEach((path) => this._fsEventsHandler._addToFsEvents(path));
+  } else {
+    if (!this._readyCount) this._readyCount = 0;
+    this._readyCount += paths.length;
+    Promise.all(
+      paths.map(async path => {
+        const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, 0, 0, _origAdd);
+        if (res) this._emitReady();
+        return res;
+      })
+    ).then(results => {
+      if (this.closed) return;
+      results.filter(item => item).forEach(item => {
+        this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));
+      });
+    });
+  }
+
+  return this;
+}
+
+/**
+ * Close watchers or start ignoring events from specified paths.
+ * @param {Path|Array<Path>} paths_ - string or array of strings, file/directory paths and/or globs
+ * @returns {FSWatcher} for chaining
+*/
+unwatch(paths_) {
+  if (this.closed) return this;
+  const paths = unifyPaths(paths_);
+  const {cwd} = this.options;
+
+  paths.forEach((path) => {
+    // convert to absolute path unless relative path already matches
+    if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {
+      if (cwd) path = sysPath.join(cwd, path);
+      path = sysPath.resolve(path);
+    }
+
+    this._closePath(path);
+
+    this._ignoredPaths.add(path);
+    if (this._watched.has(path)) {
+      this._ignoredPaths.add(path + SLASH_GLOBSTAR);
+    }
+
+    // reset the cached userIgnored anymatch fn
+    // to make ignoredPaths changes effective
+    this._userIgnored = undefined;
+  });
+
+  return this;
+}
+
+/**
+ * Close watchers and remove all listeners from watched paths.
+ * @returns {Promise<void>}.
+*/
+close() {
+  if (this.closed) return this._closePromise;
+  this.closed = true;
+
+  // Memory management.
+  this.removeAllListeners();
+  const closers = [];
+  this._closers.forEach(closerList => closerList.forEach(closer => {
+    const promise = closer();
+    if (promise instanceof Promise) closers.push(promise);
+  }));
+  this._streams.forEach(stream => stream.destroy());
+  this._userIgnored = undefined;
+  this._readyCount = 0;
+  this._readyEmitted = false;
+  this._watched.forEach(dirent => dirent.dispose());
+  ['closers', 'watched', 'streams', 'symlinkPaths', 'throttled'].forEach(key => {
+    this[`_${key}`].clear();
+  });
+
+  this._closePromise = closers.length ? Promise.all(closers).then(() => undefined) : Promise.resolve();
+  return this._closePromise;
+}
+
+/**
+ * Expose list of watched paths
+ * @returns {Object} for chaining
+*/
+getWatched() {
+  const watchList = {};
+  this._watched.forEach((entry, dir) => {
+    const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;
+    watchList[key || ONE_DOT] = entry.getChildren().sort();
+  });
+  return watchList;
+}
+
+emitWithAll(event, args) {
+  this.emit(...args);
+  if (event !== EV_ERROR) this.emit(EV_ALL, ...args);
+}
+
+// Common helpers
+// --------------
+
+/**
+ * Normalize and emit events.
+ * Calling _emit DOES NOT MEAN emit() would be called!
+ * @param {EventName} event Type of event
+ * @param {Path} path File or directory path
+ * @param {*=} val1 arguments to be passed with event
+ * @param {*=} val2
+ * @param {*=} val3
+ * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
+ */
+async _emit(event, path, val1, val2, val3) {
+  if (this.closed) return;
+
+  const opts = this.options;
+  if (isWindows) path = sysPath.normalize(path);
+  if (opts.cwd) path = sysPath.relative(opts.cwd, path);
+  /** @type Array<any> */
+  const args = [event, path];
+  if (val3 !== undefined) args.push(val1, val2, val3);
+  else if (val2 !== undefined) args.push(val1, val2);
+  else if (val1 !== undefined) args.push(val1);
+
+  const awf = opts.awaitWriteFinish;
+  let pw;
+  if (awf && (pw = this._pendingWrites.get(path))) {
+    pw.lastChange = new Date();
+    return this;
+  }
+
+  if (opts.atomic) {
+    if (event === EV_UNLINK) {
+      this._pendingUnlinks.set(path, args);
+      setTimeout(() => {
+        this._pendingUnlinks.forEach((entry, path) => {
+          this.emit(...entry);
+          this.emit(EV_ALL, ...entry);
+          this._pendingUnlinks.delete(path);
+        });
+      }, typeof opts.atomic === 'number' ? opts.atomic : 100);
+      return this;
+    }
+    if (event === EV_ADD && this._pendingUnlinks.has(path)) {
+      event = args[0] = EV_CHANGE;
+      this._pendingUnlinks.delete(path);
+    }
+  }
+
+  if (awf && (event === EV_ADD || event === EV_CHANGE) && this._readyEmitted) {
+    const awfEmit = (err, stats) => {
+      if (err) {
+        event = args[0] = EV_ERROR;
+        args[1] = err;
+        this.emitWithAll(event, args);
+      } else if (stats) {
+        // if stats doesn't exist the file must have been deleted
+        if (args.length > 2) {
+          args[2] = stats;
+        } else {
+          args.push(stats);
+        }
+        this.emitWithAll(event, args);
+      }
+    };
+
+    this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);
+    return this;
+  }
+
+  if (event === EV_CHANGE) {
+    const isThrottled = !this._throttle(EV_CHANGE, path, 50);
+    if (isThrottled) return this;
+  }
+
+  if (opts.alwaysStat && val1 === undefined &&
+    (event === EV_ADD || event === EV_ADD_DIR || event === EV_CHANGE)
+  ) {
+    const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;
+    let stats;
+    try {
+      stats = await stat(fullPath);
+    } catch (err) {}
+    // Suppress event when fs_stat fails, to avoid sending undefined 'stat'
+    if (!stats || this.closed) return;
+    args.push(stats);
+  }
+  this.emitWithAll(event, args);
+
+  return this;
+}
+
+/**
+ * Common handler for errors
+ * @param {Error} error
+ * @returns {Error|Boolean} The error if defined, otherwise the value of the FSWatcher instance's `closed` flag
+ */
+_handleError(error) {
+  const code = error && error.code;
+  if (error && code !== 'ENOENT' && code !== 'ENOTDIR' &&
+    (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))
+  ) {
+    this.emit(EV_ERROR, error);
+  }
+  return error || this.closed;
+}
+
+/**
+ * Helper utility for throttling
+ * @param {ThrottleType} actionType type being throttled
+ * @param {Path} path being acted upon
+ * @param {Number} timeout duration of time to suppress duplicate actions
+ * @returns {Object|false} tracking object or false if action should be suppressed
+ */
+_throttle(actionType, path, timeout) {
+  if (!this._throttled.has(actionType)) {
+    this._throttled.set(actionType, new Map());
+  }
+
+  /** @type {Map<Path, Object>} */
+  const action = this._throttled.get(actionType);
+  /** @type {Object} */
+  const actionPath = action.get(path);
+
+  if (actionPath) {
+    actionPath.count++;
+    return false;
+  }
+
+  let timeoutObject;
+  const clear = () => {
+    const item = action.get(path);
+    const count = item ? item.count : 0;
+    action.delete(path);
+    clearTimeout(timeoutObject);
+    if (item) clearTimeout(item.timeoutObject);
+    return count;
+  };
+  timeoutObject = setTimeout(clear, timeout);
+  const thr = {timeoutObject, clear, count: 0};
+  action.set(path, thr);
+  return thr;
+}
+
+_incrReadyCount() {
+  return this._readyCount++;
+}
+
+/**
+ * Awaits write operation to finish.
+ * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.
+ * @param {Path} path being acted upon
+ * @param {Number} threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished
+ * @param {EventName} event
+ * @param {Function} awfEmit Callback to be called when ready for event to be emitted.
+ */
+_awaitWriteFinish(path, threshold, event, awfEmit) {
+  let timeoutHandler;
+
+  let fullPath = path;
+  if (this.options.cwd && !sysPath.isAbsolute(path)) {
+    fullPath = sysPath.join(this.options.cwd, path);
+  }
+
+  const now = new Date();
+
+  const awaitWriteFinish = (prevStat) => {
+    fs.stat(fullPath, (err, curStat) => {
+      if (err || !this._pendingWrites.has(path)) {
+        if (err && err.code !== 'ENOENT') awfEmit(err);
+        return;
+      }
+
+      const now = Number(new Date());
+
+      if (prevStat && curStat.size !== prevStat.size) {
+        this._pendingWrites.get(path).lastChange = now;
+      }
+      const pw = this._pendingWrites.get(path);
+      const df = now - pw.lastChange;
+
+      if (df >= threshold) {
+        this._pendingWrites.delete(path);
+        awfEmit(undefined, curStat);
+      } else {
+        timeoutHandler = setTimeout(
+          awaitWriteFinish,
+          this.options.awaitWriteFinish.pollInterval,
+          curStat
+        );
+      }
+    });
+  };
+
+  if (!this._pendingWrites.has(path)) {
+    this._pendingWrites.set(path, {
+      lastChange: now,
+      cancelWait: () => {
+        this._pendingWrites.delete(path);
+        clearTimeout(timeoutHandler);
+        return event;
+      }
+    });
+    timeoutHandler = setTimeout(
+      awaitWriteFinish,
+      this.options.awaitWriteFinish.pollInterval
+    );
+  }
+}
+
+_getGlobIgnored() {
+  return [...this._ignoredPaths.values()];
+}
+
+/**
+ * Determines whether user has asked to ignore this path.
+ * @param {Path} path filepath or dir
+ * @param {fs.Stats=} stats result of fs.stat
+ * @returns {Boolean}
+ */
+_isIgnored(path, stats) {
+  if (this.options.atomic && DOT_RE.test(path)) return true;
+  if (!this._userIgnored) {
+    const {cwd} = this.options;
+    const ign = this.options.ignored;
+
+    const ignored = ign && ign.map(normalizeIgnored(cwd));
+    const paths = arrify(ignored)
+      .filter((path) => typeof path === STRING_TYPE && !isGlob(path))
+      .map((path) => path + SLASH_GLOBSTAR);
+    const list = this._getGlobIgnored().map(normalizeIgnored(cwd)).concat(ignored, paths);
+    this._userIgnored = anymatch(list, undefined, ANYMATCH_OPTS);
+  }
+
+  return this._userIgnored([path, stats]);
+}
+
+_isntIgnored(path, stat) {
+  return !this._isIgnored(path, stat);
+}
+
+/**
+ * Provides a set of common helpers and properties relating to symlink and glob handling.
+ * @param {Path} path file, directory, or glob pattern being watched
+ * @param {Number=} depth at any depth > 0, this isn't a glob
+ * @returns {WatchHelper} object containing helpers for this path
+ */
+_getWatchHelpers(path, depth) {
+  const watchPath = depth || this.options.disableGlobbing || !isGlob(path) ? path : globParent(path);
+  const follow = this.options.followSymlinks;
+
+  return new WatchHelper(path, watchPath, follow, this);
+}
+
+// Directory helpers
+// -----------------
+
+/**
+ * Provides directory tracking objects
+ * @param {String} directory path of the directory
+ * @returns {DirEntry} the directory's tracking object
+ */
+_getWatchedDir(directory) {
+  if (!this._boundRemove) this._boundRemove = this._remove.bind(this);
+  const dir = sysPath.resolve(directory);
+  if (!this._watched.has(dir)) this._watched.set(dir, new DirEntry(dir, this._boundRemove));
+  return this._watched.get(dir);
+}
+
+// File helpers
+// ------------
+
+/**
+ * Check for read permissions.
+ * Based on this answer on SO: https://stackoverflow.com/a/11781404/1358405
+ * @param {fs.Stats} stats - object, result of fs_stat
+ * @returns {Boolean} indicates whether the file can be read
+*/
+_hasReadPermissions(stats) {
+  if (this.options.ignorePermissionErrors) return true;
+
+  // stats.mode may be bigint
+  const md = stats && Number.parseInt(stats.mode, 10);
+  const st = md & 0o777;
+  const it = Number.parseInt(st.toString(8)[0], 10);
+  return Boolean(4 & it);
+}
+
+/**
+ * Handles emitting unlink events for
+ * files and directories, and via recursion, for
+ * files and directories within directories that are unlinked
+ * @param {String} directory within which the following item is located
+ * @param {String} item      base path of item/directory
+ * @returns {void}
+*/
+_remove(directory, item, isDirectory) {
+  // if what is being deleted is a directory, get that directory's paths
+  // for recursive deleting and cleaning of watched object
+  // if it is not a directory, nestedDirectoryChildren will be empty array
+  const path = sysPath.join(directory, item);
+  const fullPath = sysPath.resolve(path);
+  isDirectory = isDirectory != null
+    ? isDirectory
+    : this._watched.has(path) || this._watched.has(fullPath);
+
+  // prevent duplicate handling in case of arriving here nearly simultaneously
+  // via multiple paths (such as _handleFile and _handleDir)
+  if (!this._throttle('remove', path, 100)) return;
+
+  // if the only watched file is removed, watch for its return
+  if (!isDirectory && !this.options.useFsEvents && this._watched.size === 1) {
+    this.add(directory, item, true);
+  }
+
+  // This will create a new entry in the watched object in either case
+  // so we got to do the directory check beforehand
+  const wp = this._getWatchedDir(path);
+  const nestedDirectoryChildren = wp.getChildren();
+
+  // Recursively remove children directories / files.
+  nestedDirectoryChildren.forEach(nested => this._remove(path, nested));
+
+  // Check if item was on the watched list and remove it
+  const parent = this._getWatchedDir(directory);
+  const wasTracked = parent.has(item);
+  parent.remove(item);
+
+  // Fixes issue #1042 -> Relative paths were detected and added as symlinks
+  // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),
+  // but never removed from the map in case the path was deleted.
+  // This leads to an incorrect state if the path was recreated:
+  // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553
+  if (this._symlinkPaths.has(fullPath)) {
+    this._symlinkPaths.delete(fullPath);
+  }
+
+  // If we wait for this file to be fully written, cancel the wait.
+  let relPath = path;
+  if (this.options.cwd) relPath = sysPath.relative(this.options.cwd, path);
+  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
+    const event = this._pendingWrites.get(relPath).cancelWait();
+    if (event === EV_ADD) return;
+  }
+
+  // The Entry will either be a directory that just got removed
+  // or a bogus entry to a file, in either case we have to remove it
+  this._watched.delete(path);
+  this._watched.delete(fullPath);
+  const eventName = isDirectory ? EV_UNLINK_DIR : EV_UNLINK;
+  if (wasTracked && !this._isIgnored(path)) this._emit(eventName, path);
+
+  // Avoid conflicts if we later create another file with the same name
+  if (!this.options.useFsEvents) {
+    this._closePath(path);
+  }
+}
+
+/**
+ * Closes all watchers for a path
+ * @param {Path} path
+ */
+_closePath(path) {
+  this._closeFile(path)
+  const dir = sysPath.dirname(path);
+  this._getWatchedDir(dir).remove(sysPath.basename(path));
+}
+
+/**
+ * Closes only file-specific watchers
+ * @param {Path} path
+ */
+_closeFile(path) {
+  const closers = this._closers.get(path);
+  if (!closers) return;
+  closers.forEach(closer => closer());
+  this._closers.delete(path);
+}
+
+/**
+ *
+ * @param {Path} path
+ * @param {Function} closer
+ */
+_addPathCloser(path, closer) {
+  if (!closer) return;
+  let list = this._closers.get(path);
+  if (!list) {
+    list = [];
+    this._closers.set(path, list);
+  }
+  list.push(closer);
+}
+
+_readdirp(root, opts) {
+  if (this.closed) return;
+  const options = {type: EV_ALL, alwaysStat: true, lstat: true, ...opts};
+  let stream = readdirp(root, options);
+  this._streams.add(stream);
+  stream.once(STR_CLOSE, () => {
+    stream = undefined;
+  });
+  stream.once(STR_END, () => {
+    if (stream) {
+      this._streams.delete(stream);
+      stream = undefined;
+    }
+  });
+  return stream;
+}
+
+}
+
+// Export FSWatcher class
+exports.FSWatcher = FSWatcher;
+
+/**
+ * Instantiates watcher with paths to be tracked.
+ * @param {String|Array<String>} paths file/directory paths and/or globs
+ * @param {Object=} options chokidar opts
+ * @returns an instance of FSWatcher for chaining.
+ */
+const watch = (paths, options) => {
+  const watcher = new FSWatcher(options);
+  watcher.add(paths);
+  return watcher;
+};
+
+exports.watch = watch;

+ 66 - 0
node_modules/chokidar/lib/constants.js

@@ -0,0 +1,66 @@
+'use strict';
+
+const {sep} = require('path');
+const {platform} = process;
+const os = require('os');
+
+exports.EV_ALL = 'all';
+exports.EV_READY = 'ready';
+exports.EV_ADD = 'add';
+exports.EV_CHANGE = 'change';
+exports.EV_ADD_DIR = 'addDir';
+exports.EV_UNLINK = 'unlink';
+exports.EV_UNLINK_DIR = 'unlinkDir';
+exports.EV_RAW = 'raw';
+exports.EV_ERROR = 'error';
+
+exports.STR_DATA = 'data';
+exports.STR_END = 'end';
+exports.STR_CLOSE = 'close';
+
+exports.FSEVENT_CREATED = 'created';
+exports.FSEVENT_MODIFIED = 'modified';
+exports.FSEVENT_DELETED = 'deleted';
+exports.FSEVENT_MOVED = 'moved';
+exports.FSEVENT_CLONED = 'cloned';
+exports.FSEVENT_UNKNOWN = 'unknown';
+exports.FSEVENT_FLAG_MUST_SCAN_SUBDIRS = 1;
+exports.FSEVENT_TYPE_FILE = 'file';
+exports.FSEVENT_TYPE_DIRECTORY = 'directory';
+exports.FSEVENT_TYPE_SYMLINK = 'symlink';
+
+exports.KEY_LISTENERS = 'listeners';
+exports.KEY_ERR = 'errHandlers';
+exports.KEY_RAW = 'rawEmitters';
+exports.HANDLER_KEYS = [exports.KEY_LISTENERS, exports.KEY_ERR, exports.KEY_RAW];
+
+exports.DOT_SLASH = `.${sep}`;
+
+exports.BACK_SLASH_RE = /\\/g;
+exports.DOUBLE_SLASH_RE = /\/\//;
+exports.SLASH_OR_BACK_SLASH_RE = /[/\\]/;
+exports.DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
+exports.REPLACER_RE = /^\.[/\\]/;
+
+exports.SLASH = '/';
+exports.SLASH_SLASH = '//';
+exports.BRACE_START = '{';
+exports.BANG = '!';
+exports.ONE_DOT = '.';
+exports.TWO_DOTS = '..';
+exports.STAR = '*';
+exports.GLOBSTAR = '**';
+exports.ROOT_GLOBSTAR = '/**/*';
+exports.SLASH_GLOBSTAR = '/**';
+exports.DIR_SUFFIX = 'Dir';
+exports.ANYMATCH_OPTS = {dot: true};
+exports.STRING_TYPE = 'string';
+exports.FUNCTION_TYPE = 'function';
+exports.EMPTY_STR = '';
+exports.EMPTY_FN = () => {};
+exports.IDENTITY_FN = val => val;
+
+exports.isWindows = platform === 'win32';
+exports.isMacos = platform === 'darwin';
+exports.isLinux = platform === 'linux';
+exports.isIBMi = os.type() === 'OS400';

+ 526 - 0
node_modules/chokidar/lib/fsevents-handler.js

@@ -0,0 +1,526 @@
+'use strict';
+
+const fs = require('fs');
+const sysPath = require('path');
+const { promisify } = require('util');
+
+let fsevents;
+try {
+  fsevents = require('fsevents');
+} catch (error) {
+  if (process.env.CHOKIDAR_PRINT_FSEVENTS_REQUIRE_ERROR) console.error(error);
+}
+
+if (fsevents) {
+  // TODO: real check
+  const mtch = process.version.match(/v(\d+)\.(\d+)/);
+  if (mtch && mtch[1] && mtch[2]) {
+    const maj = Number.parseInt(mtch[1], 10);
+    const min = Number.parseInt(mtch[2], 10);
+    if (maj === 8 && min < 16) {
+      fsevents = undefined;
+    }
+  }
+}
+
+const {
+  EV_ADD,
+  EV_CHANGE,
+  EV_ADD_DIR,
+  EV_UNLINK,
+  EV_ERROR,
+  STR_DATA,
+  STR_END,
+  FSEVENT_CREATED,
+  FSEVENT_MODIFIED,
+  FSEVENT_DELETED,
+  FSEVENT_MOVED,
+  // FSEVENT_CLONED,
+  FSEVENT_UNKNOWN,
+  FSEVENT_FLAG_MUST_SCAN_SUBDIRS,
+  FSEVENT_TYPE_FILE,
+  FSEVENT_TYPE_DIRECTORY,
+  FSEVENT_TYPE_SYMLINK,
+
+  ROOT_GLOBSTAR,
+  DIR_SUFFIX,
+  DOT_SLASH,
+  FUNCTION_TYPE,
+  EMPTY_FN,
+  IDENTITY_FN
+} = require('./constants');
+
+const Depth = (value) => isNaN(value) ? {} : {depth: value};
+
+const stat = promisify(fs.stat);
+const lstat = promisify(fs.lstat);
+const realpath = promisify(fs.realpath);
+
+const statMethods = { stat, lstat };
+
+/**
+ * @typedef {String} Path
+ */
+
+/**
+ * @typedef {Object} FsEventsWatchContainer
+ * @property {Set<Function>} listeners
+ * @property {Function} rawEmitter
+ * @property {{stop: Function}} watcher
+ */
+
+// fsevents instance helper functions
+/**
+ * Object to hold per-process fsevents instances (may be shared across chokidar FSWatcher instances)
+ * @type {Map<Path,FsEventsWatchContainer>}
+ */
+const FSEventsWatchers = new Map();
+
+// Threshold of duplicate path prefixes at which to start
+// consolidating going forward
+const consolidateThreshhold = 10;
+
+const wrongEventFlags = new Set([
+  69888, 70400, 71424, 72704, 73472, 131328, 131840, 262912
+]);
+
+/**
+ * Instantiates the fsevents interface
+ * @param {Path} path path to be watched
+ * @param {Function} callback called when fsevents is bound and ready
+ * @returns {{stop: Function}} new fsevents instance
+ */
+const createFSEventsInstance = (path, callback) => {
+  const stop = fsevents.watch(path, callback);
+  return {stop};
+};
+
+/**
+ * Instantiates the fsevents interface or binds listeners to an existing one covering
+ * the same file tree.
+ * @param {Path} path           - to be watched
+ * @param {Path} realPath       - real path for symlinks
+ * @param {Function} listener   - called when fsevents emits events
+ * @param {Function} rawEmitter - passes data to listeners of the 'raw' event
+ * @returns {Function} closer
+ */
+function setFSEventsListener(path, realPath, listener, rawEmitter) {
+  let watchPath = sysPath.extname(realPath) ? sysPath.dirname(realPath) : realPath;
+
+  const parentPath = sysPath.dirname(watchPath);
+  let cont = FSEventsWatchers.get(watchPath);
+
+  // If we've accumulated a substantial number of paths that
+  // could have been consolidated by watching one directory
+  // above the current one, create a watcher on the parent
+  // path instead, so that we do consolidate going forward.
+  if (couldConsolidate(parentPath)) {
+    watchPath = parentPath;
+  }
+
+  const resolvedPath = sysPath.resolve(path);
+  const hasSymlink = resolvedPath !== realPath;
+
+  const filteredListener = (fullPath, flags, info) => {
+    if (hasSymlink) fullPath = fullPath.replace(realPath, resolvedPath);
+    if (
+      fullPath === resolvedPath ||
+      !fullPath.indexOf(resolvedPath + sysPath.sep)
+    ) listener(fullPath, flags, info);
+  };
+
+  // check if there is already a watcher on a parent path
+  // modifies `watchPath` to the parent path when it finds a match
+  let watchedParent = false;
+  for (const watchedPath of FSEventsWatchers.keys()) {
+    if (realPath.indexOf(sysPath.resolve(watchedPath) + sysPath.sep) === 0) {
+      watchPath = watchedPath;
+      cont = FSEventsWatchers.get(watchPath);
+      watchedParent = true;
+      break;
+    }
+  }
+
+  if (cont || watchedParent) {
+    cont.listeners.add(filteredListener);
+  } else {
+    cont = {
+      listeners: new Set([filteredListener]),
+      rawEmitter,
+      watcher: createFSEventsInstance(watchPath, (fullPath, flags) => {
+        if (!cont.listeners.size) return;
+        if (flags & FSEVENT_FLAG_MUST_SCAN_SUBDIRS) return;
+        const info = fsevents.getInfo(fullPath, flags);
+        cont.listeners.forEach(list => {
+          list(fullPath, flags, info);
+        });
+
+        cont.rawEmitter(info.event, fullPath, info);
+      })
+    };
+    FSEventsWatchers.set(watchPath, cont);
+  }
+
+  // removes this instance's listeners and closes the underlying fsevents
+  // instance if there are no more listeners left
+  return () => {
+    const lst = cont.listeners;
+
+    lst.delete(filteredListener);
+    if (!lst.size) {
+      FSEventsWatchers.delete(watchPath);
+      if (cont.watcher) return cont.watcher.stop().then(() => {
+        cont.rawEmitter = cont.watcher = undefined;
+        Object.freeze(cont);
+      });
+    }
+  };
+}
+
+// Decide whether or not we should start a new higher-level
+// parent watcher
+const couldConsolidate = (path) => {
+  let count = 0;
+  for (const watchPath of FSEventsWatchers.keys()) {
+    if (watchPath.indexOf(path) === 0) {
+      count++;
+      if (count >= consolidateThreshhold) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+};
+
+// returns boolean indicating whether fsevents can be used
+const canUse = () => fsevents && FSEventsWatchers.size < 128;
+
+// determines subdirectory traversal levels from root to path
+const calcDepth = (path, root) => {
+  let i = 0;
+  while (!path.indexOf(root) && (path = sysPath.dirname(path)) !== root) i++;
+  return i;
+};
+
+// returns boolean indicating whether the fsevents' event info has the same type
+// as the one returned by fs.stat
+const sameTypes = (info, stats) => (
+  info.type === FSEVENT_TYPE_DIRECTORY && stats.isDirectory() ||
+  info.type === FSEVENT_TYPE_SYMLINK && stats.isSymbolicLink() ||
+  info.type === FSEVENT_TYPE_FILE && stats.isFile()
+)
+
+/**
+ * @mixin
+ */
+class FsEventsHandler {
+
+/**
+ * @param {import('../index').FSWatcher} fsw
+ */
+constructor(fsw) {
+  this.fsw = fsw;
+}
+checkIgnored(path, stats) {
+  const ipaths = this.fsw._ignoredPaths;
+  if (this.fsw._isIgnored(path, stats)) {
+    ipaths.add(path);
+    if (stats && stats.isDirectory()) {
+      ipaths.add(path + ROOT_GLOBSTAR);
+    }
+    return true;
+  }
+
+  ipaths.delete(path);
+  ipaths.delete(path + ROOT_GLOBSTAR);
+}
+
+addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
+  const event = watchedDir.has(item) ? EV_CHANGE : EV_ADD;
+  this.handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts);
+}
+
+async checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts) {
+  try {
+    const stats = await stat(path)
+    if (this.fsw.closed) return;
+    if (sameTypes(info, stats)) {
+      this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
+    } else {
+      this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts);
+    }
+  } catch (error) {
+    if (error.code === 'EACCES') {
+      this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
+    } else {
+      this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts);
+    }
+  }
+}
+
+handleEvent(event, path, fullPath, realPath, parent, watchedDir, item, info, opts) {
+  if (this.fsw.closed || this.checkIgnored(path)) return;
+
+  if (event === EV_UNLINK) {
+    const isDirectory = info.type === FSEVENT_TYPE_DIRECTORY
+    // suppress unlink events on never before seen files
+    if (isDirectory || watchedDir.has(item)) {
+      this.fsw._remove(parent, item, isDirectory);
+    }
+  } else {
+    if (event === EV_ADD) {
+      // track new directories
+      if (info.type === FSEVENT_TYPE_DIRECTORY) this.fsw._getWatchedDir(path);
+
+      if (info.type === FSEVENT_TYPE_SYMLINK && opts.followSymlinks) {
+        // push symlinks back to the top of the stack to get handled
+        const curDepth = opts.depth === undefined ?
+          undefined : calcDepth(fullPath, realPath) + 1;
+        return this._addToFsEvents(path, false, true, curDepth);
+      }
+
+      // track new paths
+      // (other than symlinks being followed, which will be tracked soon)
+      this.fsw._getWatchedDir(parent).add(item);
+    }
+    /**
+     * @type {'add'|'addDir'|'unlink'|'unlinkDir'}
+     */
+    const eventName = info.type === FSEVENT_TYPE_DIRECTORY ? event + DIR_SUFFIX : event;
+    this.fsw._emit(eventName, path);
+    if (eventName === EV_ADD_DIR) this._addToFsEvents(path, false, true);
+  }
+}
+
+/**
+ * Handle symlinks encountered during directory scan
+ * @param {String} watchPath  - file/dir path to be watched with fsevents
+ * @param {String} realPath   - real path (in case of symlinks)
+ * @param {Function} transform  - path transformer
+ * @param {Function} globFilter - path filter in case a glob pattern was provided
+ * @returns {Function} closer for the watcher instance
+*/
+_watchWithFsEvents(watchPath, realPath, transform, globFilter) {
+  if (this.fsw.closed || this.fsw._isIgnored(watchPath)) return;
+  const opts = this.fsw.options;
+  const watchCallback = async (fullPath, flags, info) => {
+    if (this.fsw.closed) return;
+    if (
+      opts.depth !== undefined &&
+      calcDepth(fullPath, realPath) > opts.depth
+    ) return;
+    const path = transform(sysPath.join(
+      watchPath, sysPath.relative(watchPath, fullPath)
+    ));
+    if (globFilter && !globFilter(path)) return;
+    // ensure directories are tracked
+    const parent = sysPath.dirname(path);
+    const item = sysPath.basename(path);
+    const watchedDir = this.fsw._getWatchedDir(
+      info.type === FSEVENT_TYPE_DIRECTORY ? path : parent
+    );
+
+    // correct for wrong events emitted
+    if (wrongEventFlags.has(flags) || info.event === FSEVENT_UNKNOWN) {
+      if (typeof opts.ignored === FUNCTION_TYPE) {
+        let stats;
+        try {
+          stats = await stat(path);
+        } catch (error) {}
+        if (this.fsw.closed) return;
+        if (this.checkIgnored(path, stats)) return;
+        if (sameTypes(info, stats)) {
+          this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
+        } else {
+          this.handleEvent(EV_UNLINK, path, fullPath, realPath, parent, watchedDir, item, info, opts);
+        }
+      } else {
+        this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
+      }
+    } else {
+      switch (info.event) {
+      case FSEVENT_CREATED:
+      case FSEVENT_MODIFIED:
+        return this.addOrChange(path, fullPath, realPath, parent, watchedDir, item, info, opts);
+      case FSEVENT_DELETED:
+      case FSEVENT_MOVED:
+        return this.checkExists(path, fullPath, realPath, parent, watchedDir, item, info, opts);
+      }
+    }
+  };
+
+  const closer = setFSEventsListener(
+    watchPath,
+    realPath,
+    watchCallback,
+    this.fsw._emitRaw
+  );
+
+  this.fsw._emitReady();
+  return closer;
+}
+
+/**
+ * Handle symlinks encountered during directory scan
+ * @param {String} linkPath path to symlink
+ * @param {String} fullPath absolute path to the symlink
+ * @param {Function} transform pre-existing path transformer
+ * @param {Number} curDepth level of subdirectories traversed to where symlink is
+ * @returns {Promise<void>}
+ */
+async _handleFsEventsSymlink(linkPath, fullPath, transform, curDepth) {
+  // don't follow the same symlink more than once
+  if (this.fsw.closed || this.fsw._symlinkPaths.has(fullPath)) return;
+
+  this.fsw._symlinkPaths.set(fullPath, true);
+  this.fsw._incrReadyCount();
+
+  try {
+    const linkTarget = await realpath(linkPath);
+    if (this.fsw.closed) return;
+    if (this.fsw._isIgnored(linkTarget)) {
+      return this.fsw._emitReady();
+    }
+
+    this.fsw._incrReadyCount();
+
+    // add the linkTarget for watching with a wrapper for transform
+    // that causes emitted paths to incorporate the link's path
+    this._addToFsEvents(linkTarget || linkPath, (path) => {
+      let aliasedPath = linkPath;
+      if (linkTarget && linkTarget !== DOT_SLASH) {
+        aliasedPath = path.replace(linkTarget, linkPath);
+      } else if (path !== DOT_SLASH) {
+        aliasedPath = sysPath.join(linkPath, path);
+      }
+      return transform(aliasedPath);
+    }, false, curDepth);
+  } catch(error) {
+    if (this.fsw._handleError(error)) {
+      return this.fsw._emitReady();
+    }
+  }
+}
+
+/**
+ *
+ * @param {Path} newPath
+ * @param {fs.Stats} stats
+ */
+emitAdd(newPath, stats, processPath, opts, forceAdd) {
+  const pp = processPath(newPath);
+  const isDir = stats.isDirectory();
+  const dirObj = this.fsw._getWatchedDir(sysPath.dirname(pp));
+  const base = sysPath.basename(pp);
+
+  // ensure empty dirs get tracked
+  if (isDir) this.fsw._getWatchedDir(pp);
+  if (dirObj.has(base)) return;
+  dirObj.add(base);
+
+  if (!opts.ignoreInitial || forceAdd === true) {
+    this.fsw._emit(isDir ? EV_ADD_DIR : EV_ADD, pp, stats);
+  }
+}
+
+initWatch(realPath, path, wh, processPath) {
+  if (this.fsw.closed) return;
+  const closer = this._watchWithFsEvents(
+    wh.watchPath,
+    sysPath.resolve(realPath || wh.watchPath),
+    processPath,
+    wh.globFilter
+  );
+  this.fsw._addPathCloser(path, closer);
+}
+
+/**
+ * Handle added path with fsevents
+ * @param {String} path file/dir path or glob pattern
+ * @param {Function|Boolean=} transform converts working path to what the user expects
+ * @param {Boolean=} forceAdd ensure add is emitted
+ * @param {Number=} priorDepth Level of subdirectories already traversed.
+ * @returns {Promise<void>}
+ */
+async _addToFsEvents(path, transform, forceAdd, priorDepth) {
+  if (this.fsw.closed) {
+    return;
+  }
+  const opts = this.fsw.options;
+  const processPath = typeof transform === FUNCTION_TYPE ? transform : IDENTITY_FN;
+
+  const wh = this.fsw._getWatchHelpers(path);
+
+  // evaluate what is at the path we're being asked to watch
+  try {
+    const stats = await statMethods[wh.statMethod](wh.watchPath);
+    if (this.fsw.closed) return;
+    if (this.fsw._isIgnored(wh.watchPath, stats)) {
+      throw null;
+    }
+    if (stats.isDirectory()) {
+      // emit addDir unless this is a glob parent
+      if (!wh.globFilter) this.emitAdd(processPath(path), stats, processPath, opts, forceAdd);
+
+      // don't recurse further if it would exceed depth setting
+      if (priorDepth && priorDepth > opts.depth) return;
+
+      // scan the contents of the dir
+      this.fsw._readdirp(wh.watchPath, {
+        fileFilter: entry => wh.filterPath(entry),
+        directoryFilter: entry => wh.filterDir(entry),
+        ...Depth(opts.depth - (priorDepth || 0))
+      }).on(STR_DATA, (entry) => {
+        // need to check filterPath on dirs b/c filterDir is less restrictive
+        if (this.fsw.closed) {
+          return;
+        }
+        if (entry.stats.isDirectory() && !wh.filterPath(entry)) return;
+
+        const joinedPath = sysPath.join(wh.watchPath, entry.path);
+        const {fullPath} = entry;
+
+        if (wh.followSymlinks && entry.stats.isSymbolicLink()) {
+          // preserve the current depth here since it can't be derived from
+          // real paths past the symlink
+          const curDepth = opts.depth === undefined ?
+            undefined : calcDepth(joinedPath, sysPath.resolve(wh.watchPath)) + 1;
+
+          this._handleFsEventsSymlink(joinedPath, fullPath, processPath, curDepth);
+        } else {
+          this.emitAdd(joinedPath, entry.stats, processPath, opts, forceAdd);
+        }
+      }).on(EV_ERROR, EMPTY_FN).on(STR_END, () => {
+        this.fsw._emitReady();
+      });
+    } else {
+      this.emitAdd(wh.watchPath, stats, processPath, opts, forceAdd);
+      this.fsw._emitReady();
+    }
+  } catch (error) {
+    if (!error || this.fsw._handleError(error)) {
+      // TODO: Strange thing: "should not choke on an ignored watch path" will be failed without 2 ready calls -__-
+      this.fsw._emitReady();
+      this.fsw._emitReady();
+    }
+  }
+
+  if (opts.persistent && forceAdd !== true) {
+    if (typeof transform === FUNCTION_TYPE) {
+      // realpath has already been resolved
+      this.initWatch(undefined, path, wh, processPath);
+    } else {
+      let realPath;
+      try {
+        realPath = await realpath(wh.watchPath);
+      } catch (e) {}
+      this.initWatch(realPath, path, wh, processPath);
+    }
+  }
+}
+
+}
+
+module.exports = FsEventsHandler;
+module.exports.canUse = canUse;

+ 654 - 0
node_modules/chokidar/lib/nodefs-handler.js

@@ -0,0 +1,654 @@
+'use strict';
+
+const fs = require('fs');
+const sysPath = require('path');
+const { promisify } = require('util');
+const isBinaryPath = require('is-binary-path');
+const {
+  isWindows,
+  isLinux,
+  EMPTY_FN,
+  EMPTY_STR,
+  KEY_LISTENERS,
+  KEY_ERR,
+  KEY_RAW,
+  HANDLER_KEYS,
+  EV_CHANGE,
+  EV_ADD,
+  EV_ADD_DIR,
+  EV_ERROR,
+  STR_DATA,
+  STR_END,
+  BRACE_START,
+  STAR
+} = require('./constants');
+
+const THROTTLE_MODE_WATCH = 'watch';
+
+const open = promisify(fs.open);
+const stat = promisify(fs.stat);
+const lstat = promisify(fs.lstat);
+const close = promisify(fs.close);
+const fsrealpath = promisify(fs.realpath);
+
+const statMethods = { lstat, stat };
+
+// TODO: emit errors properly. Example: EMFILE on Macos.
+const foreach = (val, fn) => {
+  if (val instanceof Set) {
+    val.forEach(fn);
+  } else {
+    fn(val);
+  }
+};
+
+const addAndConvert = (main, prop, item) => {
+  let container = main[prop];
+  if (!(container instanceof Set)) {
+    main[prop] = container = new Set([container]);
+  }
+  container.add(item);
+};
+
+const clearItem = cont => key => {
+  const set = cont[key];
+  if (set instanceof Set) {
+    set.clear();
+  } else {
+    delete cont[key];
+  }
+};
+
+const delFromSet = (main, prop, item) => {
+  const container = main[prop];
+  if (container instanceof Set) {
+    container.delete(item);
+  } else if (container === item) {
+    delete main[prop];
+  }
+};
+
+const isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
+
+/**
+ * @typedef {String} Path
+ */
+
+// fs_watch helpers
+
+// object to hold per-process fs_watch instances
+// (may be shared across chokidar FSWatcher instances)
+
+/**
+ * @typedef {Object} FsWatchContainer
+ * @property {Set} listeners
+ * @property {Set} errHandlers
+ * @property {Set} rawEmitters
+ * @property {fs.FSWatcher=} watcher
+ * @property {Boolean=} watcherUnusable
+ */
+
+/**
+ * @type {Map<String,FsWatchContainer>}
+ */
+const FsWatchInstances = new Map();
+
+/**
+ * Instantiates the fs_watch interface
+ * @param {String} path to be watched
+ * @param {Object} options to be passed to fs_watch
+ * @param {Function} listener main event handler
+ * @param {Function} errHandler emits info about errors
+ * @param {Function} emitRaw emits raw event data
+ * @returns {fs.FSWatcher} new fsevents instance
+ */
+function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
+  const handleEvent = (rawEvent, evPath) => {
+    listener(path);
+    emitRaw(rawEvent, evPath, {watchedPath: path});
+
+    // emit based on events occurring for files from a directory's watcher in
+    // case the file's watcher misses it (and rely on throttling to de-dupe)
+    if (evPath && path !== evPath) {
+      fsWatchBroadcast(
+        sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath)
+      );
+    }
+  };
+  try {
+    return fs.watch(path, options, handleEvent);
+  } catch (error) {
+    errHandler(error);
+  }
+}
+
+/**
+ * Helper for passing fs_watch event data to a collection of listeners
+ * @param {Path} fullPath absolute path bound to fs_watch instance
+ * @param {String} type listener type
+ * @param {*=} val1 arguments to be passed to listeners
+ * @param {*=} val2
+ * @param {*=} val3
+ */
+const fsWatchBroadcast = (fullPath, type, val1, val2, val3) => {
+  const cont = FsWatchInstances.get(fullPath);
+  if (!cont) return;
+  foreach(cont[type], (listener) => {
+    listener(val1, val2, val3);
+  });
+};
+
+/**
+ * Instantiates the fs_watch interface or binds listeners
+ * to an existing one covering the same file system entry
+ * @param {String} path
+ * @param {String} fullPath absolute path
+ * @param {Object} options to be passed to fs_watch
+ * @param {Object} handlers container for event listener functions
+ */
+const setFsWatchListener = (path, fullPath, options, handlers) => {
+  const {listener, errHandler, rawEmitter} = handlers;
+  let cont = FsWatchInstances.get(fullPath);
+
+  /** @type {fs.FSWatcher=} */
+  let watcher;
+  if (!options.persistent) {
+    watcher = createFsWatchInstance(
+      path, options, listener, errHandler, rawEmitter
+    );
+    return watcher.close.bind(watcher);
+  }
+  if (cont) {
+    addAndConvert(cont, KEY_LISTENERS, listener);
+    addAndConvert(cont, KEY_ERR, errHandler);
+    addAndConvert(cont, KEY_RAW, rawEmitter);
+  } else {
+    watcher = createFsWatchInstance(
+      path,
+      options,
+      fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
+      errHandler, // no need to use broadcast here
+      fsWatchBroadcast.bind(null, fullPath, KEY_RAW)
+    );
+    if (!watcher) return;
+    watcher.on(EV_ERROR, async (error) => {
+      const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
+      cont.watcherUnusable = true; // documented since Node 10.4.1
+      // Workaround for https://github.com/joyent/node/issues/4337
+      if (isWindows && error.code === 'EPERM') {
+        try {
+          const fd = await open(path, 'r');
+          await close(fd);
+          broadcastErr(error);
+        } catch (err) {}
+      } else {
+        broadcastErr(error);
+      }
+    });
+    cont = {
+      listeners: listener,
+      errHandlers: errHandler,
+      rawEmitters: rawEmitter,
+      watcher
+    };
+    FsWatchInstances.set(fullPath, cont);
+  }
+  // const index = cont.listeners.indexOf(listener);
+
+  // removes this instance's listeners and closes the underlying fs_watch
+  // instance if there are no more listeners left
+  return () => {
+    delFromSet(cont, KEY_LISTENERS, listener);
+    delFromSet(cont, KEY_ERR, errHandler);
+    delFromSet(cont, KEY_RAW, rawEmitter);
+    if (isEmptySet(cont.listeners)) {
+      // Check to protect against issue gh-730.
+      // if (cont.watcherUnusable) {
+      cont.watcher.close();
+      // }
+      FsWatchInstances.delete(fullPath);
+      HANDLER_KEYS.forEach(clearItem(cont));
+      cont.watcher = undefined;
+      Object.freeze(cont);
+    }
+  };
+};
+
+// fs_watchFile helpers
+
+// object to hold per-process fs_watchFile instances
+// (may be shared across chokidar FSWatcher instances)
+const FsWatchFileInstances = new Map();
+
+/**
+ * Instantiates the fs_watchFile interface or binds listeners
+ * to an existing one covering the same file system entry
+ * @param {String} path to be watched
+ * @param {String} fullPath absolute path
+ * @param {Object} options options to be passed to fs_watchFile
+ * @param {Object} handlers container for event listener functions
+ * @returns {Function} closer
+ */
+const setFsWatchFileListener = (path, fullPath, options, handlers) => {
+  const {listener, rawEmitter} = handlers;
+  let cont = FsWatchFileInstances.get(fullPath);
+
+  /* eslint-disable no-unused-vars, prefer-destructuring */
+  let listeners = new Set();
+  let rawEmitters = new Set();
+
+  const copts = cont && cont.options;
+  if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
+    // "Upgrade" the watcher to persistence or a quicker interval.
+    // This creates some unlikely edge case issues if the user mixes
+    // settings in a very weird way, but solving for those cases
+    // doesn't seem worthwhile for the added complexity.
+    listeners = cont.listeners;
+    rawEmitters = cont.rawEmitters;
+    fs.unwatchFile(fullPath);
+    cont = undefined;
+  }
+
+  /* eslint-enable no-unused-vars, prefer-destructuring */
+
+  if (cont) {
+    addAndConvert(cont, KEY_LISTENERS, listener);
+    addAndConvert(cont, KEY_RAW, rawEmitter);
+  } else {
+    // TODO
+    // listeners.add(listener);
+    // rawEmitters.add(rawEmitter);
+    cont = {
+      listeners: listener,
+      rawEmitters: rawEmitter,
+      options,
+      watcher: fs.watchFile(fullPath, options, (curr, prev) => {
+        foreach(cont.rawEmitters, (rawEmitter) => {
+          rawEmitter(EV_CHANGE, fullPath, {curr, prev});
+        });
+        const currmtime = curr.mtimeMs;
+        if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
+          foreach(cont.listeners, (listener) => listener(path, curr));
+        }
+      })
+    };
+    FsWatchFileInstances.set(fullPath, cont);
+  }
+  // const index = cont.listeners.indexOf(listener);
+
+  // Removes this instance's listeners and closes the underlying fs_watchFile
+  // instance if there are no more listeners left.
+  return () => {
+    delFromSet(cont, KEY_LISTENERS, listener);
+    delFromSet(cont, KEY_RAW, rawEmitter);
+    if (isEmptySet(cont.listeners)) {
+      FsWatchFileInstances.delete(fullPath);
+      fs.unwatchFile(fullPath);
+      cont.options = cont.watcher = undefined;
+      Object.freeze(cont);
+    }
+  };
+};
+
+/**
+ * @mixin
+ */
+class NodeFsHandler {
+
+/**
+ * @param {import("../index").FSWatcher} fsW
+ */
+constructor(fsW) {
+  this.fsw = fsW;
+  this._boundHandleError = (error) => fsW._handleError(error);
+}
+
+/**
+ * Watch file for changes with fs_watchFile or fs_watch.
+ * @param {String} path to file or dir
+ * @param {Function} listener on fs change
+ * @returns {Function} closer for the watcher instance
+ */
+_watchWithNodeFs(path, listener) {
+  const opts = this.fsw.options;
+  const directory = sysPath.dirname(path);
+  const basename = sysPath.basename(path);
+  const parent = this.fsw._getWatchedDir(directory);
+  parent.add(basename);
+  const absolutePath = sysPath.resolve(path);
+  const options = {persistent: opts.persistent};
+  if (!listener) listener = EMPTY_FN;
+
+  let closer;
+  if (opts.usePolling) {
+    options.interval = opts.enableBinaryInterval && isBinaryPath(basename) ?
+      opts.binaryInterval : opts.interval;
+    closer = setFsWatchFileListener(path, absolutePath, options, {
+      listener,
+      rawEmitter: this.fsw._emitRaw
+    });
+  } else {
+    closer = setFsWatchListener(path, absolutePath, options, {
+      listener,
+      errHandler: this._boundHandleError,
+      rawEmitter: this.fsw._emitRaw
+    });
+  }
+  return closer;
+}
+
+/**
+ * Watch a file and emit add event if warranted.
+ * @param {Path} file Path
+ * @param {fs.Stats} stats result of fs_stat
+ * @param {Boolean} initialAdd was the file added at watch instantiation?
+ * @returns {Function} closer for the watcher instance
+ */
+_handleFile(file, stats, initialAdd) {
+  if (this.fsw.closed) {
+    return;
+  }
+  const dirname = sysPath.dirname(file);
+  const basename = sysPath.basename(file);
+  const parent = this.fsw._getWatchedDir(dirname);
+  // stats is always present
+  let prevStats = stats;
+
+  // if the file is already being watched, do nothing
+  if (parent.has(basename)) return;
+
+  const listener = async (path, newStats) => {
+    if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5)) return;
+    if (!newStats || newStats.mtimeMs === 0) {
+      try {
+        const newStats = await stat(file);
+        if (this.fsw.closed) return;
+        // Check that change event was not fired because of changed only accessTime.
+        const at = newStats.atimeMs;
+        const mt = newStats.mtimeMs;
+        if (!at || at <= mt || mt !== prevStats.mtimeMs) {
+          this.fsw._emit(EV_CHANGE, file, newStats);
+        }
+        if (isLinux && prevStats.ino !== newStats.ino) {
+          this.fsw._closeFile(path)
+          prevStats = newStats;
+          this.fsw._addPathCloser(path, this._watchWithNodeFs(file, listener));
+        } else {
+          prevStats = newStats;
+        }
+      } catch (error) {
+        // Fix issues where mtime is null but file is still present
+        this.fsw._remove(dirname, basename);
+      }
+      // add is about to be emitted if file not already tracked in parent
+    } else if (parent.has(basename)) {
+      // Check that change event was not fired because of changed only accessTime.
+      const at = newStats.atimeMs;
+      const mt = newStats.mtimeMs;
+      if (!at || at <= mt || mt !== prevStats.mtimeMs) {
+        this.fsw._emit(EV_CHANGE, file, newStats);
+      }
+      prevStats = newStats;
+    }
+  }
+  // kick off the watcher
+  const closer = this._watchWithNodeFs(file, listener);
+
+  // emit an add event if we're supposed to
+  if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {
+    if (!this.fsw._throttle(EV_ADD, file, 0)) return;
+    this.fsw._emit(EV_ADD, file, stats);
+  }
+
+  return closer;
+}
+
+/**
+ * Handle symlinks encountered while reading a dir.
+ * @param {Object} entry returned by readdirp
+ * @param {String} directory path of dir being read
+ * @param {String} path of this item
+ * @param {String} item basename of this item
+ * @returns {Promise<Boolean>} true if no more processing is needed for this entry.
+ */
+async _handleSymlink(entry, directory, path, item) {
+  if (this.fsw.closed) {
+    return;
+  }
+  const full = entry.fullPath;
+  const dir = this.fsw._getWatchedDir(directory);
+
+  if (!this.fsw.options.followSymlinks) {
+    // watch symlink directly (don't follow) and detect changes
+    this.fsw._incrReadyCount();
+
+    let linkPath;
+    try {
+      linkPath = await fsrealpath(path);
+    } catch (e) {
+      this.fsw._emitReady();
+      return true;
+    }
+
+    if (this.fsw.closed) return;
+    if (dir.has(item)) {
+      if (this.fsw._symlinkPaths.get(full) !== linkPath) {
+        this.fsw._symlinkPaths.set(full, linkPath);
+        this.fsw._emit(EV_CHANGE, path, entry.stats);
+      }
+    } else {
+      dir.add(item);
+      this.fsw._symlinkPaths.set(full, linkPath);
+      this.fsw._emit(EV_ADD, path, entry.stats);
+    }
+    this.fsw._emitReady();
+    return true;
+  }
+
+  // don't follow the same symlink more than once
+  if (this.fsw._symlinkPaths.has(full)) {
+    return true;
+  }
+
+  this.fsw._symlinkPaths.set(full, true);
+}
+
+_handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
+  // Normalize the directory name on Windows
+  directory = sysPath.join(directory, EMPTY_STR);
+
+  if (!wh.hasGlob) {
+    throttler = this.fsw._throttle('readdir', directory, 1000);
+    if (!throttler) return;
+  }
+
+  const previous = this.fsw._getWatchedDir(wh.path);
+  const current = new Set();
+
+  let stream = this.fsw._readdirp(directory, {
+    fileFilter: entry => wh.filterPath(entry),
+    directoryFilter: entry => wh.filterDir(entry),
+    depth: 0
+  }).on(STR_DATA, async (entry) => {
+    if (this.fsw.closed) {
+      stream = undefined;
+      return;
+    }
+    const item = entry.path;
+    let path = sysPath.join(directory, item);
+    current.add(item);
+
+    if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) {
+      return;
+    }
+
+    if (this.fsw.closed) {
+      stream = undefined;
+      return;
+    }
+    // Files that present in current directory snapshot
+    // but absent in previous are added to watch list and
+    // emit `add` event.
+    if (item === target || !target && !previous.has(item)) {
+      this.fsw._incrReadyCount();
+
+      // ensure relativeness of path is preserved in case of watcher reuse
+      path = sysPath.join(dir, sysPath.relative(dir, path));
+
+      this._addToNodeFs(path, initialAdd, wh, depth + 1);
+    }
+  }).on(EV_ERROR, this._boundHandleError);
+
+  return new Promise(resolve =>
+    stream.once(STR_END, () => {
+      if (this.fsw.closed) {
+        stream = undefined;
+        return;
+      }
+      const wasThrottled = throttler ? throttler.clear() : false;
+
+      resolve();
+
+      // Files that absent in current directory snapshot
+      // but present in previous emit `remove` event
+      // and are removed from @watched[directory].
+      previous.getChildren().filter((item) => {
+        return item !== directory &&
+          !current.has(item) &&
+          // in case of intersecting globs;
+          // a path may have been filtered out of this readdir, but
+          // shouldn't be removed because it matches a different glob
+          (!wh.hasGlob || wh.filterPath({
+            fullPath: sysPath.resolve(directory, item)
+          }));
+      }).forEach((item) => {
+        this.fsw._remove(directory, item);
+      });
+
+      stream = undefined;
+
+      // one more time for any missed in case changes came in extremely quickly
+      if (wasThrottled) this._handleRead(directory, false, wh, target, dir, depth, throttler);
+    })
+  );
+}
+
+/**
+ * Read directory to add / remove files from `@watched` list and re-read it on change.
+ * @param {String} dir fs path
+ * @param {fs.Stats} stats
+ * @param {Boolean} initialAdd
+ * @param {Number} depth relative to user-supplied path
+ * @param {String} target child path targeted for watch
+ * @param {Object} wh Common watch helpers for this path
+ * @param {String} realpath
+ * @returns {Promise<Function>} closer for the watcher instance.
+ */
+async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {
+  const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
+  const tracked = parentDir.has(sysPath.basename(dir));
+  if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
+    if (!wh.hasGlob || wh.globFilter(dir)) this.fsw._emit(EV_ADD_DIR, dir, stats);
+  }
+
+  // ensure dir is tracked (harmless if redundant)
+  parentDir.add(sysPath.basename(dir));
+  this.fsw._getWatchedDir(dir);
+  let throttler;
+  let closer;
+
+  const oDepth = this.fsw.options.depth;
+  if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {
+    if (!target) {
+      await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);
+      if (this.fsw.closed) return;
+    }
+
+    closer = this._watchWithNodeFs(dir, (dirPath, stats) => {
+      // if current directory is removed, do nothing
+      if (stats && stats.mtimeMs === 0) return;
+
+      this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
+    });
+  }
+  return closer;
+}
+
+/**
+ * Handle added file, directory, or glob pattern.
+ * Delegates call to _handleFile / _handleDir after checks.
+ * @param {String} path to file or ir
+ * @param {Boolean} initialAdd was the file added at watch instantiation?
+ * @param {Object} priorWh depth relative to user-supplied path
+ * @param {Number} depth Child path actually targeted for watch
+ * @param {String=} target Child path actually targeted for watch
+ * @returns {Promise}
+ */
+async _addToNodeFs(path, initialAdd, priorWh, depth, target) {
+  const ready = this.fsw._emitReady;
+  if (this.fsw._isIgnored(path) || this.fsw.closed) {
+    ready();
+    return false;
+  }
+
+  const wh = this.fsw._getWatchHelpers(path, depth);
+  if (!wh.hasGlob && priorWh) {
+    wh.hasGlob = priorWh.hasGlob;
+    wh.globFilter = priorWh.globFilter;
+    wh.filterPath = entry => priorWh.filterPath(entry);
+    wh.filterDir = entry => priorWh.filterDir(entry);
+  }
+
+  // evaluate what is at the path we're being asked to watch
+  try {
+    const stats = await statMethods[wh.statMethod](wh.watchPath);
+    if (this.fsw.closed) return;
+    if (this.fsw._isIgnored(wh.watchPath, stats)) {
+      ready();
+      return false;
+    }
+
+    const follow = this.fsw.options.followSymlinks && !path.includes(STAR) && !path.includes(BRACE_START);
+    let closer;
+    if (stats.isDirectory()) {
+      const absPath = sysPath.resolve(path);
+      const targetPath = follow ? await fsrealpath(path) : path;
+      if (this.fsw.closed) return;
+      closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
+      if (this.fsw.closed) return;
+      // preserve this symlink's target path
+      if (absPath !== targetPath && targetPath !== undefined) {
+        this.fsw._symlinkPaths.set(absPath, targetPath);
+      }
+    } else if (stats.isSymbolicLink()) {
+      const targetPath = follow ? await fsrealpath(path) : path;
+      if (this.fsw.closed) return;
+      const parent = sysPath.dirname(wh.watchPath);
+      this.fsw._getWatchedDir(parent).add(wh.watchPath);
+      this.fsw._emit(EV_ADD, wh.watchPath, stats);
+      closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
+      if (this.fsw.closed) return;
+
+      // preserve this symlink's target path
+      if (targetPath !== undefined) {
+        this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
+      }
+    } else {
+      closer = this._handleFile(wh.watchPath, stats, initialAdd);
+    }
+    ready();
+
+    this.fsw._addPathCloser(path, closer);
+    return false;
+
+  } catch (error) {
+    if (this.fsw._handleError(error)) {
+      ready();
+      return path;
+    }
+  }
+}
+
+}
+
+module.exports = NodeFsHandler;

+ 70 - 0
node_modules/chokidar/package.json

@@ -0,0 +1,70 @@
+{
+  "name": "chokidar",
+  "description": "Minimal and efficient cross-platform file watching library",
+  "version": "3.6.0",
+  "homepage": "https://github.com/paulmillr/chokidar",
+  "author": "Paul Miller (https://paulmillr.com)",
+  "contributors": [
+    "Paul Miller (https://paulmillr.com)",
+    "Elan Shanker"
+  ],
+  "engines": {
+    "node": ">= 8.10.0"
+  },
+  "main": "index.js",
+  "types": "./types/index.d.ts",
+  "dependencies": {
+    "anymatch": "~3.1.2",
+    "braces": "~3.0.2",
+    "glob-parent": "~5.1.2",
+    "is-binary-path": "~2.1.0",
+    "is-glob": "~4.0.1",
+    "normalize-path": "~3.0.0",
+    "readdirp": "~3.6.0"
+  },
+  "optionalDependencies": {
+    "fsevents": "~2.3.2"
+  },
+  "devDependencies": {
+    "@types/node": "^14",
+    "chai": "^4.3",
+    "dtslint": "^3.3.0",
+    "eslint": "^7.0.0",
+    "mocha": "^7.0.0",
+    "rimraf": "^3.0.0",
+    "sinon": "^9.0.1",
+    "sinon-chai": "^3.3.0",
+    "typescript": "^4.4.3",
+    "upath": "^1.2.0"
+  },
+  "files": [
+    "index.js",
+    "lib/*.js",
+    "types/index.d.ts"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/paulmillr/chokidar.git"
+  },
+  "bugs": {
+    "url": "https://github.com/paulmillr/chokidar/issues"
+  },
+  "license": "MIT",
+  "scripts": {
+    "dtslint": "dtslint types",
+    "lint": "eslint --report-unused-disable-directives --ignore-path .gitignore .",
+    "build": "npm ls",
+    "mocha": "mocha --exit --timeout 90000",
+    "test": "npm run lint && npm run mocha"
+  },
+  "keywords": [
+    "fs",
+    "watch",
+    "watchFile",
+    "watcher",
+    "watching",
+    "file",
+    "fsevents"
+  ],
+  "funding": "https://paulmillr.com/funding/"
+}

+ 192 - 0
node_modules/chokidar/types/index.d.ts

@@ -0,0 +1,192 @@
+// TypeScript Version: 3.0
+
+/// <reference types="node" />
+
+import * as fs from "fs";
+import { EventEmitter } from "events";
+import { Matcher } from 'anymatch';
+
+export class FSWatcher extends EventEmitter implements fs.FSWatcher {
+  options: WatchOptions;
+
+  /**
+   * Constructs a new FSWatcher instance with optional WatchOptions parameter.
+   */
+  constructor(options?: WatchOptions);
+
+  /**
+   * Add files, directories, or glob patterns for tracking. Takes an array of strings or just one
+   * string.
+   */
+  add(paths: string | ReadonlyArray<string>): this;
+
+  /**
+   * Stop watching files, directories, or glob patterns. Takes an array of strings or just one
+   * string.
+   */
+  unwatch(paths: string | ReadonlyArray<string>): this;
+
+  /**
+   * Returns an object representing all the paths on the file system being watched by this
+   * `FSWatcher` instance. The object's keys are all the directories (using absolute paths unless
+   * the `cwd` option was used), and the values are arrays of the names of the items contained in
+   * each directory.
+   */
+  getWatched(): {
+    [directory: string]: string[];
+  };
+
+  /**
+   * Removes all listeners from watched files.
+   */
+  close(): Promise<void>;
+
+  on(event: 'add'|'addDir'|'change', listener: (path: string, stats?: fs.Stats) => void): this;
+
+  on(event: 'all', listener: (eventName: 'add'|'addDir'|'change'|'unlink'|'unlinkDir', path: string, stats?: fs.Stats) => void): this;
+
+  /**
+   * Error occurred
+   */
+  on(event: 'error', listener: (error: Error) => void): this;
+
+  /**
+   * Exposes the native Node `fs.FSWatcher events`
+   */
+  on(event: 'raw', listener: (eventName: string, path: string, details: any) => void): this;
+
+  /**
+   * Fires when the initial scan is complete
+   */
+  on(event: 'ready', listener: () => void): this;
+
+  on(event: 'unlink'|'unlinkDir', listener: (path: string) => void): this;
+
+  on(event: string, listener: (...args: any[]) => void): this;
+
+  ref(): this;
+  
+  unref(): this;
+}
+
+export interface WatchOptions {
+  /**
+   * Indicates whether the process should continue to run as long as files are being watched. If
+   * set to `false` when using `fsevents` to watch, no more events will be emitted after `ready`,
+   * even if the process continues to run.
+   */
+  persistent?: boolean;
+
+  /**
+   * ([anymatch](https://github.com/micromatch/anymatch)-compatible definition) Defines files/paths to
+   * be ignored. The whole relative or absolute path is tested, not just filename. If a function
+   * with two arguments is provided, it gets called twice per path - once with a single argument
+   * (the path), second time with two arguments (the path and the
+   * [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object of that path).
+   */
+  ignored?: Matcher;
+
+  /**
+   * If set to `false` then `add`/`addDir` events are also emitted for matching paths while
+   * instantiating the watching as chokidar discovers these file paths (before the `ready` event).
+   */
+  ignoreInitial?: boolean;
+
+  /**
+   * When `false`, only the symlinks themselves will be watched for changes instead of following
+   * the link references and bubbling events through the link's path.
+   */
+  followSymlinks?: boolean;
+
+  /**
+   * The base directory from which watch `paths` are to be derived. Paths emitted with events will
+   * be relative to this.
+   */
+  cwd?: string;
+
+  /**
+   *  If set to true then the strings passed to .watch() and .add() are treated as literal path
+   *  names, even if they look like globs. Default: false.
+   */
+  disableGlobbing?: boolean;
+
+  /**
+   * Whether to use fs.watchFile (backed by polling), or fs.watch. If polling leads to high CPU
+   * utilization, consider setting this to `false`. It is typically necessary to **set this to
+   * `true` to successfully watch files over a network**, and it may be necessary to successfully
+   * watch files in other non-standard situations. Setting to `true` explicitly on OS X overrides
+   * the `useFsEvents` default.
+   */
+  usePolling?: boolean;
+
+  /**
+   * Whether to use the `fsevents` watching interface if available. When set to `true` explicitly
+   * and `fsevents` is available this supercedes the `usePolling` setting. When set to `false` on
+   * OS X, `usePolling: true` becomes the default.
+   */
+  useFsEvents?: boolean;
+
+  /**
+   * If relying upon the [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats) object that
+   * may get passed with `add`, `addDir`, and `change` events, set this to `true` to ensure it is
+   * provided even in cases where it wasn't already available from the underlying watch events.
+   */
+  alwaysStat?: boolean;
+
+  /**
+   * If set, limits how many levels of subdirectories will be traversed.
+   */
+  depth?: number;
+
+  /**
+   * Interval of file system polling.
+   */
+  interval?: number;
+
+  /**
+   * Interval of file system polling for binary files. ([see list of binary extensions](https://gi
+   * thub.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json))
+   */
+  binaryInterval?: number;
+
+  /**
+   *  Indicates whether to watch files that don't have read permissions if possible. If watching
+   *  fails due to `EPERM` or `EACCES` with this set to `true`, the errors will be suppressed
+   *  silently.
+   */
+  ignorePermissionErrors?: boolean;
+
+  /**
+   * `true` if `useFsEvents` and `usePolling` are `false`). Automatically filters out artifacts
+   * that occur when using editors that use "atomic writes" instead of writing directly to the
+   * source file. If a file is re-added within 100 ms of being deleted, Chokidar emits a `change`
+   * event rather than `unlink` then `add`. If the default of 100 ms does not work well for you,
+   * you can override it by setting `atomic` to a custom value, in milliseconds.
+   */
+  atomic?: boolean | number;
+
+  /**
+   * can be set to an object in order to adjust timing params:
+   */
+  awaitWriteFinish?: AwaitWriteFinishOptions | boolean;
+}
+
+export interface AwaitWriteFinishOptions {
+  /**
+   * Amount of time in milliseconds for a file size to remain constant before emitting its event.
+   */
+  stabilityThreshold?: number;
+
+  /**
+   * File size polling interval.
+   */
+  pollInterval?: number;
+}
+
+/**
+ * produces an instance of `FSWatcher`.
+ */
+export function watch(
+  paths: string | ReadonlyArray<string>,
+  options?: WatchOptions
+): FSWatcher;

+ 246 - 0
node_modules/clean-css-cli/History.md

@@ -0,0 +1,246 @@
+[5.6.3 / 2023-11-30](https://github.com/clean-css/clean-css-cli/compare/v5.6.2...v5.6.3)
+==================
+
+* Bumps clean-css dependency to 5.3.3
+
+[5.6.2 / 2023-01-19](https://github.com/clean-css/clean-css-cli/compare/v5.6.1...v5.6.2)
+==================
+
+* Bumps clean-css dependency to 5.3.2
+
+[5.6.1 / 2022-07-13](https://github.com/clean-css/clean-css-cli/compare/v5.6.0...v5.6.1)
+==================
+
+* Bumps clean-css dependency to 5.3.1.
+
+[5.6.0 / 2022-03-31](https://github.com/clean-css/clean-css-cli/compare/v5.5.2...v5.6.0)
+==================
+
+* Bumps clean-css dependency to 5.3.0.
+
+[5.5.2 / 2022-01-28](https://github.com/clean-css/clean-css-cli/compare/v5.5.1...v5.5.2)
+==================
+
+* Bumps clean-css dependency to 5.2.4.
+
+[5.5.1 / 2022-01-26](https://github.com/clean-css/clean-css-cli/compare/v5.5.0...v5.5.1)
+==================
+
+* Bumps clean-css dependency to 5.2.3.
+
+[5.5.0 / 2021-12-08](https://github.com/clean-css/clean-css-cli/compare/5.4...v5.5.0)
+==================
+
+* Adds a new `--watch` switch, which makes CLI re-run optimizations when watched file(s) change.
+
+[5.4.2 / 2021-10-21](https://github.com/clean-css/clean-css-cli/compare/v5.4.1...v5.4.2)
+==================
+
+* Bumps clean-css dependency to 5.2.2.
+
+[5.4.1 / 2021-09-30](https://github.com/clean-css/clean-css-cli/compare/v5.4.0...v5.4.1)
+==================
+
+* Bumps clean-css dependency to 5.2.1.
+
+[5.4.0 / 2021-09-30](https://github.com/clean-css/clean-css-cli/compare/5.3...v5.4.0)
+==================
+
+* Bumps clean-css dependency to 5.2.0.
+
+[5.3.3 / 2021-08-05](https://github.com/clean-css/clean-css-cli/compare/v5.3.2...v5.3.3)
+==================
+
+* Bumps clean-css dependency to 5.1.5.
+
+[5.3.2 / 2021-07-29](https://github.com/clean-css/clean-css-cli/compare/v5.3.1...v5.3.2)
+==================
+
+* Bumps clean-css dependency to 5.1.4.
+
+[5.3.1 / 2021-07-29](https://github.com/clean-css/clean-css-cli/compare/v5.3.0...v5.3.1)
+==================
+
+* Bumps clean-css dependency to 5.1.3.
+
+[5.3.0 / 2021-04-28](https://github.com/clean-css/clean-css-cli/compare/5.2...v5.3.0)
+==================
+
+* Fixed issue [#61](https://github.com/clean-css/clean-css-cli/issues/61) - source maps, rebasing, and batch processing.
+* Fixed issue [#65](https://github.com/clean-css/clean-css-cli/issues/65) - batch processing with output path.
+
+[5.2.2 / 2021-03-19](https://github.com/clean-css/clean-css-cli/compare/v5.2.1...v5.2.2)
+==================
+
+* Bumps clean-css dependency to 5.1.2.
+
+[5.2.1 / 2021-03-03](https://github.com/clean-css/clean-css-cli/compare/v5.2.0...v5.2.1)
+==================
+
+* Bumps clean-css dependency to 5.1.1.
+
+[5.2.0 / 2021-02-18](https://github.com/clean-css/clean-css-cli/compare/5.1...v5.2.0)
+==================
+
+* Bumps clean-css dependency to 5.1.0.
+
+[5.1.0 / 2021-02-12](https://github.com/clean-css/clean-css-cli/compare/5.0...v5.1.0)
+==================
+
+* Fixed issue [#51](https://github.com/clean-css/clean-css-cli/issues/51) - excluding files via glob negated pattern.
+
+[5.0.1 / 2021-02-11](https://github.com/clean-css/clean-css-cli/compare/v5.0.0...v5.0.1)
+==================
+
+* Fixed issue [#54](https://github.com/clean-css/clean-css-cli/issues/54) - rebasing is still on if output option is used.
+
+[5.0.0 / 2021-02-10](https://github.com/clean-css/clean-css-cli/compare/4.3...v5.0.0)
+==================
+
+* Adds `--batch-suffix` option to specify what gets appended to output filename in batch mode.
+* Bumps clean-css dependency to 5.0.
+* Bumps commander dependency to 7.0.
+* Fixed issue [#18](https://github.com/clean-css/clean-css-cli/issues/18) - allows batch processing of input files.
+* Fixed issue [#36](https://github.com/clean-css/clean-css-cli/issues/36) - automatically creates missing output directories.
+
+[4.3.0 / 2019-04-06](https://github.com/clean-css/clean-css-cli/compare/4.2...v4.3.0)
+==================
+
+* Bumps clean-css dependency to 4.2.1.
+* Fixed issue [#21](https://github.com/clean-css/clean-css-cli/issues/21) - sanity check for printing out help.
+* Fixed issue [#27](https://github.com/clean-css/clean-css-cli/issues/27) - way to provide input source map.
+
+[4.2.0 / 2018-08-02](https://github.com/clean-css/clean-css-cli/compare/4.1...v4.2.0)
+==================
+
+* Bumps clean-css dependency to 4.2.0.
+
+[4.1.11 / 2018-03-02](https://github.com/clean-css/clean-css-cli/compare/v4.1.10...v4.1.11)
+==================
+
+* Fixed issue [#17](https://github.com/clean-css/clean-css-cli/issues/17) - empty `--inline` switch.
+
+[4.1.10 / 2017-09-19](https://github.com/clean-css/clean-css-cli/compare/v4.1.9...v4.1.10)
+==================
+
+* Bumps clean-css dependency to 4.1.9.
+
+[4.1.9 / 2017-09-03](https://github.com/clean-css/clean-css-cli/compare/v4.1.8...v4.1.9)
+==================
+
+* Bumps clean-css dependency to 4.1.8.
+
+[4.1.8 / 2017-09-03](https://github.com/clean-css/clean-css-cli/compare/v4.1.7...v4.1.8)
+==================
+
+* Bumps clean-css dependency to 4.1.7.
+
+[4.1.7 / 2017-09-03](https://github.com/clean-css/clean-css-cli/compare/v4.1.6...v4.1.7)
+==================
+
+* Bumps clean-css dependency to 4.1.6.
+
+[4.1.6 / 2017-06-29](https://github.com/clean-css/clean-css-cli/compare/v4.1.5...v4.1.6)
+==================
+
+* Bumps clean-css dependency to 4.1.5.
+
+[4.1.5 / 2017-06-14](https://github.com/clean-css/clean-css-cli/compare/v4.1.4...v4.1.5)
+==================
+
+* Bumps clean-css dependency to 4.1.4.
+
+[4.1.4 / 2017-06-09](https://github.com/clean-css/clean-css-cli/compare/v4.1.3...v4.1.4)
+==================
+
+* Fixed issue [#10](https://github.com/clean-css/clean-css-cli/issues/10) - IE/Edge source maps.
+
+[4.1.3 / 2017-05-18](https://github.com/clean-css/clean-css-cli/compare/v4.1.2...v4.1.3)
+==================
+
+* Bumps clean-css dependency to 4.1.3.
+
+[4.1.2 / 2017-05-10](https://github.com/clean-css/clean-css-cli/compare/v4.1.1...v4.1.2)
+==================
+
+* Bumps clean-css dependency to 4.1.2.
+
+[4.1.1 / 2017-05-10](https://github.com/clean-css/clean-css-cli/compare/v4.1.0...v4.1.1)
+==================
+
+* Bumps clean-css dependency to 4.1.1.
+
+[4.1.0 / 2017-05-08](https://github.com/clean-css/clean-css-cli/compare/4.0...v4.1.0)
+==================
+
+* Bumps clean-css dependency to 4.1.x.
+* Fixed issue [#1](https://github.com/clean-css/clean-css-cli/issues/1) - option to remove inlined files.
+* Fixed issue [#2](https://github.com/clean-css/clean-css-cli/issues/2) - glob matching source paths.
+* Fixed issue [#5](https://github.com/clean-css/clean-css-cli/issues/5) - non-boolean compatibility options.
+* Fixed issue [#7](https://github.com/clean-css/clean-css-cli/issues/7) - using CLI as a module.
+
+[4.0.12 / 2017-04-12](https://github.com/clean-css/clean-css-cli/compare/v4.0.11...v4.0.12)
+==================
+
+* Bumps clean-css dependency to 4.0.12.
+
+[4.0.11 / 2017-04-11](https://github.com/clean-css/clean-css-cli/compare/v4.0.10...v4.0.11)
+==================
+
+* Bumps clean-css dependency to 4.0.11.
+
+[4.0.10 / 2017-03-22](https://github.com/clean-css/clean-css-cli/compare/v4.0.9...v4.0.10)
+==================
+
+* Bumps clean-css dependency to 4.0.10.
+
+[4.0.9 / 2017-03-15](https://github.com/clean-css/clean-css-cli/compare/v4.0.8...v4.0.9)
+==================
+
+* Bumps clean-css dependency to 4.0.9.
+
+[4.0.8 / 2017-02-22](https://github.com/clean-css/clean-css-cli/compare/v4.0.7...v4.0.8)
+==================
+
+* Bumps clean-css dependency to 4.0.8.
+
+[4.0.7 / 2017-02-14](https://github.com/clean-css/clean-css-cli/compare/v4.0.6...v4.0.7)
+==================
+
+* Bumps clean-css dependency to 4.0.7.
+
+[4.0.6 / 2017-02-10](https://github.com/clean-css/clean-css-cli/compare/v4.0.5...v4.0.6)
+==================
+
+* Bumps clean-css dependency to 4.0.6.
+
+[4.0.5 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.4...v4.0.5)
+==================
+
+* Bumps clean-css dependency to 4.0.5.
+
+[4.0.4 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.3...v4.0.4)
+==================
+
+* Bumps clean-css dependency to 4.0.4.
+
+[4.0.3 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.2...v4.0.3)
+==================
+
+* Bumps clean-css dependency to 4.0.3.
+
+[4.0.2 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.1...v4.0.2)
+==================
+
+* Bumps clean-css dependency to 4.0.2.
+
+[4.0.1 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.0...v4.0.1)
+==================
+
+* Bumps clean-css dependency to 4.0.1.
+
+4.0.0 / 2017-01-23
+==================
+
+* Initial release of separate clean-css-cli.
+* See [clean-css release notes](https://github.com/clean-css/clean-css/blob/master/History.md#400--2017-01-23) for a full list of changes.

+ 21 - 0
node_modules/clean-css-cli/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Jakub Pawlowicz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 480 - 0
node_modules/clean-css-cli/README.md

@@ -0,0 +1,480 @@
+<h1 align="center">
+  <br/>
+  <img src="https://cdn.rawgit.com/jakubpawlowicz/clean-css/master/logo.v2.svg" alt="clean-css logo" width="525px"/>
+  <br/>
+  <br/>
+</h1>
+
+[![NPM version](https://img.shields.io/npm/v/clean-css-cli.svg?style=flat)](https://www.npmjs.com/package/clean-css-cli)
+![x86 Linux build](https://github.com/clean-css/clean-css-cli/workflows/x86%20Linux%20build/badge.svg)
+[![Dependency Status](https://img.shields.io/david/clean-css/clean-css-cli.svg?style=flat)](https://david-dm.org/clean-css/clean-css-cli)
+[![NPM Downloads](https://img.shields.io/npm/dm/clean-css-cli.svg)](https://www.npmjs.com/package/clean-css-cli)
+
+clean-css-cli is a command-line interface to [clean-css](https://github.com/jakubpawlowicz/clean-css) - fast and efficient CSS optimizer for [Node.js](http://nodejs.org/).
+
+Previously a part of clean-css it's a separate package since clean-css 4.0.
+
+**Table of Contents**
+
+- [Node.js version support](#nodejs-version-support)
+- [Install](#install)
+- [Use](#use)
+  * [What's new in version 5.5](#whats-new-in-version-55)
+  * [What's new in version 5.1](#whats-new-in-version-51)
+  * [What's new in version 5.0](#whats-new-in-version-50)
+  * [What's new in version 4.3](#whats-new-in-version-43)
+  * [What's new in version 4.2](#whats-new-in-version-42)
+  * [What's new in version 4.1](#whats-new-in-version-41)
+  * [What's new in version 4.0](#whats-new-in-version-40)
+  * [CLI options](#cli-options)
+  * [Compatibility modes](#compatibility-modes)
+  * [Formatting options](#formatting-options)
+  * [Inlining options](#inlining-options)
+  * [Optimization levels](#optimization-levels)
+    + [Level 0 optimizations](#level-0-optimizations)
+    + [Level 1 optimizations](#level-1-optimizations)
+    + [Level 2 optimizations](#level-2-optimizations)
+  * [As a module](#as-a-module)
+- [FAQ](#faq)
+  * [How to optimize multiple files?](#how-to-optimize-multiple-files)
+  * [How to process multiple files without concatenating them into one output file?](#how-to-process-multiple-files-without-concatenating-them-into-one-output-file)
+  * [How to specify a custom rounding precision?](#how-to-specify-a-custom-rounding-precision)
+  * [How to rebase relative image URLs?](#how-to-rebase-relative-image-urls)
+  * [How to apply level 1 & 2 optimizations at the same time?](#how-to-apply-level-1--2-optimizations-at-the-same-time)
+- [Contributing](#contributing)
+  * [How to get started?](#how-to-get-started)
+- [License](#license)
+
+# Node.js version support
+
+clean-css-cli requires Node.js 10.0+ (tested on Linux)
+
+# Install
+
+```shell
+npm install clean-css-cli -g
+```
+Note: Global install via -g option is recommended unless you want to execute the binary via a relative path, i.e. ./node_modules/.bin/cleancss
+
+# Use
+
+```shell
+cleancss -o one.min.css one.css
+```
+
+## What's new in version 5.5
+
+clean-css-cli 5.5 introduces the following changes / features:
+
+* adds a new `--watch` switch, which makes `cleancss` re-run optimizations when watched file(s) change.
+
+## What's new in version 5.1
+
+clean-css-cli 5.1 introduces the following changes / features:
+
+* accept `!path/to/file` as a way of telling `cleancss` to ignore such file, also accepts any available glob patterns.
+
+## What's new in version 5.0
+
+clean-css-cli 5.0 introduces the following changes / features:
+
+* adds `--batch` option (off by default) which processes input files one by one without joining them together;
+* adds `--batch-suffix` option to specify what gets appended to output filename in batch mode;
+* automatically creates missing output directories;
+* clean-css 5.0 with loads of bugfixes;
+* drops official support for Node.js 4, 6, and 8;
+* `--skip-rebase` option has been removed as rebasing URLs is disabled by default now
+* `--with-rebase` option is added if you really want URLs rebasing
+
+## What's new in version 4.3
+
+clean-css-cli 4.3 introduces the following changes / features:
+
+* `--input-source-map` option which accepts a path to input source map file.
+
+## What's new in version 4.2
+
+clean-css-cli 4.2 introduces the following changes / features:
+
+* [clean-css 4.2](https://github.com/jakubpawlowicz/clean-css#whats-new-in-version-42) as a dependency;
+
+## What's new in version 4.1
+
+clean-css-cli 4.1 introduces the following changes / features:
+
+* [clean-css 4.1](https://github.com/jakubpawlowicz/clean-css#whats-new-in-version-41) as a dependency;
+* `--remove-inlined-files` option for removing files inlined in <source-file ...> or via `@import` statements;
+* adds glob pattern matching to source paths, see [example](#how-to-optimize-multiple-files);
+* allows non-boolean compatibility options, e.g. `--compatibility selectors.mergeLimit=512`;
+* extracts CLI into an importable module, so it can be reused and enhanced if needed;
+* adds `beforeMinify` callback as a second argument to CLI module, see [example use case](#as-a-module).
+
+## What's new in version 4.0
+
+clean-css-cli 4.0 introduces some breaking changes:
+
+* API and CLI interfaces are split, so CLI has been moved to this repository while API stays at [clean-css](https://github.com/jakubpawlowicz/clean-css);
+* `--root` and `--relativeTo` options are replaced by a single option taken from `--output` path - this means that rebasing URLs and import inlining is much simpler but may not be (YMMV) as powerful as in 3.x;
+* `--rounding-precision` is disabled by default;
+* `--rounding-precision` applies to **all** units now, not only `px` as in 3.x;
+* `--skip-import` and `--skip-import-from` are merged into `--inline` option which defaults to `local`. Remote `@import` rules are **NOT** inlined by default anymore;
+* renames `--timeout` option to `--inline-timeout`;
+* remote resources without a protocol, e.g. `//fonts.googleapis.com/css?family=Domine:700`, are not inlined anymore;
+* changes default Internet Explorer compatibility from 9+ to 10+, to revert the old default use `--compatibility ie9` option;
+* moves `--rounding-precision`, `--s0`, and `--s1` options to level 1 optimization options, see examples;
+* moves `--skip-media-merging`, `--skip-restructuring`, `--semantic-merging`, and `--skip-shorthand-compacting` to level 2 optimizations options, see examples below;
+* level 1 optimizations are the new default, up to 3.x it was level 2;
+* `--keep-breaks` option is replaced with `--format keep-breaks` to ease transition;
+* `--skip-aggressive-merging` option is removed as aggressive merging is replaced by smarter override merging.
+
+## CLI options
+
+```shell
+-b, --batch                    If enabled, optimizes input files one by one instead of joining them together
+-c, --compatibility [ie7|ie8]  Force compatibility mode (see Readme for advanced examples)
+-d, --debug                    Shows debug information (minification time & compression efficiency)
+-f, --format <options>         Controls output formatting, see examples below
+-h, --help                     output usage information
+-o, --output [output-file]     Use [output-file] as output instead of STDOUT
+-O <n> [optimizations]         Turn on level <n> optimizations; optionally accepts a list of fine-grained options, defaults to `1`, IMPORTANT: the prefix is O (a capital o letter), NOT a 0 (zero, a number)
+-v, --version                  output the version number
+--inline [rules]               Enables inlining for listed sources (defaults to `local`)
+--inline-timeout [seconds]     Per connection timeout when fetching remote stylesheets (defaults to 5 seconds)
+--input-source-map [file]      Specifies the path of the input source map file
+--remove-inlined-files         Remove files inlined in <source-file ...> or via `@import` statements
+--source-map                   Enables building input's source map
+--source-map-inline-sources    Enables inlining sources inside source maps
+--with-rebase                  Enables URLs rebasing
+```
+
+## Compatibility modes
+
+There is a certain number of compatibility mode shortcuts, namely:
+
+* `--compatibility '*'` (default) - Internet Explorer 10+ compatibility mode
+* `--compatibility ie9` - Internet Explorer 9+ compatibility mode
+* `--compatibility ie8` - Internet Explorer 8+ compatibility mode
+* `--compatibility ie7` - Internet Explorer 7+ compatibility mode
+
+Each of these modes is an alias to a [fine grained configuration](https://github.com/jakubpawlowicz/clean-css/blob/master/lib/options/compatibility.js), with the following options available:
+
+```shell
+cleancss --compatibility '*,-properties.urlQuotes'
+cleancss --compatibility '*,+properties.ieBangHack,+properties.ieFilters'
+# [+-]colors.opacity controls `rgba()` / `hsla()` color support; defaults to `on` (+)
+# [+-]properties.backgroundClipMerging controls background-clip merging into shorthand; defaults to `on` (+)
+# [+-]properties.backgroundOriginMerging controls background-origin merging into shorthand; defaults to `on` (+)
+# [+-]properties.backgroundSizeMerging controls background-size merging into shorthand; defaults to `on` (+)
+# [+-]properties.colors controls color optimizations; defaults to `on` (+)
+# [+-]properties.ieBangHack controls keeping IE bang hack; defaults to `off` (-)
+# [+-]properties.ieFilters controls keeping IE `filter` / `-ms-filter`; defaults to `off` (-)
+# [+-]properties.iePrefixHack controls keeping IE prefix hack; defaults to `off` (-)
+# [+-]properties.ieSuffixHack controls keeping IE suffix hack; defaults to `off` (-)
+# [+-]properties.merging controls property merging based on understandability; defaults to `on` (+)
+# [+-]properties.shorterLengthUnits controls shortening pixel units into `pc`, `pt`, or `in` units; defaults to `off` (-)
+# [+-]properties.spaceAfterClosingBrace controls keeping space after closing brace - `url() no-repeat` cleancss --compatibility '*,into `url('roperties.no-repeat`; defaults to `on` (+)
+# [+-]properties.urlQuotes controls keeping quoting inside `url()`; defaults to `off` (-)
+# [+-]properties.zeroUnitsf units `0` value; defaults to `on` (+)
+# [+-]selectors.adjacentSpace controls extra space before `nav` element; defaults to `off` (-)
+# [+-]selectors.ie7Hack controls removal of IE7 selector hacks, e.g. `*+html...`; defaults to `on` (+)
+# [+-]units.ch controls treating `ch` as a supported unit; defaults to `on` (+)
+# [+-]units.in controls treating `in` as a supported unit; defaults to `on` (+)
+# [+-]units.pc controls treating `pc` as a supported unit; defaults to `on` (+)
+# [+-]units.pt controls treating `pt` as a supported unit; defaults to `on` (+)
+# [+-]units.rem controls treating `rem` as a supported unit; defaults to `on` (+)
+# [+-]units.vh controls treating `vh` as a supported unit; defaults to `on` (+)
+# [+-]units.vm controls treating `vm` as a supported unit; defaults to `on` (+)
+# [+-]units.vmax controls treating `vmax` as a supported unit; defaults to `on` (+)
+# [+-]units.vmin controls treating `vmin` as a supported unit; defaults to `on` (+)
+```
+
+You can also chain more rules after a shortcut when setting a compatibility:
+
+```shell
+cleancss --compatibility 'ie9,-colors.opacity,-units.rem' one.css
+```
+
+## Formatting options
+
+The `--format` option accept the following options:
+
+```shell
+cleancss --format beautify one.css
+cleancss --format keep-breaks one.css
+cleancss --format 'indentBy:1;indentWith:tab' one.css
+cleancss --format 'breaks:afterBlockBegins=on;spaces:aroundSelectorRelation=on' one.css
+# `breaks` controls where to insert breaks
+#   `afterAtRule` controls if a line break comes after an at-rule; e.g. `@charset`; defaults to `off` (alias to `false`)
+#   `afterBlockBegins` controls if a line break comes after a block begins; e.g. `@media`; defaults to `off`
+#   `afterBlockEnds` controls if a line break comes after a block ends, defaults to `off`
+#   `afterComment` controls if a line break comes after a comment; defaults to `off`
+#   `afterProperty` controls if a line break comes after a property; defaults to `off`
+#   `afterRuleBegins` controls if a line break comes after a rule begins; defaults to `off`
+#   `afterRuleEnds` controls if a line break comes after a rule ends; defaults to `off`
+#   `beforeBlockEnds` controls if a line break comes before a block ends; defaults to `off`
+#   `betweenSelectors` controls if a line break comes between selectors; defaults to `off`
+# `breakWith` controls the new line character, can be `windows` or `unix` (aliased via `crlf` and `lf`); defaults to system one, so former on Windows and latter on Unix
+# `indentBy` controls number of characters to indent with; defaults to `0`
+# `indentWith` controls a character to indent with, can be `space` or `tab`; defaults to `space`
+# `spaces` controls where to insert spaces
+#   `aroundSelectorRelation` controls if spaces come around selector relations; e.g. `div > a`; defaults to `off`
+#   `beforeBlockBegins` controls if a space comes before a block begins; e.g. `.block {`; defaults to `off`
+#   `beforeValue` controls if a space comes before a value; e.g. `width: 1rem`; defaults to `off`
+# `wrapAt` controls maximum line length; defaults to `off`
+```
+
+## Inlining options
+
+`--inline` option whitelists which `@import` rules will be processed, e.g.
+
+```shell
+cleancss --inline local one.css # default
+```
+
+```shell
+cleancss --inline all # same as local,remote
+```
+
+```shell
+cleancss --inline local,mydomain.example.com one.css
+```
+
+```shell
+cleancss --inline 'local,remote,!fonts.googleapis.com' one.css
+```
+
+## Optimization levels
+
+The `-O` option can be either `0`, `1` (default), or `2`, e.g.
+
+```shell
+cleancss -O2 one.css
+```
+
+or a fine-grained configuration given via a string.
+
+Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
+
+Important: The `-O` option is using the capital letter O (as in "Oscar"), not the number zero.
+
+### Level 0 optimizations
+
+Level 0 optimizations simply means "no optimizations". Use it when you'd like to inline imports and / or rebase URLs but skip everything else, e.g.
+
+```shell
+cleancss -O0 one.css
+```
+
+### Level 1 optimizations
+
+Level 1 optimizations (default) operate on single properties only, e.g. can remove units when not required, turn rgb colors to a shorter hex representation, remove comments, etc
+
+Here is a full list of available options:
+
+```shell
+cleancss -O1 one.css
+cleancss -O1 removeQuotes:off;roundingPrecision:4;specialComments:1 one.css
+# `cleanupCharsets` controls `@charset` moving to the front of a stylesheet; defaults to `on`
+# `normalizeUrls` controls URL normalzation; default to `on`
+# `optimizeBackground` controls `background` property optimizatons; defaults to `on`
+# `optimizeBorderRadius` controls `border-radius` property optimizatons; defaults to `on`
+# `optimizeFilter` controls `filter` property optimizatons; defaults to `on`
+# `optimizeFontWeight` controls `font-weight` property optimizatons; defaults to `on`
+# `optimizeOutline` controls `outline` property optimizatons; defaults to `on`
+# `removeEmpty` controls removing empty rules and nested blocks; defaults to `on` (since 4.1.0)
+# `removeNegativePaddings` controls removing negative paddings; defaults to `on`
+# `removeQuotes` controls removing quotes when unnecessary; defaults to `on`
+# `removeWhitespace` controls removing unused whitespace; defaults to `on`
+# `replaceMultipleZeros` contols removing redundant zeros; defaults to `on`
+# `replaceTimeUnits` controls replacing time units with shorter values; defaults to `on
+# `replaceZeroUnits` controls replacing zero values with units; defaults to `on`
+# `roundingPrecision` rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`
+# `selectorsSortingMethod` denotes selector sorting method; can be `natural` or `standard`; defaults to `standard`
+# `specialComments` denotes a number of /*! ... */ comments preserved; defaults to `all`
+# `tidyAtRules` controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `on`
+# `tidyBlockScopes` controls block scopes (e.g. `@media`) optimizing; defaults to `on`
+# `tidySelectors` controls selectors optimizing; defaults to `on`
+```
+
+There is an `all` shortcut for toggling all options at the same time, e.g.
+
+```shell
+cleancss -O1 'all:off;tidySelectors:on' one.css
+```
+
+### Level 2 optimizations
+
+Level 2 optimizations operate at rules or multiple properties level, e.g. can remove duplicate rules, remove properties redefined further down a stylesheet, or restructure rules by moving them around.
+
+Please note that if level 2 optimizations are turned on then, unless explicitely disabled, level 1 optimizations are applied as well.
+
+Here is a full list of available options:
+
+```shell
+cleancss -O2 one.css
+cleancss -O2 mergeMedia:off;restructureRules:off;mergeSemantically:on;mergeIntoShorthands:off one.css
+# `mergeAdjacentRules` controls adjacent rules merging; defaults to `on`
+# `mergeIntoShorthands` controls merging properties into shorthands; defaults to `on`
+# `mergeMedia` controls `@media` merging; defaults to `on`
+# `mergeNonAdjacentRules` controls non-adjacent rule merging; defaults to `on`
+# `mergeSemantically` controls semantic merging; defaults to `off`
+# `overrideProperties` controls property overriding based on understandability; defaults to `on`
+# `reduceNonAdjacentRules` controls non-adjacent rule reducing; defaults to `on`
+# `removeDuplicateFontRules` controls duplicate `@font-face` removing; defaults to `on`
+# `removeDuplicateMediaBlocks` controls duplicate `@media` removing; defaults to `on`
+# `removeDuplicateRules` controls duplicate rules removing; defaults to `on`
+# `removeEmpty` controls removing empty rules and nested blocks; defaults to `on` (since 4.1.0)
+# `removeUnusedAtRules` controls unused at rule removing; defaults to `off` (since 4.1.0)
+# `restructureRules` controls rule restructuring; defaults to `off`
+# `skipProperties` controls which properties won\'t be optimized, defaults to empty list which means all will be optimized (since 4.1.0)
+```
+
+There is an `all` shortcut for toggling all options at the same time, e.g.
+
+```shell
+cleancss -O2 'all:off;removeDuplicateRules:on' one.css
+```
+
+# As a module
+
+clean-css-cli can also be used as a module in a way of enhancing its functionality in a programmatic way, e.g.
+
+```js
+#!/usr/bin/env node
+
+var cleanCssCli = require('clean-css-cli');
+
+var customPlugin = {
+  level1: {
+    value: function (propertyName, propertyValue, options) {
+      if (propertyName == 'background-image' && propertyValue.indexOf('../valid/path/to') == -1) {
+        return propertyValue.replace('url(', 'url(../valid/path/to/');
+      } else {
+        return propertyValue;
+      }
+    }
+  }
+}
+
+return cleanCssCli(process, function (cleanCss) {
+  cleanCss.options.plugins.level1Value.push(customPlugin.level1.value);
+});
+```
+
+# FAQ
+
+More answers can be found in [clean-css FAQ section](https://github.com/jakubpawlowicz/clean-css#faq).
+
+## How to optimize multiple files?
+
+It can be done by passing in paths to multiple files, e.g.
+
+```shell
+cleancss -o merged.min.css one.css two.css three.css
+```
+
+Since version 4.1.0 it can also be done using glob pattern matching, e.g.
+
+```shell
+cleancss -o merged.min.css *.css
+```
+
+## How to process multiple files without concatenating them into one output file?
+
+Since clean-css-cli 5.0 you can optimize files one by one, without joining them into one output file, e.g.
+
+```shell
+cleancss --batch styles/*.css
+```
+
+By default it will pick up every single file from `styles` directory, optimize it, add a `-min` suffix to filename (before extension), and write it to disk.
+
+You can use `--batch-suffix` option to customize the `-min` suffix, e.g.
+
+```shell
+cleancss --batch --batch-suffix '.min' styles/*.css # output will have `.min` suffix before `.css`, e.g. styles.min.css
+```
+
+or
+
+```shell
+cleancss --batch --batch-suffix '' styles/*.css # output files will OVERRIDE input files
+```
+
+Remember you can use [glob matching](https://www.npmjs.com/package/glob#glob-primer) to match exactly the files you want.
+
+Since clean-css-cli 5.1 you can also use a negated pattern to exclude some files from being matched, e.g.
+
+```shell
+cleancss --batch styles/*.css !styles/*.min.css
+```
+
+## How to specify a custom rounding precision?
+
+The level 1 `roundingPrecision` optimization option accept a string with per-unit rounding precision settings, e.g.
+
+```shell
+cleancss -O1 roundingPrecision:all=3,px=5
+```
+
+which sets all units rounding precision to 3 digits except `px` unit precision of 5 digits.
+
+## How to rebase relative image URLs?
+
+clean-css-cli will rebase paths it automatically for you when full paths to input files are passed, and `--with-rebase` & `--output` options are used, e.g
+
+```css
+/*! one.css */
+a {
+  background:url(image.png)
+}
+```
+
+```shell
+cleancss --with-rebase -o build/one.min.css one.css
+```
+
+```css
+/*! build/one.min.css */
+a{background:url(../image.png)}
+```
+
+## How to apply level 1 & 2 optimizations at the same time?
+
+Using `-O` option twice and specifying optimization options in each, e.g.
+
+```shell
+cleancss -O1 all:on,normalizeUrls:off -O2 restructureRules:on one.css
+```
+
+will apply level 1 optimizations, except url normalization, and default level 2 optimizations with rule restructuring.
+
+# Contributing
+
+See [CONTRIBUTING.md](https://github.com/clean-css/clean-css-cli/blob/master/CONTRIBUTING.md).
+
+## How to get started?
+
+First clone the sources:
+
+```shell
+git clone [email protected]:clean-css/clean-css-cli.git
+```
+
+then install dependencies:
+
+```shell
+cd clean-css-cli
+npm install
+```
+
+then use any of the following commands to verify your copy:
+
+```shell
+npm run check # to lint JS sources with [JSHint](https://github.com/jshint/jshint/)
+npm test # to run all tests
+```
+
+# License
+
+clean-css-cli is released under the [MIT License](https://github.com/clean-css/clean-css-cli/blob/master/LICENSE).

+ 4 - 0
node_modules/clean-css-cli/bin/cleancss

@@ -0,0 +1,4 @@
+#!/usr/bin/env node
+
+var cleanCssCli = require('../index');
+return cleanCssCli(process);

+ 376 - 0
node_modules/clean-css-cli/index.js

@@ -0,0 +1,376 @@
+var fs = require('fs');
+var path = require('path');
+
+var CleanCSS = require('clean-css');
+var program = require('commander');
+var glob = require('glob');
+
+var COMPATIBILITY_PATTERN = /([\w\.]+)=(\w+)/g;
+var lineBreak = require('os').EOL;
+
+function cli(process, beforeMinifyCallback) {
+  var packageConfig = fs.readFileSync(path.join(__dirname, 'package.json'));
+  var buildVersion = JSON.parse(packageConfig).version;
+  var fromStdin;
+  var inputOptions;
+  var options;
+  var stdin;
+  var data;
+
+  beforeMinifyCallback = beforeMinifyCallback || Function.prototype;
+
+  // Specify commander options to parse command line params correctly
+  program
+    .usage('[options] <source-file ...>')
+    .option('-b, --batch', 'If enabled, optimizes input files one by one instead of joining them together')
+    .option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode (see Readme for advanced examples)')
+    .option('-d, --debug', 'Shows debug information (minification time & compression efficiency)')
+    .option('-f, --format <options>', 'Controls output formatting, see examples below')
+    .option('-h, --help', 'display this help')
+    .option('-o, --output [output-file]', 'Use [output-file] as output instead of STDOUT')
+    .option('-O <n> [optimizations]', 'Turn on level <n> optimizations; optionally accepts a list of fine-grained options, defaults to `1`, see examples below, IMPORTANT: the prefix is O (a capital o letter), NOT a 0 (zero, a number)', function (val) { return Math.abs(parseInt(val)); })
+    .version(buildVersion, '-v, --version')
+    .option('--batch-suffix <suffix>', 'A suffix (without extension) appended to input file name when processing in batch mode (`-min` is the default)', '-min')
+    .option('--inline [rules]', 'Enables inlining for listed sources (defaults to `local`)')
+    .option('--inline-timeout [seconds]', 'Per connection timeout when fetching remote stylesheets (defaults to 5 seconds)', parseFloat)
+    .option('--input-source-map [file]', 'Specifies the path of the input source map file')
+    .option('--remove-inlined-files', 'Remove files inlined in <source-file ...> or via `@import` statements')
+    .option('--source-map', 'Enables building input\'s source map')
+    .option('--source-map-inline-sources', 'Enables inlining sources inside source maps')
+    .option('--with-rebase', 'Enable URLs rebasing')
+    .option('--watch', 'Runs CLI in watch mode');
+
+  program.on('--help', function () {
+    console.log('');
+    console.log('Examples:\n');
+    console.log('  %> cleancss one.css');
+    console.log('  %> cleancss -o one-min.css one.css');
+    console.log('  %> cleancss -o merged-and-minified.css one.css two.css three.css');
+    console.log('  %> cleancss one.css two.css three.css | gzip -9 -c > merged-minified-and-gzipped.css.gz');
+    console.log('');
+    console.log('Formatting options:');
+    console.log('  %> cleancss --format beautify one.css');
+    console.log('  %> cleancss --format keep-breaks one.css');
+    console.log('  %> cleancss --format \'indentBy:1;indentWith:tab\' one.css');
+    console.log('  %> cleancss --format \'breaks:afterBlockBegins=on;spaces:aroundSelectorRelation=on\' one.css');
+    console.log('  %> cleancss --format \'breaks:afterBlockBegins=2;spaces:aroundSelectorRelation=on\' one.css');
+    console.log('');
+    console.log('Level 0 optimizations:');
+    console.log('  %> cleancss -O0 one.css');
+    console.log('');
+    console.log('Level 1 optimizations:');
+    console.log('  %> cleancss -O1 one.css');
+    console.log('  %> cleancss -O1 removeQuotes:off;roundingPrecision:4;specialComments:1 one.css');
+    console.log('  %> cleancss -O1 all:off;specialComments:1 one.css');
+    console.log('');
+    console.log('Level 2 optimizations:');
+    console.log('  %> cleancss -O2 one.css');
+    console.log('  %> cleancss -O2 mergeMedia:off;restructureRules:off;mergeSemantically:on;mergeIntoShorthands:off one.css');
+    console.log('  %> cleancss -O2 all:off;removeDuplicateRules:on one.css');
+
+    process.exit();
+  });
+
+  program.parse(process.argv);
+  inputOptions = program.opts();
+
+  // If no sensible data passed in just print help and exit
+  if (program.args.length === 0) {
+    fromStdin = !process.env.__DIRECT__ && !process.stdin.isTTY;
+    if (!fromStdin) {
+      program.outputHelp();
+      return 0;
+    }
+  }
+
+  // Now coerce arguments into CleanCSS configuration...
+  options = {
+    batch: inputOptions.batch,
+    compatibility: inputOptions.compatibility,
+    format: inputOptions.format,
+    inline: typeof inputOptions.inline == 'string' ? inputOptions.inline : 'local',
+    inlineTimeout: inputOptions.inlineTimeout * 1000,
+    level: { 1: true },
+    output: inputOptions.output,
+    rebase: inputOptions.withRebase ? true : false,
+    rebaseTo: undefined,
+    sourceMap: inputOptions.sourceMap,
+    sourceMapInlineSources: inputOptions.sourceMapInlineSources
+  };
+
+  if (program.rawArgs.indexOf('-O0') > -1) {
+    options.level[0] = true;
+  }
+
+  if (program.rawArgs.indexOf('-O1') > -1) {
+    options.level[1] = findArgumentTo('-O1', program.rawArgs, program.args);
+  }
+
+  if (program.rawArgs.indexOf('-O2') > -1) {
+    options.level[2] = findArgumentTo('-O2', program.rawArgs, program.args);
+  }
+
+  if (inputOptions.inputSourceMap && !options.sourceMap) {
+    options.sourceMap = true;
+  }
+
+  if (options.sourceMap && !options.output && !options.batch) {
+    outputFeedback(['Source maps will not be built because you have not specified an output file.'], true);
+    options.sourceMap = false;
+  }
+
+  if (options.output && options.batch) {
+    fs.mkdirSync(options.output, {recursive: true});
+  }
+
+  if (inputOptions.withRebase && ('output' in inputOptions) && inputOptions.output.length > 0) {
+    if (isDirectory(path.resolve(inputOptions.output))) {
+      options.rebaseTo = path.resolve(inputOptions.output);
+    } else {
+      options.rebaseTo = path.dirname(path.resolve(inputOptions.output));
+    }
+  } else {
+    if (inputOptions.withRebase) {
+      options.rebaseTo = process.cwd();
+    }
+  }
+
+  var configurations = {
+    batchSuffix: inputOptions.batchSuffix,
+    beforeMinifyCallback: beforeMinifyCallback,
+    debugMode: inputOptions.debug,
+    removeInlinedFiles: inputOptions.removeInlinedFiles,
+    inputSourceMap: inputOptions.inputSourceMap
+  };
+
+  // ... and do the magic!
+  if (program.args.length > 0) {
+    var expandedGlobs = expandGlobs(program.args);
+    if (inputOptions.watch) {
+      var inputPaths = expandedGlobs.map(function (path) { return path.expanded; });
+
+      minify(process, options, configurations, expandedGlobs);
+      require('chokidar').watch(inputPaths).on('change', function (pathToChangedFile) {
+        console.log(`File '${pathToChangedFile}' has changed. Rerunning all optimizations...`);
+        minify(process, options, configurations, expandedGlobs);
+      });
+    } else {
+      minify(process, options, configurations, expandedGlobs);
+    }
+  } else {
+    stdin = process.openStdin();
+    stdin.setEncoding('utf-8');
+    data = '';
+    stdin.on('data', function (chunk) {
+      data += chunk;
+    });
+    stdin.on('end', function () {
+      minify(process, options, configurations, data);
+    });
+  }
+}
+
+function isDirectory(path) {
+  try {
+    return fs.statSync(path).isDirectory();
+  } catch (e) {
+    if (e.code == 'ENOENT') {
+      return false;
+    } else {
+      throw e;
+    }
+  }
+}
+
+function findArgumentTo(option, rawArgs, args) {
+  var value = true;
+  var optionAt = rawArgs.indexOf(option);
+  var nextOption = rawArgs[optionAt + 1];
+  var looksLikePath;
+  var asArgumentAt;
+
+  if (!nextOption) {
+    return value;
+  }
+
+  looksLikePath = nextOption.indexOf('.css') > -1 ||
+    /\//.test(nextOption) ||
+    /\\[^\-]/.test(nextOption) ||
+    /^https?:\/\//.test(nextOption);
+  asArgumentAt = args.indexOf(nextOption);
+
+  if (!looksLikePath) {
+    value = nextOption;
+  }
+
+  if (!looksLikePath && asArgumentAt > -1) {
+    args.splice(asArgumentAt, 1);
+  }
+
+  return value;
+}
+
+function expandGlobs(paths) {
+  var globPatterns = paths.filter(function (path) { return path[0] != '!'; });
+  var ignoredGlobPatterns = paths
+    .filter(function (path) { return path[0] == '!'; })
+    .map(function (path) { return path.substring(1); });
+
+  return globPatterns.reduce(function (accumulator, path) {
+    var expandedWithSource =
+      glob.sync(path, { ignore: ignoredGlobPatterns, nodir: true, nonull: true })
+      .map(function (expandedPath) { return { expanded: expandedPath, source: path }; });
+
+    return accumulator.concat(expandedWithSource);
+  }, []);
+}
+
+function minify(process, options, configurations, data) {
+  var cleanCss = new CleanCSS(options);
+  var input = typeof(data) == 'string' ?
+    data :
+    data.map(function (o) { return o.expanded; });
+
+  applyNonBooleanCompatibilityFlags(cleanCss, options.compatibility);
+  configurations.beforeMinifyCallback(cleanCss);
+  cleanCss.minify(input, getSourceMapContent(configurations.inputSourceMap), function (errors, minified) {
+    var inputPath;
+    var outputPath;
+
+    if (options.batch && !('styles' in minified)) {
+      for (inputPath in minified) {
+        outputPath = options.batch && options.output ?
+          toBatchOutputPath(inputPath, configurations.batchSuffix, options.output, data) :
+          toSimpleOutputPath(inputPath, configurations.batchSuffix);
+
+        processMinified(process, configurations, minified[inputPath], inputPath, outputPath);
+      }
+    } else {
+      processMinified(process, configurations, minified, null, options.output);
+    }
+  });
+}
+
+function toSimpleOutputPath(inputPath, batchSuffix) {
+  var extensionName = path.extname(inputPath);
+
+  return inputPath.replace(new RegExp(extensionName + '$'), batchSuffix + extensionName);
+}
+
+function toBatchOutputPath(inputPath, batchSuffix, output, expandedWithSource) {
+  var extensionName = path.extname(inputPath);
+  var inputSource = expandedWithSource.find(function (ic) { return ic.expanded == inputPath; }).source;
+  var inputSourceRoot = inputSource.indexOf('*') > -1 ?
+    inputSource.substring(0, inputSource.indexOf('*')) :
+    path.dirname(inputSource);
+
+  return path.join(output, inputPath.replace(inputSourceRoot, '').replace(new RegExp(extensionName + '$'), batchSuffix + extensionName));
+}
+
+function processMinified(process, configurations, minified, inputPath, outputPath) {
+  var mapOutputPath;
+
+  if (configurations.debugMode) {
+    if (inputPath) {
+      console.error('File: %s', inputPath);
+    }
+
+    console.error('Original: %d bytes', minified.stats.originalSize);
+    console.error('Minified: %d bytes', minified.stats.minifiedSize);
+    console.error('Efficiency: %d%', ~~(minified.stats.efficiency * 10000) / 100.0);
+    console.error('Time spent: %dms', minified.stats.timeSpent);
+
+    if (minified.inlinedStylesheets.length > 0) {
+      console.error('Inlined stylesheets:');
+      minified.inlinedStylesheets.forEach(function (uri) {
+        console.error('- %s', uri);
+      });
+    }
+
+    console.error('');
+  }
+
+  outputFeedback(minified.errors, true);
+  outputFeedback(minified.warnings);
+
+  if (minified.errors.length > 0) {
+    process.exit(1);
+  }
+
+  if (configurations.removeInlinedFiles) {
+    minified.inlinedStylesheets.forEach(fs.unlinkSync);
+  }
+
+  if (minified.sourceMap) {
+    mapOutputPath = outputPath + '.map';
+    output(process, outputPath, minified.styles + lineBreak + '/*# sourceMappingURL=' + path.basename(mapOutputPath) + ' */');
+    outputMap(mapOutputPath, minified.sourceMap);
+  } else {
+    output(process, outputPath, minified.styles);
+  }
+}
+
+function applyNonBooleanCompatibilityFlags(cleanCss, compatibility) {
+  var match;
+  var scope;
+  var parts;
+  var i, l;
+
+  if (!compatibility) {
+    return;
+  }
+
+  patternLoop:
+  while ((match = COMPATIBILITY_PATTERN.exec(compatibility)) !== null) {
+    scope = cleanCss.options.compatibility;
+    parts = match[1].split('.');
+
+    for (i = 0, l = parts.length - 1; i < l; i++) {
+      scope = scope[parts[i]];
+
+      if (!scope) {
+        continue patternLoop;
+      }
+    }
+
+    scope[parts.pop()] = match[2];
+  }
+}
+
+function outputFeedback(messages, isError) {
+  var prefix = isError ? '\x1B[31mERROR\x1B[39m:' : 'WARNING:';
+
+  messages.forEach(function (message) {
+    console.error('%s %s', prefix, message);
+  });
+}
+
+function getSourceMapContent(sourceMapPath) {
+  if (!sourceMapPath || !fs.existsSync(sourceMapPath)) {
+    return null;
+  }
+  var content = null;
+
+  try {
+    content = fs.readFileSync(sourceMapPath).toString();
+  } catch (e) {
+    console.error('Failed to read the input source map file.');
+  }
+
+  return content;
+}
+
+function output(process, outputPath, minified) {
+  if (outputPath) {
+    fs.mkdirSync(path.dirname(outputPath), {recursive: true});
+    fs.writeFileSync(outputPath, minified, 'utf8');
+  } else {
+    process.stdout.write(minified);
+  }
+}
+
+function outputMap(mapOutputPath, sourceMap) {
+  fs.writeFileSync(mapOutputPath, sourceMap.toString(), 'utf-8');
+}
+
+module.exports = cli;

+ 51 - 0
node_modules/clean-css-cli/package.json

@@ -0,0 +1,51 @@
+{
+  "name": "clean-css-cli",
+  "version": "5.6.3",
+  "description": "A command-line interface to clean-css CSS optimization library",
+  "scripts": {
+    "check": "jshint ./bin/cleancss .",
+    "prepublish": "npm run check",
+    "test": "vows"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/clean-css/clean-css-cli.git"
+  },
+  "keywords": [
+    "css",
+    "optimizer",
+    "minifier"
+  ],
+  "bin": {
+    "cleancss": "./bin/cleancss"
+  },
+  "author": "Jakub Pawlowicz <[email protected]>",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/clean-css/clean-css-cli/issues"
+  },
+  "main": "index.js",
+  "files": [
+    "bin",
+    "History.md",
+    "index.js",
+    "LICENSE",
+    "README.md"
+  ],
+  "homepage": "https://github.com/clean-css/clean-css-cli#readme",
+  "dependencies": {
+    "chokidar": "^3.5.2",
+    "clean-css": "^5.3.3",
+    "commander": "7.x",
+    "glob": "^7.1.6"
+  },
+  "devDependencies": {
+    "http-proxy": "1.x",
+    "jshint": "^2.13.0",
+    "source-map": "0.5.x",
+    "vows": "^0.8.3"
+  },
+  "engines": {
+    "node": ">= 10.12.0"
+  }
+}

+ 1504 - 0
node_modules/clean-css/History.md

@@ -0,0 +1,1504 @@
+[5.3.3 / 2023-11-30](https://github.com/clean-css/clean-css/compare/v5.3.2...v5.3.3)
+==================
+
+* Fixed issue [#1262](https://github.com/clean-css/clean-css/issues/1262) - dynamically require os for edge runtime compatibility.
+
+[5.3.2 / 2023-01-19](https://github.com/clean-css/clean-css/compare/v5.3.1...v5.3.2)
+==================
+
+* Fixed issue [#1224](https://github.com/clean-css/clean-css/issues/1224) - incorrect parsing of selectors with double hyphen.
+* Fixed issue [#1228](https://github.com/clean-css/clean-css/issues/1228) - incorrect appending of '%' inside rgba colors.
+* Fixed issue [#1232](https://github.com/clean-css/clean-css/issues/1232) - support for `@container` keyword.
+* Fixed issue [#1239](https://github.com/clean-css/clean-css/issues/1239) - edge case in handling `@import` statements.
+* Fixed issue [#1242](https://github.com/clean-css/clean-css/issues/1242) - support for `@layer` keyword.
+
+[5.3.1 / 2022-07-13](https://github.com/clean-css/clean-css/compare/v5.3.0...v5.3.1)
+==================
+
+* Fixed issue [#1218](https://github.com/clean-css/clean-css/issues/1218) - double hyphen in at-rule breaks parsing.
+* Fixed issue [#1220](https://github.com/clean-css/clean-css/issues/1220) - adds optimization for nth-* rules.
+
+[5.3.0 / 2022-03-31](https://github.com/clean-css/clean-css/compare/v5.2.3...v5.3.0)
+==================
+
+* Adds customizable value optimizers for variables.
+* Fixed issue [#1159](https://github.com/clean-css/clean-css/issues/1159) - adds optimization for `nth-child` and `nth-of-type`.
+* Fixed issue [#1181](https://github.com/clean-css/clean-css/issues/1181) - CSS level 4 color functions with spaces.
+* Fixed issue [#1183](https://github.com/clean-css/clean-css/issues/1183) - fraction optimizer breaks `image-set`.
+* Fixed issue [#1208](https://github.com/clean-css/clean-css/issues/1208) - handling generic family names.
+* Fixed issue [#1210](https://github.com/clean-css/clean-css/issues/1210) - handling `file://` protocol.
+
+[5.2.4 / 2022-01-28](https://github.com/clean-css/clean-css/compare/v5.2.3...v5.2.4)
+==================
+
+* Fixed issue [#1196](https://github.com/clean-css/clean-css/issues/1196) - correctly parse variables & comments mix.
+
+[5.2.3 / 2022-01-26](https://github.com/clean-css/clean-css/compare/v5.2.2...v5.2.3)
+==================
+
+* Fixed issue [#1185](https://github.com/clean-css/clean-css/issues/1185) - keeping comments inside variables.
+* Fixed issue [#1194](https://github.com/clean-css/clean-css/issues/1194) - unexpected end of JSON input when source map is empty.
+
+[5.2.2 / 2021-10-21](https://github.com/clean-css/clean-css/compare/v5.2.1...v5.2.2)
+==================
+
+* Fixed an unsafe data URI regex, which, when clean-css is used as a service, could be used in a DOS attack.
+
+[5.2.1 / 2021-09-30](https://github.com/clean-css/clean-css/compare/v5.2.0...v5.2.1)
+==================
+
+* Fixed issue [#1186](https://github.com/clean-css/clean-css/issues/1186) - bad error handling in batch mode with promises.
+
+[5.2.0 / 2021-09-25](https://github.com/clean-css/clean-css/compare/5.1...v5.2.0)
+==================
+
+* Fixed issue [#1180](https://github.com/clean-css/clean-css/issues/1180) - properly handle empty variable values.
+
+[5.1.5 / 2021-08-05](https://github.com/clean-css/clean-css/compare/v5.1.4...v5.1.5)
+==================
+
+* Fixed issue [#1178](https://github.com/clean-css/clean-css/issues/1178) - fixes lack of space removal in variable blocks.
+
+[5.1.4 / 2021-07-29](https://github.com/clean-css/clean-css/compare/v5.1.3...v5.1.4)
+==================
+
+* Fixed issue [#1177](https://github.com/clean-css/clean-css/issues/1177) - fix to missing local imports when only remote ones allowed.
+
+[5.1.3 / 2021-06-25](https://github.com/clean-css/clean-css/compare/v5.1.2...v5.1.3)
+==================
+
+* Fixed issue [#1160](https://github.com/clean-css/clean-css/issues/1160) - keep zero units when inside multiple functions.
+* Fixed issue [#1161](https://github.com/clean-css/clean-css/issues/1161) - extra whitespace in URLs.
+* Fixed issue [#1166](https://github.com/clean-css/clean-css/issues/1166) - incorrect compoment splitting when empty multiplex part.
+
+[5.1.2 / 2021-03-19](https://github.com/clean-css/clean-css/compare/v5.1.1...v5.1.2)
+==================
+
+* Fixed issue [#996](https://github.com/clean-css/clean-css/issues/996) - space removed from pseudo classes.
+
+[5.1.1 / 2021-03-03](https://github.com/clean-css/clean-css/compare/v5.1.0...v5.1.1)
+==================
+
+* Fixed issue [#1156](https://github.com/clean-css/clean-css/issues/1156) - invalid hsl/hsla validation in level 2 optimizations.
+
+[5.1.0 / 2021-02-18](https://github.com/clean-css/clean-css/compare/5.0...v5.1.0)
+==================
+
+* Fixes stripping '%' from inside color functions.
+* Improves tokenization speed by ~30%.
+* Fixed issue [#1143](https://github.com/clean-css/clean-css/issues/1143) - some missing level 1 value optimizations.
+
+
+[5.0.1 / 2021-01-29](https://github.com/clean-css/clean-css/compare/v5.0.0...v5.0.1)
+==================
+
+* Fixed issue [#1139](https://github.com/clean-css/clean-css/issues/1139) - overriding & merging properties without `canOverride` set.
+
+[5.0.0 / 2021-01-29](https://github.com/clean-css/clean-css/compare/4.2...v5.0.0)
+==================
+
+* Adds a way process input files without bundling it into one big output file.
+* Adds level 1 and level 2 optimization plugins.
+* Disables URL rebasing by default.
+* Disables URL unquoting by default.
+* Drops support for Node.js 6 & 8 to support last 3 Node.js releases: 10, 12, and 14.
+* Fixed issue [#889](https://github.com/clean-css/clean-css/issues/889) - whitelisted level 1 optimizations.
+* Fixed issue [#975](https://github.com/clean-css/clean-css/issues/975) - incorrect block name optimization.
+* Fixed issue [#1009](https://github.com/clean-css/clean-css/issues/1009) - whitespace around comments.
+* Fixed issue [#1021](https://github.com/clean-css/clean-css/issues/1021) - allow one- and two-letter property names.
+* Fixed issue [#1022](https://github.com/clean-css/clean-css/issues/1022) - merging into shorthands new property positioning.
+* Fixed issue [#1032](https://github.com/clean-css/clean-css/issues/1032) - wrong order of merged shorthands with inherit.
+* Fixed issue [#1043](https://github.com/clean-css/clean-css/issues/1043) - `calc` fallback removed within other function.
+* Fixed issue [#1045](https://github.com/clean-css/clean-css/issues/1045) - non-standard protocol-less URL first slash removed.
+* Fixed issue [#1050](https://github.com/clean-css/clean-css/issues/1050) - correctly keeps default animation duration if delay is also set.
+* Fixed issue [#1053](https://github.com/clean-css/clean-css/issues/1053) - treats `calc()` as first class width value.
+* Fixed issue [#1055](https://github.com/clean-css/clean-css/issues/1055) - supports 4- and 8-character hex with alpha color notation.
+* Fixed issue [#1057](https://github.com/clean-css/clean-css/issues/1057) - level 2 optimizations and quoted font family name.
+* Fixed issue [#1059](https://github.com/clean-css/clean-css/issues/1059) - animation time units as CSS expressions.
+* Fixed issue [#1060](https://github.com/clean-css/clean-css/issues/1060) - variable removed when shorthand's only value.
+* Fixed issue [#1062](https://github.com/clean-css/clean-css/issues/1062) - wrong optimization of CSS pseudo-classes with selector list.
+* Fixed issue [#1073](https://github.com/clean-css/clean-css/issues/1073) - adds support for non-standard `rpx` units.
+* Fixed issue [#1075](https://github.com/clean-css/clean-css/issues/1075) - media merging and variables.
+* Fixed issue [#1087](https://github.com/clean-css/clean-css/issues/1087) - allow units with any case.
+* Fixed issue [#1088](https://github.com/clean-css/clean-css/issues/1088) - building source maps with source preserved via comments.
+* Fixed issue [#1090](https://github.com/clean-css/clean-css/issues/1090) - edge case in merging for `border` and `border-image`.
+* Fixed issue [#1103](https://github.com/clean-css/clean-css/issues/1103) - don't allow merging longhand into `unset` shorthand.
+* Fixed issue [#1115](https://github.com/clean-css/clean-css/issues/1115) - incorrect multiplex longhand into shorthand merging.
+* Fixed issue [#1117](https://github.com/clean-css/clean-css/issues/1117) - don't change zero values inside `min`, `max`, and `clamp` functions.
+* Fixed issue [#1122](https://github.com/clean-css/clean-css/issues/1122) - don't wrap data URI in single quotes.
+* Fixed issue [#1125](https://github.com/clean-css/clean-css/issues/1125) - quotes stripped from withing `@supports` clause.
+* Fixed issue [#1128](https://github.com/clean-css/clean-css/issues/1128) - take variables into account when reordering properties.
+* Fixed issue [#1132](https://github.com/clean-css/clean-css/issues/1132) - vendor-prefixed classes inside `:not()`.
+* Reworks all level 1 optimizations to conform to plugin style.
+
+[4.2.3 / 2020-01-28](https://github.com/clean-css/clean-css/compare/v4.2.2...v4.2.3)
+==================
+
+* Fixed issue [#1106](https://github.com/clean-css/clean-css/issues/1106) - regression in handling RGBA/HSLA colors.
+
+[4.2.2 / 2020-01-25](https://github.com/clean-css/clean-css/compare/v4.2.1...v4.2.2)
+==================
+
+* Fixed error when property block has no value.
+* Fixed issue [#1077](https://github.com/clean-css/clean-css/issues/1077) - local fonts with color in name.
+* Fixed issue [#1082](https://github.com/clean-css/clean-css/issues/1082) - correctly convert colors if alpha >= 1.
+* Fixed issue [#1085](https://github.com/clean-css/clean-css/issues/1085) - prevent unquoting of grid elements.
+
+[4.2.1 / 2018-08-07](https://github.com/clean-css/clean-css/compare/v4.2.0...v4.2.1)
+==================
+
+* Fixes giving `breakWith` option via a string.
+
+[4.2.0 / 2018-08-02](https://github.com/clean-css/clean-css/compare/4.1...v4.2.0)
+==================
+
+* Adds `process` method for compatibility with optimize-css-assets-webpack-plugin.
+* Fixed issue [#861](https://github.com/clean-css/clean-css/issues/861) - new `transition` property optimizer.
+* Fixed issue [#895](https://github.com/clean-css/clean-css/issues/895) - ignoring specific styles.
+* Fixed issue [#947](https://github.com/clean-css/clean-css/issues/947) - selector based filtering.
+* Fixed issue [#964](https://github.com/clean-css/clean-css/issues/964) - adds configurable line breaks.
+* Fixed issue [#986](https://github.com/clean-css/clean-css/issues/986) - level 2 optimizations and CSS 4 colors.
+* Fixed issue [#1000](https://github.com/clean-css/clean-css/issues/1000) - carriage return handling in tokenizer.
+* Fixed issue [#1038](https://github.com/clean-css/clean-css/issues/1038) - `font-variation-settings` quoting.
+* Fixes ReDOS vulnerabilities in validator code.
+
+[4.1.11 / 2018-03-06](https://github.com/clean-css/clean-css/compare/v4.1.10...v4.1.11)
+==================
+
+* Backports fixes to ReDOS vulnerabilities in validator code.
+
+[4.1.10 / 2018-03-05](https://github.com/clean-css/clean-css/compare/v4.1.9...v4.1.10)
+==================
+
+* Fixed issue [#988](https://github.com/clean-css/clean-css/issues/988) - edge case in dropping default animation-duration.
+* Fixed issue [#989](https://github.com/clean-css/clean-css/issues/989) - edge case in removing unused at rules.
+* Fixed issue [#1001](https://github.com/clean-css/clean-css/issues/1001) - corrupted tokenizer state.
+* Fixed issue [#1006](https://github.com/clean-css/clean-css/issues/1006) - edge case in handling invalid source maps.
+* Fixed issue [#1008](https://github.com/clean-css/clean-css/issues/1008) - edge case in breaking up `font` shorthand.
+
+[4.1.9 / 2017-09-19](https://github.com/clean-css/clean-css/compare/v4.1.8...v4.1.9)
+==================
+
+* Fixed issue [#971](https://github.com/clean-css/clean-css/issues/971) - edge case in removing unused at rules.
+
+[4.1.8 / 2017-09-02](https://github.com/clean-css/clean-css/compare/v4.1.7...v4.1.8)
+==================
+
+* Fixed issue [#959](https://github.com/clean-css/clean-css/issues/959) - regression in shortening long hex values.
+* Fixed issue [#960](https://github.com/clean-css/clean-css/issues/960) - better explanation of `efficiency` stat.
+* Fixed issue [#965](https://github.com/clean-css/clean-css/issues/965) - edge case in parsing comment endings.
+* Fixed issue [#966](https://github.com/clean-css/clean-css/issues/966) - remote `@import`s referenced from local ones.
+
+[4.1.7 / 2017-07-14](https://github.com/clean-css/clean-css/compare/v4.1.6...v4.1.7)
+==================
+
+* Fixed issue [#957](https://github.com/clean-css/clean-css/issues/957) - `0%` minification of `width` property.
+
+[4.1.6 / 2017-07-08](https://github.com/clean-css/clean-css/compare/v4.1.5...v4.1.6)
+==================
+
+* Fixed issue [#887](https://github.com/clean-css/clean-css/issues/887) - edge case in serializing comments.
+* Fixed issue [#953](https://github.com/clean-css/clean-css/issues/953) - beautify breaks attribute selectors.
+
+[4.1.5 / 2017-06-29](https://github.com/clean-css/clean-css/compare/v4.1.4...v4.1.5)
+==================
+
+* Fixed issue [#945](https://github.com/clean-css/clean-css/issues/945) - hex RGBA colors in IE filters.
+* Fixed issue [#952](https://github.com/clean-css/clean-css/issues/952) - parsing `@page` according to CSS3 spec.
+
+[4.1.4 / 2017-06-14](https://github.com/clean-css/clean-css/compare/v4.1.3...v4.1.4)
+==================
+
+* Fixed issue [#950](https://github.com/clean-css/clean-css/issues/950) - bug in removing unused `@font-face` rules.
+
+[4.1.3 / 2017-05-18](https://github.com/clean-css/clean-css/compare/v4.1.2...v4.1.3)
+==================
+
+* Fixed issue [#946](https://github.com/clean-css/clean-css/issues/946) - tokenizing `-ms-grid-columns` repeat syntax.
+
+[4.1.2 / 2017-05-10](https://github.com/clean-css/clean-css/compare/v4.1.1...v4.1.2)
+==================
+
+* Fixed issue [#939](https://github.com/clean-css/clean-css/issues/939) - semicolon after `@apply` at rule.
+* Fixed issue [#940](https://github.com/clean-css/clean-css/issues/940) - handling more `font` keywords.
+* Fixed issue [#941](https://github.com/clean-css/clean-css/issues/941) - breaking up vendor prefixed `animation`.
+
+[4.1.1 / 2017-05-08](https://github.com/clean-css/clean-css/compare/v4.1.0...v4.1.1)
+==================
+
+* Fixed issue [#938](https://github.com/clean-css/clean-css/issues/938) - removing unused at-rules with `!important`.
+
+[4.1.0 / 2017-05-07](https://github.com/clean-css/clean-css/compare/4.0...v4.1.0)
+==================
+
+* Improves longhand-into-shorthand merging mechanism in complex cases as with `border-*` shorthands.
+* Fixed issue [#254](https://github.com/clean-css/clean-css/issues/254) - adds `font` property optimizer.
+* Fixed issue [#525](https://github.com/clean-css/clean-css/issues/525) - restores `inherit`-based merging.
+* Fixed issue [#755](https://github.com/clean-css/clean-css/issues/755) - adds custom handling of remote requests.
+* Fixed issue [#860](https://github.com/clean-css/clean-css/issues/860) - adds `animation` property optimizer.
+* Fixed issue [#862](https://github.com/clean-css/clean-css/issues/862) - allows removing unused at rules.
+* Fixed issue [#886](https://github.com/clean-css/clean-css/issues/886) - better multi pseudo class / element merging.
+* Fixed issue [#890](https://github.com/clean-css/clean-css/issues/890) - adds toggle to disable empty tokens removal.
+* Fixed issue [#893](https://github.com/clean-css/clean-css/issues/893) - `inline: false` as alias to `inline: 'none'`.
+* Fixed issue [#905](https://github.com/clean-css/clean-css/issues/905) - allows disabling selector sorting.
+* Fixed issue [#906](https://github.com/clean-css/clean-css/issues/906) - improves usability of web UI settings.
+* Fixed issue [#908](https://github.com/clean-css/clean-css/issues/908) - improved `minify` method signature.
+* Fixed issue [#916](https://github.com/clean-css/clean-css/issues/916) - maximum number of merged selectors.
+* Fixed issue [#920](https://github.com/clean-css/clean-css/issues/920) - allows skipping certain properties in level 2 optimizations.
+* Fixed issue [#934](https://github.com/clean-css/clean-css/issues/934) - smarter longhand into shorthand merging.
+
+[4.0.13 / 2017-05-10](https://github.com/clean-css/clean-css/compare/v4.0.12...v4.0.13)
+==================
+
+* Backports [#939](https://github.com/clean-css/clean-css/issues/939) - semicolon after `@apply` at rule.
+
+[4.0.12 / 2017-04-12](https://github.com/clean-css/clean-css/compare/v4.0.11...v4.0.12)
+==================
+
+* Fixed issue [#930](https://github.com/clean-css/clean-css/issues/930) - regression in tidying selectors.
+
+[4.0.11 / 2017-04-04](https://github.com/clean-css/clean-css/compare/v4.0.10...v4.0.11)
+==================
+
+* Fixed issue [#924](https://github.com/clean-css/clean-css/issues/924) - `hsl` zero percent eager optimization.
+
+[4.0.10 / 2017-03-22](https://github.com/clean-css/clean-css/compare/v4.0.9...v4.0.10)
+==================
+
+* Fixed issue [#917](https://github.com/clean-css/clean-css/issues/917) - prevents grid area unquoting.
+* Backported [#916](https://github.com/clean-css/clean-css/issues/916) - maximum number of merged selectors.
+* Refixed issue [#556](https://github.com/clean-css/clean-css/issues/556) - IE backslash hacks.
+
+[4.0.9 / 2017-03-15](https://github.com/clean-css/clean-css/compare/v4.0.8...v4.0.9)
+==================
+
+* Fixed issue [#902](https://github.com/clean-css/clean-css/issues/902) - case insensitive attribute matchers.
+* Fixed issue [#903](https://github.com/clean-css/clean-css/issues/903) - web UI and source maps.
+* Fixed issue [#907](https://github.com/clean-css/clean-css/issues/907) - space after closing brace in `@supports`.
+* Fixed issue [#910](https://github.com/clean-css/clean-css/issues/910) - too aggressive precision optimizations.
+
+[4.0.8 / 2017-02-22](https://github.com/clean-css/clean-css/compare/v4.0.7...v4.0.8)
+==================
+
+* Fixes edge case in remote stylesheet fetching.
+* Fixed issue [#899](https://github.com/clean-css/clean-css/issues/899) - regression in optimizing pseudo class arguments.
+
+[4.0.7 / 2017-02-14](https://github.com/clean-css/clean-css/compare/v4.0.6...v4.0.7)
+==================
+
+* Fixed issue [#891](https://github.com/clean-css/clean-css/issues/891) - merging vendor-prefixed pseudo-classes.
+
+[4.0.6 / 2017-02-10](https://github.com/clean-css/clean-css/compare/v4.0.5...v4.0.6)
+==================
+
+* Fixed issue [#885](https://github.com/clean-css/clean-css/issues/885) - unquoting `font-feature-settings`.
+
+[4.0.5 / 2017-02-07](https://github.com/clean-css/clean-css/compare/v4.0.4...v4.0.5)
+==================
+
+* Fixed issue [#884](https://github.com/clean-css/clean-css/issues/884) - handling absolute paths on Windows.
+* Fixed issue [#881](https://github.com/clean-css/clean-css/issues/881) - incorrect `require` arity.
+* Fixed issue [#880](https://github.com/clean-css/clean-css/issues/880) - incorrect token type identification.
+
+[4.0.4 / 2017-02-04](https://github.com/clean-css/clean-css/compare/v4.0.3...v4.0.4)
+==================
+
+* Fixed issue [#879](https://github.com/clean-css/clean-css/issues/879) - incorrect handling of spaces in paths.
+* Fixed issue [#878](https://github.com/clean-css/clean-css/issues/878) - invalid double backslash tokenization.
+
+[4.0.3 / 2017-01-30](https://github.com/clean-css/clean-css/compare/v4.0.2...v4.0.3)
+==================
+
+* Fixed issue [#875](https://github.com/clean-css/clean-css/issues/875) - invalid traversing in semantic merging.
+
+[4.0.2 / 2017-01-26](https://github.com/clean-css/clean-css/compare/v4.0.1...v4.0.2)
+==================
+
+* Fixed issue [#874](https://github.com/clean-css/clean-css/issues/874) - regression in at-rule tokenization.
+
+[4.0.1 / 2017-01-25](https://github.com/clean-css/clean-css/compare/v4.0.0...v4.0.1)
+==================
+
+* Fixed issue [#866](https://github.com/clean-css/clean-css/issues/866) - edge case in `inline` option.
+* Fixed issue [#867](https://github.com/clean-css/clean-css/issues/867) - skip optimizing variable values.
+* Fixed issue [#868](https://github.com/clean-css/clean-css/issues/868) - accept absolute paths in input hash.
+* Fixed issue [#872](https://github.com/clean-css/clean-css/issues/872) - edge case in CSS tokenization.
+
+[4.0.0 / 2017-01-23](https://github.com/clean-css/clean-css/compare/v3.4.24...v4.0.0)
+==================
+
+* Adds more detailed error & warning messages on top of the new tokenizer.
+* Disables restructuring optimizations by default until optimized in #533.
+* Fixes a bug ignoring incorrect properties in complex restructuring.
+* Requires Node.js 4.0+ to run.
+* Removes `benchmark` API option as total time is always reported under `stats` property.
+* Removes `debug` API switch as stats are always gathered and available under `stats` property.
+* Replaces the old tokenizer with a new one which doesn't use any escaping.
+* Replaces the old `@import` inlining with one on top of the new tokenizer.
+* Re-enables `background-(clip|origin|size)` merging with `background` shorthand.
+* Simplifies URL rebasing with a single `rebaseTo` option in API or inferred from `--output` in CLI.
+* Splits `inliner` option into `inlineRequest` and `inlineTimeout`.
+* Fixed issue [#209](https://github.com/clean-css/clean-css/issues/209) - adds output formatting via `format` flag.
+* Fixed issue [#290](https://github.com/clean-css/clean-css/issues/290) - removes aggressive merging.
+* Fixed issue [#432](https://github.com/clean-css/clean-css/issues/432) - adds URLs normalization.
+* Fixed issue [#460](https://github.com/clean-css/clean-css/issues/460) - unescaped semicolon in selector.
+* Fixed issue [#657](https://github.com/clean-css/clean-css/issues/657) - adds property name validation.
+* Fixed issue [#685](https://github.com/clean-css/clean-css/issues/685) - adds lowercasing hex colors optimization.
+* Fixed issue [#686](https://github.com/clean-css/clean-css/issues/686) - adds rounding precision for all units.
+* Fixed issue [#703](https://github.com/clean-css/clean-css/issues/703) - changes default IE compatibility to 10+.
+* Fixed issue [#731](https://github.com/clean-css/clean-css/issues/731) - adds granular control over level 2 optimizations.
+* Fixed issue [#739](https://github.com/clean-css/clean-css/issues/739) - error when a closing brace is missing.
+* Fixed issue [#750](https://github.com/clean-css/clean-css/issues/750) - allows `width` overriding.
+* Fixed issue [#756](https://github.com/clean-css/clean-css/issues/756) - adds disabling font-weight optimizations.
+* Fixed issue [#758](https://github.com/clean-css/clean-css/issues/758) - ignores rules with empty selector.
+* Fixed issue [#767](https://github.com/clean-css/clean-css/issues/767) - disables remote `@import` inlining by default.
+* Fixed issue [#773](https://github.com/clean-css/clean-css/issues/773) - adds reordering based on selector specificity.
+* Fixed issue [#785](https://github.com/clean-css/clean-css/issues/785) - adds `@font-face` de-duplication.
+* Fixed issue [#791](https://github.com/clean-css/clean-css/issues/791) - resolves imports in-memory if possible.
+* Fixed issue [#796](https://github.com/clean-css/clean-css/issues/796) - semantic merging for `@media` blocks.
+* Fixed issue [#801](https://github.com/clean-css/clean-css/issues/801) - smarter `@import` inlining.
+* Fixed issue [#806](https://github.com/clean-css/clean-css/issues/806) - skip optimizing variable properties.
+* Fixed issue [#817](https://github.com/clean-css/clean-css/issues/817) - makes `off` disable rounding.
+* Fixed issue [#818](https://github.com/clean-css/clean-css/issues/818) - disables `px` rounding by default.
+* Fixed issue [#828](https://github.com/clean-css/clean-css/issues/828) - `-chrome-` hack support.
+* Fixed issue [#829](https://github.com/clean-css/clean-css/issues/829) - adds more strict selector merging rules.
+* Fixed issue [#834](https://github.com/clean-css/clean-css/issues/834) - adds extra line break in nested blocks.
+* Fixed issue [#836](https://github.com/clean-css/clean-css/issues/836) - enables level `0` optimizations.
+* Fixed issue [#839](https://github.com/clean-css/clean-css/issues/839) - allows URIs in import inlining rules.
+* Fixed issue [#840](https://github.com/clean-css/clean-css/issues/840) - allows input source map as map object.
+* Fixed issue [#843](https://github.com/clean-css/clean-css/issues/843) - regression in selector handling.
+* Fixed issue [#845](https://github.com/clean-css/clean-css/issues/845) - web compatibility of 4.0 branch.
+* Fixed issue [#847](https://github.com/clean-css/clean-css/issues/847) - regression in handling invalid selectors.
+* Fixed issue [#849](https://github.com/clean-css/clean-css/issues/849) - disables inlining protocol-less resources.
+* Fixed issue [#856](https://github.com/clean-css/clean-css/issues/856) - allows `minify` to return a promise.
+* Fixed issue [#857](https://github.com/clean-css/clean-css/issues/857) - normalizes CleanCSS API interface.
+* Fixed issue [#863](https://github.com/clean-css/clean-css/issues/863) - adds `transform` callback for custom optimizations.
+
+[3.4.26 / 2017-05-10](https://github.com/clean-css/clean-css/compare/v3.4.25...v3.4.26)
+==================
+
+* Backports [#939](https://github.com/clean-css/clean-css/issues/939) - semicolon after `@apply` at-rule.
+
+[3.4.25 / 2017-02-22](https://github.com/clean-css/clean-css/compare/v3.4.24...v3.4.25)
+==================
+
+* Fixed issue [#897](https://github.com/clean-css/clean-css/issues/897) - tokenization with escaped markers.
+
+[3.4.24 / 2017-01-20](https://github.com/clean-css/clean-css/compare/v3.4.23...v3.4.24)
+==================
+
+* Fixed issue [#859](https://github.com/clean-css/clean-css/issues/859) - avoid `-webkit-border-radius` optimizations.
+
+[3.4.23 / 2016-12-17](https://github.com/clean-css/clean-css/compare/v3.4.22...v3.4.23)
+==================
+
+* Fixed issue [#844](https://github.com/clean-css/clean-css/issues/844) - regression in property values extraction.
+
+[3.4.22 / 2016-12-12](https://github.com/clean-css/clean-css/compare/v3.4.21...v3.4.22)
+==================
+
+* Fixed issue [#841](https://github.com/clean-css/clean-css/issues/841) - disabled importing and files passed as array.
+* Ignores `@import` at-rules if appearing after any non-`@import` rules.
+
+[3.4.21 / 2016-11-16](https://github.com/clean-css/clean-css/compare/v3.4.20...v3.4.21)
+==================
+
+* Fixed issue [#821](https://github.com/clean-css/clean-css/issues/821) - reducing non-adjacent rules.
+* Fixed issue [#830](https://github.com/clean-css/clean-css/issues/830) - reordering border-* properties.
+* Fixed issue [#833](https://github.com/clean-css/clean-css/issues/833) - moving `@media` queries.
+
+[3.4.20 / 2016-09-26](https://github.com/clean-css/clean-css/compare/v3.4.19...v3.4.20)
+==================
+
+* Fixed issue [#814](https://github.com/clean-css/clean-css/issues/814) - `:selection` rule merging.
+
+[3.4.19 / 2016-07-25](https://github.com/clean-css/clean-css/compare/v3.4.18...v3.4.19)
+==================
+
+* Fixed issue [#795](https://github.com/clean-css/clean-css/issues/795) - `!important` and override compacting.
+
+[3.4.18 / 2016-06-15](https://github.com/clean-css/clean-css/compare/v3.4.17...v3.4.18)
+==================
+
+* Fixed issue [#787](https://github.com/clean-css/clean-css/issues/787) - regression in processing data URIs.
+
+[3.4.17 / 2016-06-04](https://github.com/clean-css/clean-css/compare/v3.4.16...v3.4.17)
+==================
+
+* Fixed issue [#783](https://github.com/clean-css/clean-css/issues/783) - regression in processing data URIs.
+
+[3.4.16 / 2016-06-02](https://github.com/clean-css/clean-css/compare/v3.4.15...v3.4.16)
+==================
+
+* Fixed issue [#781](https://github.com/clean-css/clean-css/issues/781) - regression in override compacting.
+* Fixed issue [#782](https://github.com/clean-css/clean-css/issues/782) - regression in processing data URIs.
+
+[3.4.15 / 2016-06-01](https://github.com/clean-css/clean-css/compare/v3.4.14...v3.4.15)
+==================
+
+* Fixed issue [#776](https://github.com/clean-css/clean-css/issues/776) - edge case in quoted data URIs.
+* Fixed issue [#779](https://github.com/clean-css/clean-css/issues/779) - merging `background-(position|size)`.
+* Fixed issue [#780](https://github.com/clean-css/clean-css/issues/780) - space after inlined variables.
+
+[3.4.14 / 2016-05-31](https://github.com/clean-css/clean-css/compare/v3.4.13...v3.4.14)
+==================
+
+* Fixed issue [#751](https://github.com/clean-css/clean-css/issues/751) - stringifying CSS variables.
+* Fixed issue [#763](https://github.com/clean-css/clean-css/issues/763) - data URI SVG and quoting.
+* Fixed issue [#765](https://github.com/clean-css/clean-css/issues/765) - two values of border-radius.
+* Fixed issue [#768](https://github.com/clean-css/clean-css/issues/768) - invalid border-radius property.
+
+[3.4.13 / 2016-05-23](https://github.com/clean-css/clean-css/compare/v3.4.12...v3.4.13)
+==================
+
+* Fixed issue [#734](https://github.com/clean-css/clean-css/issues/769) - Node.js 6.x support.
+
+[3.4.12 / 2016-04-09](https://github.com/clean-css/clean-css/compare/v3.4.11...v3.4.12)
+==================
+
+* Fixed issue [#734](https://github.com/clean-css/clean-css/issues/734) - `--root` option edge case.
+* Fixed issue [#758](https://github.com/clean-css/clean-css/issues/758) - treats empty rule as unmergeable.
+
+[3.4.11 / 2016-04-01](https://github.com/clean-css/clean-css/compare/v3.4.10...v3.4.11)
+==================
+
+* Fixed issue [#738](https://github.com/clean-css/clean-css/issues/738) - edge case in comment processing.
+* Fixed issue [#741](https://github.com/clean-css/clean-css/issues/741) - HTTP proxy with HTTPS inlining.
+* Fixed issue [#743](https://github.com/clean-css/clean-css/issues/743) - background shorthand and source maps.
+* Fixed issue [#745](https://github.com/clean-css/clean-css/issues/745) - matching mixed case `!important`.
+
+[3.4.10 / 2016-02-29](https://github.com/clean-css/clean-css/compare/v3.4.9...v3.4.10)
+==================
+
+* Fixed issue [#735](https://github.com/clean-css/clean-css/issues/735) - whitespace removal with escaped chars.
+
+[3.4.9 / 2016-01-03](https://github.com/clean-css/clean-css/compare/v3.4.8...v3.4.9)
+==================
+
+* Sped up merging by body advanced optimization.
+* Fixed issue [#693](https://github.com/clean-css/clean-css/issues/693) - restructuring edge case.
+* Fixed issue [#711](https://github.com/clean-css/clean-css/issues/711) - border fuzzy matching.
+* Fixed issue [#714](https://github.com/clean-css/clean-css/issues/714) - stringifying property level at rules.
+* Fixed issue [#715](https://github.com/clean-css/clean-css/issues/715) - stack too deep in comment scan.
+
+[3.4.8 / 2015-11-13](https://github.com/clean-css/clean-css/compare/v3.4.7...v3.4.8)
+==================
+
+* Fixed issue [#676](https://github.com/clean-css/clean-css/issues/676) - fuzzy matching unqoted data URIs.
+
+[3.4.7 / 2015-11-10](https://github.com/clean-css/clean-css/compare/v3.4.6...v3.4.7)
+==================
+
+* Fixed issue [#692](https://github.com/clean-css/clean-css/issues/692) - edge case in URL quoting.
+* Fixed issue [#695](https://github.com/clean-css/clean-css/issues/695) - shorthand overriding edge case.
+* Fixed issue [#699](https://github.com/clean-css/clean-css/issues/699) - IE9 transparent hack.
+* Fixed issue [#701](https://github.com/clean-css/clean-css/issues/701) - `url` quoting with hash arguments.
+
+[3.4.6 / 2015-10-14](https://github.com/clean-css/clean-css/compare/v3.4.5...v3.4.6)
+==================
+
+* Fixed issue [#679](https://github.com/clean-css/clean-css/issues/679) - wrong rebasing of remote URLs.
+
+[3.4.5 / 2015-09-28](https://github.com/clean-css/clean-css/compare/v3.4.4...v3.4.5)
+==================
+
+* Fixed issue [#681](https://github.com/clean-css/clean-css/issues/681) - property inheritance & restructuring.
+* Fixed issue [#675](https://github.com/clean-css/clean-css/issues/675) - overriding with `!important`.
+
+[3.4.4 / 2015-09-21](https://github.com/clean-css/clean-css/compare/v3.4.3...v3.4.4)
+==================
+
+* Fixed issue [#626](https://github.com/clean-css/clean-css/issues/626) - edge case in import rebasing.
+* Fixed issue [#674](https://github.com/clean-css/clean-css/issues/674) - adjacent merging order.
+
+[3.4.3 / 2015-09-15](https://github.com/clean-css/clean-css/compare/v3.4.2...v3.4.3)
+==================
+
+* Fixed issue [#668](https://github.com/clean-css/clean-css/issues/668) - node v4 path.join.
+* Fixed issue [#669](https://github.com/clean-css/clean-css/issues/669) - adjacent overriding with `!important`.
+
+[3.4.2 / 2015-09-14](https://github.com/clean-css/clean-css/compare/v3.4.1...v3.4.2)
+==================
+
+* Fixed issue [#598](https://github.com/clean-css/clean-css/issues/598) - restructuring border properties.
+* Fixed issue [#654](https://github.com/clean-css/clean-css/issues/654) - disables length optimizations.
+* Fixed issue [#655](https://github.com/clean-css/clean-css/issues/655) - shorthands override merging.
+* Fixed issue [#660](https://github.com/clean-css/clean-css/issues/660) - !important token overriding.
+* Fixed issue [#662](https://github.com/clean-css/clean-css/issues/662) - !important selector reducing.
+* Fixed issue [#667](https://github.com/clean-css/clean-css/issues/667) - rebasing remote URLs.
+
+[3.4.1 / 2015-08-27](https://github.com/clean-css/clean-css/compare/v3.4.0...v3.4.1)
+==================
+
+* Fixed issue [#652](https://github.com/clean-css/clean-css/issues/652) - order of restoring and removing tokens.
+
+[3.4.0 / 2015-08-27](https://github.com/clean-css/clean-css/compare/v3.3.10...v3.4.0)
+==================
+
+* Adds an option for a fine-grained `@import` control.
+* Adds unit compatibility switches to disable length optimizations.
+* Adds inferring proxy settings from HTTP_PROXY environment variable.
+* Adds support for Polymer / Web Components special selectors.
+* Adds support for Polymer mixins.
+* Adds testing source maps in batch mode.
+* Unifies wrappers for simple & advanced optimizations.
+* Fixed issue [#596](https://github.com/clean-css/clean-css/issues/596) - support for !ie IE<8 hack.
+* Fixed issue [#599](https://github.com/clean-css/clean-css/issues/599) - support for inlined source maps.
+* Fixed issue [#607](https://github.com/clean-css/clean-css/issues/607) - adds better rule reordering.
+* Fixed issue [#612](https://github.com/clean-css/clean-css/issues/612) - adds HTTP proxy support.
+* Fixed issue [#618](https://github.com/clean-css/clean-css/issues/618) - adds safer function validation.
+* Fixed issue [#625](https://github.com/clean-css/clean-css/issues/625) - adds length unit optimizations.
+* Fixed issue [#632](https://github.com/clean-css/clean-css/issues/632) - adds disabling remote `import`s.
+* Fixed issue [#635](https://github.com/clean-css/clean-css/issues/635) - adds safer `0%` optimizations.
+* Fixed issue [#644](https://github.com/clean-css/clean-css/issues/644) - adds time unit optimizations.
+* Fixed issue [#645](https://github.com/clean-css/clean-css/issues/645) - adds bottom to top `media` merging.
+* Fixed issue [#648](https://github.com/clean-css/clean-css/issues/648) - adds property level at-rule support.
+
+[3.3.10 / 2015-08-27](https://github.com/clean-css/clean-css/compare/v3.3.9...v3.3.10)
+==================
+
+* Adds better comments + keepBreaks handling.
+* Adds better text normalizing in source maps mode.
+* Fixes non-adjacent optimizations for source maps.
+* Fixes removing unused items.
+* Improves `outline` break up with source maps.
+* Refixed issue [#629](https://github.com/clean-css/clean-css/issues/629) - source maps & background shorthands.
+
+[3.3.9 / 2015-08-09](https://github.com/clean-css/clean-css/compare/v3.3.8...v3.3.9)
+==================
+
+* Fixed issue [#640](https://github.com/clean-css/clean-css/issues/640) - URI processing regression.
+
+[3.3.8 / 2015-08-06](https://github.com/clean-css/clean-css/compare/v3.3.7...v3.3.8)
+==================
+
+* Fixed issue [#629](https://github.com/clean-css/clean-css/issues/629) - source maps & background shorthands.
+* Fixed issue [#630](https://github.com/clean-css/clean-css/issues/630) - vendor prefixed flex optimizations.
+* Fixed issue [#633](https://github.com/clean-css/clean-css/issues/633) - handling data URI with brackets.
+* Fixed issue [#634](https://github.com/clean-css/clean-css/issues/634) - merging :placeholder selectors.
+
+[3.3.7 / 2015-07-29](https://github.com/clean-css/clean-css/compare/v3.3.6...v3.3.7)
+==================
+
+* Fixed issue [#616](https://github.com/clean-css/clean-css/issues/616) - ordering in restructuring.
+
+[3.3.6 / 2015-07-14](https://github.com/clean-css/clean-css/compare/v3.3.5...v3.3.6)
+==================
+
+* Fixed issue [#620](https://github.com/clean-css/clean-css/issues/620) - `bold` style in font shorthands.
+
+[3.3.5 / 2015-07-01](https://github.com/clean-css/clean-css/compare/v3.3.4...v3.3.5)
+==================
+
+* Fixed issue [#608](https://github.com/clean-css/clean-css/issues/608) - custom URI protocols handling.
+
+[3.3.4 / 2015-06-24](https://github.com/clean-css/clean-css/compare/v3.3.3...v3.3.4)
+==================
+
+* Fixed issue [#610](https://github.com/clean-css/clean-css/issues/610) - `border:inherit` restoring.
+* Fixed issue [#611](https://github.com/clean-css/clean-css/issues/611) - edge case in quote stripping.
+
+[3.3.3 / 2015-06-16](https://github.com/clean-css/clean-css/compare/v3.3.2...v3.3.3)
+==================
+
+* Fixed issue [#603](https://github.com/clean-css/clean-css/issues/603) - IE suffix hack defaults to on.
+
+[3.3.2 / 2015-06-14](https://github.com/clean-css/clean-css/compare/v3.3.1...v3.3.2)
+==================
+
+* Fixed issue [#595](https://github.com/clean-css/clean-css/issues/595) - more relaxed block matching.
+* Fixed issue [#601](https://github.com/clean-css/clean-css/issues/601) - percentage minifying inside `flex`.
+* Fixed issue [#602](https://github.com/clean-css/clean-css/issues/602) - backslash IE hacks after a space.
+
+[3.3.1 / 2015-06-02](https://github.com/clean-css/clean-css/compare/v3.3.0...v3.3.1)
+==================
+
+* Fixed issue [#590](https://github.com/clean-css/clean-css/issues/590) - edge case in `@import` processing.
+
+[3.3.0 / 2015-05-31](https://github.com/clean-css/clean-css/compare/v3.2.11...v3.3.0)
+==================
+
+* Cleans up url rebase code getting rid of unnecessary state.
+* Cleans up tokenizer code getting rid of unnecessary state.
+* Moves source maps tracker into lib/source-maps/track.
+* Moves tokenizer code into lib/tokenizer.
+* Moves URL scanner into lib/urls/reduce (was named incorrectly before).
+* Moves URL rebasing & rewriting into lib/urls.
+* Fixed issue [#375](https://github.com/clean-css/clean-css/issues/375) - unit compatibility switches.
+* Fixed issue [#436](https://github.com/clean-css/clean-css/issues/436) - refactors URI rewriting.
+* Fixed issue [#448](https://github.com/clean-css/clean-css/issues/448) - rebasing no protocol URIs.
+* Fixed issue [#517](https://github.com/clean-css/clean-css/issues/517) - turning off color optimizations.
+* Fixed issue [#542](https://github.com/clean-css/clean-css/issues/542) - space after closing brace in IE.
+* Fixed issue [#562](https://github.com/clean-css/clean-css/issues/562) - optimizing invalid color values.
+* Fixed issue [#563](https://github.com/clean-css/clean-css/issues/563) - `background:inherit` restoring.
+* Fixed issue [#570](https://github.com/clean-css/clean-css/issues/570) - rebasing "no-url()" imports.
+* Fixed issue [#574](https://github.com/clean-css/clean-css/issues/574) - rewriting internal URLs.
+* Fixed issue [#575](https://github.com/clean-css/clean-css/issues/575) - missing directory as a `target`.
+* Fixed issue [#577](https://github.com/clean-css/clean-css/issues/577) - `background-clip` into shorthand.
+* Fixed issue [#579](https://github.com/clean-css/clean-css/issues/579) - `background-origin` into shorthand.
+* Fixed issue [#580](https://github.com/clean-css/clean-css/issues/580) - mixed `@import` processing.
+* Fixed issue [#582](https://github.com/clean-css/clean-css/issues/582) - overriding with prefixed values.
+* Fixed issue [#583](https://github.com/clean-css/clean-css/issues/583) - URL quoting for SVG data.
+* Fixed issue [#587](https://github.com/clean-css/clean-css/issues/587) - too aggressive `border` reordering.
+
+[3.2.11 / 2015-05-31](https://github.com/clean-css/clean-css/compare/v3.2.10...v3.2.11)
+==================
+
+* Fixed issue [#563](https://github.com/clean-css/clean-css/issues/563) - `background:inherit` restoring.
+* Fixed issue [#582](https://github.com/clean-css/clean-css/issues/582) - overriding with prefixed values.
+* Fixed issue [#583](https://github.com/clean-css/clean-css/issues/583) - URL quoting for SVG data.
+* Fixed issue [#587](https://github.com/clean-css/clean-css/issues/587) - too aggressive `border` reordering.
+
+[3.2.10 / 2015-05-14](https://github.com/clean-css/clean-css/compare/v3.2.9...v3.2.10)
+==================
+
+* Fixed issue [#572](https://github.com/clean-css/clean-css/issues/572) - empty elements removal.
+
+[3.2.9 / 2015-05-08](https://github.com/clean-css/clean-css/compare/v3.2.8...v3.2.9)
+==================
+
+* Fixed issue [#567](https://github.com/clean-css/clean-css/issues/567) - merging colors as functions.
+
+[3.2.8 / 2015-05-04](https://github.com/clean-css/clean-css/compare/v3.2.7...v3.2.8)
+==================
+
+* Fixed issue [#561](https://github.com/clean-css/clean-css/issues/561) - restructuring special selectors.
+
+[3.2.7 / 2015-05-03](https://github.com/clean-css/clean-css/compare/v3.2.6...v3.2.7)
+==================
+
+* Fixed issue [#551](https://github.com/clean-css/clean-css/issues/551) - edge case in restructuring.
+* Fixed issue [#553](https://github.com/clean-css/clean-css/issues/553) - another style of SVG fallback.
+* Fixed issue [#558](https://github.com/clean-css/clean-css/issues/558) - units in same selector merging.
+
+[3.2.6 / 2015-04-28](https://github.com/clean-css/clean-css/compare/v3.2.5...v3.2.6)
+==================
+
+* Fixed issue [#550](https://github.com/clean-css/clean-css/issues/550) - proper `contentSources` tracking.
+* Fixed issue [#556](https://github.com/clean-css/clean-css/issues/556) - regression in IE backslash hacks.
+
+[3.2.5 / 2015-04-25](https://github.com/clean-css/clean-css/compare/v3.2.4...v3.2.5)
+==================
+
+* Fixed issue [#543](https://github.com/clean-css/clean-css/issues/543) - better "comment in body" handling.
+* Fixed issue [#548](https://github.com/clean-css/clean-css/issues/548) - regression in font minifying.
+* Fixed issue [#549](https://github.com/clean-css/clean-css/issues/549) - special comments in source maps.
+
+[3.2.4 / 2015-04-24](https://github.com/clean-css/clean-css/compare/v3.2.3...v3.2.4)
+==================
+
+* Fixed issue [#544](https://github.com/clean-css/clean-css/issues/544) - regression in same value merging.
+* Fixed issue [#546](https://github.com/clean-css/clean-css/issues/546) - IE<11 `calc()` issue.
+
+[3.2.3 / 2015-04-22](https://github.com/clean-css/clean-css/compare/v3.2.2...v3.2.3)
+==================
+
+* Fixed issue [#541](https://github.com/clean-css/clean-css/issues/541) - `outline-style:auto` in shorthand.
+
+[3.2.2 / 2015-04-21](https://github.com/clean-css/clean-css/compare/v3.2.1...v3.2.2)
+==================
+
+* Fixed issue [#537](https://github.com/clean-css/clean-css/issues/537) - regression in simple optimizer.
+
+[3.2.1 / 2015-04-20](https://github.com/clean-css/clean-css/compare/v3.2.0...v3.2.1)
+==================
+
+* Fixed issue [#534](https://github.com/clean-css/clean-css/issues/534) - wrong `@font-face` stringifying.
+
+[3.2.0 / 2015-04-19](https://github.com/clean-css/clean-css/compare/v3.1.9...v3.2.0)
+==================
+
+* Bumps commander to 2.8.x.
+* Fixes remote asset rebasing when passing data as a hash.
+* Improves path resolution inside source maps.
+* Makes `root` option implicitely default to `process.cwd()`.
+* Fixed issue [#371](https://github.com/clean-css/clean-css/issues/371) - `background` fallback with `none`.
+* Fixed issue [#376](https://github.com/clean-css/clean-css/issues/376) - option to disable `0[unit]` -> `0`.
+* Fixed issue [#396](https://github.com/clean-css/clean-css/issues/396) - better input source maps tracking.
+* Fixed issue [#397](https://github.com/clean-css/clean-css/issues/397) - support for source map sources.
+* Fixed issue [#399](https://github.com/clean-css/clean-css/issues/399) - support compacting with source maps.
+* Fixed issue [#429](https://github.com/clean-css/clean-css/issues/429) - unifies data tokenization.
+* Fixed issue [#446](https://github.com/clean-css/clean-css/issues/446) - `list-style` fuzzy matching.
+* Fixed issue [#468](https://github.com/clean-css/clean-css/issues/468) - bumps `source-map` to 0.4.x.
+* Fixed issue [#480](https://github.com/clean-css/clean-css/issues/480) - extracting uppercase property names.
+* Fixed issue [#487](https://github.com/clean-css/clean-css/issues/487) - source map paths under Windows.
+* Fixed issue [#490](https://github.com/clean-css/clean-css/issues/490) - vendor prefixed multivalue `background`.
+* Fixed issue [#500](https://github.com/clean-css/clean-css/issues/500) - merging duplicate adjacent properties.
+* Fixed issue [#504](https://github.com/clean-css/clean-css/issues/504) - keeping `url()` quotes.
+* Fixed issue [#507](https://github.com/clean-css/clean-css/issues/507) - merging longhands into many shorthands.
+* Fixed issue [#508](https://github.com/clean-css/clean-css/issues/508) - removing duplicate media queries.
+* Fixed issue [#521](https://github.com/clean-css/clean-css/issues/521) - unit optimizations inside `calc()`.
+* Fixed issue [#524](https://github.com/clean-css/clean-css/issues/524) - timeouts in `@import` inlining.
+* Fixed issue [#526](https://github.com/clean-css/clean-css/issues/526) - shorthand overriding into a function.
+* Fixed issue [#528](https://github.com/clean-css/clean-css/issues/528) - better support for IE<9 hacks.
+* Fixed issue [#529](https://github.com/clean-css/clean-css/issues/529) - wrong font weight minification.
+
+[3.1.9 / 2015-04-04](https://github.com/clean-css/clean-css/compare/v3.1.8...v3.1.9)
+==================
+
+* Fixes issue [#511](https://github.com/clean-css/clean-css/issues/511) - `)` advanced processing.
+
+[3.1.8 / 2015-03-17](https://github.com/clean-css/clean-css/compare/v3.1.7...v3.1.8)
+==================
+
+* Fixes issue [#498](https://github.com/clean-css/clean-css/issues/498) - reordering and flexbox.
+* Fixes issue [#499](https://github.com/clean-css/clean-css/issues/499) - too aggressive `-` removal.
+
+[3.1.7 / 2015-03-16](https://github.com/clean-css/clean-css/compare/v3.1.6...v3.1.7)
+==================
+
+* Backports fix to [#480](https://github.com/clean-css/clean-css/issues/480) - reordering and uppercase properties.
+* Fixes issue [#496](https://github.com/clean-css/clean-css/issues/496) - space after bracket removal.
+
+[3.1.6 / 2015-03-12](https://github.com/clean-css/clean-css/compare/v3.1.5...v3.1.6)
+==================
+
+* Fixes issue [#489](https://github.com/clean-css/clean-css/issues/489) - `AlphaImageLoader` IE filter.
+
+[3.1.5 / 2015-03-06](https://github.com/clean-css/clean-css/compare/v3.1.4...v3.1.5)
+==================
+
+* Fixes issue [#483](https://github.com/clean-css/clean-css/issues/483) - property order in restructuring.
+
+[3.1.4 / 2015-03-04](https://github.com/clean-css/clean-css/compare/v3.1.3...v3.1.4)
+==================
+
+* Fixes issue [#472](https://github.com/clean-css/clean-css/issues/472) - broken function minification.
+* Fixes issue [#477](https://github.com/clean-css/clean-css/issues/477) - `@import`s order in restructuring.
+* Fixes issue [#478](https://github.com/clean-css/clean-css/issues/478) - ultimate fix to brace whitespace.
+
+[3.1.3 / 2015-03-03](https://github.com/clean-css/clean-css/compare/v3.1.2...v3.1.3)
+==================
+
+* Fixes issue [#464](https://github.com/clean-css/clean-css/issues/464) - data URI with quoted braces.
+* Fixes issue [#475](https://github.com/clean-css/clean-css/issues/475) - whitespace after closing brace.
+
+[3.1.2 / 2015-03-01](https://github.com/clean-css/clean-css/compare/v3.1.1...v3.1.2)
+==================
+
+* Refixed issue [#471](https://github.com/clean-css/clean-css/issues/471) - correct order after restructuring.
+* Fixes issue [#466](https://github.com/clean-css/clean-css/issues/466) - rebuilding background shorthand.
+* Fixes issue [#462](https://github.com/clean-css/clean-css/issues/462) - escaped apostrophes in selectors.
+
+[3.1.1 / 2015-02-27](https://github.com/clean-css/clean-css/compare/v3.1.0...v3.1.1)
+==================
+
+* Fixed issue [#469](https://github.com/clean-css/clean-css/issues/469) - extracting broken property.
+* Fixed issue [#470](https://github.com/clean-css/clean-css/issues/470) - negative padding removal.
+* Fixed issue [#471](https://github.com/clean-css/clean-css/issues/471) - correct order after restructuring.
+
+[3.1.0 / 2015-02-26](https://github.com/clean-css/clean-css/compare/v3.0.10...v3.1.0)
+==================
+
+* Adds `0deg` to `0` minification where possible.
+* Adds better non-adjacent selector merging when body is the same.
+* Adds official support for node.js 0.12.
+* Adds official support for io.js 1.0.
+* Adds restructuring optimizations to reorganize selectors, which vastly improves minification.
+* Fixed issue [#158](https://github.com/clean-css/clean-css/issues/158) - adds body-based selectors reduction.
+* Fixed issue [#182](https://github.com/clean-css/clean-css/issues/182) - removing space after closing brace.
+* Fixed issue [#204](https://github.com/clean-css/clean-css/issues/204) - `@media` merging.
+* Fixed issue [#351](https://github.com/clean-css/clean-css/issues/351) - remote `@import`s after content.
+* Fixed issue [#357](https://github.com/clean-css/clean-css/issues/357) - non-standard but valid URLs.
+* Fixed issue [#416](https://github.com/clean-css/clean-css/issues/416) - accepts hash as `minify` argument.
+* Fixed issue [#419](https://github.com/clean-css/clean-css/issues/419) - multiple input source maps.
+* Fixed issue [#435](https://github.com/clean-css/clean-css/issues/435) - `background-clip` in shorthand.
+* Fixed issue [#439](https://github.com/clean-css/clean-css/issues/439) - `background-origin` in shorthand.
+* Fixed issue [#442](https://github.com/clean-css/clean-css/issues/442) - space before adjacent `nav`.
+* Fixed issue [#445](https://github.com/clean-css/clean-css/issues/445) - regression issue in url processor.
+* Fixed issue [#449](https://github.com/clean-css/clean-css/issues/449) - warns of missing close braces.
+* Fixed issue [#463](https://github.com/clean-css/clean-css/issues/463) - relative remote `@import` URLs.
+
+[3.0.10 / 2015-02-07](https://github.com/clean-css/clean-css/compare/v3.0.9...v3.0.10)
+==================
+
+* Fixed issue [#453](https://github.com/clean-css/clean-css/issues/453) - double `background-repeat`.
+* Fixed issue [#455](https://github.com/clean-css/clean-css/issues/455) - property extracting regression.
+
+[3.0.9 / 2015-02-04](https://github.com/clean-css/clean-css/compare/v3.0.8...v3.0.9)
+==================
+
+* Fixed issue [#452](https://github.com/clean-css/clean-css/issues/452) - regression in advanced merging.
+
+[3.0.8 / 2015-01-31](https://github.com/clean-css/clean-css/compare/v3.0.7...v3.0.8)
+==================
+
+* Fixed issue [#447](https://github.com/clean-css/clean-css/issues/447) - `background-color` in shorthands.
+* Fixed issue [#450](https://github.com/clean-css/clean-css/issues/450) - name to hex color converting.
+
+[3.0.7 / 2015-01-22](https://github.com/clean-css/clean-css/compare/v3.0.6...v3.0.7)
+==================
+
+* Fixed issue [#441](https://github.com/clean-css/clean-css/issues/441) - hex to name color converting.
+
+[3.0.6 / 2015-01-20](https://github.com/clean-css/clean-css/compare/v3.0.5...v3.0.6)
+==================
+
+* Refixed issue [#414](https://github.com/clean-css/clean-css/issues/414) - source maps position fallback.
+
+[3.0.5 / 2015-01-18](https://github.com/clean-css/clean-css/compare/v3.0.4...v3.0.5)
+==================
+
+* Fixed issue [#414](https://github.com/clean-css/clean-css/issues/414) - source maps position fallback.
+* Fixed issue [#433](https://github.com/clean-css/clean-css/issues/433) - meging `!important` in shorthands.
+
+[3.0.4 / 2015-01-11](https://github.com/clean-css/clean-css/compare/v3.0.3...v3.0.4)
+==================
+
+* Fixed issue [#314](https://github.com/clean-css/clean-css/issues/314) - spaces inside `calc`.
+
+[3.0.3 / 2015-01-07](https://github.com/clean-css/clean-css/compare/v3.0.2...v3.0.3)
+==================
+
+* Just a version bump as npm incorrectly things 2.2.23 is the latest one.
+
+[3.0.2 / 2015-01-04](https://github.com/clean-css/clean-css/compare/v3.0.1...v3.0.2)
+==================
+
+* Fixed issue [#422](https://github.com/clean-css/clean-css/issues/422) - handling `calc` as a unit.
+
+[3.0.1 / 2014-12-19](https://github.com/clean-css/clean-css/compare/v3.0.0...v3.0.1)
+==================
+
+* Fixed issue [#410](https://github.com/clean-css/clean-css/issues/410) - advanced merging and comments.
+* Fixed issue [#411](https://github.com/clean-css/clean-css/issues/411) - properties and important comments.
+
+[3.0.0 / 2014-12-18](https://github.com/clean-css/clean-css/compare/v2.2.22...v3.0.0)
+==================
+
+* Adds more granular control over compatibility settings.
+* Adds support for @counter-style at-rule.
+* Adds `--source-map`/`sourceMap` switch for building input's source map.
+* Adds `--skip-shorthand-compacting`/`shorthandComacting` option for disabling shorthand compacting.
+* Allows `target` option to be a path to a folder instead of a file.
+* Allows disabling rounding precision. By [@superlukas](https://github.com/superlukas).
+* Breaks 2.x compatibility for using CleanCSS as a function.
+* Changes `minify` method output to handle multiple outputs.
+* Reworks minification to tokenize first then minify.
+  See [changes](https://github.com/clean-css/clean-css/compare/b06f37d...dd8c14a).
+* Removes support for node.js 0.8.x.
+* Renames `noAdvanced` option into `advanced`.
+* Renames `noAggressiveMerging` option into `aggressiveMerging`.
+* Renames `noRebase` option into `rebase`.
+* Speeds up advanced processing by shortening optimize loop.
+* Fixed issue [#125](https://github.com/clean-css/clean-css/issues/125) - source maps!
+* Fixed issue [#344](https://github.com/clean-css/clean-css/issues/344) - merging `background-size` into shorthand.
+* Fixed issue [#352](https://github.com/clean-css/clean-css/issues/352) - honors rebasing in imported stylesheets.
+* Fixed issue [#360](https://github.com/clean-css/clean-css/issues/360) - adds 7 extra CSS colors.
+* Fixed issue [#363](https://github.com/clean-css/clean-css/issues/363) - `rem` units overriding `px`.
+* Fixed issue [#373](https://github.com/clean-css/clean-css/issues/373) - proper `background` shorthand merging.
+* Fixed issue [#395](https://github.com/clean-css/clean-css/issues/395) - unescaped brackets in data URIs.
+* Fixed issue [#398](https://github.com/clean-css/clean-css/issues/398) - restoring important comments.
+* Fixed issue [#400](https://github.com/clean-css/clean-css/issues/400) - API to accept an array of filenames.
+* Fixed issue [#403](https://github.com/clean-css/clean-css/issues/403) - tracking input files in source maps.
+* Fixed issue [#404](https://github.com/clean-css/clean-css/issues/404) - no state sharing in API.
+* Fixed issue [#405](https://github.com/clean-css/clean-css/issues/405) - disables default `background-size` merging.
+* Refixed issue [#304](https://github.com/clean-css/clean-css/issues/304) - `background-position` merging.
+
+[2.2.22 / 2014-12-13](https://github.com/clean-css/clean-css/compare/v2.2.21...v2.2.22)
+==================
+
+* Backports fix to issue [#304](https://github.com/clean-css/clean-css/issues/304) - `background-position` merging.
+
+[2.2.21 / 2014-12-10](https://github.com/clean-css/clean-css/compare/v2.2.20...v2.2.21)
+==================
+
+* Backports fix to issue [#373](https://github.com/clean-css/clean-css/issues/373) - `background` shorthand merging.
+
+[2.2.20 / 2014-12-02](https://github.com/clean-css/clean-css/compare/v2.2.19...v2.2.20)
+==================
+
+* Backports fix to issue [#390](https://github.com/clean-css/clean-css/issues/390) - pseudo-class merging.
+
+[2.2.19 / 2014-11-20](https://github.com/clean-css/clean-css/compare/v2.2.18...v2.2.19)
+==================
+
+* Fixed issue [#385](https://github.com/clean-css/clean-css/issues/385) - edge cases in processing cut off data.
+
+[2.2.18 / 2014-11-17](https://github.com/clean-css/clean-css/compare/v2.2.17...v2.2.18)
+==================
+
+* Fixed issue [#383](https://github.com/clean-css/clean-css/issues/383) - rounding fractions once again.
+
+[2.2.17 / 2014-11-09](https://github.com/clean-css/clean-css/compare/v2.2.16...v2.2.17)
+==================
+
+* Fixed issue [#380](https://github.com/clean-css/clean-css/issues/380) - rounding fractions to a whole number.
+
+[2.2.16 / 2014-09-16](https://github.com/clean-css/clean-css/compare/v2.2.15...v2.2.16)
+==================
+
+* Fixed issue [#359](https://github.com/clean-css/clean-css/issues/359) - handling escaped double backslash.
+* Fixed issue [#358](https://github.com/clean-css/clean-css/issues/358) - property merging in compatibility mode.
+* Fixed issue [#356](https://github.com/clean-css/clean-css/issues/356) - preserving `*+html` hack.
+* Fixed issue [#354](https://github.com/clean-css/clean-css/issues/354) - `!important` overriding in shorthands.
+
+[2.2.15 / 2014-09-01](https://github.com/clean-css/clean-css/compare/v2.2.14...v2.2.15)
+==================
+
+* Fixed issue [#343](https://github.com/clean-css/clean-css/issues/343) - too aggressive `rgba`/`hsla` minification.
+* Fixed issue [#345](https://github.com/clean-css/clean-css/issues/345) - URL rebasing for document relative ones.
+* Fixed issue [#346](https://github.com/clean-css/clean-css/issues/346) - overriding `!important` by `!important`.
+* Fixed issue [#350](https://github.com/clean-css/clean-css/issues/350) - edge cases in `@import` processing.
+
+[2.2.14 / 2014-08-25](https://github.com/clean-css/clean-css/compare/v2.2.13...v2.2.14)
+==================
+
+* Makes multival operations idempotent.
+* Fixed issue [#339](https://github.com/clean-css/clean-css/issues/339) - skips invalid properties.
+* Fixed issue [#341](https://github.com/clean-css/clean-css/issues/341) - ensure output is shorter than input.
+
+[2.2.13 / 2014-08-12](https://github.com/clean-css/clean-css/compare/v2.2.12...v2.2.13)
+==================
+
+* Fixed issue [#337](https://github.com/clean-css/clean-css/issues/337) - handling component importance.
+
+[2.2.12 / 2014-08-02](https://github.com/clean-css/clean-css/compare/v2.2.11...v2.2.12)
+==================
+
+* Fixed issue with tokenizer removing first selector after an unknown @ rule.
+* Fixed issue [#329](https://github.com/clean-css/clean-css/issues/329) - `font` shorthands incorrectly processed.
+* Fixed issue [#332](https://github.com/clean-css/clean-css/issues/332) - `background` shorthand with colors.
+* Refixed issue [#325](https://github.com/clean-css/clean-css/issues/325) - invalid charset declarations.
+
+[2.2.11 / 2014-07-28](https://github.com/clean-css/clean-css/compare/v2.2.10...v2.2.11)
+==================
+
+* Fixed issue [#326](https://github.com/clean-css/clean-css/issues/326) - `background-size` regression.
+
+[2.2.10 / 2014-07-27](https://github.com/clean-css/clean-css/compare/v2.2.9...v2.2.10)
+==================
+
+* Improved performance of advanced mode validators.
+* Fixed issue [#307](https://github.com/clean-css/clean-css/issues/307) - `background-color` in multiple backgrounds.
+* Fixed issue [#322](https://github.com/clean-css/clean-css/issues/322) - adds `background-size` support.
+* Fixed issue [#323](https://github.com/clean-css/clean-css/issues/323) - stripping variable references.
+* Fixed issue [#325](https://github.com/clean-css/clean-css/issues/325) - removing invalid `@charset` declarations.
+
+[2.2.9 / 2014-07-23](https://github.com/clean-css/clean-css/compare/v2.2.8...v2.2.9)
+==================
+
+* Adds `background` normalization according to W3C spec.
+* Fixed issue [#316](https://github.com/clean-css/clean-css/issues/316) - incorrect `background` processing.
+
+[2.2.8 / 2014-07-14](https://github.com/clean-css/clean-css/compare/v2.2.7...v2.2.8)
+==================
+
+* Fixed issue [#313](https://github.com/clean-css/clean-css/issues/313) - processing comment marks in URLs.
+* Fixed issue [#315](https://github.com/clean-css/clean-css/issues/315) - `rgba`/`hsla` -> `transparent` in gradients.
+
+[2.2.7 / 2014-07-10](https://github.com/clean-css/clean-css/compare/v2.2.6...v2.2.7)
+==================
+
+* Fixed issue [#304](https://github.com/clean-css/clean-css/issues/304) - merging multiple backgrounds.
+* Fixed issue [#312](https://github.com/clean-css/clean-css/issues/312) - merging with mixed repeat.
+
+[2.2.6 / 2014-07-05](https://github.com/clean-css/clean-css/compare/v2.2.5...v2.2.6)
+==================
+
+* Adds faster quote matching in QuoteScanner.
+* Improves QuoteScanner to handle comments correctly.
+* Fixed issue [#308](https://github.com/clean-css/clean-css/issues/308) - parsing comments in quoted URLs.
+* Fixed issue [#311](https://github.com/clean-css/clean-css/issues/311) - leading/trailing decimal points.
+
+[2.2.5 / 2014-06-29](https://github.com/clean-css/clean-css/compare/v2.2.4...v2.2.5)
+==================
+
+* Adds removing extra spaces around / in border-radius.
+* Adds replacing same horizontal & vertical value in border-radius.
+* Fixed issue [#305](https://github.com/clean-css/clean-css/issues/305) - allows width keywords in `border-width`.
+
+[2.2.4 / 2014-06-27](https://github.com/clean-css/clean-css/compare/v2.2.3...v2.2.4)
+==================
+
+* Fixed issue [#301](https://github.com/clean-css/clean-css/issues/301) - proper `border-radius` processing.
+* Fixed issue [#303](https://github.com/clean-css/clean-css/issues/303) - correctly preserves viewport units.
+
+[2.2.3 / 2014-06-24](https://github.com/clean-css/clean-css/compare/v2.2.2...v2.2.3)
+==================
+
+* Fixed issue [#302](https://github.com/clean-css/clean-css/issues/302) - handling of `outline-style: auto`.
+
+[2.2.2 / 2014-06-18](https://github.com/clean-css/clean-css/compare/v2.2.1...v2.2.2)
+==================
+
+* Fixed issue [#297](https://github.com/clean-css/clean-css/issues/297) - `box-shadow` zeros minification.
+
+[2.2.1 / 2014-06-14](https://github.com/clean-css/clean-css/compare/v2.2.0...v2.2.1)
+==================
+
+* Fixes new property optimizer for 'none' values.
+* Fixed issue [#294](https://github.com/clean-css/clean-css/issues/294) - space after `rgba`/`hsla` in IE<=11.
+
+[2.2.0 / 2014-06-11](https://github.com/clean-css/clean-css/compare/v2.1.8...v2.2.0)
+==================
+
+* Adds a better algorithm for quotation marks' removal.
+* Adds a better non-adjacent optimizer compatible with the upcoming new property optimizer.
+* Adds minifying remote files directly from CLI.
+* Adds `--rounding-precision` to control rounding precision.
+* Moves quotation matching into a `QuoteScanner` class.
+* Adds `npm run browserify` for creating embeddable version of clean-css.
+* Fixed list-style-* advanced processing.
+* Fixed issue [#134](https://github.com/clean-css/clean-css/issues/134) - merges properties into shorthand form.
+* Fixed issue [#164](https://github.com/clean-css/clean-css/issues/164) - removes default values if not needed.
+* Fixed issue [#168](https://github.com/clean-css/clean-css/issues/168) - adds better property merging algorithm.
+* Fixed issue [#173](https://github.com/clean-css/clean-css/issues/173) - merges same properties if grouped.
+* Fixed issue [#184](https://github.com/clean-css/clean-css/issues/184) - uses `!important` for optimization opportunities.
+* Fixed issue [#190](https://github.com/clean-css/clean-css/issues/190) - uses shorthand to override another shorthand.
+* Fixed issue [#197](https://github.com/clean-css/clean-css/issues/197) - adds borders merging by understandability.
+* Fixed issue [#210](https://github.com/clean-css/clean-css/issues/210) - adds temporary workaround for aggressive merging.
+* Fixed issue [#246](https://github.com/clean-css/clean-css/issues/246) - removes IE hacks when not in compatibility mode.
+* Fixed issue [#247](https://github.com/clean-css/clean-css/issues/247) - removes deprecated `selectorsMergeMode` switch.
+* Refixed issue [#250](https://github.com/clean-css/clean-css/issues/250) - based on new quotation marks removal.
+* Fixed issue [#257](https://github.com/clean-css/clean-css/issues/257) - turns `rgba`/`hsla` to `transparent` if possible.
+* Fixed issue [#265](https://github.com/clean-css/clean-css/issues/265) - adds support for multiple input files.
+* Fixed issue [#275](https://github.com/clean-css/clean-css/issues/275) - handling transform properties.
+* Fixed issue [#276](https://github.com/clean-css/clean-css/issues/276) - corrects unicode handling.
+* Fixed issue [#288](https://github.com/clean-css/clean-css/issues/288) - adds smarter expression parsing.
+* Fixed issue [#293](https://github.com/clean-css/clean-css/issues/293) - handles escaped `@` symbols in class names and IDs.
+
+[2.1.8 / 2014-03-28](https://github.com/clean-css/clean-css/compare/v2.1.7...v2.1.8)
+==================
+
+* Fixed issue [#267](https://github.com/clean-css/clean-css/issues/267) - incorrect non-adjacent selector merging.
+
+[2.1.7 / 2014-03-24](https://github.com/clean-css/clean-css/compare/v2.1.6...v2.1.7)
+==================
+
+* Fixed issue [#264](https://github.com/clean-css/clean-css/issues/264) - `@import` statements inside comments.
+
+[2.1.6 / 2014-03-10](https://github.com/clean-css/clean-css/compare/v2.1.5...v2.1.6)
+==================
+
+* Fixed issue [#258](https://github.com/clean-css/clean-css/issues/258) - wrong `@import` handling in `EmptyRemoval`.
+
+[2.1.5 / 2014-03-07](https://github.com/clean-css/clean-css/compare/v2.1.4...v2.1.5)
+==================
+
+* Fixed issue [#255](https://github.com/clean-css/clean-css/issues/255) - incorrect processing of a trailing `-0`.
+
+[2.1.4 / 2014-03-01](https://github.com/clean-css/clean-css/compare/v2.1.3...v2.1.4)
+==================
+
+* Fixed issue [#250](https://github.com/clean-css/clean-css/issues/250) - correctly handle JSON data in quotations.
+
+[2.1.3 / 2014-02-26](https://github.com/clean-css/clean-css/compare/v2.1.2...v2.1.3)
+==================
+
+* Fixed issue [#248](https://github.com/clean-css/clean-css/issues/248) - incorrect merging for vendor selectors.
+
+[2.1.2 / 2014-02-25](https://github.com/clean-css/clean-css/compare/v2.1.1...v2.1.2)
+==================
+
+* Fixed issue [#245](https://github.com/clean-css/clean-css/issues/245) - incorrect handling of backslash IE hack.
+
+[2.1.1 / 2014-02-18](https://github.com/clean-css/clean-css/compare/v2.1.0...v2.1.1)
+==================
+
+* Adds faster selectors processing in advanced optimizer.
+* Fixed issue [#241](https://github.com/clean-css/clean-css/issues/241) - incorrect handling of `:not()` selectors.
+
+[2.1.0 / 2014-02-13](https://github.com/clean-css/clean-css/compare/v2.0.8...v2.1.0)
+==================
+
+* Adds an optional callback to minify method.
+* Deprecates `--selectors-merge-mode` / `selectorsMergeMode` in favor to `--compatibility` / `compatibility`.
+* Fixes debug mode stats for stylesheets using `@import` statements.
+* Skips empty removal if advanced processing is enabled.
+* Fixed issue [#85](https://github.com/clean-css/clean-css/issues/85) - resolving protocol `@import`s.
+* Fixed issue [#160](https://github.com/clean-css/clean-css/issues/160) - re-runs optimizer until a clean pass.
+* Fixed issue [#161](https://github.com/clean-css/clean-css/issues/161) - improves tokenizer performance.
+* Fixed issue [#163](https://github.com/clean-css/clean-css/issues/163) - round pixels to 2nd decimal place.
+* Fixed issue [#165](https://github.com/clean-css/clean-css/issues/165) - extra space after trailing parenthesis.
+* Fixed issue [#186](https://github.com/clean-css/clean-css/issues/186) - strip unit from `0rem`.
+* Fixed issue [#207](https://github.com/clean-css/clean-css/issues/207) - bug in parsing protocol `@import`s.
+* Fixed issue [#213](https://github.com/clean-css/clean-css/issues/213) - faster `rgb` to `hex` transforms.
+* Fixed issue [#215](https://github.com/clean-css/clean-css/issues/215) - leading zeros in numerical values.
+* Fixed issue [#217](https://github.com/clean-css/clean-css/issues/217) - whitespace inside attribute selectors and URLs.
+* Fixed issue [#218](https://github.com/clean-css/clean-css/issues/218) - `@import` statements cleanup.
+* Fixed issue [#220](https://github.com/clean-css/clean-css/issues/220) - selector between comments.
+* Fixed issue [#223](https://github.com/clean-css/clean-css/issues/223) - two-pass adjacent selectors merging.
+* Fixed issue [#226](https://github.com/clean-css/clean-css/issues/226) - don't minify `border:none` to `border:0`.
+* Fixed issue [#229](https://github.com/clean-css/clean-css/issues/229) - improved processing of fraction numbers.
+* Fixed issue [#230](https://github.com/clean-css/clean-css/issues/230) - better handling of zero values.
+* Fixed issue [#235](https://github.com/clean-css/clean-css/issues/235) - IE7 compatibility mode.
+* Fixed issue [#236](https://github.com/clean-css/clean-css/issues/236) - incorrect rebasing with nested `import`s.
+
+[2.0.8 / 2014-02-07](https://github.com/clean-css/clean-css/compare/v2.0.7...v2.0.8)
+==================
+
+* Fixed issue [#232](https://github.com/clean-css/clean-css/issues/232) - edge case in non-adjacent selectors merging.
+
+[2.0.7 / 2014-01-16](https://github.com/clean-css/clean-css/compare/v2.0.6...v2.0.7)
+==================
+
+* Fixed issue [#208](https://github.com/clean-css/clean-css/issues/208) - don't swallow `@page` and `@viewport`.
+
+[2.0.6 / 2014-01-04](https://github.com/clean-css/clean-css/compare/v2.0.5...v2.0.6)
+==================
+
+* Fixed issue [#198](https://github.com/clean-css/clean-css/issues/198) - process comments and `@import`s correctly.
+* Fixed issue [#205](https://github.com/clean-css/clean-css/issues/205) - freeze on broken `@import` declaration.
+
+[2.0.5 / 2014-01-03](https://github.com/clean-css/clean-css/compare/v2.0.4...v2.0.5)
+==================
+
+* Fixed issue [#199](https://github.com/clean-css/clean-css/issues/199) - keep line breaks with no advanced optimizations.
+* Fixed issue [#203](https://github.com/clean-css/clean-css/issues/203) - Buffer as a first argument to minify method.
+
+[2.0.4 / 2013-12-19](https://github.com/clean-css/clean-css/compare/v2.0.3...v2.0.4)
+==================
+
+* Fixed issue [#193](https://github.com/clean-css/clean-css/issues/193) - HSL color space normalization.
+
+[2.0.3 / 2013-12-18](https://github.com/clean-css/clean-css/compare/v2.0.2...v2.0.3)
+==================
+
+* Fixed issue [#191](https://github.com/clean-css/clean-css/issues/191) - leading numbers in `font`/`animation` names.
+* Fixed issue [#192](https://github.com/clean-css/clean-css/issues/192) - many `@import`s inside a comment.
+
+[2.0.2 / 2013-11-18](https://github.com/clean-css/clean-css/compare/v2.0.1...v2.0.2)
+==================
+
+* Fixed issue [#177](https://github.com/clean-css/clean-css/issues/177) - process broken content correctly.
+
+[2.0.1 / 2013-11-14](https://github.com/clean-css/clean-css/compare/v2.0.0...v2.0.1)
+==================
+
+* Fixed issue [#176](https://github.com/clean-css/clean-css/issues/176) - hangs on `undefined` keyword.
+
+[2.0.0 / 2013-11-04](https://github.com/clean-css/clean-css/compare/v1.1.7...v2.0.0)
+==================
+
+* Adds simplified and more advanced text escaping / restoring via `EscapeStore` class.
+* Adds simplified and much faster empty elements removal.
+* Adds missing `@import` processing to our benchmark (run via `npm run bench`).
+* Adds CSS tokenizer which will make it possible to optimize content by reordering and/or merging selectors.
+* Adds basic optimizer removing duplicate selectors from a list.
+* Adds merging duplicate properties within a single selector's body.
+* Adds merging adjacent selectors within a scope (single and multiple ones).
+* Changes behavior of `--keep-line-breaks`/`keepBreaks` option to keep breaks after trailing braces only.
+* Makes all multiple selectors ordered alphabetically (aids merging).
+* Adds property overriding so more coarse properties override more granular ones.
+* Adds reducing non-adjacent selectors.
+* Adds `--skip-advanced`/`noAdvanced` switch to disable advanced optimizations.
+* Adds reducing non-adjacent selectors when overridden by more complex selectors.
+* Fixed issue [#138](https://github.com/clean-css/clean-css/issues/138) - makes CleanCSS interface OO.
+* Fixed issue [#139](https://github.com/clean-css/clean-css/issues/138) - consistent error & warning handling.
+* Fixed issue [#145](https://github.com/clean-css/clean-css/issues/145) - debug mode in library too.
+* Fixed issue [#157](https://github.com/clean-css/clean-css/issues/157) - gets rid of `removeEmpty` option.
+* Fixed issue [#159](https://github.com/clean-css/clean-css/issues/159) - escaped quotes inside content.
+* Fixed issue [#162](https://github.com/clean-css/clean-css/issues/162) - strip quotes from Base64 encoded URLs.
+* Fixed issue [#166](https://github.com/clean-css/clean-css/issues/166) - `debug` formatting in CLI
+* Fixed issue [#167](https://github.com/clean-css/clean-css/issues/167) - `background:transparent` minification.
+
+[1.1.7 / 2013-10-28](https://github.com/clean-css/clean-css/compare/v1.1.6...v1.1.7)
+==================
+
+* Fixed issue [#156](https://github.com/clean-css/clean-css/issues/156) - `@import`s inside comments.
+
+[1.1.6 / 2013-10-26](https://github.com/clean-css/clean-css/compare/v1.1.5...v1.1.6)
+==================
+
+* Fixed issue [#155](https://github.com/clean-css/clean-css/issues/155) - broken irregular CSS content.
+
+[1.1.5 / 2013-10-24](https://github.com/clean-css/clean-css/compare/v1.1.4...v1.1.5)
+==================
+
+* Fixed issue [#153](https://github.com/clean-css/clean-css/issues/153) - `keepSpecialComments` `0`/`1` as a string.
+
+[1.1.4 / 2013-10-23](https://github.com/clean-css/clean-css/compare/v1.1.3...v1.1.4)
+==================
+
+* Fixed issue [#152](https://github.com/clean-css/clean-css/issues/152) - adds an option to disable rebasing.
+
+[1.1.3 / 2013-10-04](https://github.com/clean-css/clean-css/compare/v1.1.2...v1.1.3)
+==================
+
+* Fixed issue [#150](https://github.com/clean-css/clean-css/issues/150) - minifying `background:none`.
+
+[1.1.2 / 2013-09-29](https://github.com/clean-css/clean-css/compare/v1.1.1...v1.1.2)
+==================
+
+* Fixed issue [#149](https://github.com/clean-css/clean-css/issues/149) - shorthand `font` property.
+
+[1.1.1 / 2013-09-07](https://github.com/clean-css/clean-css/compare/v1.1.0...v1.1.1)
+==================
+
+* Fixed issue [#144](https://github.com/clean-css/clean-css/issues/144) - skip URLs rebasing by default.
+
+[1.1.0 / 2013-09-06](https://github.com/clean-css/clean-css/compare/v1.0.12...v1.1.0)
+==================
+
+* Renamed lib's `debug` option to `benchmark` when doing per-minification benchmarking.
+* Added simplified comments processing & imports.
+* Fixed issue [#43](https://github.com/clean-css/clean-css/issues/43) - `--debug` switch for minification stats.
+* Fixed issue [#65](https://github.com/clean-css/clean-css/issues/65) - full color name / hex shortening.
+* Fixed issue [#84](https://github.com/clean-css/clean-css/issues/84) - support for `@import` with media queries.
+* Fixed issue [#124](https://github.com/clean-css/clean-css/issues/124) - raise error on broken imports.
+* Fixed issue [#126](https://github.com/clean-css/clean-css/issues/126) - proper CSS expressions handling.
+* Fixed issue [#129](https://github.com/clean-css/clean-css/issues/129) - rebasing imported URLs.
+* Fixed issue [#130](https://github.com/clean-css/clean-css/issues/130) - better code modularity.
+* Fixed issue [#135](https://github.com/clean-css/clean-css/issues/135) - require node.js 0.8+.
+
+[1.0.12 / 2013-07-19](https://github.com/clean-css/clean-css/compare/v1.0.11...v1.0.12)
+===================
+
+* Fixed issue [#121](https://github.com/clean-css/clean-css/issues/121) - ability to skip `@import` processing.
+
+[1.0.11 / 2013-07-08](https://github.com/clean-css/clean-css/compare/v1.0.10...v1.0.11)
+===================
+
+* Fixed issue [#117](https://github.com/clean-css/clean-css/issues/117) - line break escaping in comments.
+
+[1.0.10 / 2013-06-13](https://github.com/clean-css/clean-css/compare/v1.0.9...v1.0.10)
+===================
+
+* Fixed issue [#114](https://github.com/clean-css/clean-css/issues/114) - comments in imported stylesheets.
+
+[1.0.9 / 2013-06-11](https://github.com/clean-css/clean-css/compare/v1.0.8...v1.0.9)
+==================
+
+* Fixed issue [#113](https://github.com/clean-css/clean-css/issues/113) - `@import` in comments.
+
+[1.0.8 / 2013-06-10](https://github.com/clean-css/clean-css/compare/v1.0.7...v1.0.8)
+==================
+
+* Fixed issue [#112](https://github.com/clean-css/clean-css/issues/112) - reducing `box-shadow` zeros.
+
+[1.0.7 / 2013-06-05](https://github.com/clean-css/clean-css/compare/v1.0.6...v1.0.7)
+==================
+
+* Support for `@import` URLs starting with `//`. By [@petetak](https://github.com/petetak).
+
+[1.0.6 / 2013-06-04](https://github.com/clean-css/clean-css/compare/v1.0.5...v1.0.6)
+==================
+
+* Fixed issue [#110](https://github.com/clean-css/clean-css/issues/110) - data URIs in URLs.
+
+[1.0.5 / 2013-05-26](https://github.com/clean-css/clean-css/compare/v1.0.4...v1.0.5)
+==================
+
+* Fixed issue [#107](https://github.com/clean-css/clean-css/issues/107) - data URIs in imported stylesheets.
+
+1.0.4 / 2013-05-23
+==================
+
+* Rewrite relative URLs in imported stylesheets. By [@bluej100](https://github.com/bluej100).
+
+1.0.3 / 2013-05-20
+==================
+
+* Support alternative `@import` syntax with file name not wrapped inside `url()` statement.
+  By [@bluej100](https://github.com/bluej100).
+
+1.0.2 / 2013-04-29
+==================
+
+* Fixed issue [#97](https://github.com/clean-css/clean-css/issues/97) - `--remove-empty` & FontAwesome.
+
+1.0.1 / 2013-04-08
+==================
+
+* Do not pick up `bench` and `test` while building `npm` package.
+  By [@sindresorhus](https://https://github.com/sindresorhus).
+
+1.0.0 / 2013-03-30
+==================
+
+* Fixed issue [#2](https://github.com/clean-css/clean-css/issues/2) - resolving `@import` rules.
+* Fixed issue [#44](https://github.com/clean-css/clean-css/issues/44) - examples in `--help`.
+* Fixed issue [#46](https://github.com/clean-css/clean-css/issues/46) - preserving special characters in URLs and attributes.
+* Fixed issue [#80](https://github.com/clean-css/clean-css/issues/80) - quotation in multi line strings.
+* Fixed issue [#83](https://github.com/clean-css/clean-css/issues/83) - HSL to hex color conversions.
+* Fixed issue [#86](https://github.com/clean-css/clean-css/issues/86) - broken `@charset` replacing.
+* Fixed issue [#88](https://github.com/clean-css/clean-css/issues/88) - removes space in `! important`.
+* Fixed issue [#92](https://github.com/clean-css/clean-css/issues/92) - uppercase hex to short versions.
+
+0.10.2 / 2013-03-19
+===================
+
+* Fixed issue [#79](https://github.com/clean-css/clean-css/issues/79) - node.js 0.10.x compatibility.
+
+0.10.1 / 2013-02-14
+===================
+
+* Fixed issue [#66](https://github.com/clean-css/clean-css/issues/66) - line breaks without extra spaces should
+  be handled correctly.
+
+0.10.0 / 2013-02-09
+===================
+
+* Switched from [optimist](https://github.com/substack/node-optimist) to
+  [commander](https://github.com/visionmedia/commander.js) for CLI processing.
+* Changed long options from `--removeempty` to `--remove-empty` and from `--keeplinebreaks` to `--keep-line-breaks`.
+* Fixed performance issue with replacing multiple `@charset` declarations and issue
+  with line break after `@charset` when using `keepLineBreaks` option. By [@rrjaime](https://github.com/rrjamie).
+* Removed Makefile in favor to `npm run` commands (e.g. `make check` -> `npm run check`).
+* Fixed issue [#47](https://github.com/clean-css/clean-css/issues/47) - commandline issues on Windows.
+* Fixed issue [#49](https://github.com/clean-css/clean-css/issues/49) - remove empty selectors from media query.
+* Fixed issue [#52](https://github.com/clean-css/clean-css/issues/52) - strip fraction zeros if not needed.
+* Fixed issue [#58](https://github.com/clean-css/clean-css/issues/58) - remove colon where possible.
+* Fixed issue [#59](https://github.com/clean-css/clean-css/issues/59) - content property handling.
+
+0.9.1 / 2012-12-19
+==================
+
+* Fixed issue [#37](https://github.com/clean-css/clean-css/issues/37) - converting
+  `white` and other colors in class names (reported by [@malgorithms](https://github.com/malgorithms)).
+
+0.9.0 / 2012-12-15
+==================
+
+* Added stripping quotation from font names (if possible).
+* Added stripping quotation from `@keyframes` declaration, `animation` and
+  `animation-name` property.
+* Added stripping quotations from attributes' value (e.g. `[data-target='x']`).
+* Added better hex->name and name->hex color shortening.
+* Added `font: normal` and `font: bold` shortening the same way as `font-weight` is.
+* Refactored shorthand selectors and added `border-radius`, `border-style`
+  and `border-color` shortening.
+* Added `margin`, `padding` and `border-width` shortening.
+* Added removing line break after commas.
+* Fixed removing whitespace inside media query definition.
+* Added removing line breaks after a comma, so all declarations are one-liners now.
+* Speed optimizations (~10% despite many new features).
+* Added [JSHint](https://github.com/jshint/jshint/) validation rules via `make check`.
+
+0.8.3 / 2012-11-29
+==================
+
+* Fixed HSL/HSLA colors processing.
+
+0.8.2 / 2012-10-31
+==================
+
+* Fixed shortening hex colors and their relation to hashes in URLs.
+* Cleanup by [@XhmikosR](https://github.com/XhmikosR).
+
+0.8.1 / 2012-10-28
+==================
+
+* Added better zeros processing for `rect(...)` syntax (clip property).
+
+0.8.0 / 2012-10-21
+==================
+
+* Added removing URLs quotation if possible.
+* Rewrote breaks processing.
+* Added `keepBreaks`/`-b` option to keep line breaks in the minimized file.
+* Reformatted [lib/clean.js](/lib/clean.js) so it's easier to follow the rules.
+* Minimized test data is now minimized with line breaks so it's easier to
+  compare the changes line by line.
+
+0.7.0 / 2012-10-14
+==================
+
+* Added stripping special comments to CLI (`--s0` and `--s1` options).
+* Added stripping special comments to programmatic interface
+  (`keepSpecialComments` option).
+
+0.6.0 / 2012-08-05
+==================
+
+* Full Windows support with tests (./test.bat).
+
+0.5.0 / 2012-08-02
+==================
+
+* Made path to vows local.
+* Explicit node.js 0.6 requirement.
+
+0.4.2 / 2012-06-28
+==================
+
+* Updated binary `-v` option (version).
+* Updated binary to output help when no options given (but not in piped mode).
+* Added binary tests.
+
+0.4.1 / 2012-06-10
+==================
+
+* Fixed stateless mode where calling `CleanCSS#process` directly was giving
+  errors (reported by [@facelessuser](https://github.com/facelessuser)).
+
+0.4.0 / 2012-06-04
+==================
+
+* Speed improvements up to 4x thanks to the rewrite of comments and CSS' content
+  processing.
+* Stripping empty CSS tags is now optional (see [bin/cleancss](/bin/cleancss) for details).
+* Improved debugging mode (see [test/bench.js](/test/bench.js))
+* Added `make bench` for a one-pass benchmark.
+
+0.3.3 / 2012-05-27
+==================
+
+* Fixed tests, [package.json](/package.json) for development, and regex
+  for removing empty declarations (thanks to [@vvo](https://github.com/vvo)).
+
+0.3.2 / 2012-01-17
+==================
+
+* Fixed output method under node.js 0.6 which incorrectly tried to close
+  `process.stdout`.
+
+0.3.1 / 2011-12-16
+==================
+
+* Fixed cleaning up `0 0 0 0` expressions.
+
+0.3.0 / 2011-11-29
+==================
+
+* Clean-css requires node.js 0.4.0+ to run.
+* Removed node.js's 0.2.x 'sys' package dependency
+  (thanks to [@jmalonzo](https://github.com/jmalonzo) for a patch).
+
+0.2.6 / 2011-11-27
+==================
+
+* Fixed expanding `+` signs in `calc()` when mixed up with adjacent `+` selector.
+
+0.2.5 / 2011-11-27
+==================
+
+* Fixed issue with cleaning up spaces inside `calc`/`-moz-calc` declarations
+  (thanks to [@cvan](https://github.com/cvan) for reporting it).
+* Fixed converting `#f00` to `red` in borders and gradients.
+
+0.2.4 / 2011-05-25
+==================
+
+* Fixed problem with expanding `none` to `0` in partial/full background
+  declarations.
+* Fixed including clean-css library from binary (global to local).
+
+0.2.3 / 2011-04-18
+==================
+
+* Fixed problem with optimizing IE filters.
+
+0.2.2 / 2011-04-17
+==================
+
+* Fixed problem with space before color in `border` property.
+
+0.2.1 / 2011-03-19
+==================
+
+* Added stripping space before `!important` keyword.
+* Updated repository location and author information in [package.json](/package.json).
+
+0.2.0 / 2011-03-02
+==================
+
+* Added options parsing via optimist.
+* Changed code inclusion (thus the version bump).
+
+0.1.0 / 2011-02-27
+==================
+
+* First version of clean-css library.
+* Implemented all basic CSS transformations.

+ 19 - 0
node_modules/clean-css/LICENSE

@@ -0,0 +1,19 @@
+Copyright (C) 2017 JakubPawlowicz.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.

+ 987 - 0
node_modules/clean-css/README.md

@@ -0,0 +1,987 @@
+<h1 align="center">
+  <br/>
+  <img src="./logo.v2.svg" alt="clean-css logo" width="525px"/>
+  <br/>
+  <br/>
+</h1>
+
+[![npm version](https://img.shields.io/npm/v/clean-css.svg?style=flat)](https://www.npmjs.com/package/clean-css)
+[![Build Status](https://img.shields.io/github/workflow/status/clean-css/clean-css/Tests/master)](https://github.com/clean-css/clean-css/actions?query=workflow%3ATests+branch%3Amaster)
+[![PPC Linux Build Status](https://img.shields.io/travis/clean-css/clean-css/master.svg?style=flat&label=PPC%20Linux%20build)](https://travis-ci.org/clean-css/clean-css)
+[![Dependency Status](https://img.shields.io/david/clean-css/clean-css.svg?style=flat)](https://david-dm.org/clean-css/clean-css)
+[![npm Downloads](https://img.shields.io/npm/dm/clean-css.svg)](https://npmcharts.com/compare/clean-css?minimal=true)
+
+clean-css is a fast and efficient CSS optimizer for [Node.js](http://nodejs.org/) platform and [any modern browser](https://clean-css.github.io/).
+
+According to [tests](http://goalsmashers.github.io/css-minification-benchmark/) it is one of the best available.
+
+**Table of Contents**
+
+- [Node.js version support](#nodejs-version-support)
+- [Install](#install)
+- [Use](#use)
+  * [What's new in version 5.3](#whats-new-in-version-53)
+  * [What's new in version 5.0](#whats-new-in-version-50)
+  * [What's new in version 4.2](#whats-new-in-version-42)
+  * [What's new in version 4.1](#whats-new-in-version-41)
+  * [Important: 4.0 breaking changes](#important-40-breaking-changes)
+  * [Constructor options](#constructor-options)
+  * [Compatibility modes](#compatibility-modes)
+  * [Fetch option](#fetch-option)
+  * [Formatting options](#formatting-options)
+  * [Inlining options](#inlining-options)
+  * [Optimization levels](#optimization-levels)
+    + [Level 0 optimizations](#level-0-optimizations)
+    + [Level 1 optimizations](#level-1-optimizations)
+    + [Level 2 optimizations](#level-2-optimizations)
+  * [Plugins](#plugins)
+  * [Minify method](#minify-method)
+  * [Promise interface](#promise-interface)
+  * [CLI utility](#cli-utility)
+- [FAQ](#faq)
+  * [How to optimize multiple files?](#how-to-optimize-multiple-files)
+  * [How to process multiple files without concatenating them into one output file?](#how-to-process-multiple-files-without-concatenating-them-into-one-output-file)
+  * [How to process remote `@import`s correctly?](#how-to-process-remote-imports-correctly)
+  * [How to apply arbitrary transformations to CSS properties?](#how-to-apply-arbitrary-transformations-to-css-properties)
+  * [How to specify a custom rounding precision?](#how-to-specify-a-custom-rounding-precision)
+  * [How to keep a CSS fragment intact?](#how-to-keep-a-css-fragment-intact)
+  * [How to preserve a comment block?](#how-to-preserve-a-comment-block)
+  * [How to rebase relative image URLs?](#how-to-rebase-relative-image-urls)
+  * [How to work with source maps?](#how-to-work-with-source-maps)
+  * [How to apply level 1 & 2 optimizations at the same time?](#how-to-apply-level-1--2-optimizations-at-the-same-time)
+  * [What level 2 optimizations do?](#what-level-2-optimizations-do)
+  * [What errors and warnings are?](#what-errors-and-warnings-are)
+  * [How to use clean-css with build tools?](#how-to-use-clean-css-with-build-tools)
+  * [How to use clean-css from web browser?](#how-to-use-clean-css-from-web-browser)
+- [Contributing](#contributing)
+  * [How to get started?](#how-to-get-started)
+- [Acknowledgments](#acknowledgments)
+- [License](#license)
+
+# Node.js version support
+
+clean-css requires Node.js 10.0+ (tested on Linux, OS X, and Windows)
+
+# Install
+
+```
+npm install --save-dev clean-css
+```
+
+# Use
+
+```js
+var CleanCSS = require('clean-css');
+var input = 'a{font-weight:bold;}';
+var options = { /* options */ };
+var output = new CleanCSS(options).minify(input);
+```
+
+## What's new in version 5.3
+
+clean-css 5.3 introduces one new feature:
+
+* variables can be optimized using level 1's `variableValueOptimizers` option, which accepts a list of [value optimizers](https://github.com/clean-css/clean-css/blob/master/lib/optimizer/level-1/value-optimizers.js) or a list of their names, e.g. `variableValueOptimizers: ['color', 'fraction']`.
+
+## What's new in version 5.0
+
+clean-css 5.0 introduced some breaking changes:
+
+* Node.js 6.x and 8.x are officially no longer supported;
+* `transform` callback in level-1 optimizations is removed in favor of new [plugins](#plugins) interface;
+* changes default Internet Explorer compatibility from 10+ to >11, to revert the old default use `{ compatibility: 'ie10' }` flag;
+* changes default `rebase` option from `true` to `false` so URLs are not rebased by default. Please note that if you set `rebaseTo` option it still counts as setting `rebase: true` to preserve some of the backward compatibility.
+
+And on the new features side of things:
+
+* format options now accepts numerical values for all breaks, which will allow you to have more control over output formatting, e.g. `format: {breaks: {afterComment: 2}}` means clean-css will add two line breaks after each comment
+* a new `batch` option (defaults to `false`) is added, when set to `true` it will process all inputs, given either as an array or a hash, without concatenating them.
+
+## What's new in version 4.2
+
+clean-css 4.2 introduces the following changes / features:
+
+* Adds `process` method for compatibility with optimize-css-assets-webpack-plugin;
+* new `transition` property optimizer;
+* preserves any CSS content between `/* clean-css ignore:start */` and `/* clean-css ignore:end */` comments;
+* allows filtering based on selector in `transform` callback, see [example](#how-to-apply-arbitrary-transformations-to-css-properties);
+* adds configurable line breaks via `format: { breakWith: 'lf' }` option.
+
+## What's new in version 4.1
+
+clean-css 4.1 introduces the following changes / features:
+
+* `inline: false` as an alias to `inline: ['none']`;
+* `multiplePseudoMerging` compatibility flag controlling merging of rules with multiple pseudo classes / elements;
+* `removeEmpty` flag in level 1 optimizations controlling removal of rules and nested blocks;
+* `removeEmpty` flag in level 2 optimizations controlling removal of rules and nested blocks;
+* `compatibility: { selectors: { mergeLimit: <number> } }` flag in compatibility settings controlling maximum number of selectors in a single rule;
+* `minify` method improved signature accepting a list of hashes for a predictable traversal;
+* `selectorsSortingMethod` level 1 optimization allows `false` or `'none'` for disabling selector sorting;
+* `fetch` option controlling a function for handling remote requests;
+* new `font` shorthand and `font-*` longhand optimizers;
+* removal of `optimizeFont` flag in level 1 optimizations due to new `font` shorthand optimizer;
+* `skipProperties` flag in level 2 optimizations controlling which properties won't be optimized;
+* new `animation` shorthand and `animation-*` longhand optimizers;
+* `removeUnusedAtRules` level 2 optimization controlling removal of unused `@counter-style`, `@font-face`, `@keyframes`, and `@namespace` at rules;
+* the [web interface](https://clean-css.github.io/) gets an improved settings panel with "reset to defaults", instant option changes, and settings being persisted across sessions.
+
+## Important: 4.0 breaking changes
+
+clean-css 4.0 introduces some breaking changes:
+
+* API and CLI interfaces are split, so API stays in this repository while CLI moves to [clean-css-cli](https://github.com/clean-css/clean-css-cli);
+* `root`, `relativeTo`, and `target` options are replaced by a single `rebaseTo` option - this means that rebasing URLs and import inlining is much simpler but may not be (YMMV) as powerful as in 3.x;
+* `debug` option is gone as stats are always provided in output object under `stats` property;
+* `roundingPrecision` is disabled by default;
+* `roundingPrecision` applies to **all** units now, not only `px` as in 3.x;
+* `processImport` and `processImportFrom` are merged into `inline` option which defaults to `local`. Remote `@import` rules are **NOT** inlined by default anymore;
+* splits `inliner: { request: ..., timeout: ... }` option into `inlineRequest` and `inlineTimeout` options;
+* remote resources without a protocol, e.g. `//fonts.googleapis.com/css?family=Domine:700`, are not inlined anymore;
+* changes default Internet Explorer compatibility from 9+ to 10+, to revert the old default use `{ compatibility: 'ie9' }` flag;
+* renames `keepSpecialComments` to `specialComments`;
+* moves `roundingPrecision` and `specialComments` to level 1 optimizations options, see examples;
+* moves `mediaMerging`, `restructuring`, `semanticMerging`, and `shorthandCompacting` to level 2 optimizations options, see examples below;
+* renames `shorthandCompacting` option to `mergeIntoShorthands`;
+* level 1 optimizations are the new default, up to 3.x it was level 2;
+* `keepBreaks` option is replaced with `{ format: 'keep-breaks' }` to ease transition;
+* `sourceMap` option has to be a boolean from now on - to specify an input source map pass it a 2nd argument to `minify` method or via a hash instead;
+* `aggressiveMerging` option is removed as aggressive merging is replaced by smarter override merging.
+
+## Constructor options
+
+clean-css constructor accepts a hash as a parameter with the following options available:
+
+* `compatibility` - controls compatibility mode used; defaults to `ie10+`; see [compatibility modes](#compatibility-modes) for examples;
+* `fetch` - controls a function for handling remote requests; see [fetch option](#fetch-option) for examples (since 4.1.0);
+* `format` - controls output CSS formatting; defaults to `false`; see [formatting options](#formatting-options) for examples;
+* `inline` - controls `@import` inlining rules; defaults to `'local'`; see [inlining options](#inlining-options) for examples;
+* `inlineRequest` - controls extra options for inlining remote `@import` rules, can be any of [HTTP(S) request options](https://nodejs.org/api/http.html#http_http_request_options_callback);
+* `inlineTimeout` - controls number of milliseconds after which inlining a remote `@import` fails; defaults to 5000;
+* `level` - controls optimization level used; defaults to `1`; see [optimization levels](#optimization-levels) for examples;
+* `rebase` - controls URL rebasing; defaults to `false`;
+* `rebaseTo` - controls a directory to which all URLs are rebased, most likely the directory under which the output file will live; defaults to the current directory;
+* `returnPromise` - controls whether `minify` method returns a Promise object or not; defaults to `false`; see [promise interface](#promise-interface) for examples;
+* `sourceMap` - controls whether an output source map is built; defaults to `false`;
+* `sourceMapInlineSources` - controls embedding sources inside a source map's `sourcesContent` field; defaults to false.
+
+## Compatibility modes
+
+There is a certain number of compatibility mode shortcuts, namely:
+
+* `new CleanCSS({ compatibility: '*' })` (default) - Internet Explorer 10+ compatibility mode
+* `new CleanCSS({ compatibility: 'ie9' })` - Internet Explorer 9+ compatibility mode
+* `new CleanCSS({ compatibility: 'ie8' })` - Internet Explorer 8+ compatibility mode
+* `new CleanCSS({ compatibility: 'ie7' })` - Internet Explorer 7+ compatibility mode
+
+Each of these modes is an alias to a [fine grained configuration](https://github.com/clean-css/clean-css/blob/master/lib/options/compatibility.js), with the following options available:
+
+```js
+new CleanCSS({
+  compatibility: {
+    colors: {
+      hexAlpha: false, // controls 4- and 8-character hex color support
+      opacity: true // controls `rgba()` / `hsla()` color support
+    },
+    properties: {
+      backgroundClipMerging: true, // controls background-clip merging into shorthand
+      backgroundOriginMerging: true, // controls background-origin merging into shorthand
+      backgroundSizeMerging: true, // controls background-size merging into shorthand
+      colors: true, // controls color optimizations
+      ieBangHack: false, // controls keeping IE bang hack
+      ieFilters: false, // controls keeping IE `filter` / `-ms-filter`
+      iePrefixHack: false, // controls keeping IE prefix hack
+      ieSuffixHack: false, // controls keeping IE suffix hack
+      merging: true, // controls property merging based on understandability
+      shorterLengthUnits: false, // controls shortening pixel units into `pc`, `pt`, or `in` units
+      spaceAfterClosingBrace: true, // controls keeping space after closing brace - `url() no-repeat` into `url()no-repeat`
+      urlQuotes: true, // controls keeping quoting inside `url()`
+      zeroUnits: true // controls removal of units `0` value
+    },
+    selectors: {
+      adjacentSpace: false, // controls extra space before `nav` element
+      ie7Hack: true, // controls removal of IE7 selector hacks, e.g. `*+html...`
+      mergeablePseudoClasses: [':active', ...], // controls a whitelist of mergeable pseudo classes
+      mergeablePseudoElements: ['::after', ...], // controls a whitelist of mergeable pseudo elements
+      mergeLimit: 8191, // controls maximum number of selectors in a single rule (since 4.1.0)
+      multiplePseudoMerging: true // controls merging of rules with multiple pseudo classes / elements (since 4.1.0)
+    },
+    units: {
+      ch: true, // controls treating `ch` as a supported unit
+      in: true, // controls treating `in` as a supported unit
+      pc: true, // controls treating `pc` as a supported unit
+      pt: true, // controls treating `pt` as a supported unit
+      rem: true, // controls treating `rem` as a supported unit
+      vh: true, // controls treating `vh` as a supported unit
+      vm: true, // controls treating `vm` as a supported unit
+      vmax: true, // controls treating `vmax` as a supported unit
+      vmin: true // controls treating `vmin` as a supported unit
+    }
+  }
+})
+```
+
+You can also use a string when setting a compatibility mode, e.g.
+
+```js
+new CleanCSS({
+  compatibility: 'ie9,-properties.merging' // sets compatibility to IE9 mode with disabled property merging
+})
+```
+
+## Fetch option
+
+The `fetch` option accepts a function which handles remote resource fetching, e.g.
+
+```js
+var request = require('request');
+var source = '@import url(http://example.com/path/to/stylesheet.css);';
+new CleanCSS({
+  fetch: function (uri, inlineRequest, inlineTimeout, callback) {
+    request(uri, function (error, response, body) {
+      if (error) {
+        callback(error, null);
+      } else if (response && response.statusCode != 200) {
+        callback(response.statusCode, null);
+      } else {
+        callback(null, body);
+      }
+    });
+  }
+}).minify(source);
+```
+
+This option provides a convenient way of overriding the default fetching logic if it doesn't support a particular feature, say CONNECT proxies.
+
+Unless given, the default [loadRemoteResource](https://github.com/clean-css/clean-css/blob/master/lib/reader/load-remote-resource.js) logic is used.
+
+## Formatting options
+
+By default output CSS is formatted without any whitespace unless a `format` option is given.
+First of all there are two shorthands:
+
+```js
+new CleanCSS({
+  format: 'beautify' // formats output in a really nice way
+})
+```
+
+and
+
+```js
+new CleanCSS({
+  format: 'keep-breaks' // formats output the default way but adds line breaks for improved readability
+})
+```
+
+however `format` option also accept a fine-grained set of options:
+
+```js
+new CleanCSS({
+  format: {
+    breaks: { // controls where to insert breaks
+      afterAtRule: false, // controls if a line break comes after an at-rule; e.g. `@charset`; defaults to `false`
+      afterBlockBegins: false, // controls if a line break comes after a block begins; e.g. `@media`; defaults to `false`
+      afterBlockEnds: false, // controls if a line break comes after a block ends, defaults to `false`
+      afterComment: false, // controls if a line break comes after a comment; defaults to `false`
+      afterProperty: false, // controls if a line break comes after a property; defaults to `false`
+      afterRuleBegins: false, // controls if a line break comes after a rule begins; defaults to `false`
+      afterRuleEnds: false, // controls if a line break comes after a rule ends; defaults to `false`
+      beforeBlockEnds: false, // controls if a line break comes before a block ends; defaults to `false`
+      betweenSelectors: false // controls if a line break comes between selectors; defaults to `false`
+    },
+    breakWith: '\n', // controls the new line character, can be `'\r\n'` or `'\n'` (aliased as `'windows'` and `'unix'` or `'crlf'` and `'lf'`); defaults to system one, so former on Windows and latter on Unix
+    indentBy: 0, // controls number of characters to indent with; defaults to `0`
+    indentWith: 'space', // controls a character to indent with, can be `'space'` or `'tab'`; defaults to `'space'`
+    spaces: { // controls where to insert spaces
+      aroundSelectorRelation: false, // controls if spaces come around selector relations; e.g. `div > a`; defaults to `false`
+      beforeBlockBegins: false, // controls if a space comes before a block begins; e.g. `.block {`; defaults to `false`
+      beforeValue: false // controls if a space comes before a value; e.g. `width: 1rem`; defaults to `false`
+    },
+    wrapAt: false, // controls maximum line length; defaults to `false`
+    semicolonAfterLastProperty: false // controls removing trailing semicolons in rule; defaults to `false` - means remove
+  }
+})
+```
+
+Also since clean-css 5.0 you can use numerical values for all line breaks, which will repeat a line break that many times, e.g:
+
+```js
+  new CleanCSS({
+    format: {
+      breaks: {
+        afterAtRule: 2,
+        afterBlockBegins: 1, // 1 is synonymous with `true`
+        afterBlockEnds: 2,
+        afterComment: 1,
+        afterProperty: 1,
+        afterRuleBegins: 1,
+        afterRuleEnds: 1,
+        beforeBlockEnds: 1,
+        betweenSelectors: 0 // 0 is synonymous with `false`
+      }
+    }
+  })
+```
+
+which will add nicer spacing between at rules and blocks.
+
+## Inlining options
+
+`inline` option whitelists which `@import` rules will be processed, e.g.
+
+```js
+new CleanCSS({
+  inline: ['local'] // default; enables local inlining only
+})
+```
+
+```js
+new CleanCSS({
+  inline: ['none'] // disables all inlining
+})
+```
+
+```js
+// introduced in clean-css 4.1.0
+
+new CleanCSS({
+  inline: false // disables all inlining (alias to `['none']`)
+})
+```
+
+```js
+new CleanCSS({
+  inline: ['all'] // enables all inlining, same as ['local', 'remote']
+})
+```
+
+```js
+new CleanCSS({
+  inline: ['local', 'mydomain.example.com'] // enables local inlining plus given remote source
+})
+```
+
+```js
+new CleanCSS({
+  inline: ['local', 'remote', '!fonts.googleapis.com'] // enables all inlining but from given remote source
+})
+```
+
+## Optimization levels
+
+The `level` option can be either `0`, `1` (default), or `2`, e.g.
+
+```js
+new CleanCSS({
+  level: 2
+})
+```
+
+or a fine-grained configuration given via a hash.
+
+Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
+
+### Level 0 optimizations
+
+Level 0 optimizations simply means "no optimizations". Use it when you'd like to inline imports and / or rebase URLs but skip everything else.
+
+### Level 1 optimizations
+
+Level 1 optimizations (default) operate on single properties only, e.g. can remove units when not required, turn rgb colors to a shorter hex representation, remove comments, etc
+
+Here is a full list of available options:
+
+```js
+new CleanCSS({
+  level: {
+    1: {
+      cleanupCharsets: true, // controls `@charset` moving to the front of a stylesheet; defaults to `true`
+      normalizeUrls: true, // controls URL normalization; defaults to `true`
+      optimizeBackground: true, // controls `background` property optimizations; defaults to `true`
+      optimizeBorderRadius: true, // controls `border-radius` property optimizations; defaults to `true`
+      optimizeFilter: true, // controls `filter` property optimizations; defaults to `true`
+      optimizeFont: true, // controls `font` property optimizations; defaults to `true`
+      optimizeFontWeight: true, // controls `font-weight` property optimizations; defaults to `true`
+      optimizeOutline: true, // controls `outline` property optimizations; defaults to `true`
+      removeEmpty: true, // controls removing empty rules and nested blocks; defaults to `true`
+      removeNegativePaddings: true, // controls removing negative paddings; defaults to `true`
+      removeQuotes: true, // controls removing quotes when unnecessary; defaults to `true`
+      removeWhitespace: true, // controls removing unused whitespace; defaults to `true`
+      replaceMultipleZeros: true, // contols removing redundant zeros; defaults to `true`
+      replaceTimeUnits: true, // controls replacing time units with shorter values; defaults to `true`
+      replaceZeroUnits: true, // controls replacing zero values with units; defaults to `true`
+      roundingPrecision: false, // rounds pixel values to `N` decimal places; `false` disables rounding; defaults to `false`
+      selectorsSortingMethod: 'standard', // denotes selector sorting method; can be `'natural'` or `'standard'`, `'none'`, or false (the last two since 4.1.0); defaults to `'standard'`
+      specialComments: 'all', // denotes a number of /*! ... */ comments preserved; defaults to `all`
+      tidyAtRules: true, // controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `true`
+      tidyBlockScopes: true, // controls block scopes (e.g. `@media`) optimizing; defaults to `true`
+      tidySelectors: true, // controls selectors optimizing; defaults to `true`,
+      variableValueOptimizers: [] // controls value optimizers which are applied to variables
+    }
+  }
+});
+```
+
+There is an `all` shortcut for toggling all options at the same time, e.g.
+
+```js
+new CleanCSS({
+  level: {
+    1: {
+      all: false, // set all values to `false`
+      tidySelectors: true // turns on optimizing selectors
+    }
+  }
+});
+```
+
+### Level 2 optimizations
+
+Level 2 optimizations operate at rules or multiple properties level, e.g. can remove duplicate rules, remove properties redefined further down a stylesheet, or restructure rules by moving them around.
+
+Please note that if level 2 optimizations are turned on then, unless explicitely disabled, level 1 optimizations are applied as well.
+
+Here is a full list of available options:
+
+```js
+new CleanCSS({
+  level: {
+    2: {
+      mergeAdjacentRules: true, // controls adjacent rules merging; defaults to true
+      mergeIntoShorthands: true, // controls merging properties into shorthands; defaults to true
+      mergeMedia: true, // controls `@media` merging; defaults to true
+      mergeNonAdjacentRules: true, // controls non-adjacent rule merging; defaults to true
+      mergeSemantically: false, // controls semantic merging; defaults to false
+      overrideProperties: true, // controls property overriding based on understandability; defaults to true
+      removeEmpty: true, // controls removing empty rules and nested blocks; defaults to `true`
+      reduceNonAdjacentRules: true, // controls non-adjacent rule reducing; defaults to true
+      removeDuplicateFontRules: true, // controls duplicate `@font-face` removing; defaults to true
+      removeDuplicateMediaBlocks: true, // controls duplicate `@media` removing; defaults to true
+      removeDuplicateRules: true, // controls duplicate rules removing; defaults to true
+      removeUnusedAtRules: false, // controls unused at rule removing; defaults to false (available since 4.1.0)
+      restructureRules: false, // controls rule restructuring; defaults to false
+      skipProperties: [] // controls which properties won't be optimized, defaults to `[]` which means all will be optimized (since 4.1.0)
+    }
+  }
+});
+```
+
+There is an `all` shortcut for toggling all options at the same time, e.g.
+
+```js
+new CleanCSS({
+  level: {
+    2: {
+      all: false, // sets all values to `false`
+      removeDuplicateRules: true // turns on removing duplicate rules
+    }
+  }
+});
+```
+
+## Plugins
+
+In clean-css version 5 and above you can define plugins which run alongside level 1 and level 2 optimizations, e.g.
+
+```js
+var myPlugin = {
+  level1: {
+    property: function removeRepeatedBackgroundRepeat(_rule, property, _options) {
+      // So `background-repeat:no-repeat no-repeat` becomes `background-repeat:no-repeat`
+      if (property.name == 'background-repeat' && property.value.length == 2 && property.value[0][1] == property.value[1][1]) {
+        property.value.pop();
+        property.dirty = true;
+      }
+    }
+  }
+}
+
+new CleanCSS({plugins: [myPlugin]})
+
+```
+
+Search `test\module-test.js` for `plugins` or check out `lib/optimizer/level-1/property-optimizers` and `lib/optimizer/level-1/value-optimizers` for more examples.
+
+__Important__: To rewrite your old `transform` as a plugin, check out [this commit](https://github.com/clean-css/clean-css/commit/b6ddc523267fc42cf0f6bd1626a79cad97319e17#diff-a71ef45f934725cdb25860dc0b606bcd59e3acee9788cd6df4f9d05339e8a153).
+
+## Minify method
+
+Once configured clean-css provides a `minify` method to optimize a given CSS, e.g.
+
+```js
+var output = new CleanCSS(options).minify(source);
+```
+
+The output of the `minify` method is a hash with following fields:
+
+```js
+console.log(output.styles); // optimized output CSS as a string
+console.log(output.sourceMap); // output source map if requested with `sourceMap` option
+console.log(output.errors); // a list of errors raised
+console.log(output.warnings); // a list of warnings raised
+console.log(output.stats.originalSize); // original content size after import inlining
+console.log(output.stats.minifiedSize); // optimized content size
+console.log(output.stats.timeSpent); // time spent on optimizations in milliseconds
+console.log(output.stats.efficiency); // `(originalSize - minifiedSize) / originalSize`, e.g. 0.25 if size is reduced from 100 bytes to 75 bytes
+```
+Example: Minifying a CSS string:
+
+```js
+const CleanCSS = require("clean-css");
+
+const output = new CleanCSS().minify(`
+
+  a {
+    color: blue;
+  }
+  div {
+    margin: 5px
+  }
+
+`);
+
+console.log(output);
+
+// Log:
+{
+  styles: 'a{color:#00f}div{margin:5px}',
+  stats: {
+    efficiency: 0.6704545454545454,
+    minifiedSize: 29,
+    originalSize: 88,
+    timeSpent: 6
+  },
+  errors: [],
+  inlinedStylesheets: [],
+  warnings: []
+}
+```
+
+The `minify` method also accepts an input source map, e.g.
+
+```js
+var output = new CleanCSS(options).minify(source, inputSourceMap);
+```
+
+or a callback invoked when optimizations are finished, e.g.
+
+```js
+new CleanCSS(options).minify(source, function (error, output) {
+  // `output` is the same as in the synchronous call above
+});
+```
+
+To optimize a single file, without reading it first, pass a path to it to `minify` method as follows:
+
+```js
+var output = new CleanCSS(options).minify(['path/to/file.css'])
+```
+
+(if you won't enclose the path in an array, it will be treated as a CSS source instead).
+
+There are several ways to optimize multiple files at the same time, see [How to optimize multiple files?](#how-to-optimize-multiple-files).
+
+## Promise interface
+
+If you prefer clean-css to return a Promise object then you need to explicitely ask for it, e.g.
+
+```js
+new CleanCSS({ returnPromise: true })
+  .minify(source)
+  .then(function (output) { console.log(output.styles); })
+  .catch(function (error) { // deal with errors });
+```
+
+## CLI utility
+
+Clean-css has an associated command line utility that can be installed separately using `npm install clean-css-cli`. For more detailed information, please visit https://github.com/clean-css/clean-css-cli.
+
+# FAQ
+
+## How to optimize multiple files?
+
+It can be done either by passing an array of paths, or, when sources are already available, a hash or an array of hashes:
+
+```js
+new CleanCSS().minify(['path/to/file/one', 'path/to/file/two']);
+```
+
+```js
+new CleanCSS().minify({
+  'path/to/file/one': {
+    styles: 'contents of file one'
+  },
+  'path/to/file/two': {
+    styles: 'contents of file two'
+  }
+});
+```
+
+```js
+new CleanCSS().minify([
+  {'path/to/file/one': {styles: 'contents of file one'}},
+  {'path/to/file/two': {styles: 'contents of file two'}}
+]);
+```
+
+Passing an array of hashes allows you to explicitly specify the order in which the input files are concatenated. Whereas when you use a single hash the order is determined by the [traversal order of object properties](http://2ality.com/2015/10/property-traversal-order-es6.html) - available since 4.1.0.
+
+Important note - any `@import` rules already present in the hash will be resolved in memory.
+
+## How to process multiple files without concatenating them into one output file?
+
+Since clean-css 5.0 you can, when passing an array of paths, hash, or array of hashes (see above), ask clean-css not to join styles into one output, but instead return stylesheets optimized one by one, e.g.
+
+```js
+var output = new CleanCSS({ batch: true }).minify(['path/to/file/one', 'path/to/file/two']);
+var outputOfFile1 = output['path/to/file/one'].styles // all other fields, like errors, warnings, or stats are there too
+var outputOfFile2 = output['path/to/file/two'].styles
+```
+
+## How to process remote `@import`s correctly?
+
+In order to inline remote `@import` statements you need to provide a callback to minify method as fetching remote assets is an asynchronous operation, e.g.:
+
+```js
+var source = '@import url(http://example.com/path/to/remote/styles);';
+new CleanCSS({ inline: ['remote'] }).minify(source, function (error, output) {
+  // output.styles
+});
+```
+
+If you don't provide a callback, then remote `@import`s will be left as is.
+
+## How to apply arbitrary transformations to CSS properties?
+
+Please see [plugins](#plugins).
+
+## How to specify a custom rounding precision?
+
+The level 1 `roundingPrecision` optimization option accept a string with per-unit rounding precision settings, e.g.
+
+```js
+new CleanCSS({
+  level: {
+    1: {
+      roundingPrecision: 'all=3,px=5'
+    }
+  }
+}).minify(source)
+```
+
+which sets all units rounding precision to 3 digits except `px` unit precision of 5 digits.
+
+## How to optimize a stylesheet with custom `rpx` units?
+
+Since `rpx` is a non standard unit (see [#1074](https://github.com/clean-css/clean-css/issues/1074)), it will be dropped by default as an invalid value.
+
+However you can treat `rpx` units as regular ones:
+
+```js
+new CleanCSS({
+  compatibility: {
+    customUnits: {
+      rpx: true
+    }
+  }
+}).minify(source)
+```
+
+## How to keep a CSS fragment intact?
+
+Note: available since 4.2.0.
+
+Wrap the CSS fragment in special comments which instruct clean-css to preserve it, e.g.
+
+```css
+.block-1 {
+  color: red
+}
+/* clean-css ignore:start */
+.block-special {
+  color: transparent
+}
+/* clean-css ignore:end */
+.block-2 {
+  margin: 0
+}
+```
+
+Optimizing this CSS will result in the following output:
+
+```css
+.block-1{color:red}
+.block-special {
+  color: transparent
+}
+.block-2{margin:0}
+```
+
+## How to preserve a comment block?
+
+Use the `/*!` notation instead of the standard one `/*`:
+
+```css
+/*!
+  Important comments included in optimized output.
+*/
+```
+
+## How to rebase relative image URLs?
+
+clean-css will handle it automatically for you in the following cases:
+
+* when full paths to input files are passed in as options;
+* when correct paths are passed in via a hash;
+* when `rebaseTo` is used with any of above two.
+
+## How to work with source maps?
+
+To generate a source map, use `sourceMap: true` option, e.g.:
+
+```js
+new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
+  .minify(source, function (error, output) {
+    // access output.sourceMap for SourceMapGenerator object
+    // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
+});
+```
+
+You can also pass an input source map directly as a 2nd argument to `minify` method:
+
+```js
+new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory })
+  .minify(source, inputSourceMap, function (error, output) {
+    // access output.sourceMap to access SourceMapGenerator object
+    // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details
+});
+```
+
+or even multiple input source maps at once:
+
+```js
+new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory }).minify({
+  'path/to/source/1': {
+    styles: '...styles...',
+    sourceMap: '...source-map...'
+  },
+  'path/to/source/2': {
+    styles: '...styles...',
+    sourceMap: '...source-map...'
+  }
+}, function (error, output) {
+  // access output.sourceMap as above
+});
+```
+
+## How to apply level 1 & 2 optimizations at the same time?
+
+Using the hash configuration specifying both optimization levels, e.g.
+
+```js
+new CleanCSS({
+  level: {
+    1: {
+      all: true,
+      normalizeUrls: false
+    },
+    2: {
+      restructureRules: true
+    }
+  }
+})
+```
+
+will apply level 1 optimizations, except url normalization, and default level 2 optimizations with rule restructuring.
+
+## What level 2 optimizations do?
+
+All level 2 optimizations are dispatched [here](https://github.com/clean-css/clean-css/blob/master/lib/optimizer/level-2/optimize.js#L67), and this is what they do:
+
+* `recursivelyOptimizeBlocks` - does all the following operations on a nested block, like `@media` or `@keyframe`;
+* `recursivelyOptimizeProperties` - optimizes properties in rulesets and flat at-rules, like @font-face, by splitting them into components (e.g. `margin` into `margin-(bottom|left|right|top)`), optimizing, and restoring them back. You may want to use `mergeIntoShorthands` option to control whether you want to turn multiple components into shorthands;
+* `removeDuplicates` - gets rid of duplicate rulesets with exactly the same set of properties, e.g. when including a Sass / Less partial twice for no good reason;
+* `mergeAdjacent` - merges adjacent rulesets with the same selector or rules;
+* `reduceNonAdjacent` - identifies which properties are overridden in same-selector non-adjacent rulesets, and removes them;
+* `mergeNonAdjacentBySelector` - identifies same-selector non-adjacent rulesets which can be moved (!) to be merged, requires all intermediate rulesets to not redefine the moved properties, or if redefined to have the same value;
+* `mergeNonAdjacentByBody` - same as the one above but for same-selector non-adjacent rulesets;
+* `restructure` - tries to reorganize different-selector different-rules rulesets so they take less space, e.g. `.one{padding:0}.two{margin:0}.one{margin-bottom:3px}` into `.two{margin:0}.one{padding:0;margin-bottom:3px}`;
+* `removeDuplicateFontAtRules` - removes duplicated `@font-face` rules;
+* `removeDuplicateMediaQueries` - removes duplicated `@media` nested blocks;
+* `mergeMediaQueries` - merges non-adjacent `@media` at-rules by the same rules as `mergeNonAdjacentBy*` above;
+
+## What errors and warnings are?
+
+If clean-css encounters invalid CSS, it will try to remove the invalid part and continue optimizing the rest of the code. It will make you aware of the problem by generating an error or warning. Although clean-css can work with invalid CSS, it is always recommended that you fix warnings and errors in your CSS.
+
+Example: Minify invalid CSS, resulting in two warnings:
+
+```js
+const CleanCSS = require("clean-css");
+
+const output = new CleanCSS().minify(`
+
+  a {
+    -notarealproperty-: 5px;
+    color:
+  }
+  div {
+    margin: 5px
+  }
+
+`);
+
+console.log(output);
+
+// Log:
+{
+  styles: 'div{margin:5px}',
+  stats: {
+    efficiency: 0.8695652173913043,
+    minifiedSize: 15,
+    originalSize: 115,
+    timeSpent: 1
+  },
+  errors: [],
+  inlinedStylesheets: [],
+  warnings: [
+    "Invalid property name '-notarealproperty-' at 4:8. Ignoring.",
+    "Empty property 'color' at 5:8. Ignoring."
+  ]
+}
+```
+
+Example: Minify invalid CSS, resulting in one error:
+
+```js
+const CleanCSS = require("clean-css");
+
+const output = new CleanCSS().minify(`
+
+  @import "idontexist.css";
+  a {
+    color: blue;
+  }
+  div {
+    margin: 5px
+  }
+
+`);
+
+console.log(output);
+
+// Log:
+{
+  styles: 'a{color:#00f}div{margin:5px}',
+  stats: {
+    efficiency: 0.7627118644067796,
+    minifiedSize: 28,
+    originalSize: 118,
+    timeSpent: 2
+  },
+  errors: [
+    'Ignoring local @import of "idontexist.css" as resource is missing.'
+  ],
+  inlinedStylesheets: [],
+  warnings: []
+}
+```
+## Clean-css for Gulp
+An example of how you can include clean-css in gulp
+```js
+const { src, dest, series } = require('gulp');
+const CleanCSS = require('clean-css');
+const concat = require('gulp-concat');
+
+function css() {
+    const options = {
+        compatibility: '*', // (default) - Internet Explorer 10+ compatibility mode
+        inline: ['all'], // enables all inlining, same as ['local', 'remote']
+        level: 2 // Optimization levels. The level option can be either 0, 1 (default), or 2, e.g.
+        // Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users.
+    };
+
+    return src('app/**/*.css')
+        .pipe(concat('style.min.css'))
+        .on('data', function(file) {
+            const buferFile = new CleanCSS(options).minify(file.contents)
+            return file.contents = Buffer.from(buferFile.styles)
+        })
+        .pipe(dest('build'))
+}
+exports.css = series(css)
+```
+
+## How to use clean-css with build tools?
+
+There is a number of 3rd party plugins to popular build tools:
+
+* [Broccoli](https://github.com/broccolijs/broccoli#broccoli): [broccoli-clean-css](https://github.com/shinnn/broccoli-clean-css)
+* [Brunch](http://brunch.io/): [clean-css-brunch](https://github.com/brunch/clean-css-brunch)
+* [Grunt](http://gruntjs.com): [grunt-contrib-cssmin](https://github.com/gruntjs/grunt-contrib-cssmin)
+* [Gulp](http://gulpjs.com/): [gulp-clean-css](https://github.com/scniro/gulp-clean-css)
+* [Gulp](http://gulpjs.com/): [using vinyl-map as a wrapper - courtesy of @sogko](https://github.com/clean-css/clean-css/issues/342)
+* [component-builder2](https://github.com/component/builder2.js): [builder-clean-css](https://github.com/poying/builder-clean-css)
+* [Metalsmith](http://metalsmith.io): [metalsmith-clean-css](https://github.com/aymericbeaumet/metalsmith-clean-css)
+* [Lasso](https://github.com/lasso-js/lasso): [lasso-clean-css](https://github.com/yomed/lasso-clean-css)
+* [Start](https://github.com/start-runner/start): [start-clean-css](https://github.com/start-runner/clean-css)
+
+## How to use clean-css from web browser?
+
+* https://clean-css.github.io/ (official web interface)
+* http://refresh-sf.com/
+* http://adamburgess.github.io/clean-css-online/
+
+# Contributing
+
+See [CONTRIBUTING.md](https://github.com/clean-css/clean-css/blob/master/CONTRIBUTING.md).
+
+## How to get started?
+
+First clone the sources:
+
+```bash
+git clone [email protected]:clean-css/clean-css.git
+```
+
+then install dependencies:
+
+```bash
+cd clean-css
+npm install
+```
+
+then use any of the following commands to verify your copy:
+
+```bash
+npm run bench # for clean-css benchmarks (see [test/bench.js](https://github.com/clean-css/clean-css/blob/master/test/bench.js) for details)
+npm run browserify # to create the browser-ready clean-css version
+npm run check # to lint JS sources with [JSHint](https://github.com/jshint/jshint/)
+npm test # to run all tests
+```
+
+# Acknowledgments
+
+Sorted alphabetically by GitHub handle:
+
+* [@abarre](https://github.com/abarre) (Anthony Barre) for improvements to `@import` processing;
+* [@alexlamsl](https://github.com/alexlamsl) (Alex Lam S.L.) for testing early clean-css 4 versions, reporting bugs, and suggesting numerous improvements.
+* [@altschuler](https://github.com/altschuler) (Simon Altschuler) for fixing `@import` processing inside comments;
+* [@ben-eb](https://github.com/ben-eb) (Ben Briggs) for sharing ideas about CSS optimizations;
+* [@davisjam](https://github.com/davisjam) (Jamie Davis) for disclosing ReDOS vulnerabilities;
+* [@facelessuser](https://github.com/facelessuser) (Isaac) for pointing out a flaw in clean-css' stateless mode;
+* [@grandrath](https://github.com/grandrath) (Martin Grandrath) for improving `minify` method source traversal in ES6;
+* [@jmalonzo](https://github.com/jmalonzo) (Jan Michael Alonzo) for a patch removing node.js' old `sys` package;
+* [@lukeapage](https://github.com/lukeapage) (Luke Page) for suggestions and testing the source maps feature;
+  Plus everyone else involved in [#125](https://github.com/clean-css/clean-css/issues/125) for pushing it forward;
+* [@madwizard-thomas](https://github.com/madwizard-thomas) for sharing ideas about `@import` inlining and URL rebasing.
+* [@ngyikp](https://github.com/ngyikp) (Ng Yik Phang) for testing early clean-css 4 versions, reporting bugs, and suggesting numerous improvements.
+* [@wagenet](https://github.com/wagenet) (Peter Wagenet) for suggesting improvements to `@import` inlining behavior;
+* [@venemo](https://github.com/venemo) (Timur Kristóf) for an outstanding contribution of advanced property optimizer for 2.2 release;
+* [@vvo](https://github.com/vvo) (Vincent Voyer) for a patch with better empty element regex and for inspiring us to do many performance improvements in 0.4 release;
+* [@xhmikosr](https://github.com/xhmikosr) for suggesting new features, like option to remove special comments and strip out URLs quotation, and pointing out numerous improvements like JSHint, media queries, etc.
+
+# License
+
+clean-css is released under the [MIT License](https://github.com/clean-css/clean-css/blob/master/LICENSE).

+ 1 - 0
node_modules/clean-css/index.js

@@ -0,0 +1 @@
+module.exports = require('./lib/clean');

+ 241 - 0
node_modules/clean-css/lib/clean.js

@@ -0,0 +1,241 @@
+/**
+ * Clean-css - https://github.com/clean-css/clean-css
+ * Released under the terms of MIT license
+ */
+
+var level0Optimize = require('./optimizer/level-0/optimize');
+var level1Optimize = require('./optimizer/level-1/optimize');
+var level2Optimize = require('./optimizer/level-2/optimize');
+var validator = require('./optimizer/validator');
+
+var compatibilityFrom = require('./options/compatibility');
+var fetchFrom = require('./options/fetch');
+var formatFrom = require('./options/format').formatFrom;
+var inlineFrom = require('./options/inline');
+var inlineRequestFrom = require('./options/inline-request');
+var inlineTimeoutFrom = require('./options/inline-timeout');
+var OptimizationLevel = require('./options/optimization-level').OptimizationLevel;
+var optimizationLevelFrom = require('./options/optimization-level').optimizationLevelFrom;
+var pluginsFrom = require('./options/plugins');
+var rebaseFrom = require('./options/rebase');
+var rebaseToFrom = require('./options/rebase-to');
+
+var inputSourceMapTracker = require('./reader/input-source-map-tracker');
+var readSources = require('./reader/read-sources');
+
+var serializeStyles = require('./writer/simple');
+var serializeStylesAndSourceMap = require('./writer/source-maps');
+
+var CleanCSS = module.exports = function CleanCSS(options) {
+  options = options || {};
+
+  this.options = {
+    batch: !!options.batch,
+    compatibility: compatibilityFrom(options.compatibility),
+    explicitRebaseTo: 'rebaseTo' in options,
+    fetch: fetchFrom(options.fetch),
+    format: formatFrom(options.format),
+    inline: inlineFrom(options.inline),
+    inlineRequest: inlineRequestFrom(options.inlineRequest),
+    inlineTimeout: inlineTimeoutFrom(options.inlineTimeout),
+    level: optimizationLevelFrom(options.level),
+    plugins: pluginsFrom(options.plugins),
+    rebase: rebaseFrom(options.rebase, options.rebaseTo),
+    rebaseTo: rebaseToFrom(options.rebaseTo),
+    returnPromise: !!options.returnPromise,
+    sourceMap: !!options.sourceMap,
+    sourceMapInlineSources: !!options.sourceMapInlineSources
+  };
+};
+
+// for compatibility with optimize-css-assets-webpack-plugin
+CleanCSS.process = function(input, opts) {
+  var cleanCss;
+  var optsTo = opts.to;
+
+  delete opts.to;
+  cleanCss = new CleanCSS(Object.assign({
+    returnPromise: true, rebaseTo: optsTo
+  }, opts));
+
+  return cleanCss.minify(input)
+    .then(function(output) {
+      return { css: output.styles };
+    });
+};
+
+CleanCSS.prototype.minify = function(input, maybeSourceMap, maybeCallback) {
+  var options = this.options;
+
+  if (options.returnPromise) {
+    return new Promise(function(resolve, reject) {
+      minifyAll(input, options, maybeSourceMap, function(errors, output) {
+        return errors
+          ? reject(errors)
+          : resolve(output);
+      });
+    });
+  }
+  return minifyAll(input, options, maybeSourceMap, maybeCallback);
+};
+
+function minifyAll(input, options, maybeSourceMap, maybeCallback) {
+  if (options.batch && Array.isArray(input)) {
+    return minifyInBatchesFromArray(input, options, maybeSourceMap, maybeCallback);
+  } if (options.batch && (typeof input == 'object')) {
+    return minifyInBatchesFromHash(input, options, maybeSourceMap, maybeCallback);
+  }
+  return minify(input, options, maybeSourceMap, maybeCallback);
+}
+
+function minifyInBatchesFromArray(input, options, maybeSourceMap, maybeCallback) {
+  var callback = typeof maybeCallback == 'function'
+    ? maybeCallback
+    : (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
+  var errors = [];
+  var outputAsHash = {};
+  var inputValue;
+  var i, l;
+
+  function whenHashBatchDone(innerErrors, output) {
+    outputAsHash = Object.assign(outputAsHash, output);
+
+    if (innerErrors !== null) {
+      errors = errors.concat(innerErrors);
+    }
+  }
+
+  for (i = 0, l = input.length; i < l; i++) {
+    if (typeof input[i] == 'object') {
+      minifyInBatchesFromHash(input[i], options, whenHashBatchDone);
+    } else {
+      inputValue = input[i];
+
+      outputAsHash[inputValue] = minify([inputValue], options);
+      errors = errors.concat(outputAsHash[inputValue].errors);
+    }
+  }
+
+  return callback
+    ? callback(errors.length > 0 ? errors : null, outputAsHash)
+    : outputAsHash;
+}
+
+function minifyInBatchesFromHash(input, options, maybeSourceMap, maybeCallback) {
+  var callback = typeof maybeCallback == 'function'
+    ? maybeCallback
+    : (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
+  var errors = [];
+  var outputAsHash = {};
+  var inputKey;
+  var inputValue;
+
+  for (inputKey in input) {
+    inputValue = input[inputKey];
+
+    outputAsHash[inputKey] = minify(inputValue.styles, options, inputValue.sourceMap);
+    errors = errors.concat(outputAsHash[inputKey].errors);
+  }
+
+  return callback
+    ? callback(errors.length > 0 ? errors : null, outputAsHash)
+    : outputAsHash;
+}
+
+function minify(input, options, maybeSourceMap, maybeCallback) {
+  var sourceMap = typeof maybeSourceMap != 'function'
+    ? maybeSourceMap
+    : null;
+  var callback = typeof maybeCallback == 'function'
+    ? maybeCallback
+    : (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
+  var context = {
+    stats: {
+      efficiency: 0,
+      minifiedSize: 0,
+      originalSize: 0,
+      startedAt: Date.now(),
+      timeSpent: 0
+    },
+    cache: { specificity: {} },
+    errors: [],
+    inlinedStylesheets: [],
+    inputSourceMapTracker: inputSourceMapTracker(),
+    localOnly: !callback,
+    options: options,
+    source: null,
+    sourcesContent: {},
+    validator: validator(options.compatibility),
+    warnings: []
+  };
+  var implicitRebaseToWarning;
+
+  if (sourceMap) {
+    context.inputSourceMapTracker.track(undefined, sourceMap);
+  }
+
+  if (options.rebase && !options.explicitRebaseTo) {
+    implicitRebaseToWarning = 'You have set `rebase: true` without giving `rebaseTo` option, which, in this case, defaults to the current working directory. '
+      + 'You are then warned this can lead to unexpected URL rebasing (aka here be dragons)! '
+      + 'If you are OK with the clean-css output, then you can get rid of this warning by giving clean-css a `rebaseTo: process.cwd()` option.';
+    context.warnings.push(implicitRebaseToWarning);
+  }
+
+  return runner(context.localOnly)(function() {
+    return readSources(input, context, function(tokens) {
+      var serialize = context.options.sourceMap
+        ? serializeStylesAndSourceMap
+        : serializeStyles;
+
+      var optimizedTokens = optimize(tokens, context);
+      var optimizedStyles = serialize(optimizedTokens, context);
+      var output = withMetadata(optimizedStyles, context);
+
+      return callback
+        ? callback(context.errors.length > 0 ? context.errors : null, output)
+        : output;
+    });
+  });
+}
+
+function runner(localOnly) {
+  // to always execute code asynchronously when a callback is given
+  // more at blog.izs.me/post/59142742143/designing-apis-for-asynchrony
+  return localOnly
+    ? function(callback) { return callback(); }
+    : process.nextTick;
+}
+
+function optimize(tokens, context) {
+  var optimized = level0Optimize(tokens, context);
+
+  optimized = OptimizationLevel.One in context.options.level
+    ? level1Optimize(tokens, context)
+    : tokens;
+  optimized = OptimizationLevel.Two in context.options.level
+    ? level2Optimize(tokens, context, true)
+    : optimized;
+
+  return optimized;
+}
+
+function withMetadata(output, context) {
+  output.stats = calculateStatsFrom(output.styles, context);
+  output.errors = context.errors;
+  output.inlinedStylesheets = context.inlinedStylesheets;
+  output.warnings = context.warnings;
+
+  return output;
+}
+
+function calculateStatsFrom(styles, context) {
+  var finishedAt = Date.now();
+  var timeSpent = finishedAt - context.stats.startedAt;
+
+  delete context.stats.startedAt;
+  context.stats.timeSpent = timeSpent;
+  context.stats.efficiency = 1 - styles.length / context.stats.originalSize;
+  context.stats.minifiedSize = styles.length;
+
+  return context.stats;
+}

+ 33 - 0
node_modules/clean-css/lib/optimizer/clone.js

@@ -0,0 +1,33 @@
+var wrapSingle = require('./wrap-for-optimizing').single;
+
+var Token = require('../tokenizer/token');
+
+function deep(property) {
+  var cloned = shallow(property);
+  for (var i = property.components.length - 1; i >= 0; i--) {
+    var component = shallow(property.components[i]);
+    component.value = property.components[i].value.slice(0);
+    cloned.components.unshift(component);
+  }
+
+  cloned.dirty = true;
+  cloned.value = property.value.slice(0);
+
+  return cloned;
+}
+
+function shallow(property) {
+  var cloned = wrapSingle([
+    Token.PROPERTY,
+    [Token.PROPERTY_NAME, property.name]
+  ]);
+  cloned.important = property.important;
+  cloned.hack = property.hack;
+  cloned.unused = false;
+  return cloned;
+}
+
+module.exports = {
+  deep: deep,
+  shallow: shallow
+};

+ 1640 - 0
node_modules/clean-css/lib/optimizer/configuration.js

@@ -0,0 +1,1640 @@
+// Contains the interpretation of CSS properties, as used by the property optimizer
+
+var breakUp = require('./configuration/break-up');
+var canOverride = require('./configuration/can-override');
+var restore = require('./configuration/restore');
+
+var propertyOptimizers = require('./level-1/property-optimizers');
+var valueOptimizers = require('./level-1/value-optimizers');
+
+var override = require('../utils/override');
+
+// Properties to process
+// Extend this object in order to add support for more properties in the optimizer.
+//
+// Each key in this object represents a CSS property and should be an object.
+// Such an object contains properties that describe how the represented CSS property should be handled.
+// Possible options:
+//
+// * components: array (Only specify for shorthand properties.)
+//   Contains the names of the granular properties this shorthand compacts.
+//
+// * canOverride: function
+//   Returns whether two tokens of this property can be merged with each other.
+//   This property has no meaning for shorthands.
+//
+// * defaultValue: string
+//   Specifies the default value of the property according to the CSS standard.
+//   For shorthand, this is used when every component is set to its default value, therefore it should be the shortest possible default value of all the components.
+//
+// * shortestValue: string
+//   Specifies the shortest possible value the property can possibly have.
+//   (Falls back to defaultValue if unspecified.)
+//
+// * breakUp: function (Only specify for shorthand properties.)
+//   Breaks the shorthand up to its components.
+//
+// * restore: function (Only specify for shorthand properties.)
+//   Puts the shorthand together from its components.
+//
+var configuration = {
+  animation: {
+    canOverride: canOverride.generic.components([
+      canOverride.generic.time,
+      canOverride.generic.timingFunction,
+      canOverride.generic.time,
+      canOverride.property.animationIterationCount,
+      canOverride.property.animationDirection,
+      canOverride.property.animationFillMode,
+      canOverride.property.animationPlayState,
+      canOverride.property.animationName
+    ]),
+    components: [
+      'animation-duration',
+      'animation-timing-function',
+      'animation-delay',
+      'animation-iteration-count',
+      'animation-direction',
+      'animation-fill-mode',
+      'animation-play-state',
+      'animation-name'
+    ],
+    breakUp: breakUp.multiplex(breakUp.animation),
+    defaultValue: 'none',
+    restore: restore.multiplex(restore.withoutDefaults),
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.textQuotes,
+      valueOptimizers.time,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-delay': {
+    canOverride: canOverride.generic.time,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: '0s',
+    intoMultiplexMode: 'real',
+    valueOptimizers: [
+      valueOptimizers.time,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-direction': {
+    canOverride: canOverride.property.animationDirection,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: 'normal',
+    intoMultiplexMode: 'real',
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-duration': {
+    canOverride: canOverride.generic.time,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: '0s',
+    intoMultiplexMode: 'real',
+    keepUnlessDefault: 'animation-delay',
+    valueOptimizers: [
+      valueOptimizers.time,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-fill-mode': {
+    canOverride: canOverride.property.animationFillMode,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: 'none',
+    intoMultiplexMode: 'real',
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-iteration-count': {
+    canOverride: canOverride.property.animationIterationCount,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: '1',
+    intoMultiplexMode: 'real',
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-name': {
+    canOverride: canOverride.property.animationName,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: 'none',
+    intoMultiplexMode: 'real',
+    valueOptimizers: [
+      valueOptimizers.textQuotes
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-play-state': {
+    canOverride: canOverride.property.animationPlayState,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: 'running',
+    intoMultiplexMode: 'real',
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'animation-timing-function': {
+    canOverride: canOverride.generic.timingFunction,
+    componentOf: [
+      'animation'
+    ],
+    defaultValue: 'ease',
+    intoMultiplexMode: 'real',
+    vendorPrefixes: [
+      '-moz-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  background: {
+    canOverride: canOverride.generic.components([
+      canOverride.generic.image,
+      canOverride.property.backgroundPosition,
+      canOverride.property.backgroundSize,
+      canOverride.property.backgroundRepeat,
+      canOverride.property.backgroundAttachment,
+      canOverride.property.backgroundOrigin,
+      canOverride.property.backgroundClip,
+      canOverride.generic.color
+    ]),
+    components: [
+      'background-image',
+      'background-position',
+      'background-size',
+      'background-repeat',
+      'background-attachment',
+      'background-origin',
+      'background-clip',
+      'background-color'
+    ],
+    breakUp: breakUp.multiplex(breakUp.background),
+    defaultValue: '0 0',
+    propertyOptimizer: propertyOptimizers.background,
+    restore: restore.multiplex(restore.background),
+    shortestValue: '0',
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.urlWhiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.zero,
+      valueOptimizers.color,
+      valueOptimizers.urlPrefix,
+      valueOptimizers.urlQuotes
+    ]
+  },
+  'background-attachment': {
+    canOverride: canOverride.property.backgroundAttachment,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: 'scroll',
+    intoMultiplexMode: 'real'
+  },
+  'background-clip': {
+    canOverride: canOverride.property.backgroundClip,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: 'border-box',
+    intoMultiplexMode: 'real',
+    shortestValue: 'border-box'
+  },
+  'background-color': {
+    canOverride: canOverride.generic.color,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: 'transparent',
+    intoMultiplexMode: 'real', // otherwise real color will turn into default since color appears in last multiplex only
+    multiplexLastOnly: true,
+    nonMergeableValue: 'none',
+    shortestValue: 'red',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'background-image': {
+    canOverride: canOverride.generic.image,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: 'none',
+    intoMultiplexMode: 'default',
+    valueOptimizers: [
+      valueOptimizers.urlWhiteSpace,
+      valueOptimizers.urlPrefix,
+      valueOptimizers.urlQuotes,
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero,
+      valueOptimizers.color
+    ]
+  },
+  'background-origin': {
+    canOverride: canOverride.property.backgroundOrigin,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: 'padding-box',
+    intoMultiplexMode: 'real',
+    shortestValue: 'border-box'
+  },
+  'background-position': {
+    canOverride: canOverride.property.backgroundPosition,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: ['0', '0'],
+    doubleValues: true,
+    intoMultiplexMode: 'real',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'background-repeat': {
+    canOverride: canOverride.property.backgroundRepeat,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: ['repeat'],
+    doubleValues: true,
+    intoMultiplexMode: 'real'
+  },
+  'background-size': {
+    canOverride: canOverride.property.backgroundSize,
+    componentOf: [
+      'background'
+    ],
+    defaultValue: ['auto'],
+    doubleValues: true,
+    intoMultiplexMode: 'real',
+    shortestValue: '0 0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  bottom: {
+    canOverride: canOverride.property.bottom,
+    defaultValue: 'auto',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  border: {
+    breakUp: breakUp.border,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.property.borderStyle,
+      canOverride.generic.color
+    ]),
+    components: [
+      'border-width',
+      'border-style',
+      'border-color'
+    ],
+    defaultValue: 'none',
+    overridesShorthands: [
+      'border-bottom',
+      'border-left',
+      'border-right',
+      'border-top'
+    ],
+    restore: restore.withoutDefaults,
+    shorthand: true,
+    shorthandComponents: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.zero,
+      valueOptimizers.color
+    ]
+  },
+  'border-bottom': {
+    breakUp: breakUp.border,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.property.borderStyle,
+      canOverride.generic.color
+    ]),
+    components: [
+      'border-bottom-width',
+      'border-bottom-style',
+      'border-bottom-color'
+    ],
+    defaultValue: 'none',
+    restore: restore.withoutDefaults,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.zero,
+      valueOptimizers.color
+    ]
+  },
+  'border-bottom-color': {
+    canOverride: canOverride.generic.color,
+    componentOf: [
+      'border-bottom',
+      'border-color'
+    ],
+    defaultValue: 'none',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'border-bottom-left-radius': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-radius'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.borderRadius,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-'
+    ]
+  },
+  'border-bottom-right-radius': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-radius'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.borderRadius,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-'
+    ]
+  },
+  'border-bottom-style': {
+    canOverride: canOverride.property.borderStyle,
+    componentOf: [
+      'border-bottom',
+      'border-style'
+    ],
+    defaultValue: 'none'
+  },
+  'border-bottom-width': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-bottom',
+      'border-width'
+    ],
+    defaultValue: 'medium',
+    oppositeTo: 'border-top-width',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'border-collapse': {
+    canOverride: canOverride.property.borderCollapse,
+    defaultValue: 'separate'
+  },
+  'border-color': {
+    breakUp: breakUp.fourValues,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.color,
+      canOverride.generic.color,
+      canOverride.generic.color,
+      canOverride.generic.color
+    ]),
+    componentOf: [
+      'border'
+    ],
+    components: [
+      'border-top-color',
+      'border-right-color',
+      'border-bottom-color',
+      'border-left-color'
+    ],
+    defaultValue: 'none',
+    restore: restore.fourValues,
+    shortestValue: 'red',
+    shorthand: true,
+    singleTypeComponents: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'border-left': {
+    breakUp: breakUp.border,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.property.borderStyle,
+      canOverride.generic.color
+    ]),
+    components: [
+      'border-left-width',
+      'border-left-style',
+      'border-left-color'
+    ],
+    defaultValue: 'none',
+    restore: restore.withoutDefaults,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.zero,
+      valueOptimizers.color
+    ]
+  },
+  'border-left-color': {
+    canOverride: canOverride.generic.color,
+    componentOf: [
+      'border-color',
+      'border-left'
+    ],
+    defaultValue: 'none',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'border-left-style': {
+    canOverride: canOverride.property.borderStyle,
+    componentOf: [
+      'border-left',
+      'border-style'
+    ],
+    defaultValue: 'none'
+  },
+  'border-left-width': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-left',
+      'border-width'
+    ],
+    defaultValue: 'medium',
+    oppositeTo: 'border-right-width',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'border-radius': {
+    breakUp: breakUp.borderRadius,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit
+    ]),
+    components: [
+      'border-top-left-radius',
+      'border-top-right-radius',
+      'border-bottom-right-radius',
+      'border-bottom-left-radius'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.borderRadius,
+    restore: restore.borderRadius,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-'
+    ]
+  },
+  'border-right': {
+    breakUp: breakUp.border,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.property.borderStyle,
+      canOverride.generic.color
+    ]),
+    components: [
+      'border-right-width',
+      'border-right-style',
+      'border-right-color'
+    ],
+    defaultValue: 'none',
+    restore: restore.withoutDefaults,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'border-right-color': {
+    canOverride: canOverride.generic.color,
+    componentOf: [
+      'border-color',
+      'border-right'
+    ],
+    defaultValue: 'none',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'border-right-style': {
+    canOverride: canOverride.property.borderStyle,
+    componentOf: [
+      'border-right',
+      'border-style'
+    ],
+    defaultValue: 'none'
+  },
+  'border-right-width': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-right',
+      'border-width'
+    ],
+    defaultValue: 'medium',
+    oppositeTo: 'border-left-width',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'border-style': {
+    breakUp: breakUp.fourValues,
+    canOverride: canOverride.generic.components([
+      canOverride.property.borderStyle,
+      canOverride.property.borderStyle,
+      canOverride.property.borderStyle,
+      canOverride.property.borderStyle
+    ]),
+    componentOf: [
+      'border'
+    ],
+    components: [
+      'border-top-style',
+      'border-right-style',
+      'border-bottom-style',
+      'border-left-style'
+    ],
+    defaultValue: 'none',
+    restore: restore.fourValues,
+    shorthand: true,
+    singleTypeComponents: true
+  },
+  'border-top': {
+    breakUp: breakUp.border,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.property.borderStyle,
+      canOverride.generic.color
+    ]),
+    components: [
+      'border-top-width',
+      'border-top-style',
+      'border-top-color'
+    ],
+    defaultValue: 'none',
+    restore: restore.withoutDefaults,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.zero,
+      valueOptimizers.color,
+      valueOptimizers.unit
+    ]
+  },
+  'border-top-color': {
+    canOverride: canOverride.generic.color,
+    componentOf: [
+      'border-color',
+      'border-top'
+    ],
+    defaultValue: 'none',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'border-top-left-radius': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-radius'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.borderRadius,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-'
+    ]
+  },
+  'border-top-right-radius': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-radius'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.borderRadius,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-o-'
+    ]
+  },
+  'border-top-style': {
+    canOverride: canOverride.property.borderStyle,
+    componentOf: [
+      'border-style',
+      'border-top'
+    ],
+    defaultValue: 'none'
+  },
+  'border-top-width': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'border-top',
+      'border-width'
+    ],
+    defaultValue: 'medium',
+    oppositeTo: 'border-bottom-width',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'border-width': {
+    breakUp: breakUp.fourValues,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit
+    ]),
+    componentOf: [
+      'border'
+    ],
+    components: [
+      'border-top-width',
+      'border-right-width',
+      'border-bottom-width',
+      'border-left-width'
+    ],
+    defaultValue: 'medium',
+    restore: restore.fourValues,
+    shortestValue: '0',
+    shorthand: true,
+    singleTypeComponents: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'box-shadow': {
+    propertyOptimizer: propertyOptimizers.boxShadow,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero,
+      valueOptimizers.color
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  clear: {
+    canOverride: canOverride.property.clear,
+    defaultValue: 'none'
+  },
+  clip: {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  color: {
+    canOverride: canOverride.generic.color,
+    defaultValue: 'transparent',
+    shortestValue: 'red',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'column-gap': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  cursor: {
+    canOverride: canOverride.property.cursor,
+    defaultValue: 'auto'
+  },
+  display: { canOverride: canOverride.property.display },
+  filter: {
+    propertyOptimizer: propertyOptimizers.filter,
+    valueOptimizers: [
+      valueOptimizers.fraction
+    ]
+  },
+  float: {
+    canOverride: canOverride.property.float,
+    defaultValue: 'none'
+  },
+  font: {
+    breakUp: breakUp.font,
+    canOverride: canOverride.generic.components([
+      canOverride.property.fontStyle,
+      canOverride.property.fontVariant,
+      canOverride.property.fontWeight,
+      canOverride.property.fontStretch,
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.property.fontFamily
+    ]),
+    components: [
+      'font-style',
+      'font-variant',
+      'font-weight',
+      'font-stretch',
+      'font-size',
+      'line-height',
+      'font-family'
+    ],
+    restore: restore.font,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.textQuotes
+    ]
+  },
+  'font-family': {
+    canOverride: canOverride.property.fontFamily,
+    defaultValue: 'user|agent|specific',
+    valueOptimizers: [
+      valueOptimizers.textQuotes
+    ]
+  },
+  'font-size': {
+    canOverride: canOverride.generic.unit,
+    defaultValue: 'medium',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.fraction
+    ]
+  },
+  'font-stretch': {
+    canOverride: canOverride.property.fontStretch,
+    defaultValue: 'normal'
+  },
+  'font-style': {
+    canOverride: canOverride.property.fontStyle,
+    defaultValue: 'normal'
+  },
+  'font-variant': {
+    canOverride: canOverride.property.fontVariant,
+    defaultValue: 'normal'
+  },
+  'font-weight': {
+    canOverride: canOverride.property.fontWeight,
+    defaultValue: 'normal',
+    propertyOptimizer: propertyOptimizers.fontWeight,
+    shortestValue: '400'
+  },
+  gap: {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  height: {
+    canOverride: canOverride.generic.unit,
+    defaultValue: 'auto',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  left: {
+    canOverride: canOverride.property.left,
+    defaultValue: 'auto',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'letter-spacing': {
+    valueOptimizers: [
+      valueOptimizers.fraction,
+      valueOptimizers.zero
+    ]
+  },
+  'line-height': {
+    canOverride: canOverride.generic.unitOrNumber,
+    defaultValue: 'normal',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.fraction,
+      valueOptimizers.zero
+    ]
+  },
+  'list-style': {
+    canOverride: canOverride.generic.components([
+      canOverride.property.listStyleType,
+      canOverride.property.listStylePosition,
+      canOverride.property.listStyleImage
+    ]),
+    components: [
+      'list-style-type',
+      'list-style-position',
+      'list-style-image'
+    ],
+    breakUp: breakUp.listStyle,
+    restore: restore.withoutDefaults,
+    defaultValue: 'outside', // can't use 'disc' because that'd override default 'decimal' for <ol>
+    shortestValue: 'none',
+    shorthand: true
+  },
+  'list-style-image': {
+    canOverride: canOverride.generic.image,
+    componentOf: [
+      'list-style'
+    ],
+    defaultValue: 'none'
+  },
+  'list-style-position': {
+    canOverride: canOverride.property.listStylePosition,
+    componentOf: [
+      'list-style'
+    ],
+    defaultValue: 'outside',
+    shortestValue: 'inside'
+  },
+  'list-style-type': {
+    canOverride: canOverride.property.listStyleType,
+    componentOf: [
+      'list-style'
+    ],
+    // NOTE: we can't tell the real default value here, it's 'disc' for <ul> and 'decimal' for <ol>
+    // this is a hack, but it doesn't matter because this value will be either overridden or
+    // it will disappear at the final step anyway
+    defaultValue: 'decimal|disc',
+    shortestValue: 'none'
+  },
+  margin: {
+    breakUp: breakUp.fourValues,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit
+    ]),
+    components: [
+      'margin-top',
+      'margin-right',
+      'margin-bottom',
+      'margin-left'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.margin,
+    restore: restore.fourValues,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'margin-bottom': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'margin'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'margin-top',
+    propertyOptimizer: propertyOptimizers.margin,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'margin-inline-end': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'margin-inline-start': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'margin-left': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'margin'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'margin-right',
+    propertyOptimizer: propertyOptimizers.margin,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'margin-right': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'margin'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'margin-left',
+    propertyOptimizer: propertyOptimizers.margin,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'margin-top': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'margin'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'margin-bottom',
+    propertyOptimizer: propertyOptimizers.margin,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'max-height': {
+    canOverride: canOverride.generic.unit,
+    defaultValue: 'none',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'max-width': {
+    canOverride: canOverride.generic.unit,
+    defaultValue: 'none',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'min-height': {
+    canOverride: canOverride.generic.unit,
+    defaultValue: '0',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'min-width': {
+    canOverride: canOverride.generic.unit,
+    defaultValue: '0',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  opacity: {
+    valueOptimizers: [
+      valueOptimizers.fraction,
+      valueOptimizers.precision
+    ]
+  },
+  outline: {
+    canOverride: canOverride.generic.components([
+      canOverride.generic.color,
+      canOverride.property.outlineStyle,
+      canOverride.generic.unit
+    ]),
+    components: [
+      'outline-color',
+      'outline-style',
+      'outline-width'
+    ],
+    breakUp: breakUp.outline,
+    restore: restore.withoutDefaults,
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.outline,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'outline-color': {
+    canOverride: canOverride.generic.color,
+    componentOf: [
+      'outline'
+    ],
+    defaultValue: 'invert',
+    shortestValue: 'red',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.color
+    ]
+  },
+  'outline-style': {
+    canOverride: canOverride.property.outlineStyle,
+    componentOf: [
+      'outline'
+    ],
+    defaultValue: 'none'
+  },
+  'outline-width': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'outline'
+    ],
+    defaultValue: 'medium',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  overflow: {
+    canOverride: canOverride.property.overflow,
+    defaultValue: 'visible'
+  },
+  'overflow-x': {
+    canOverride: canOverride.property.overflow,
+    defaultValue: 'visible'
+  },
+  'overflow-y': {
+    canOverride: canOverride.property.overflow,
+    defaultValue: 'visible'
+  },
+  padding: {
+    breakUp: breakUp.fourValues,
+    canOverride: canOverride.generic.components([
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit,
+      canOverride.generic.unit
+    ]),
+    components: [
+      'padding-top',
+      'padding-right',
+      'padding-bottom',
+      'padding-left'
+    ],
+    defaultValue: '0',
+    propertyOptimizer: propertyOptimizers.padding,
+    restore: restore.fourValues,
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'padding-bottom': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'padding'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'padding-top',
+    propertyOptimizer: propertyOptimizers.padding,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'padding-left': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'padding'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'padding-right',
+    propertyOptimizer: propertyOptimizers.padding,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'padding-right': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'padding'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'padding-left',
+    propertyOptimizer: propertyOptimizers.padding,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'padding-top': {
+    canOverride: canOverride.generic.unit,
+    componentOf: [
+      'padding'
+    ],
+    defaultValue: '0',
+    oppositeTo: 'padding-bottom',
+    propertyOptimizer: propertyOptimizers.padding,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  position: {
+    canOverride: canOverride.property.position,
+    defaultValue: 'static'
+  },
+  right: {
+    canOverride: canOverride.property.right,
+    defaultValue: 'auto',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'row-gap': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  src: {
+    valueOptimizers: [
+      valueOptimizers.urlWhiteSpace,
+      valueOptimizers.urlPrefix,
+      valueOptimizers.urlQuotes
+    ]
+  },
+  'stroke-width': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'text-align': {
+    canOverride: canOverride.property.textAlign,
+    // NOTE: we can't tell the real default value here, as it depends on default text direction
+    // this is a hack, but it doesn't matter because this value will be either overridden or
+    // it will disappear anyway
+    defaultValue: 'left|right'
+  },
+  'text-decoration': {
+    canOverride: canOverride.property.textDecoration,
+    defaultValue: 'none'
+  },
+  'text-indent': {
+    canOverride: canOverride.property.textOverflow,
+    defaultValue: 'none',
+    valueOptimizers: [
+      valueOptimizers.fraction,
+      valueOptimizers.zero
+    ]
+  },
+  'text-overflow': {
+    canOverride: canOverride.property.textOverflow,
+    defaultValue: 'none'
+  },
+  'text-shadow': {
+    canOverride: canOverride.property.textShadow,
+    defaultValue: 'none',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.zero,
+      valueOptimizers.color
+    ]
+  },
+  top: {
+    canOverride: canOverride.property.top,
+    defaultValue: 'auto',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  transform: {
+    canOverride: canOverride.property.transform,
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.degrees,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  transition: {
+    breakUp: breakUp.multiplex(breakUp.transition),
+    canOverride: canOverride.generic.components([
+      canOverride.property.transitionProperty,
+      canOverride.generic.time,
+      canOverride.generic.timingFunction,
+      canOverride.generic.time
+    ]),
+    components: [
+      'transition-property',
+      'transition-duration',
+      'transition-timing-function',
+      'transition-delay'
+    ],
+    defaultValue: 'none',
+    restore: restore.multiplex(restore.withoutDefaults),
+    shorthand: true,
+    valueOptimizers: [
+      valueOptimizers.time,
+      valueOptimizers.fraction
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'transition-delay': {
+    canOverride: canOverride.generic.time,
+    componentOf: [
+      'transition'
+    ],
+    defaultValue: '0s',
+    intoMultiplexMode: 'real',
+    valueOptimizers: [
+      valueOptimizers.time
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'transition-duration': {
+    canOverride: canOverride.generic.time,
+    componentOf: [
+      'transition'
+    ],
+    defaultValue: '0s',
+    intoMultiplexMode: 'real',
+    keepUnlessDefault: 'transition-delay',
+    valueOptimizers: [
+      valueOptimizers.time,
+      valueOptimizers.fraction
+    ],
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'transition-property': {
+    canOverride: canOverride.generic.propertyName,
+    componentOf: [
+      'transition'
+    ],
+    defaultValue: 'all',
+    intoMultiplexMode: 'placeholder',
+    placeholderValue: '_', // it's a short value that won't match any property and still be a valid `transition-property`
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'transition-timing-function': {
+    canOverride: canOverride.generic.timingFunction,
+    componentOf: [
+      'transition'
+    ],
+    defaultValue: 'ease',
+    intoMultiplexMode: 'real',
+    vendorPrefixes: [
+      '-moz-',
+      '-ms-',
+      '-o-',
+      '-webkit-'
+    ]
+  },
+  'vertical-align': {
+    canOverride: canOverride.property.verticalAlign,
+    defaultValue: 'baseline',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  visibility: {
+    canOverride: canOverride.property.visibility,
+    defaultValue: 'visible'
+  },
+  '-webkit-tap-highlight-color': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.color
+    ]
+  },
+  '-webkit-margin-end': {
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'white-space': {
+    canOverride: canOverride.property.whiteSpace,
+    defaultValue: 'normal'
+  },
+  width: {
+    canOverride: canOverride.generic.unit,
+    defaultValue: 'auto',
+    shortestValue: '0',
+    valueOptimizers: [
+      valueOptimizers.whiteSpace,
+      valueOptimizers.fraction,
+      valueOptimizers.precision,
+      valueOptimizers.unit,
+      valueOptimizers.zero
+    ]
+  },
+  'z-index': {
+    canOverride: canOverride.property.zIndex,
+    defaultValue: 'auto'
+  }
+};
+
+// generate vendor-prefixed configuration
+var vendorPrefixedConfiguration = {};
+
+function cloneDescriptor(propertyName, prefix) {
+  var clonedDescriptor = override(configuration[propertyName], {});
+
+  if ('componentOf' in clonedDescriptor) {
+    clonedDescriptor.componentOf = clonedDescriptor.componentOf.map(function(shorthandName) {
+      return prefix + shorthandName;
+    });
+  }
+
+  if ('components' in clonedDescriptor) {
+    clonedDescriptor.components = clonedDescriptor.components.map(function(longhandName) {
+      return prefix + longhandName;
+    });
+  }
+
+  if ('keepUnlessDefault' in clonedDescriptor) {
+    clonedDescriptor.keepUnlessDefault = prefix + clonedDescriptor.keepUnlessDefault;
+  }
+
+  return clonedDescriptor;
+}
+
+for (var propertyName in configuration) {
+  var descriptor = configuration[propertyName];
+
+  if (!('vendorPrefixes' in descriptor)) {
+    continue;
+  }
+
+  for (var i = 0; i < descriptor.vendorPrefixes.length; i++) {
+    var prefix = descriptor.vendorPrefixes[i];
+    var clonedDescriptor = cloneDescriptor(propertyName, prefix);
+    delete clonedDescriptor.vendorPrefixes;
+
+    vendorPrefixedConfiguration[prefix + propertyName] = clonedDescriptor;
+  }
+
+  delete descriptor.vendorPrefixes;
+}
+
+module.exports = override(configuration, vendorPrefixedConfiguration);

+ 656 - 0
node_modules/clean-css/lib/optimizer/configuration/break-up.js

@@ -0,0 +1,656 @@
+var InvalidPropertyError = require('../invalid-property-error');
+
+var wrapSingle = require('../wrap-for-optimizing').single;
+
+var Token = require('../../tokenizer/token');
+var Marker = require('../../tokenizer/marker');
+
+var formatPosition = require('../../utils/format-position');
+
+function _anyIsInherit(values) {
+  var i, l;
+
+  for (i = 0, l = values.length; i < l; i++) {
+    if (values[i][1] == 'inherit') {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+function _colorFilter(validator) {
+  return function(value) {
+    return value[1] == 'invert' || validator.isColor(value[1]) || validator.isPrefixed(value[1]);
+  };
+}
+
+function _styleFilter(validator) {
+  return function(value) {
+    return value[1] != 'inherit' && validator.isStyleKeyword(value[1]) && !validator.isColorFunction(value[1]);
+  };
+}
+
+function _wrapDefault(name, property, configuration) {
+  var descriptor = configuration[name];
+  if (descriptor.doubleValues && descriptor.defaultValue.length == 2) {
+    return wrapSingle([
+      Token.PROPERTY,
+      [Token.PROPERTY_NAME, name],
+      [Token.PROPERTY_VALUE, descriptor.defaultValue[0]],
+      [Token.PROPERTY_VALUE, descriptor.defaultValue[1]]
+    ]);
+  } if (descriptor.doubleValues && descriptor.defaultValue.length == 1) {
+    return wrapSingle([
+      Token.PROPERTY,
+      [Token.PROPERTY_NAME, name],
+      [Token.PROPERTY_VALUE, descriptor.defaultValue[0]]
+    ]);
+  }
+  return wrapSingle([
+    Token.PROPERTY,
+    [Token.PROPERTY_NAME, name],
+    [Token.PROPERTY_VALUE, descriptor.defaultValue]
+  ]);
+}
+
+function _widthFilter(validator) {
+  return function(value) {
+    return value[1] != 'inherit'
+      && (validator.isWidth(value[1]) || validator.isUnit(value[1]) || validator.isDynamicUnit(value[1]))
+      && !validator.isStyleKeyword(value[1])
+      && !validator.isColorFunction(value[1]);
+  };
+}
+
+function animation(property, configuration, validator) {
+  var duration = _wrapDefault(property.name + '-duration', property, configuration);
+  var timing = _wrapDefault(property.name + '-timing-function', property, configuration);
+  var delay = _wrapDefault(property.name + '-delay', property, configuration);
+  var iteration = _wrapDefault(property.name + '-iteration-count', property, configuration);
+  var direction = _wrapDefault(property.name + '-direction', property, configuration);
+  var fill = _wrapDefault(property.name + '-fill-mode', property, configuration);
+  var play = _wrapDefault(property.name + '-play-state', property, configuration);
+  var name = _wrapDefault(property.name + '-name', property, configuration);
+  var components = [duration, timing, delay, iteration, direction, fill, play, name];
+  var values = property.value;
+  var value;
+  var durationSet = false;
+  var timingSet = false;
+  var delaySet = false;
+  var iterationSet = false;
+  var directionSet = false;
+  var fillSet = false;
+  var playSet = false;
+  var nameSet = false;
+  var i;
+  var l;
+
+  if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+    // eslint-disable-next-line max-len
+    duration.value = timing.value = delay.value = iteration.value = direction.value = fill.value = play.value = name.value = property.value;
+    return components;
+  }
+
+  if (values.length > 1 && _anyIsInherit(values)) {
+    throw new InvalidPropertyError('Invalid animation values at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  for (i = 0, l = values.length; i < l; i++) {
+    value = values[i];
+
+    if (validator.isTime(value[1]) && !durationSet) {
+      duration.value = [value];
+      durationSet = true;
+    } else if (validator.isTime(value[1]) && !delaySet) {
+      delay.value = [value];
+      delaySet = true;
+    } else if ((validator.isGlobal(value[1]) || validator.isTimingFunction(value[1])) && !timingSet) {
+      timing.value = [value];
+      timingSet = true;
+    } else if ((validator.isAnimationIterationCountKeyword(value[1])
+      || validator.isPositiveNumber(value[1]))
+      && !iterationSet) {
+      iteration.value = [value];
+      iterationSet = true;
+    } else if (validator.isAnimationDirectionKeyword(value[1]) && !directionSet) {
+      direction.value = [value];
+      directionSet = true;
+    } else if (validator.isAnimationFillModeKeyword(value[1]) && !fillSet) {
+      fill.value = [value];
+      fillSet = true;
+    } else if (validator.isAnimationPlayStateKeyword(value[1]) && !playSet) {
+      play.value = [value];
+      playSet = true;
+    } else if ((validator.isAnimationNameKeyword(value[1]) || validator.isIdentifier(value[1])) && !nameSet) {
+      name.value = [value];
+      nameSet = true;
+    } else {
+      throw new InvalidPropertyError('Invalid animation value at ' + formatPosition(value[2][0]) + '. Ignoring.');
+    }
+  }
+
+  return components;
+}
+
+function background(property, configuration, validator) {
+  var image = _wrapDefault('background-image', property, configuration);
+  var position = _wrapDefault('background-position', property, configuration);
+  var size = _wrapDefault('background-size', property, configuration);
+  var repeat = _wrapDefault('background-repeat', property, configuration);
+  var attachment = _wrapDefault('background-attachment', property, configuration);
+  var origin = _wrapDefault('background-origin', property, configuration);
+  var clip = _wrapDefault('background-clip', property, configuration);
+  var color = _wrapDefault('background-color', property, configuration);
+  var components = [image, position, size, repeat, attachment, origin, clip, color];
+  var values = property.value;
+
+  var positionSet = false;
+  var clipSet = false;
+  var originSet = false;
+  var repeatSet = false;
+
+  var anyValueSet = false;
+
+  if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+    // NOTE: 'inherit' is not a valid value for background-attachment
+    color.value = image.value = repeat.value = position.value = size.value = origin.value = clip.value = property.value;
+    return components;
+  }
+
+  if (property.value.length == 1 && property.value[0][1] == '0 0') {
+    return components;
+  }
+
+  for (var i = values.length - 1; i >= 0; i--) {
+    var value = values[i];
+
+    if (validator.isBackgroundAttachmentKeyword(value[1])) {
+      attachment.value = [value];
+      anyValueSet = true;
+    } else if (validator.isBackgroundClipKeyword(value[1]) || validator.isBackgroundOriginKeyword(value[1])) {
+      if (clipSet) {
+        origin.value = [value];
+        originSet = true;
+      } else {
+        clip.value = [value];
+        clipSet = true;
+      }
+      anyValueSet = true;
+    } else if (validator.isBackgroundRepeatKeyword(value[1])) {
+      if (repeatSet) {
+        repeat.value.unshift(value);
+      } else {
+        repeat.value = [value];
+        repeatSet = true;
+      }
+      anyValueSet = true;
+    } else if (validator.isBackgroundPositionKeyword(value[1])
+    || validator.isBackgroundSizeKeyword(value[1])
+    || validator.isUnit(value[1])
+    || validator.isDynamicUnit(value[1])) {
+      if (i > 0) {
+        var previousValue = values[i - 1];
+
+        if (previousValue[1] == Marker.FORWARD_SLASH) {
+          size.value = [value];
+        } else if (i > 1 && values[i - 2][1] == Marker.FORWARD_SLASH) {
+          size.value = [previousValue, value];
+          i -= 2;
+        } else {
+          if (!positionSet) { position.value = []; }
+
+          position.value.unshift(value);
+          positionSet = true;
+        }
+      } else {
+        if (!positionSet) { position.value = []; }
+
+        position.value.unshift(value);
+        positionSet = true;
+      }
+      anyValueSet = true;
+    } else if ((color.value[0][1] == configuration[color.name].defaultValue || color.value[0][1] == 'none') && (validator.isColor(value[1]) || validator.isPrefixed(value[1]))) {
+      color.value = [value];
+      anyValueSet = true;
+    } else if (validator.isUrl(value[1]) || validator.isFunction(value[1])) {
+      image.value = [value];
+      anyValueSet = true;
+    }
+  }
+
+  if (clipSet && !originSet) { origin.value = clip.value.slice(0); }
+
+  if (!anyValueSet) {
+    throw new InvalidPropertyError('Invalid background value at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  return components;
+}
+
+function borderRadius(property, configuration) {
+  var values = property.value;
+  var splitAt = -1;
+
+  for (var i = 0, l = values.length; i < l; i++) {
+    if (values[i][1] == Marker.FORWARD_SLASH) {
+      splitAt = i;
+      break;
+    }
+  }
+
+  if (splitAt === 0 || splitAt === values.length - 1) {
+    throw new InvalidPropertyError('Invalid border-radius value at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  var target = _wrapDefault(property.name, property, configuration);
+  target.value = splitAt > -1
+    ? values.slice(0, splitAt)
+    : values.slice(0);
+  target.components = fourValues(target, configuration);
+
+  var remainder = _wrapDefault(property.name, property, configuration);
+  remainder.value = splitAt > -1
+    ? values.slice(splitAt + 1)
+    : values.slice(0);
+  remainder.components = fourValues(remainder, configuration);
+
+  for (var j = 0; j < 4; j++) {
+    target.components[j].multiplex = true;
+    target.components[j].value = target.components[j].value.concat(remainder.components[j].value);
+  }
+
+  return target.components;
+}
+
+function font(property, configuration, validator) {
+  var style = _wrapDefault('font-style', property, configuration);
+  var variant = _wrapDefault('font-variant', property, configuration);
+  var weight = _wrapDefault('font-weight', property, configuration);
+  var stretch = _wrapDefault('font-stretch', property, configuration);
+  var size = _wrapDefault('font-size', property, configuration);
+  var height = _wrapDefault('line-height', property, configuration);
+  var family = _wrapDefault('font-family', property, configuration);
+  var components = [style, variant, weight, stretch, size, height, family];
+  var values = property.value;
+  var fuzzyMatched = 4; // style, variant, weight, and stretch
+  var index = 0;
+  var isStretchSet = false;
+  var isStretchValid;
+  var isStyleSet = false;
+  var isStyleValid;
+  var isVariantSet = false;
+  var isVariantValid;
+  var isWeightSet = false;
+  var isWeightValid;
+  var appendableFamilyName = false;
+
+  if (!values[index]) {
+    throw new InvalidPropertyError('Missing font values at ' + formatPosition(property.all[property.position][1][2][0]) + '. Ignoring.');
+  }
+
+  if (values.length == 1 && values[0][1] == 'inherit') {
+    style.value = variant.value = weight.value = stretch.value = size.value = height.value = family.value = values;
+    return components;
+  }
+
+  if (values.length == 1
+    && (validator.isFontKeyword(values[0][1])
+    || validator.isGlobal(values[0][1])
+    || validator.isPrefixed(values[0][1]))
+  ) {
+    values[0][1] = Marker.INTERNAL + values[0][1];
+    style.value = variant.value = weight.value = stretch.value = size.value = height.value = family.value = values;
+    return components;
+  }
+
+  if (values.length < 2 || !_anyIsFontSize(values, validator) || !_anyIsFontFamily(values, validator)) {
+    throw new InvalidPropertyError('Invalid font values at ' + formatPosition(property.all[property.position][1][2][0]) + '. Ignoring.');
+  }
+
+  if (values.length > 1 && _anyIsInherit(values)) {
+    throw new InvalidPropertyError('Invalid font values at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  // fuzzy match style, variant, weight, and stretch on first elements
+  while (index < fuzzyMatched) {
+    isStretchValid = validator.isFontStretchKeyword(values[index][1]) || validator.isGlobal(values[index][1]);
+    isStyleValid = validator.isFontStyleKeyword(values[index][1]) || validator.isGlobal(values[index][1]);
+    isVariantValid = validator.isFontVariantKeyword(values[index][1]) || validator.isGlobal(values[index][1]);
+    isWeightValid = validator.isFontWeightKeyword(values[index][1]) || validator.isGlobal(values[index][1]);
+
+    if (isStyleValid && !isStyleSet) {
+      style.value = [values[index]];
+      isStyleSet = true;
+    } else if (isVariantValid && !isVariantSet) {
+      variant.value = [values[index]];
+      isVariantSet = true;
+    } else if (isWeightValid && !isWeightSet) {
+      weight.value = [values[index]];
+      isWeightSet = true;
+    } else if (isStretchValid && !isStretchSet) {
+      stretch.value = [values[index]];
+      isStretchSet = true;
+    } else if (isStyleValid
+      && isStyleSet
+      || isVariantValid
+      && isVariantSet
+      || isWeightValid
+      && isWeightSet
+      || isStretchValid
+      && isStretchSet) {
+      throw new InvalidPropertyError('Invalid font style / variant / weight / stretch value at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+    } else {
+      break;
+    }
+
+    index++;
+  }
+
+  // now comes font-size ...
+  if (validator.isFontSizeKeyword(values[index][1])
+    || validator.isUnit(values[index][1])
+    && !validator.isDynamicUnit(values[index][1])) {
+    size.value = [values[index]];
+    index++;
+  } else {
+    throw new InvalidPropertyError('Missing font size at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  if (!values[index]) {
+    throw new InvalidPropertyError('Missing font family at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  // ... and perhaps line-height
+  if (values[index]
+    && values[index][1] == Marker.FORWARD_SLASH
+    && values[index + 1]
+    && (validator.isLineHeightKeyword(values[index + 1][1])
+    || validator.isUnit(values[index + 1][1])
+    || validator.isNumber(values[index + 1][1]))) {
+    height.value = [values[index + 1]];
+    index++;
+    index++;
+  }
+
+  // ... and whatever comes next is font-family
+  family.value = [];
+
+  while (values[index]) {
+    if (values[index][1] == Marker.COMMA) {
+      appendableFamilyName = false;
+    } else {
+      if (appendableFamilyName) {
+        family.value[family.value.length - 1][1] += Marker.SPACE + values[index][1];
+      } else {
+        family.value.push(values[index]);
+      }
+
+      appendableFamilyName = true;
+    }
+
+    index++;
+  }
+
+  if (family.value.length === 0) {
+    throw new InvalidPropertyError('Missing font family at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  return components;
+}
+
+function _anyIsFontSize(values, validator) {
+  var value;
+  var i, l;
+
+  for (i = 0, l = values.length; i < l; i++) {
+    value = values[i];
+
+    if (validator.isFontSizeKeyword(value[1])
+      || validator.isUnit(value[1])
+      && !validator.isDynamicUnit(value[1])
+      || validator.isFunction(value[1])) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+function _anyIsFontFamily(values, validator) {
+  var value;
+  var i, l;
+
+  for (i = 0, l = values.length; i < l; i++) {
+    value = values[i];
+
+    if (validator.isIdentifier(value[1]) || validator.isQuotedText(value[1])) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+function fourValues(property, configuration) {
+  var componentNames = configuration[property.name].components;
+  var components = [];
+  var value = property.value;
+
+  if (value.length < 1) { return []; }
+
+  if (value.length < 2) { value[1] = value[0].slice(0); }
+  if (value.length < 3) { value[2] = value[0].slice(0); }
+  if (value.length < 4) { value[3] = value[1].slice(0); }
+
+  for (var i = componentNames.length - 1; i >= 0; i--) {
+    var component = wrapSingle([
+      Token.PROPERTY,
+      [Token.PROPERTY_NAME, componentNames[i]]
+    ]);
+    component.value = [value[i]];
+    components.unshift(component);
+  }
+
+  return components;
+}
+
+function multiplex(splitWith) {
+  return function(property, configuration, validator) {
+    var splitsAt = [];
+    var values = property.value;
+    var i, j, l, m;
+
+    // find split commas
+    for (i = 0, l = values.length; i < l; i++) {
+      if (values[i][1] == ',') { splitsAt.push(i); }
+    }
+
+    if (splitsAt.length === 0) { return splitWith(property, configuration, validator); }
+
+    var splitComponents = [];
+
+    // split over commas, and into components
+    for (i = 0, l = splitsAt.length; i <= l; i++) {
+      var from = i === 0 ? 0 : splitsAt[i - 1] + 1;
+      var to = i < l ? splitsAt[i] : values.length;
+
+      var _property = _wrapDefault(property.name, property, configuration);
+      _property.value = values.slice(from, to);
+
+      if (_property.value.length > 0) {
+        splitComponents.push(splitWith(_property, configuration, validator));
+      }
+    }
+
+    var components = splitComponents[0];
+
+    // group component values from each split
+    for (i = 0, l = components.length; i < l; i++) {
+      components[i].multiplex = true;
+
+      for (j = 1, m = splitComponents.length; j < m; j++) {
+        components[i].value.push([Token.PROPERTY_VALUE, Marker.COMMA]);
+        Array.prototype.push.apply(components[i].value, splitComponents[j][i].value);
+      }
+    }
+
+    return components;
+  };
+}
+
+function listStyle(property, configuration, validator) {
+  var type = _wrapDefault('list-style-type', property, configuration);
+  var position = _wrapDefault('list-style-position', property, configuration);
+  var image = _wrapDefault('list-style-image', property, configuration);
+  var components = [type, position, image];
+
+  if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+    type.value = position.value = image.value = [property.value[0]];
+    return components;
+  }
+
+  var values = property.value.slice(0);
+  var total = values.length;
+  var index = 0;
+
+  // `image` first...
+  for (index = 0, total = values.length; index < total; index++) {
+    if (validator.isUrl(values[index][1]) || values[index][1] == '0') {
+      image.value = [values[index]];
+      values.splice(index, 1);
+      break;
+    }
+  }
+
+  // ... then `position`
+  for (index = 0, total = values.length; index < total; index++) {
+    if (validator.isListStylePositionKeyword(values[index][1])) {
+      position.value = [values[index]];
+      values.splice(index, 1);
+      break;
+    }
+  }
+
+  // ... and what's left is a `type`
+  if (values.length > 0 && (validator.isListStyleTypeKeyword(values[0][1]) || validator.isIdentifier(values[0][1]))) {
+    type.value = [values[0]];
+  }
+
+  return components;
+}
+
+function transition(property, configuration, validator) {
+  var prop = _wrapDefault(property.name + '-property', property, configuration);
+  var duration = _wrapDefault(property.name + '-duration', property, configuration);
+  var timing = _wrapDefault(property.name + '-timing-function', property, configuration);
+  var delay = _wrapDefault(property.name + '-delay', property, configuration);
+  var components = [prop, duration, timing, delay];
+  var values = property.value;
+  var value;
+  var durationSet = false;
+  var delaySet = false;
+  var propSet = false;
+  var timingSet = false;
+  var i;
+  var l;
+
+  if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+    prop.value = duration.value = timing.value = delay.value = property.value;
+    return components;
+  }
+
+  if (values.length > 1 && _anyIsInherit(values)) {
+    throw new InvalidPropertyError('Invalid animation values at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+  }
+
+  for (i = 0, l = values.length; i < l; i++) {
+    value = values[i];
+
+    if (validator.isTime(value[1]) && !durationSet) {
+      duration.value = [value];
+      durationSet = true;
+    } else if (validator.isTime(value[1]) && !delaySet) {
+      delay.value = [value];
+      delaySet = true;
+    } else if ((validator.isGlobal(value[1]) || validator.isTimingFunction(value[1])) && !timingSet) {
+      timing.value = [value];
+      timingSet = true;
+    } else if (validator.isIdentifier(value[1]) && !propSet) {
+      prop.value = [value];
+      propSet = true;
+    } else {
+      throw new InvalidPropertyError('Invalid animation value at ' + formatPosition(value[2][0]) + '. Ignoring.');
+    }
+  }
+
+  return components;
+}
+
+function widthStyleColor(property, configuration, validator) {
+  var descriptor = configuration[property.name];
+  var components = [
+    _wrapDefault(descriptor.components[0], property, configuration),
+    _wrapDefault(descriptor.components[1], property, configuration),
+    _wrapDefault(descriptor.components[2], property, configuration)
+  ];
+  var color, style, width;
+
+  for (var i = 0; i < 3; i++) {
+    var component = components[i];
+
+    if (component.name.indexOf('color') > 0) { color = component; } else if (component.name.indexOf('style') > 0) { style = component; } else { width = component; }
+  }
+
+  if ((property.value.length == 1 && property.value[0][1] == 'inherit')
+      || (property.value.length == 3 && property.value[0][1] == 'inherit' && property.value[1][1] == 'inherit' && property.value[2][1] == 'inherit')) {
+    color.value = style.value = width.value = [property.value[0]];
+    return components;
+  }
+
+  var values = property.value.slice(0);
+  var match, matches;
+
+  // NOTE: usually users don't follow the required order of parts in this shorthand,
+  // so we'll try to parse it caring as little about order as possible
+
+  if (values.length > 0) {
+    matches = values.filter(_widthFilter(validator));
+    match = matches.length > 1 && (matches[0][1] == 'none' || matches[0][1] == 'auto') ? matches[1] : matches[0];
+    if (match) {
+      width.value = [match];
+      values.splice(values.indexOf(match), 1);
+    }
+  }
+
+  if (values.length > 0) {
+    match = values.filter(_styleFilter(validator))[0];
+    if (match) {
+      style.value = [match];
+      values.splice(values.indexOf(match), 1);
+    }
+  }
+
+  if (values.length > 0) {
+    match = values.filter(_colorFilter(validator))[0];
+    if (match) {
+      color.value = [match];
+      values.splice(values.indexOf(match), 1);
+    }
+  }
+
+  return components;
+}
+
+module.exports = {
+  animation: animation,
+  background: background,
+  border: widthStyleColor,
+  borderRadius: borderRadius,
+  font: font,
+  fourValues: fourValues,
+  listStyle: listStyle,
+  multiplex: multiplex,
+  outline: widthStyleColor,
+  transition: transition
+};

+ 314 - 0
node_modules/clean-css/lib/optimizer/configuration/can-override.js

@@ -0,0 +1,314 @@
+var understandable = require('./properties/understandable');
+
+function animationIterationCount(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isAnimationIterationCountKeyword(value2) || validator.isPositiveNumber(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  }
+
+  return validator.isAnimationIterationCountKeyword(value2) || validator.isPositiveNumber(value2);
+}
+
+function animationName(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isAnimationNameKeyword(value2) || validator.isIdentifier(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  }
+
+  return validator.isAnimationNameKeyword(value2) || validator.isIdentifier(value2);
+}
+
+function areSameFunction(validator, value1, value2) {
+  if (!validator.isFunction(value1) || !validator.isFunction(value2)) {
+    return false;
+  }
+
+  var function1Name = value1.substring(0, value1.indexOf('('));
+  var function2Name = value2.substring(0, value2.indexOf('('));
+
+  var function1Value = value1.substring(function1Name.length + 1, value1.length - 1);
+  var function2Value = value2.substring(function2Name.length + 1, value2.length - 1);
+
+  if (validator.isFunction(function1Value) || validator.isFunction(function2Value)) {
+    return function1Name === function2Name && areSameFunction(validator, function1Value, function2Value);
+  }
+  return function1Name === function2Name;
+}
+
+function backgroundPosition(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isBackgroundPositionKeyword(value2) || validator.isGlobal(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if (validator.isBackgroundPositionKeyword(value2) || validator.isGlobal(value2)) {
+    return true;
+  }
+
+  return unit(validator, value1, value2);
+}
+
+function backgroundSize(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isBackgroundSizeKeyword(value2) || validator.isGlobal(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if (validator.isBackgroundSizeKeyword(value2) || validator.isGlobal(value2)) {
+    return true;
+  }
+
+  return unit(validator, value1, value2);
+}
+
+function color(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true) && !validator.isColor(value2)) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if (!validator.colorOpacity && (validator.isRgbColor(value1) || validator.isHslColor(value1))) {
+    return false;
+  } if (!validator.colorOpacity && (validator.isRgbColor(value2) || validator.isHslColor(value2))) {
+    return false;
+  } if (!validator.colorHexAlpha && (validator.isHexAlphaColor(value1) || validator.isHexAlphaColor(value2))) {
+    return false;
+  } if (validator.isColor(value1) && validator.isColor(value2)) {
+    return true;
+  }
+
+  return sameFunctionOrValue(validator, value1, value2);
+}
+
+function components(overrideCheckers) {
+  return function(validator, value1, value2, position) {
+    return overrideCheckers[position](validator, value1, value2);
+  };
+}
+
+function fontFamily(validator, value1, value2) {
+  return understandable(validator, value1, value2, 0, true);
+}
+
+function image(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true) && !validator.isImage(value2)) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if (validator.isImage(value2)) {
+    return true;
+  } if (validator.isImage(value1)) {
+    return false;
+  }
+
+  return sameFunctionOrValue(validator, value1, value2);
+}
+
+function keyword(propertyName) {
+  return function(validator, value1, value2) {
+    if (!understandable(validator, value1, value2, 0, true) && !validator.isKeyword(propertyName)(value2)) {
+      return false;
+    } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+      return true;
+    }
+
+    return validator.isKeyword(propertyName)(value2);
+  };
+}
+
+function keywordWithGlobal(propertyName) {
+  return function(validator, value1, value2) {
+    if (!understandable(validator, value1, value2, 0, true)
+      && !(validator.isKeyword(propertyName)(value2) || validator.isGlobal(value2))) {
+      return false;
+    } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+      return true;
+    }
+
+    return validator.isKeyword(propertyName)(value2) || validator.isGlobal(value2);
+  };
+}
+
+function propertyName(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true) && !validator.isIdentifier(value2)) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  }
+
+  return validator.isIdentifier(value2);
+}
+
+function sameFunctionOrValue(validator, value1, value2) {
+  return areSameFunction(validator, value1, value2)
+    ? true
+    : value1 === value2;
+}
+
+function textShadow(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isUnit(value2)
+    || validator.isColor(value2)
+    || validator.isGlobal(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  }
+
+  return validator.isUnit(value2) || validator.isColor(value2) || validator.isGlobal(value2);
+}
+
+function time(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true) && !validator.isTime(value2)) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if (validator.isTime(value1) && !validator.isTime(value2)) {
+    return false;
+  } if (validator.isTime(value2)) {
+    return true;
+  } if (validator.isTime(value1)) {
+    return false;
+  } if (validator.isFunction(value1)
+    && !validator.isPrefixed(value1)
+    && validator.isFunction(value2)
+    && !validator.isPrefixed(value2)) {
+    return true;
+  }
+
+  return sameFunctionOrValue(validator, value1, value2);
+}
+
+function timingFunction(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isTimingFunction(value2) || validator.isGlobal(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  }
+
+  return validator.isTimingFunction(value2) || validator.isGlobal(value2);
+}
+
+function unit(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true) && !validator.isUnit(value2)) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if (validator.isUnit(value1) && !validator.isUnit(value2)) {
+    return false;
+  } if (validator.isUnit(value2)) {
+    return true;
+  } if (validator.isUnit(value1)) {
+    return false;
+  } if (validator.isFunction(value1)
+    && !validator.isPrefixed(value1)
+    && validator.isFunction(value2)
+    && !validator.isPrefixed(value2)) {
+    return true;
+  }
+
+  return sameFunctionOrValue(validator, value1, value2);
+}
+
+function unitOrKeywordWithGlobal(propertyName) {
+  var byKeyword = keywordWithGlobal(propertyName);
+
+  return function(validator, value1, value2) {
+    return unit(validator, value1, value2) || byKeyword(validator, value1, value2);
+  };
+}
+
+function unitOrNumber(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true)
+    && !(validator.isUnit(value2)
+    || validator.isNumber(value2))) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  } if ((validator.isUnit(value1)
+    || validator.isNumber(value1))
+    && !(validator.isUnit(value2)
+    || validator.isNumber(value2))) {
+    return false;
+  } if (validator.isUnit(value2) || validator.isNumber(value2)) {
+    return true;
+  } if (validator.isUnit(value1) || validator.isNumber(value1)) {
+    return false;
+  } if (validator.isFunction(value1)
+    && !validator.isPrefixed(value1)
+    && validator.isFunction(value2)
+    && !validator.isPrefixed(value2)) {
+    return true;
+  }
+
+  return sameFunctionOrValue(validator, value1, value2);
+}
+
+function zIndex(validator, value1, value2) {
+  if (!understandable(validator, value1, value2, 0, true) && !validator.isZIndex(value2)) {
+    return false;
+  } if (validator.isVariable(value1) && validator.isVariable(value2)) {
+    return true;
+  }
+
+  return validator.isZIndex(value2);
+}
+
+module.exports = {
+  generic: {
+    color: color,
+    components: components,
+    image: image,
+    propertyName: propertyName,
+    time: time,
+    timingFunction: timingFunction,
+    unit: unit,
+    unitOrNumber: unitOrNumber
+  },
+  property: {
+    animationDirection: keywordWithGlobal('animation-direction'),
+    animationFillMode: keyword('animation-fill-mode'),
+    animationIterationCount: animationIterationCount,
+    animationName: animationName,
+    animationPlayState: keywordWithGlobal('animation-play-state'),
+    backgroundAttachment: keyword('background-attachment'),
+    backgroundClip: keywordWithGlobal('background-clip'),
+    backgroundOrigin: keyword('background-origin'),
+    backgroundPosition: backgroundPosition,
+    backgroundRepeat: keyword('background-repeat'),
+    backgroundSize: backgroundSize,
+    bottom: unitOrKeywordWithGlobal('bottom'),
+    borderCollapse: keyword('border-collapse'),
+    borderStyle: keywordWithGlobal('*-style'),
+    clear: keywordWithGlobal('clear'),
+    cursor: keywordWithGlobal('cursor'),
+    display: keywordWithGlobal('display'),
+    float: keywordWithGlobal('float'),
+    left: unitOrKeywordWithGlobal('left'),
+    fontFamily: fontFamily,
+    fontStretch: keywordWithGlobal('font-stretch'),
+    fontStyle: keywordWithGlobal('font-style'),
+    fontVariant: keywordWithGlobal('font-variant'),
+    fontWeight: keywordWithGlobal('font-weight'),
+    listStyleType: keywordWithGlobal('list-style-type'),
+    listStylePosition: keywordWithGlobal('list-style-position'),
+    outlineStyle: keywordWithGlobal('*-style'),
+    overflow: keywordWithGlobal('overflow'),
+    position: keywordWithGlobal('position'),
+    right: unitOrKeywordWithGlobal('right'),
+    textAlign: keywordWithGlobal('text-align'),
+    textDecoration: keywordWithGlobal('text-decoration'),
+    textOverflow: keywordWithGlobal('text-overflow'),
+    textShadow: textShadow,
+    top: unitOrKeywordWithGlobal('top'),
+    transform: sameFunctionOrValue,
+    verticalAlign: unitOrKeywordWithGlobal('vertical-align'),
+    visibility: keywordWithGlobal('visibility'),
+    whiteSpace: keywordWithGlobal('white-space'),
+    zIndex: zIndex
+  }
+};

+ 15 - 0
node_modules/clean-css/lib/optimizer/configuration/properties/understandable.js

@@ -0,0 +1,15 @@
+var sameVendorPrefixes = require('../../vendor-prefixes').same;
+
+function understandable(validator, value1, value2, _position, isPaired) {
+  if (!sameVendorPrefixes(value1, value2)) {
+    return false;
+  }
+
+  if (isPaired && validator.isVariable(value1) !== validator.isVariable(value2)) {
+    return false;
+  }
+
+  return true;
+}
+
+module.exports = understandable;

+ 294 - 0
node_modules/clean-css/lib/optimizer/configuration/restore.js

@@ -0,0 +1,294 @@
+var shallowClone = require('../clone').shallow;
+
+var Token = require('../../tokenizer/token');
+var Marker = require('../../tokenizer/marker');
+
+function isInheritOnly(values) {
+  for (var i = 0, l = values.length; i < l; i++) {
+    var value = values[i][1];
+
+    if (value != 'inherit' && value != Marker.COMMA && value != Marker.FORWARD_SLASH) { return false; }
+  }
+
+  return true;
+}
+
+function background(property, configuration, lastInMultiplex) {
+  var components = property.components;
+  var restored = [];
+  var needsOne, needsBoth;
+
+  function restoreValue(component) {
+    Array.prototype.unshift.apply(restored, component.value);
+  }
+
+  function isDefaultValue(component) {
+    var descriptor = configuration[component.name];
+
+    if (descriptor.doubleValues && descriptor.defaultValue.length == 1) {
+      return component.value[0][1] == descriptor.defaultValue[0]
+        && (component.value[1]
+          ? component.value[1][1] == descriptor.defaultValue[0]
+          : true);
+    } if (descriptor.doubleValues && descriptor.defaultValue.length != 1) {
+      return component.value[0][1] == descriptor.defaultValue[0]
+      && ((component.value[1] ? component.value[1][1] : component.value[0][1])
+        == descriptor.defaultValue[1]);
+    }
+    return component.value[0][1] == descriptor.defaultValue;
+  }
+
+  for (var i = components.length - 1; i >= 0; i--) {
+    var component = components[i];
+    var isDefault = isDefaultValue(component);
+
+    if (component.name == 'background-clip') {
+      var originComponent = components[i - 1];
+      var isOriginDefault = isDefaultValue(originComponent);
+
+      needsOne = component.value[0][1] == originComponent.value[0][1];
+
+      needsBoth = !needsOne && (
+        (isOriginDefault && !isDefault)
+        || (!isOriginDefault && !isDefault)
+        || (!isOriginDefault && isDefault && component.value[0][1] != originComponent.value[0][1]));
+
+      if (needsOne) {
+        restoreValue(originComponent);
+      } else if (needsBoth) {
+        restoreValue(component);
+        restoreValue(originComponent);
+      }
+
+      i--;
+    } else if (component.name == 'background-size') {
+      var positionComponent = components[i - 1];
+      var isPositionDefault = isDefaultValue(positionComponent);
+
+      needsOne = !isPositionDefault && isDefault;
+
+      needsBoth = !needsOne
+        && (isPositionDefault && !isDefault || !isPositionDefault && !isDefault);
+
+      if (needsOne) {
+        restoreValue(positionComponent);
+      } else if (needsBoth) {
+        restoreValue(component);
+        restored.unshift([Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]);
+        restoreValue(positionComponent);
+      } else if (positionComponent.value.length == 1) {
+        restoreValue(positionComponent);
+      }
+
+      i--;
+    } else {
+      if (isDefault || configuration[component.name].multiplexLastOnly && !lastInMultiplex) { continue; }
+
+      restoreValue(component);
+    }
+  }
+
+  if (restored.length === 0 && property.value.length == 1 && property.value[0][1] == '0') { restored.push(property.value[0]); }
+
+  if (restored.length === 0) { restored.push([Token.PROPERTY_VALUE, configuration[property.name].defaultValue]); }
+
+  if (isInheritOnly(restored)) { return [restored[0]]; }
+
+  return restored;
+}
+
+function borderRadius(property) {
+  if (property.multiplex) {
+    var horizontal = shallowClone(property);
+    var vertical = shallowClone(property);
+
+    for (var i = 0; i < 4; i++) {
+      var component = property.components[i];
+
+      var horizontalComponent = shallowClone(property);
+      horizontalComponent.value = [component.value[0]];
+      horizontal.components.push(horizontalComponent);
+
+      var verticalComponent = shallowClone(property);
+      // FIXME: only shorthand compactor (see breakup#borderRadius) knows that border radius
+      // longhands have two values, whereas tokenizer does not care about populating 2nd value
+      // if it's missing, hence this fallback
+      verticalComponent.value = [component.value[1] || component.value[0]];
+      vertical.components.push(verticalComponent);
+    }
+
+    var horizontalValues = fourValues(horizontal);
+    var verticalValues = fourValues(vertical);
+
+    if (horizontalValues.length == verticalValues.length
+        && horizontalValues[0][1] == verticalValues[0][1]
+        && (horizontalValues.length > 1 ? horizontalValues[1][1] == verticalValues[1][1] : true)
+        && (horizontalValues.length > 2 ? horizontalValues[2][1] == verticalValues[2][1] : true)
+        && (horizontalValues.length > 3 ? horizontalValues[3][1] == verticalValues[3][1] : true)) {
+      return horizontalValues;
+    }
+    return horizontalValues.concat([[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]).concat(verticalValues);
+  }
+  return fourValues(property);
+}
+
+function font(property, configuration) {
+  var components = property.components;
+  var restored = [];
+  var component;
+  var componentIndex = 0;
+  var fontFamilyIndex = 0;
+
+  if (property.value[0][1].indexOf(Marker.INTERNAL) === 0) {
+    property.value[0][1] = property.value[0][1].substring(Marker.INTERNAL.length);
+    return property.value;
+  }
+
+  // first four components are optional
+  while (componentIndex < 4) {
+    component = components[componentIndex];
+
+    if (component.value[0][1] != configuration[component.name].defaultValue) {
+      Array.prototype.push.apply(restored, component.value);
+    }
+
+    componentIndex++;
+  }
+
+  // then comes font-size
+  Array.prototype.push.apply(restored, components[componentIndex].value);
+  componentIndex++;
+
+  // then may come line-height
+  if (components[componentIndex].value[0][1] != configuration[components[componentIndex].name].defaultValue) {
+    Array.prototype.push.apply(restored, [[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]);
+    Array.prototype.push.apply(restored, components[componentIndex].value);
+  }
+
+  componentIndex++;
+
+  // then comes font-family
+  while (components[componentIndex].value[fontFamilyIndex]) {
+    restored.push(components[componentIndex].value[fontFamilyIndex]);
+
+    if (components[componentIndex].value[fontFamilyIndex + 1]) {
+      restored.push([Token.PROPERTY_VALUE, Marker.COMMA]);
+    }
+
+    fontFamilyIndex++;
+  }
+
+  if (isInheritOnly(restored)) {
+    return [restored[0]];
+  }
+
+  return restored;
+}
+
+function fourValues(property) {
+  var components = property.components;
+  var value1 = components[0].value[0];
+  var value2 = components[1].value[0];
+  var value3 = components[2].value[0];
+  var value4 = components[3].value[0];
+
+  if (value1[1] == value2[1] && value1[1] == value3[1] && value1[1] == value4[1]) {
+    return [value1];
+  } if (value1[1] == value3[1] && value2[1] == value4[1]) {
+    return [value1, value2];
+  } if (value2[1] == value4[1]) {
+    return [value1, value2, value3];
+  }
+  return [value1, value2, value3, value4];
+}
+
+function multiplex(restoreWith) {
+  return function(property, configuration) {
+    if (!property.multiplex) { return restoreWith(property, configuration, true); }
+
+    var multiplexSize = 0;
+    var restored = [];
+    var componentMultiplexSoFar = {};
+    var i, l;
+
+    // At this point we don't know what's the multiplex size, e.g. how many background layers are there
+    for (i = 0, l = property.components[0].value.length; i < l; i++) {
+      if (property.components[0].value[i][1] == Marker.COMMA) { multiplexSize++; }
+    }
+
+    for (i = 0; i <= multiplexSize; i++) {
+      var _property = shallowClone(property);
+
+      // We split multiplex into parts and restore them one by one
+      for (var j = 0, m = property.components.length; j < m; j++) {
+        var componentToClone = property.components[j];
+        var _component = shallowClone(componentToClone);
+        _property.components.push(_component);
+
+        // The trick is some properties has more than one value, so we iterate over values looking for
+        // a multiplex separator - a comma
+        for (var k = componentMultiplexSoFar[_component.name] || 0, n = componentToClone.value.length; k < n; k++) {
+          if (componentToClone.value[k][1] == Marker.COMMA) {
+            componentMultiplexSoFar[_component.name] = k + 1;
+            break;
+          }
+
+          _component.value.push(componentToClone.value[k]);
+        }
+      }
+
+      // No we can restore shorthand value
+      var lastInMultiplex = i == multiplexSize;
+      var _restored = restoreWith(_property, configuration, lastInMultiplex);
+      Array.prototype.push.apply(restored, _restored);
+
+      if (i < multiplexSize) { restored.push([Token.PROPERTY_VALUE, Marker.COMMA]); }
+    }
+
+    return restored;
+  };
+}
+
+function withoutDefaults(property, configuration) {
+  var components = property.components;
+  var restored = [];
+
+  for (var i = components.length - 1; i >= 0; i--) {
+    var component = components[i];
+    var descriptor = configuration[component.name];
+
+    if (component.value[0][1] != descriptor.defaultValue || ('keepUnlessDefault' in descriptor) && !isDefault(components, configuration, descriptor.keepUnlessDefault)) {
+      restored.unshift(component.value[0]);
+    }
+  }
+
+  if (restored.length === 0) { restored.push([Token.PROPERTY_VALUE, configuration[property.name].defaultValue]); }
+
+  if (isInheritOnly(restored)) { return [restored[0]]; }
+
+  return restored;
+}
+
+function isDefault(components, configuration, propertyName) {
+  var component;
+  var i, l;
+
+  for (i = 0, l = components.length; i < l; i++) {
+    component = components[i];
+
+    if (component.name == propertyName && component.value[0][1] == configuration[propertyName].defaultValue) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+module.exports = {
+  background: background,
+  borderRadius: borderRadius,
+  font: font,
+  fourValues: fourValues,
+  multiplex: multiplex,
+  withoutDefaults: withoutDefaults
+};

+ 8 - 0
node_modules/clean-css/lib/optimizer/hack.js

@@ -0,0 +1,8 @@
+var Hack = {
+  ASTERISK: 'asterisk',
+  BANG: 'bang',
+  BACKSLASH: 'backslash',
+  UNDERSCORE: 'underscore'
+};
+
+module.exports = Hack;

+ 10 - 0
node_modules/clean-css/lib/optimizer/invalid-property-error.js

@@ -0,0 +1,10 @@
+function InvalidPropertyError(message) {
+  this.name = 'InvalidPropertyError';
+  this.message = message;
+  this.stack = (new Error()).stack;
+}
+
+InvalidPropertyError.prototype = Object.create(Error.prototype);
+InvalidPropertyError.prototype.constructor = InvalidPropertyError;
+
+module.exports = InvalidPropertyError;

+ 6 - 0
node_modules/clean-css/lib/optimizer/level-0/optimize.js

@@ -0,0 +1,6 @@
+function level0Optimize(tokens) {
+  // noop as level 0 means no optimizations!
+  return tokens;
+}
+
+module.exports = level0Optimize;

+ 325 - 0
node_modules/clean-css/lib/optimizer/level-1/optimize.js

@@ -0,0 +1,325 @@
+var sortSelectors = require('./sort-selectors');
+var tidyRules = require('./tidy-rules');
+var tidyBlock = require('./tidy-block');
+var tidyAtRule = require('./tidy-at-rule');
+
+var Hack = require('../hack');
+var removeUnused = require('../remove-unused');
+var restoreFromOptimizing = require('../restore-from-optimizing');
+var wrapForOptimizing = require('../wrap-for-optimizing').all;
+
+var configuration = require('../configuration');
+var optimizers = require('./value-optimizers');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var Token = require('../../tokenizer/token');
+var Marker = require('../../tokenizer/marker');
+
+var formatPosition = require('../../utils/format-position');
+
+var serializeRules = require('../../writer/one-time').rules;
+
+var CHARSET_TOKEN = '@charset';
+var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i');
+
+var DEFAULT_ROUNDING_PRECISION = require('../../options/rounding-precision').DEFAULT;
+
+var VARIABLE_PROPERTY_NAME_PATTERN = /^--\S+$/;
+var PROPERTY_NAME_PATTERN = /^(?:-chrome-|-[\w-]+\w|\w[\w-]+\w|\w{1,})$/;
+var IMPORT_PREFIX_PATTERN = /^@import/i;
+var URL_PREFIX_PATTERN = /^url\(/i;
+
+function startsAsUrl(value) {
+  return URL_PREFIX_PATTERN.test(value);
+}
+
+function isImport(token) {
+  return IMPORT_PREFIX_PATTERN.test(token[1]);
+}
+
+function isLegacyFilter(property) {
+  var value;
+
+  if (property.name == 'filter' || property.name == '-ms-filter') {
+    value = property.value[0][1];
+
+    return value.indexOf('progid') > -1
+      || value.indexOf('alpha') === 0
+      || value.indexOf('chroma') === 0;
+  }
+  return false;
+}
+
+function noop() {}
+
+function noopValueOptimizer(_name, value, _options) { return value; }
+
+function optimizeBody(rule, properties, context) {
+  var options = context.options;
+  var valueOptimizers;
+  var property, name, type, value;
+  var propertyToken;
+  var propertyOptimizer;
+  var serializedRule = serializeRules(rule);
+  var _properties = wrapForOptimizing(properties);
+  var pluginValueOptimizers = context.options.plugins.level1Value;
+  var pluginPropertyOptimizers = context.options.plugins.level1Property;
+  var isVariable;
+  var i, l;
+
+  for (i = 0, l = _properties.length; i < l; i++) {
+    var j, k, m, n;
+
+    property = _properties[i];
+    name = property.name;
+    propertyOptimizer = configuration[name] && configuration[name].propertyOptimizer || noop;
+    valueOptimizers = configuration[name] && configuration[name].valueOptimizers || [optimizers.whiteSpace];
+    isVariable = VARIABLE_PROPERTY_NAME_PATTERN.test(name);
+
+    if (isVariable) {
+      valueOptimizers = options.variableOptimizers.length > 0
+        ? options.variableOptimizers
+        : [optimizers.whiteSpace];
+    }
+
+    if (!isVariable && !PROPERTY_NAME_PATTERN.test(name)) {
+      propertyToken = property.all[property.position];
+      context.warnings.push('Invalid property name \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
+      property.unused = true;
+      continue;
+    }
+
+    if (property.value.length === 0) {
+      propertyToken = property.all[property.position];
+      context.warnings.push('Empty property \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
+      property.unused = true;
+      continue;
+    }
+
+    if (property.hack && (
+      (property.hack[0] == Hack.ASTERISK || property.hack[0] == Hack.UNDERSCORE)
+        && !options.compatibility.properties.iePrefixHack
+        || property.hack[0] == Hack.BACKSLASH && !options.compatibility.properties.ieSuffixHack
+        || property.hack[0] == Hack.BANG && !options.compatibility.properties.ieBangHack)) {
+      property.unused = true;
+      continue;
+    }
+
+    if (!options.compatibility.properties.ieFilters && isLegacyFilter(property)) {
+      property.unused = true;
+      continue;
+    }
+
+    if (property.block) {
+      optimizeBody(rule, property.value[0][1], context);
+      continue;
+    }
+
+    for (j = 0, m = property.value.length; j < m; j++) {
+      type = property.value[j][0];
+      value = property.value[j][1];
+
+      if (type == Token.PROPERTY_BLOCK) {
+        property.unused = true;
+        context.warnings.push('Invalid value token at ' + formatPosition(value[0][1][2][0]) + '. Ignoring.');
+        break;
+      }
+
+      if (startsAsUrl(value) && !context.validator.isUrl(value)) {
+        property.unused = true;
+        context.warnings.push('Broken URL \'' + value + '\' at ' + formatPosition(property.value[j][2][0]) + '. Ignoring.');
+        break;
+      }
+
+      for (k = 0, n = valueOptimizers.length; k < n; k++) {
+        value = valueOptimizers[k](name, value, options);
+      }
+
+      for (k = 0, n = pluginValueOptimizers.length; k < n; k++) {
+        value = pluginValueOptimizers[k](name, value, options);
+      }
+
+      property.value[j][1] = value;
+    }
+
+    propertyOptimizer(serializedRule, property, options);
+
+    for (j = 0, m = pluginPropertyOptimizers.length; j < m; j++) {
+      pluginPropertyOptimizers[j](serializedRule, property, options);
+    }
+  }
+
+  restoreFromOptimizing(_properties);
+  removeUnused(_properties);
+  removeComments(properties, options);
+}
+
+function removeComments(tokens, options) {
+  var token;
+  var i;
+
+  for (i = 0; i < tokens.length; i++) {
+    token = tokens[i];
+
+    if (token[0] != Token.COMMENT) {
+      continue;
+    }
+
+    optimizeComment(token, options);
+
+    if (token[1].length === 0) {
+      tokens.splice(i, 1);
+      i--;
+    }
+  }
+}
+
+function optimizeComment(token, options) {
+  if (token[1][2] == Marker.EXCLAMATION && (options.level[OptimizationLevel.One].specialComments == 'all' || options.commentsKept < options.level[OptimizationLevel.One].specialComments)) {
+    options.commentsKept++;
+    return;
+  }
+
+  token[1] = [];
+}
+
+function cleanupCharsets(tokens) {
+  var hasCharset = false;
+
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+
+    if (token[0] != Token.AT_RULE) { continue; }
+
+    if (!CHARSET_REGEXP.test(token[1])) { continue; }
+
+    if (hasCharset || token[1].indexOf(CHARSET_TOKEN) == -1) {
+      tokens.splice(i, 1);
+      i--;
+      l--;
+    } else {
+      hasCharset = true;
+      tokens.splice(i, 1);
+      tokens.unshift([Token.AT_RULE, token[1].replace(CHARSET_REGEXP, CHARSET_TOKEN)]);
+    }
+  }
+}
+
+function buildUnitRegexp(options) {
+  var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%'];
+  var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw'];
+
+  otherUnits.forEach(function(unit) {
+    if (options.compatibility.units[unit]) {
+      units.push(unit);
+    }
+  });
+
+  return new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g');
+}
+
+function buildPrecisionOptions(roundingPrecision) {
+  var precisionOptions = {
+    matcher: null,
+    units: {}
+  };
+  var optimizable = [];
+  var unit;
+  var value;
+
+  for (unit in roundingPrecision) {
+    value = roundingPrecision[unit];
+
+    if (value != DEFAULT_ROUNDING_PRECISION) {
+      precisionOptions.units[unit] = {};
+      precisionOptions.units[unit].value = value;
+      precisionOptions.units[unit].multiplier = 10 ** value;
+
+      optimizable.push(unit);
+    }
+  }
+
+  if (optimizable.length > 0) {
+    precisionOptions.enabled = true;
+    precisionOptions.decimalPointMatcher = new RegExp('(\\d)\\.($|' + optimizable.join('|') + ')($|\\W)', 'g');
+    precisionOptions.zeroMatcher = new RegExp('(\\d*)(\\.\\d+)(' + optimizable.join('|') + ')', 'g');
+  }
+
+  return precisionOptions;
+}
+
+function buildVariableOptimizers(options) {
+  return options.level[OptimizationLevel.One].variableValueOptimizers.map(function(optimizer) {
+    if (typeof (optimizer) == 'string') {
+      return optimizers[optimizer] || noopValueOptimizer;
+    }
+
+    return optimizer;
+  });
+}
+
+function level1Optimize(tokens, context) {
+  var options = context.options;
+  var levelOptions = options.level[OptimizationLevel.One];
+  var ie7Hack = options.compatibility.selectors.ie7Hack;
+  var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+  var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace;
+  var format = options.format;
+  var mayHaveCharset = false;
+  var afterRules = false;
+
+  options.unitsRegexp = options.unitsRegexp || buildUnitRegexp(options);
+  options.precision = options.precision || buildPrecisionOptions(levelOptions.roundingPrecision);
+  options.commentsKept = options.commentsKept || 0;
+  options.variableOptimizers = options.variableOptimizers || buildVariableOptimizers(options);
+
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+
+    switch (token[0]) {
+    case Token.AT_RULE:
+      token[1] = isImport(token) && afterRules ? '' : token[1];
+      token[1] = levelOptions.tidyAtRules ? tidyAtRule(token[1]) : token[1];
+      mayHaveCharset = true;
+      break;
+    case Token.AT_RULE_BLOCK:
+      optimizeBody(token[1], token[2], context);
+      afterRules = true;
+      break;
+    case Token.NESTED_BLOCK:
+      token[1] = levelOptions.tidyBlockScopes ? tidyBlock(token[1], spaceAfterClosingBrace) : token[1];
+      level1Optimize(token[2], context);
+      afterRules = true;
+      break;
+    case Token.COMMENT:
+      optimizeComment(token, options);
+      break;
+    case Token.RULE:
+      token[1] = levelOptions.tidySelectors
+        ? tidyRules(token[1], !ie7Hack, adjacentSpace, format, context.warnings)
+        : token[1];
+      token[1] = token[1].length > 1 ? sortSelectors(token[1], levelOptions.selectorsSortingMethod) : token[1];
+      optimizeBody(token[1], token[2], context);
+      afterRules = true;
+      break;
+    }
+
+    if (token[0] == Token.COMMENT
+      && token[1].length === 0
+      || levelOptions.removeEmpty
+      && (token[1].length === 0 || (token[2] && token[2].length === 0))) {
+      tokens.splice(i, 1);
+      i--;
+      l--;
+    }
+  }
+
+  if (levelOptions.cleanupCharsets && mayHaveCharset) {
+    cleanupCharsets(tokens);
+  }
+
+  return tokens;
+}
+
+module.exports = level1Optimize;

+ 10 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers.js

@@ -0,0 +1,10 @@
+module.exports = {
+  background: require('./property-optimizers/background').level1.property,
+  boxShadow: require('./property-optimizers/box-shadow').level1.property,
+  borderRadius: require('./property-optimizers/border-radius').level1.property,
+  filter: require('./property-optimizers/filter').level1.property,
+  fontWeight: require('./property-optimizers/font-weight').level1.property,
+  margin: require('./property-optimizers/margin').level1.property,
+  outline: require('./property-optimizers/outline').level1.property,
+  padding: require('./property-optimizers/padding').level1.property
+};

+ 23 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/background.js

@@ -0,0 +1,23 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var plugin = {
+  level1: {
+    property: function background(_rule, property, options) {
+      var values = property.value;
+
+      if (!options.level[OptimizationLevel.One].optimizeBackground) {
+        return;
+      }
+
+      if (values.length == 1 && values[0][1] == 'none') {
+        values[0][1] = '0 0';
+      }
+
+      if (values.length == 1 && values[0][1] == 'transparent') {
+        values[0][1] = '0 0';
+      }
+    }
+  }
+};
+
+module.exports = plugin;

+ 29 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/border-radius.js

@@ -0,0 +1,29 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var plugin = {
+  level1: {
+    property: function borderRadius(_rule, property, options) {
+      var values = property.value;
+
+      if (!options.level[OptimizationLevel.One].optimizeBorderRadius) {
+        return;
+      }
+
+      if (values.length == 3 && values[1][1] == '/' && values[0][1] == values[2][1]) {
+        property.value.splice(1);
+        property.dirty = true;
+      } else if (values.length == 5 && values[2][1] == '/' && values[0][1] == values[3][1] && values[1][1] == values[4][1]) {
+        property.value.splice(2);
+        property.dirty = true;
+      } else if (values.length == 7 && values[3][1] == '/' && values[0][1] == values[4][1] && values[1][1] == values[5][1] && values[2][1] == values[6][1]) {
+        property.value.splice(3);
+        property.dirty = true;
+      } else if (values.length == 9 && values[4][1] == '/' && values[0][1] == values[5][1] && values[1][1] == values[6][1] && values[2][1] == values[7][1] && values[3][1] == values[8][1]) {
+        property.value.splice(4);
+        property.dirty = true;
+      }
+    }
+  }
+};
+
+module.exports = plugin;

+ 15 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/box-shadow.js

@@ -0,0 +1,15 @@
+var plugin = {
+  level1: {
+    property: function boxShadow(_rule, property) {
+      var values = property.value;
+
+      // remove multiple zeros
+      if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') {
+        property.value.splice(2);
+        property.dirty = true;
+      }
+    }
+  }
+};
+
+module.exports = plugin;

+ 34 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/filter.js

@@ -0,0 +1,34 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var ALPHA_OR_CHROMA_FILTER_PATTERN = /progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/;
+var NO_SPACE_AFTER_COMMA_PATTERN = /,(\S)/g;
+var WHITESPACE_AROUND_EQUALS_PATTERN = / ?= ?/g;
+
+var plugin = {
+  level1: {
+    property: function filter(_rule, property, options) {
+      if (!options.compatibility.properties.ieFilters) {
+        return;
+      }
+
+      if (!options.level[OptimizationLevel.One].optimizeFilter) {
+        return;
+      }
+
+      if (property.value.length == 1) {
+        property.value[0][1] = property.value[0][1].replace(
+          ALPHA_OR_CHROMA_FILTER_PATTERN,
+          function(match, filter, suffix) {
+            return filter.toLowerCase() + suffix;
+          }
+        );
+      }
+
+      property.value[0][1] = property.value[0][1]
+        .replace(NO_SPACE_AFTER_COMMA_PATTERN, ', $1')
+        .replace(WHITESPACE_AROUND_EQUALS_PATTERN, '=');
+    }
+  }
+};
+
+module.exports = plugin;

+ 23 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/font-weight.js

@@ -0,0 +1,23 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var plugin = {
+  level1: {
+    property: function fontWeight(_rule, property, options) {
+      var value = property.value[0][1];
+
+      if (!options.level[OptimizationLevel.One].optimizeFontWeight) {
+        return;
+      }
+
+      if (value == 'normal') {
+        value = '400';
+      } else if (value == 'bold') {
+        value = '700';
+      }
+
+      property.value[0][1] = value;
+    }
+  }
+};
+
+module.exports = plugin;

+ 21 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/margin.js

@@ -0,0 +1,21 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var plugin = {
+  level1: {
+    property: function margin(_rule, property, options) {
+      var values = property.value;
+
+      if (!options.level[OptimizationLevel.One].replaceMultipleZeros) {
+        return;
+      }
+
+      // remove multiple zeros
+      if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') {
+        property.value.splice(1);
+        property.dirty = true;
+      }
+    }
+  }
+};
+
+module.exports = plugin;

+ 19 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/outline.js

@@ -0,0 +1,19 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var plugin = {
+  level1: {
+    property: function outline(_rule, property, options) {
+      var values = property.value;
+
+      if (!options.level[OptimizationLevel.One].optimizeOutline) {
+        return;
+      }
+
+      if (values.length == 1 && values[0][1] == 'none') {
+        values[0][1] = '0';
+      }
+    }
+  }
+};
+
+module.exports = plugin;

+ 32 - 0
node_modules/clean-css/lib/optimizer/level-1/property-optimizers/padding.js

@@ -0,0 +1,32 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+function isNegative(value) {
+  return value && value[1][0] == '-' && parseFloat(value[1]) < 0;
+}
+
+var plugin = {
+  level1: {
+    property: function padding(_rule, property, options) {
+      var values = property.value;
+
+      // remove multiple zeros
+      if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') {
+        property.value.splice(1);
+        property.dirty = true;
+      }
+
+      // remove negative paddings
+      if (options.level[OptimizationLevel.One].removeNegativePaddings
+        && (
+          isNegative(property.value[0])
+          || isNegative(property.value[1])
+          || isNegative(property.value[2])
+          || isNegative(property.value[3])
+        )) {
+        property.unused = true;
+      }
+    }
+  }
+};
+
+module.exports = plugin;

+ 23 - 0
node_modules/clean-css/lib/optimizer/level-1/sort-selectors.js

@@ -0,0 +1,23 @@
+var naturalCompare = require('../../utils/natural-compare');
+
+function naturalSorter(scope1, scope2) {
+  return naturalCompare(scope1[1], scope2[1]);
+}
+
+function standardSorter(scope1, scope2) {
+  return scope1[1] > scope2[1] ? 1 : -1;
+}
+
+function sortSelectors(selectors, method) {
+  switch (method) {
+  case 'natural':
+    return selectors.sort(naturalSorter);
+  case 'standard':
+    return selectors.sort(standardSorter);
+  case 'none':
+  case false:
+    return selectors;
+  }
+}
+
+module.exports = sortSelectors;

+ 9 - 0
node_modules/clean-css/lib/optimizer/level-1/tidy-at-rule.js

@@ -0,0 +1,9 @@
+function tidyAtRule(value) {
+  return value
+    .replace(/\s+/g, ' ')
+    .replace(/url\(\s+/g, 'url(')
+    .replace(/\s+\)/g, ')')
+    .trim();
+}
+
+module.exports = tidyAtRule;

+ 34 - 0
node_modules/clean-css/lib/optimizer/level-1/tidy-block.js

@@ -0,0 +1,34 @@
+var SUPPORTED_COMPACT_BLOCK_MATCHER = /^@media\W/;
+var SUPPORTED_QUOTE_REMOVAL_MATCHER = /^@(?:keyframes|-moz-keyframes|-o-keyframes|-webkit-keyframes)\W/;
+
+function tidyBlock(values, spaceAfterClosingBrace) {
+  var withoutSpaceAfterClosingBrace;
+  var withoutQuotes;
+  var i;
+
+  for (i = values.length - 1; i >= 0; i--) {
+    withoutSpaceAfterClosingBrace = !spaceAfterClosingBrace && SUPPORTED_COMPACT_BLOCK_MATCHER.test(values[i][1]);
+    withoutQuotes = SUPPORTED_QUOTE_REMOVAL_MATCHER.test(values[i][1]);
+
+    values[i][1] = values[i][1]
+      .replace(/\n|\r\n/g, ' ')
+      .replace(/\s+/g, ' ')
+      .replace(/(,|:|\() /g, '$1')
+      .replace(/ \)/g, ')');
+
+    if (withoutQuotes) {
+      values[i][1] = values[i][1]
+        .replace(/'([a-zA-Z][a-zA-Z\d\-_]+)'/, '$1')
+        .replace(/"([a-zA-Z][a-zA-Z\d\-_]+)"/, '$1');
+    }
+
+    if (withoutSpaceAfterClosingBrace) {
+      values[i][1] = values[i][1]
+        .replace(/\) /g, ')');
+    }
+  }
+
+  return values;
+}
+
+module.exports = tidyBlock;

+ 265 - 0
node_modules/clean-css/lib/optimizer/level-1/tidy-rules.js

@@ -0,0 +1,265 @@
+var Spaces = require('../../options/format').Spaces;
+var Marker = require('../../tokenizer/marker');
+var formatPosition = require('../../utils/format-position');
+
+var CASE_ATTRIBUTE_PATTERN = /[\s"'][iI]\s*\]/;
+var CASE_RESTORE_PATTERN = /([\d\w])([iI])\]/g;
+var DOUBLE_QUOTE_CASE_PATTERN = /="([a-zA-Z][a-zA-Z\d\-_]+)"([iI])/g;
+var DOUBLE_QUOTE_PATTERN = /="([a-zA-Z][a-zA-Z\d\-_]+)"(\s|\])/g;
+var HTML_COMMENT_PATTERN = /^(?:(?:<!--|-->)\s*)+/;
+var SINGLE_QUOTE_CASE_PATTERN = /='([a-zA-Z][a-zA-Z\d\-_]+)'([iI])/g;
+var SINGLE_QUOTE_PATTERN = /='([a-zA-Z][a-zA-Z\d\-_]+)'(\s|\])/g;
+var RELATION_PATTERN = /[>+~]/;
+var WHITESPACE_PATTERN = /\s/;
+
+var ASTERISK_PLUS_HTML_HACK = '*+html ';
+var ASTERISK_FIRST_CHILD_PLUS_HTML_HACK = '*:first-child+html ';
+var LESS_THAN = '<';
+
+var PSEUDO_CLASSES_WITH_SELECTORS = [
+  ':current',
+  ':future',
+  ':has',
+  ':host',
+  ':host-context',
+  ':is',
+  ':not',
+  ':past',
+  ':where'
+];
+
+function hasInvalidCharacters(value) {
+  var isEscaped;
+  var isInvalid = false;
+  var character;
+  var isQuote = false;
+  var i, l;
+
+  for (i = 0, l = value.length; i < l; i++) {
+    character = value[i];
+
+    if (isEscaped) {
+      // continue as always
+    } else if (character == Marker.SINGLE_QUOTE || character == Marker.DOUBLE_QUOTE) {
+      isQuote = !isQuote;
+    } else if (!isQuote
+      && (character == Marker.CLOSE_CURLY_BRACKET
+        || character == Marker.EXCLAMATION
+        || character == LESS_THAN
+        || character == Marker.SEMICOLON)
+    ) {
+      isInvalid = true;
+      break;
+    } else if (!isQuote && i === 0 && RELATION_PATTERN.test(character)) {
+      isInvalid = true;
+      break;
+    }
+
+    isEscaped = character == Marker.BACK_SLASH;
+  }
+
+  return isInvalid;
+}
+
+function removeWhitespace(value, format) {
+  var stripped = [];
+  var character;
+  var isNewLineNix;
+  var isNewLineWin;
+  var isEscaped;
+  var wasEscaped;
+  var isQuoted;
+  var isSingleQuoted;
+  var isDoubleQuoted;
+  var isAttribute;
+  var isRelation;
+  var isWhitespace;
+  var isSpaceAwarePseudoClass;
+  var roundBracketLevel = 0;
+  var wasComma = false;
+  var wasRelation = false;
+  var wasWhitespace = false;
+  var withCaseAttribute = CASE_ATTRIBUTE_PATTERN.test(value);
+  var spaceAroundRelation = format && format.spaces[Spaces.AroundSelectorRelation];
+  var i, l;
+
+  for (i = 0, l = value.length; i < l; i++) {
+    character = value[i];
+
+    isNewLineNix = character == Marker.NEW_LINE_NIX;
+    isNewLineWin = character == Marker.NEW_LINE_NIX && value[i - 1] == Marker.CARRIAGE_RETURN;
+    isQuoted = isSingleQuoted || isDoubleQuoted;
+    isRelation = !isAttribute && !isEscaped && roundBracketLevel === 0 && RELATION_PATTERN.test(character);
+    isWhitespace = WHITESPACE_PATTERN.test(character);
+    isSpaceAwarePseudoClass = roundBracketLevel == 1 && character == Marker.CLOSE_ROUND_BRACKET
+      ? false
+      : isSpaceAwarePseudoClass
+        || (roundBracketLevel === 0 && character == Marker.COLON && isPseudoClassWithSelectors(value, i));
+
+    if (wasEscaped && isQuoted && isNewLineWin) {
+      // swallow escaped new windows lines in comments
+      stripped.pop();
+      stripped.pop();
+    } else if (isEscaped && isQuoted && isNewLineNix) {
+      // swallow escaped new *nix lines in comments
+      stripped.pop();
+    } else if (isEscaped) {
+      stripped.push(character);
+    } else if (character == Marker.OPEN_SQUARE_BRACKET && !isQuoted) {
+      stripped.push(character);
+      isAttribute = true;
+    } else if (character == Marker.CLOSE_SQUARE_BRACKET && !isQuoted) {
+      stripped.push(character);
+      isAttribute = false;
+    } else if (character == Marker.OPEN_ROUND_BRACKET && !isQuoted) {
+      stripped.push(character);
+      roundBracketLevel++;
+    } else if (character == Marker.CLOSE_ROUND_BRACKET && !isQuoted) {
+      stripped.push(character);
+      roundBracketLevel--;
+    } else if (character == Marker.SINGLE_QUOTE && !isQuoted) {
+      stripped.push(character);
+      isSingleQuoted = true;
+    } else if (character == Marker.DOUBLE_QUOTE && !isQuoted) {
+      stripped.push(character);
+      isDoubleQuoted = true;
+    } else if (character == Marker.SINGLE_QUOTE && isQuoted) {
+      stripped.push(character);
+      isSingleQuoted = false;
+    } else if (character == Marker.DOUBLE_QUOTE && isQuoted) {
+      stripped.push(character);
+      isDoubleQuoted = false;
+    } else if (isWhitespace && wasRelation && !spaceAroundRelation) {
+      continue;
+    } else if (!isWhitespace && wasRelation && spaceAroundRelation) {
+      stripped.push(Marker.SPACE);
+      stripped.push(character);
+    } else if (isWhitespace && !wasWhitespace && wasComma && roundBracketLevel > 0 && isSpaceAwarePseudoClass) {
+      // skip space
+    } else if (isWhitespace && !wasWhitespace && roundBracketLevel > 0 && isSpaceAwarePseudoClass) {
+      stripped.push(character);
+    } else if (isWhitespace && (isAttribute || roundBracketLevel > 0) && !isQuoted) {
+      // skip space
+    } else if (isWhitespace && wasWhitespace && !isQuoted) {
+      // skip extra space
+    } else if ((isNewLineWin || isNewLineNix) && (isAttribute || roundBracketLevel > 0) && isQuoted) {
+      // skip newline
+    } else if (isRelation && wasWhitespace && !spaceAroundRelation) {
+      stripped.pop();
+      stripped.push(character);
+    } else if (isRelation && !wasWhitespace && spaceAroundRelation) {
+      stripped.push(Marker.SPACE);
+      stripped.push(character);
+    } else if (isWhitespace) {
+      stripped.push(Marker.SPACE);
+    } else {
+      stripped.push(character);
+    }
+
+    wasEscaped = isEscaped;
+    isEscaped = character == Marker.BACK_SLASH;
+    wasRelation = isRelation;
+    wasWhitespace = isWhitespace;
+    wasComma = character == Marker.COMMA;
+  }
+
+  return withCaseAttribute
+    ? stripped.join('').replace(CASE_RESTORE_PATTERN, '$1 $2]')
+    : stripped.join('');
+}
+
+function isPseudoClassWithSelectors(value, colonPosition) {
+  var pseudoClass = value.substring(colonPosition, value.indexOf(Marker.OPEN_ROUND_BRACKET, colonPosition));
+
+  return PSEUDO_CLASSES_WITH_SELECTORS.indexOf(pseudoClass) > -1;
+}
+
+function removeQuotes(value) {
+  if (value.indexOf('\'') == -1 && value.indexOf('"') == -1) {
+    return value;
+  }
+
+  return value
+    .replace(SINGLE_QUOTE_CASE_PATTERN, '=$1 $2')
+    .replace(SINGLE_QUOTE_PATTERN, '=$1$2')
+    .replace(DOUBLE_QUOTE_CASE_PATTERN, '=$1 $2')
+    .replace(DOUBLE_QUOTE_PATTERN, '=$1$2');
+}
+
+function replacePseudoClasses(value) {
+  return value
+    .replace('nth-child(1)', 'first-child')
+    .replace('nth-of-type(1)', 'first-of-type')
+    .replace('nth-of-type(even)', 'nth-of-type(2n)')
+    .replace('nth-child(even)', 'nth-child(2n)')
+    .replace('nth-of-type(2n+1)', 'nth-of-type(odd)')
+    .replace('nth-child(2n+1)', 'nth-child(odd)')
+    .replace('nth-last-child(1)', 'last-child')
+    .replace('nth-last-of-type(1)', 'last-of-type')
+    .replace('nth-last-of-type(even)', 'nth-last-of-type(2n)')
+    .replace('nth-last-child(even)', 'nth-last-child(2n)')
+    .replace('nth-last-of-type(2n+1)', 'nth-last-of-type(odd)')
+    .replace('nth-last-child(2n+1)', 'nth-last-child(odd)');
+}
+
+function tidyRules(rules, removeUnsupported, adjacentSpace, format, warnings) {
+  var list = [];
+  var repeated = [];
+
+  function removeHTMLComment(rule, match) {
+    warnings.push('HTML comment \'' + match + '\' at ' + formatPosition(rule[2][0]) + '. Removing.');
+    return '';
+  }
+
+  for (var i = 0, l = rules.length; i < l; i++) {
+    var rule = rules[i];
+    var reduced = rule[1];
+
+    reduced = reduced.replace(HTML_COMMENT_PATTERN, removeHTMLComment.bind(null, rule));
+
+    if (hasInvalidCharacters(reduced)) {
+      warnings.push('Invalid selector \'' + rule[1] + '\' at ' + formatPosition(rule[2][0]) + '. Ignoring.');
+      continue;
+    }
+
+    reduced = removeWhitespace(reduced, format);
+    reduced = removeQuotes(reduced);
+
+    if (adjacentSpace && reduced.indexOf('nav') > 0) {
+      reduced = reduced.replace(/\+nav(\S|$)/, '+ nav$1');
+    }
+
+    if (removeUnsupported && reduced.indexOf(ASTERISK_PLUS_HTML_HACK) > -1) {
+      continue;
+    }
+
+    if (removeUnsupported && reduced.indexOf(ASTERISK_FIRST_CHILD_PLUS_HTML_HACK) > -1) {
+      continue;
+    }
+
+    if (reduced.indexOf('*') > -1) {
+      reduced = reduced
+        .replace(/\*([:#.[])/g, '$1')
+        .replace(/^(:first-child)?\+html/, '*$1+html');
+    }
+
+    if (repeated.indexOf(reduced) > -1) {
+      continue;
+    }
+
+    reduced = replacePseudoClasses(reduced);
+
+    rule[1] = reduced;
+    repeated.push(reduced);
+    list.push(rule);
+  }
+
+  if (list.length == 1 && list[0][1].length === 0) {
+    warnings.push('Empty selector \'' + list[0][1] + '\' at ' + formatPosition(list[0][2][0]) + '. Ignoring.');
+    list = [];
+  }
+
+  return list;
+}
+
+module.exports = tidyRules;

+ 14 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers.js

@@ -0,0 +1,14 @@
+module.exports = {
+  color: require('./value-optimizers/color').level1.value,
+  degrees: require('./value-optimizers/degrees').level1.value,
+  fraction: require('./value-optimizers/fraction').level1.value,
+  precision: require('./value-optimizers/precision').level1.value,
+  textQuotes: require('./value-optimizers/text-quotes').level1.value,
+  time: require('./value-optimizers/time').level1.value,
+  unit: require('./value-optimizers/unit').level1.value,
+  urlPrefix: require('./value-optimizers/url-prefix').level1.value,
+  urlQuotes: require('./value-optimizers/url-quotes').level1.value,
+  urlWhiteSpace: require('./value-optimizers/url-whitespace').level1.value,
+  whiteSpace: require('./value-optimizers/whitespace').level1.value,
+  zero: require('./value-optimizers/zero').level1.value
+};

+ 89 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color.js

@@ -0,0 +1,89 @@
+var shortenHex = require('./color/shorten-hex');
+var shortenHsl = require('./color/shorten-hsl');
+var shortenRgb = require('./color/shorten-rgb');
+
+var split = require('../../../utils/split');
+
+var ANY_COLOR_FUNCTION_PATTERN = /(rgb|rgba|hsl|hsla)\(([^()]+)\)/gi;
+var COLOR_PREFIX_PATTERN = /#|rgb|hsl/gi;
+var HEX_LONG_PATTERN = /(^|[^='"])#([0-9a-f]{6})/gi;
+var HEX_SHORT_PATTERN = /(^|[^='"])#([0-9a-f]{3})/gi;
+var HEX_VALUE_PATTERN = /[0-9a-f]/i;
+var HSL_PATTERN = /hsl\((-?\d+),(-?\d+)%?,(-?\d+)%?\)/gi;
+var RGBA_HSLA_PATTERN = /(rgb|hsl)a?\((-?\d+),(-?\d+%?),(-?\d+%?),(0*[1-9]+[0-9]*(\.?\d*)?)\)/gi;
+var RGB_PATTERN = /rgb\((-?\d+),(-?\d+),(-?\d+)\)/gi;
+var TRANSPARENT_FUNCTION_PATTERN = /(?:rgba|hsla)\(0,0%?,0%?,0\)/g;
+
+var plugin = {
+  level1: {
+    value: function color(name, value, options) {
+      if (!options.compatibility.properties.colors) {
+        return value;
+      }
+
+      if (!value.match(COLOR_PREFIX_PATTERN)) {
+        return shortenHex(value);
+      }
+
+      value = value
+        .replace(RGBA_HSLA_PATTERN, function(match, colorFn, p1, p2, p3, alpha) {
+          return (parseInt(alpha) >= 1 ? colorFn + '(' + [p1, p2, p3].join(',') + ')' : match);
+        })
+        .replace(RGB_PATTERN, function(match, red, green, blue) {
+          return shortenRgb(red, green, blue);
+        })
+        .replace(HSL_PATTERN, function(match, hue, saturation, lightness) {
+          return shortenHsl(hue, saturation, lightness);
+        })
+        .replace(HEX_LONG_PATTERN, function(match, prefix, color, at, inputValue) {
+          var suffix = inputValue[at + match.length];
+
+          if (suffix && HEX_VALUE_PATTERN.test(suffix)) {
+            return match;
+          } if (color[0] == color[1] && color[2] == color[3] && color[4] == color[5]) {
+            return (prefix + '#' + color[0] + color[2] + color[4]).toLowerCase();
+          }
+          return (prefix + '#' + color).toLowerCase();
+        })
+        .replace(HEX_SHORT_PATTERN, function(match, prefix, color) {
+          return prefix + '#' + color.toLowerCase();
+        })
+        .replace(ANY_COLOR_FUNCTION_PATTERN, function(match, colorFunction, colorDef) {
+          var tokens = colorDef.split(',');
+          var colorFnLowercase = colorFunction && colorFunction.toLowerCase();
+          var applies = (colorFnLowercase == 'hsl' && tokens.length == 3)
+            || (colorFnLowercase == 'hsla' && tokens.length == 4)
+            || (colorFnLowercase == 'rgb' && tokens.length === 3 && colorDef.indexOf('%') > 0)
+            || (colorFnLowercase == 'rgba' && tokens.length == 4 && tokens[0].indexOf('%') > 0);
+
+          if (!applies) {
+            return match;
+          }
+
+          if (tokens[1].indexOf('%') == -1) {
+            tokens[1] += '%';
+          }
+
+          if (tokens[2].indexOf('%') == -1) {
+            tokens[2] += '%';
+          }
+
+          return colorFunction + '(' + tokens.join(',') + ')';
+        });
+
+      if (options.compatibility.colors.opacity && name.indexOf('background') == -1) {
+        value = value.replace(TRANSPARENT_FUNCTION_PATTERN, function(match) {
+          if (split(value, ',').pop().indexOf('gradient(') > -1) {
+            return match;
+          }
+
+          return 'transparent';
+        });
+      }
+
+      return shortenHex(value);
+    }
+  }
+};
+
+module.exports = plugin;

+ 189 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color/shorten-hex.js

@@ -0,0 +1,189 @@
+var COLORS = {
+  aliceblue: '#f0f8ff',
+  antiquewhite: '#faebd7',
+  aqua: '#0ff',
+  aquamarine: '#7fffd4',
+  azure: '#f0ffff',
+  beige: '#f5f5dc',
+  bisque: '#ffe4c4',
+  black: '#000',
+  blanchedalmond: '#ffebcd',
+  blue: '#00f',
+  blueviolet: '#8a2be2',
+  brown: '#a52a2a',
+  burlywood: '#deb887',
+  cadetblue: '#5f9ea0',
+  chartreuse: '#7fff00',
+  chocolate: '#d2691e',
+  coral: '#ff7f50',
+  cornflowerblue: '#6495ed',
+  cornsilk: '#fff8dc',
+  crimson: '#dc143c',
+  cyan: '#0ff',
+  darkblue: '#00008b',
+  darkcyan: '#008b8b',
+  darkgoldenrod: '#b8860b',
+  darkgray: '#a9a9a9',
+  darkgreen: '#006400',
+  darkgrey: '#a9a9a9',
+  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: '#f0f',
+  gainsboro: '#dcdcdc',
+  ghostwhite: '#f8f8ff',
+  gold: '#ffd700',
+  goldenrod: '#daa520',
+  gray: '#808080',
+  green: '#008000',
+  greenyellow: '#adff2f',
+  grey: '#808080',
+  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',
+  lightgreen: '#90ee90',
+  lightgrey: '#d3d3d3',
+  lightpink: '#ffb6c1',
+  lightsalmon: '#ffa07a',
+  lightseagreen: '#20b2aa',
+  lightskyblue: '#87cefa',
+  lightslategray: '#778899',
+  lightslategrey: '#778899',
+  lightsteelblue: '#b0c4de',
+  lightyellow: '#ffffe0',
+  lime: '#0f0',
+  limegreen: '#32cd32',
+  linen: '#faf0e6',
+  magenta: '#ff00ff',
+  maroon: '#800000',
+  mediumaquamarine: '#66cdaa',
+  mediumblue: '#0000cd',
+  mediumorchid: '#ba55d3',
+  mediumpurple: '#9370db',
+  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: '#db7093',
+  papayawhip: '#ffefd5',
+  peachpuff: '#ffdab9',
+  peru: '#cd853f',
+  pink: '#ffc0cb',
+  plum: '#dda0dd',
+  powderblue: '#b0e0e6',
+  purple: '#800080',
+  rebeccapurple: '#663399',
+  red: '#f00',
+  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',
+  turquoise: '#40e0d0',
+  violet: '#ee82ee',
+  wheat: '#f5deb3',
+  white: '#fff',
+  whitesmoke: '#f5f5f5',
+  yellow: '#ff0',
+  yellowgreen: '#9acd32'
+};
+
+var toHex = {};
+var toName = {};
+
+for (var name in COLORS) {
+  var hex = COLORS[name];
+
+  if (name.length < hex.length) {
+    toName[hex] = name;
+  } else {
+    toHex[name] = hex;
+  }
+}
+
+var toHexPattern = new RegExp('(^| |,|\\))(' + Object.keys(toHex).join('|') + ')( |,|\\)|$)', 'ig');
+var toNamePattern = new RegExp('(' + Object.keys(toName).join('|') + ')([^a-f0-9]|$)', 'ig');
+
+function hexConverter(match, prefix, colorValue, suffix) {
+  return prefix + toHex[colorValue.toLowerCase()] + suffix;
+}
+
+function nameConverter(match, colorValue, suffix) {
+  return toName[colorValue.toLowerCase()] + suffix;
+}
+
+function shortenHex(value) {
+  var hasHex = value.indexOf('#') > -1;
+  var shortened = value.replace(toHexPattern, hexConverter);
+
+  if (shortened != value) {
+    shortened = shortened.replace(toHexPattern, hexConverter);
+  }
+
+  return hasHex
+    ? shortened.replace(toNamePattern, nameConverter)
+    : shortened;
+}
+
+module.exports = shortenHex;

+ 54 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color/shorten-hsl.js

@@ -0,0 +1,54 @@
+// HSL to RGB converter. Both methods adapted from:
+// http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+
+function hslToRgb(h, s, l) {
+  var r, g, b;
+
+  // normalize hue orientation b/w 0 and 360 degrees
+  h %= 360;
+  if (h < 0) { h += 360; }
+  h = ~~h / 360;
+
+  if (s < 0) { s = 0; } else if (s > 100) { s = 100; }
+  s = ~~s / 100;
+
+  if (l < 0) { l = 0; } else if (l > 100) { l = 100; }
+  l = ~~l / 100;
+
+  if (s === 0) {
+    r = g = b = l; // achromatic
+  } else {
+    var q = l < 0.5
+      ? l * (1 + s)
+      : l + s - l * s;
+    var p = 2 * l - q;
+    r = hueToRgb(p, q, h + 1 / 3);
+    g = hueToRgb(p, q, h);
+    b = hueToRgb(p, q, h - 1 / 3);
+  }
+
+  return [~~(r * 255), ~~(g * 255), ~~(b * 255)];
+}
+
+function hueToRgb(p, q, t) {
+  if (t < 0) { t += 1; }
+  if (t > 1) { t -= 1; }
+  if (t < 1 / 6) { return p + (q - p) * 6 * t; }
+  if (t < 1 / 2) { return q; }
+  if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; }
+  return p;
+}
+
+function shortenHsl(hue, saturation, lightness) {
+  var asRgb = hslToRgb(hue, saturation, lightness);
+  var redAsHex = asRgb[0].toString(16);
+  var greenAsHex = asRgb[1].toString(16);
+  var blueAsHex = asRgb[2].toString(16);
+
+  return '#'
+    + ((redAsHex.length == 1 ? '0' : '') + redAsHex)
+    + ((greenAsHex.length == 1 ? '0' : '') + greenAsHex)
+    + ((blueAsHex.length == 1 ? '0' : '') + blueAsHex);
+}
+
+module.exports = shortenHsl;

+ 10 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/color/shorten-rgb.js

@@ -0,0 +1,10 @@
+function shortenRgb(red, green, blue) {
+  var normalizedRed = Math.max(0, Math.min(parseInt(red), 255));
+  var normalizedGreen = Math.max(0, Math.min(parseInt(green), 255));
+  var normalizedBlue = Math.max(0, Math.min(parseInt(blue), 255));
+
+  // Credit: Asen  http://jsbin.com/UPUmaGOc/2/edit?js,console
+  return '#' + ('00000' + (normalizedRed << 16 | normalizedGreen << 8 | normalizedBlue).toString(16)).slice(-6);
+}
+
+module.exports = shortenRgb;

+ 19 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/degrees.js

@@ -0,0 +1,19 @@
+var ZERO_DEG_PATTERN = /\(0deg\)/g;
+
+var plugin = {
+  level1: {
+    value: function degrees(_name, value, options) {
+      if (!options.compatibility.properties.zeroUnits) {
+        return value;
+      }
+
+      if (value.indexOf('0deg') == -1) {
+        return value;
+      }
+
+      return value.replace(ZERO_DEG_PATTERN, '(0)');
+    }
+  }
+};
+
+module.exports = plugin;

+ 72 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/fraction.js

@@ -0,0 +1,72 @@
+var split = require('../../../utils/split');
+var startsAsUrl = require('./starts-as-url');
+
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var EXPRESSION_PATTERN = /^expression\(.*\)$/;
+var ANY_FUNCTION_PATTERN = /^(-(?:moz|ms|o|webkit)-[a-z-]+|[a-z-]+)\((.+)\)$/;
+var TOKEN_SEPARATOR_PATTERN = /([\s,/])/;
+
+var DOT_ZERO_PATTERN = /(^|\D)\.0+(\D|$)/g;
+var FRACTION_PATTERN = /\.([1-9]*)0+(\D|$)/g;
+var LEADING_ZERO_FRACTION_PATTERN = /(^|\D)0\.(\d)/g;
+var MINUS_ZERO_FRACTION_PATTERN = /([^\w\d-]|^)-0([^.]|$)/g;
+var ZERO_PREFIXED_UNIT_PATTERN = /(^|\s)0+([1-9])/g;
+
+function optimizeRecursively(value) {
+  var functionTokens;
+  var tokens;
+
+  if (startsAsUrl(value)) {
+    return value;
+  }
+
+  if (EXPRESSION_PATTERN.test(value)) {
+    return value;
+  }
+
+  functionTokens = ANY_FUNCTION_PATTERN.exec(value);
+
+  if (!functionTokens) {
+    return optimizeFractions(value);
+  }
+
+  tokens = split(functionTokens[2], TOKEN_SEPARATOR_PATTERN)
+    .map(function(token) { return optimizeRecursively(token); });
+
+  return functionTokens[1] + '(' + tokens.join('') + ')';
+}
+
+function optimizeFractions(value) {
+  if (value.indexOf('0') == -1) {
+    return value;
+  }
+
+  if (value.indexOf('-') > -1) {
+    value = value
+      .replace(MINUS_ZERO_FRACTION_PATTERN, '$10$2')
+      .replace(MINUS_ZERO_FRACTION_PATTERN, '$10$2');
+  }
+
+  return value
+    .replace(ZERO_PREFIXED_UNIT_PATTERN, '$1$2')
+    .replace(DOT_ZERO_PATTERN, '$10$2')
+    .replace(FRACTION_PATTERN, function(match, nonZeroPart, suffix) {
+      return (nonZeroPart.length > 0 ? '.' : '') + nonZeroPart + suffix;
+    })
+    .replace(LEADING_ZERO_FRACTION_PATTERN, '$1.$2');
+}
+
+var plugin = {
+  level1: {
+    value: function fraction(name, value, options) {
+      if (!options.level[OptimizationLevel.One].replaceZeroUnits) {
+        return value;
+      }
+
+      return optimizeRecursively(value);
+    }
+  }
+};
+
+module.exports = plugin;

+ 22 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/precision.js

@@ -0,0 +1,22 @@
+var plugin = {
+  level1: {
+    value: function precision(_name, value, options) {
+      if (!options.precision.enabled || value.indexOf('.') === -1) {
+        return value;
+      }
+
+      return value
+        .replace(options.precision.decimalPointMatcher, '$1$2$3')
+        .replace(options.precision.zeroMatcher, function(match, integerPart, fractionPart, unit) {
+          var multiplier = options.precision.units[unit].multiplier;
+          var parsedInteger = parseInt(integerPart);
+          var integer = Number.isNaN(parsedInteger) ? 0 : parsedInteger;
+          var fraction = parseFloat(fractionPart);
+
+          return Math.round((integer + fraction) * multiplier) / multiplier + unit;
+        });
+    }
+  }
+};
+
+module.exports = plugin;

+ 7 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/starts-as-url.js

@@ -0,0 +1,7 @@
+var URL_PREFIX_PATTERN = /^url\(/i;
+
+function startsAsUrl(value) {
+  return URL_PREFIX_PATTERN.test(value);
+}
+
+module.exports = startsAsUrl;

+ 31 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/text-quotes.js

@@ -0,0 +1,31 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var LOCAL_PREFIX_PATTERN = /^local\(/i;
+var QUOTED_PATTERN = /^('.*'|".*")$/;
+var QUOTED_BUT_SAFE_PATTERN = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/;
+// eslint-disable-next-line max-len
+var GENERIC_FONT_FAMILY_PATTERN = /^['"](?:cursive|default|emoji|fangsong|fantasy|inherit|initial|math|monospace|revert|revert-layer|sans-serif|serif|system-ui|ui-monospace|ui-rounded|ui-sans-serif|ui-serif|unset)['"]$/;
+
+var plugin = {
+  level1: {
+    value: function textQuotes(name, value, options) {
+      if ((name == 'font-family' || name == 'font') && GENERIC_FONT_FAMILY_PATTERN.test(value)) {
+        return value;
+      }
+
+      if (!options.level[OptimizationLevel.One].removeQuotes) {
+        return value;
+      }
+
+      if (!QUOTED_PATTERN.test(value) && !LOCAL_PREFIX_PATTERN.test(value)) {
+        return value;
+      }
+
+      return QUOTED_BUT_SAFE_PATTERN.test(value)
+        ? value.substring(1, value.length - 1)
+        : value;
+    }
+  }
+};
+
+module.exports = plugin;

+ 31 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/time.js

@@ -0,0 +1,31 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var TIME_VALUE = /^(-?[\d.]+)(m?s)$/;
+
+var plugin = {
+  level1: {
+    value: function time(name, value, options) {
+      if (!options.level[OptimizationLevel.One].replaceTimeUnits) {
+        return value;
+      }
+
+      if (!TIME_VALUE.test(value)) {
+        return value;
+      }
+
+      return value.replace(TIME_VALUE, function(match, val, unit) {
+        var newValue;
+
+        if (unit == 'ms') {
+          newValue = parseInt(val) / 1000 + 's';
+        } else if (unit == 's') {
+          newValue = parseFloat(val) * 1000 + 'ms';
+        }
+
+        return newValue.length < match.length ? newValue : match;
+      });
+    }
+  }
+};
+
+module.exports = plugin;

+ 46 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/unit.js

@@ -0,0 +1,46 @@
+var WHOLE_PIXEL_VALUE = /(?:^|\s|\()(-?\d+)px/;
+
+var plugin = {
+  level1: {
+    value: function unit(_name, value, options) {
+      if (!WHOLE_PIXEL_VALUE.test(value)) {
+        return value;
+      }
+
+      return value.replace(WHOLE_PIXEL_VALUE, function(match, val) {
+        var newValue;
+        var intVal = parseInt(val);
+
+        if (intVal === 0) {
+          return match;
+        }
+
+        if (options.compatibility.properties.shorterLengthUnits
+          && options.compatibility.units.pt
+          && intVal * 3 % 4 === 0) {
+          newValue = intVal * 3 / 4 + 'pt';
+        }
+
+        if (options.compatibility.properties.shorterLengthUnits
+          && options.compatibility.units.pc
+          && intVal % 16 === 0) {
+          newValue = intVal / 16 + 'pc';
+        }
+
+        if (options.compatibility.properties.shorterLengthUnits
+          && options.compatibility.units.in
+          && intVal % 96 === 0) {
+          newValue = intVal / 96 + 'in';
+        }
+
+        if (newValue) {
+          newValue = match.substring(0, match.indexOf(val)) + newValue;
+        }
+
+        return newValue && newValue.length < match.length ? newValue : match;
+      });
+    }
+  }
+};
+
+module.exports = plugin;

+ 23 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/url-prefix.js

@@ -0,0 +1,23 @@
+var startsAsUrl = require('./starts-as-url');
+
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var URL_PREFIX_PATTERN = /^url\(/i;
+
+var plugin = {
+  level1: {
+    value: function urlPrefix(_name, value, options) {
+      if (!options.level[OptimizationLevel.One].normalizeUrls) {
+        return value;
+      }
+
+      if (!startsAsUrl(value)) {
+        return value;
+      }
+
+      return value.replace(URL_PREFIX_PATTERN, 'url(');
+    }
+  }
+};
+
+module.exports = plugin;

+ 22 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/url-quotes.js

@@ -0,0 +1,22 @@
+var QUOTED_URL_PATTERN = /^url\(['"].+['"]\)$/;
+var QUOTED_URL_WITH_WHITESPACE_PATTERN = /^url\(['"].*[*\s()'"].*['"]\)$/;
+var QUOTES_PATTERN = /["']/g;
+var URL_DATA_PATTERN = /^url\(['"]data:[^;]+;charset/;
+
+var plugin = {
+  level1: {
+    value: function urlQuotes(_name, value, options) {
+      if (options.compatibility.properties.urlQuotes) {
+        return value;
+      }
+
+      return QUOTED_URL_PATTERN.test(value)
+        && !QUOTED_URL_WITH_WHITESPACE_PATTERN.test(value)
+        && !URL_DATA_PATTERN.test(value)
+        ? value.replace(QUOTES_PATTERN, '')
+        : value;
+    }
+  }
+};
+
+module.exports = plugin;

+ 22 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/url-whitespace.js

@@ -0,0 +1,22 @@
+var startsAsUrl = require('./starts-as-url');
+
+var WHITESPACE_PATTERN = /\\?\n|\\?\r\n/g;
+var WHITESPACE_PREFIX_PATTERN = /(\()\s+/g;
+var WHITESPACE_SUFFIX_PATTERN = /\s+(\))/g;
+
+var plugin = {
+  level1: {
+    value: function urlWhitespace(_name, value) {
+      if (!startsAsUrl(value)) {
+        return value;
+      }
+
+      return value
+        .replace(WHITESPACE_PATTERN, '')
+        .replace(WHITESPACE_PREFIX_PATTERN, '$1')
+        .replace(WHITESPACE_SUFFIX_PATTERN, '$1');
+    }
+  }
+};
+
+module.exports = plugin;

+ 48 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/whitespace.js

@@ -0,0 +1,48 @@
+var OptimizationLevel = require('../../../options/optimization-level').OptimizationLevel;
+
+var Marker = require('../../../tokenizer/marker');
+
+var CALC_DIVISION_WHITESPACE_PATTERN = /\) ?\/ ?/g;
+var COMMA_AND_SPACE_PATTERN = /, /g;
+var LINE_BREAK_PATTERN = /\r?\n/g;
+var MULTI_WHITESPACE_PATTERN = /\s+/g;
+var FUNCTION_CLOSING_BRACE_WHITESPACE_PATTERN = /\s+(;?\))/g;
+var FUNCTION_OPENING_BRACE_WHITESPACE_PATTERN = /(\(;?)\s+/g;
+var VARIABLE_NAME_PATTERN = /^--\S+$/;
+var VARIABLE_VALUE_PATTERN = /^var\(\s*--\S+\s*\)$/;
+
+var plugin = {
+  level1: {
+    value: function whitespace(name, value, options) {
+      if (!options.level[OptimizationLevel.One].removeWhitespace) {
+        return value;
+      }
+
+      if (VARIABLE_NAME_PATTERN.test(name) && !VARIABLE_VALUE_PATTERN.test(value)) {
+        return value;
+      }
+
+      if ((value.indexOf(' ') == -1 && value.indexOf('\n') == -1) || value.indexOf('expression') === 0) {
+        return value;
+      }
+
+      if (value.indexOf(Marker.SINGLE_QUOTE) > -1 || value.indexOf(Marker.DOUBLE_QUOTE) > -1) {
+        return value;
+      }
+
+      value = value.replace(LINE_BREAK_PATTERN, '');
+      value = value.replace(MULTI_WHITESPACE_PATTERN, ' ');
+
+      if (value.indexOf('calc') > -1) {
+        value = value.replace(CALC_DIVISION_WHITESPACE_PATTERN, ')/ ');
+      }
+
+      return value
+        .replace(FUNCTION_OPENING_BRACE_WHITESPACE_PATTERN, '$1')
+        .replace(FUNCTION_CLOSING_BRACE_WHITESPACE_PATTERN, '$1')
+        .replace(COMMA_AND_SPACE_PATTERN, ',');
+    }
+  }
+};
+
+module.exports = plugin;

+ 49 - 0
node_modules/clean-css/lib/optimizer/level-1/value-optimizers/zero.js

@@ -0,0 +1,49 @@
+var split = require('../../../utils/split');
+
+var ANY_FUNCTION_PATTERN = /^(-(?:moz|ms|o|webkit)-[a-z-]+|[a-z-]+)\((.+)\)$/;
+var SKIP_FUNCTION_PATTERN = /^(?:-moz-calc|-webkit-calc|calc|rgb|hsl|rgba|hsla|min|max|clamp|expression)\(/;
+var TOKEN_SEPARATOR_PATTERN = /([\s,/])/;
+
+function removeRecursively(value, options) {
+  var functionTokens;
+  var tokens;
+
+  if (SKIP_FUNCTION_PATTERN.test(value)) {
+    return value;
+  }
+
+  functionTokens = ANY_FUNCTION_PATTERN.exec(value);
+
+  if (!functionTokens) {
+    return removeZeros(value, options);
+  }
+
+  tokens = split(functionTokens[2], TOKEN_SEPARATOR_PATTERN)
+    .map(function(token) { return removeRecursively(token, options); });
+
+  return functionTokens[1] + '(' + tokens.join('') + ')';
+}
+
+function removeZeros(value, options) {
+  return value
+    .replace(options.unitsRegexp, '$10$2')
+    .replace(options.unitsRegexp, '$10$2');
+}
+
+var plugin = {
+  level1: {
+    value: function zero(name, value, options) {
+      if (!options.compatibility.properties.zeroUnits) {
+        return value;
+      }
+
+      if (value.indexOf('%') > 0 && (name == 'height' || name == 'max-height' || name == 'width' || name == 'max-width')) {
+        return value;
+      }
+
+      return removeRecursively(value, options);
+    }
+  }
+};
+
+module.exports = plugin;

+ 61 - 0
node_modules/clean-css/lib/optimizer/level-2/extract-properties.js

@@ -0,0 +1,61 @@
+// This extractor is used in level 2 optimizations
+// IMPORTANT: Mind Token class and this code is not related!
+// Properties will be tokenized in one step, see #429
+
+var Token = require('../../tokenizer/token');
+var serializeRules = require('../../writer/one-time').rules;
+var serializeValue = require('../../writer/one-time').value;
+
+function extractProperties(token) {
+  var properties = [];
+  var inSpecificSelector;
+  var property;
+  var name;
+  var value;
+  var i, l;
+
+  if (token[0] == Token.RULE) {
+    inSpecificSelector = !/[.+>~]/.test(serializeRules(token[1]));
+
+    for (i = 0, l = token[2].length; i < l; i++) {
+      property = token[2][i];
+
+      if (property[0] != Token.PROPERTY) { continue; }
+
+      name = property[1][1];
+      if (name.length === 0) { continue; }
+
+      value = serializeValue(property, i);
+
+      properties.push([
+        name,
+        value,
+        findNameRoot(name),
+        token[2][i],
+        name + ':' + value,
+        token[1],
+        inSpecificSelector
+      ]);
+    }
+  } else if (token[0] == Token.NESTED_BLOCK) {
+    for (i = 0, l = token[2].length; i < l; i++) {
+      properties = properties.concat(extractProperties(token[2][i]));
+    }
+  }
+
+  return properties;
+}
+
+function findNameRoot(name) {
+  if (name == 'list-style') { return name; }
+  if (name.indexOf('-radius') > 0) { return 'border-radius'; }
+  if (name == 'border-collapse' || name == 'border-spacing' || name == 'border-image') { return name; }
+  if (name.indexOf('border-') === 0 && /^border-\w+-\w+$/.test(name)) { return name.match(/border-\w+/)[0]; }
+  if (name.indexOf('border-') === 0 && /^border-\w+$/.test(name)) { return 'border'; }
+  if (name.indexOf('text-') === 0) { return name; }
+  if (name == '-chrome-') { return name; }
+
+  return name.replace(/^-\w+-/, '').match(/([a-zA-Z]+)/)[0].toLowerCase();
+}
+
+module.exports = extractProperties;

+ 273 - 0
node_modules/clean-css/lib/optimizer/level-2/is-mergeable.js

@@ -0,0 +1,273 @@
+var Marker = require('../../tokenizer/marker');
+var split = require('../../utils/split');
+
+var DEEP_SELECTOR_PATTERN = /\/deep\//;
+var DOUBLE_COLON_PATTERN = /^::/;
+var VENDOR_PREFIXED_PATTERN = /:(-moz-|-ms-|-o-|-webkit-)/;
+
+var NOT_PSEUDO = ':not';
+var PSEUDO_CLASSES_WITH_ARGUMENTS = [
+  ':dir',
+  ':lang',
+  ':not',
+  ':nth-child',
+  ':nth-last-child',
+  ':nth-last-of-type',
+  ':nth-of-type'
+];
+var RELATION_PATTERN = /[>+~]/;
+var UNMIXABLE_PSEUDO_CLASSES = [
+  ':after',
+  ':before',
+  ':first-letter',
+  ':first-line',
+  ':lang'
+];
+var UNMIXABLE_PSEUDO_ELEMENTS = [
+  '::after',
+  '::before',
+  '::first-letter',
+  '::first-line'
+];
+
+var Level = {
+  DOUBLE_QUOTE: 'double-quote',
+  SINGLE_QUOTE: 'single-quote',
+  ROOT: 'root'
+};
+
+function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) {
+  var singleSelectors = split(selector, Marker.COMMA);
+  var singleSelector;
+  var i, l;
+
+  for (i = 0, l = singleSelectors.length; i < l; i++) {
+    singleSelector = singleSelectors[i];
+
+    if (singleSelector.length === 0
+        || isDeepSelector(singleSelector)
+        || isVendorPrefixed(singleSelector)
+        || (singleSelector.indexOf(Marker.COLON) > -1
+          && !areMergeable(
+            singleSelector,
+            extractPseudoFrom(singleSelector),
+            mergeablePseudoClasses,
+            mergeablePseudoElements,
+            multiplePseudoMerging
+          ))) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+function isDeepSelector(selector) {
+  return DEEP_SELECTOR_PATTERN.test(selector);
+}
+
+function isVendorPrefixed(selector) {
+  return VENDOR_PREFIXED_PATTERN.test(selector);
+}
+
+function extractPseudoFrom(selector) {
+  var list = [];
+  var character;
+  var buffer = [];
+  var level = Level.ROOT;
+  var roundBracketLevel = 0;
+  var isQuoted;
+  var isEscaped;
+  var isPseudo = false;
+  var isRelation;
+  var wasColon = false;
+  var index;
+  var len;
+
+  for (index = 0, len = selector.length; index < len; index++) {
+    character = selector[index];
+
+    isRelation = !isEscaped && RELATION_PATTERN.test(character);
+    isQuoted = level == Level.DOUBLE_QUOTE || level == Level.SINGLE_QUOTE;
+
+    if (isEscaped) {
+      buffer.push(character);
+    } else if (character == Marker.DOUBLE_QUOTE && level == Level.ROOT) {
+      buffer.push(character);
+      level = Level.DOUBLE_QUOTE;
+    } else if (character == Marker.DOUBLE_QUOTE && level == Level.DOUBLE_QUOTE) {
+      buffer.push(character);
+      level = Level.ROOT;
+    } else if (character == Marker.SINGLE_QUOTE && level == Level.ROOT) {
+      buffer.push(character);
+      level = Level.SINGLE_QUOTE;
+    } else if (character == Marker.SINGLE_QUOTE && level == Level.SINGLE_QUOTE) {
+      buffer.push(character);
+      level = Level.ROOT;
+    } else if (isQuoted) {
+      buffer.push(character);
+    } else if (character == Marker.OPEN_ROUND_BRACKET) {
+      buffer.push(character);
+      roundBracketLevel++;
+    } else if (character == Marker.CLOSE_ROUND_BRACKET && roundBracketLevel == 1 && isPseudo) {
+      buffer.push(character);
+      list.push(buffer.join(''));
+      roundBracketLevel--;
+      buffer = [];
+      isPseudo = false;
+    } else if (character == Marker.CLOSE_ROUND_BRACKET) {
+      buffer.push(character);
+      roundBracketLevel--;
+    } else if (character == Marker.COLON && roundBracketLevel === 0 && isPseudo && !wasColon) {
+      list.push(buffer.join(''));
+      buffer = [];
+      buffer.push(character);
+    } else if (character == Marker.COLON && roundBracketLevel === 0 && !wasColon) {
+      buffer = [];
+      buffer.push(character);
+      isPseudo = true;
+    } else if (character == Marker.SPACE && roundBracketLevel === 0 && isPseudo) {
+      list.push(buffer.join(''));
+      buffer = [];
+      isPseudo = false;
+    } else if (isRelation && roundBracketLevel === 0 && isPseudo) {
+      list.push(buffer.join(''));
+      buffer = [];
+      isPseudo = false;
+    } else {
+      buffer.push(character);
+    }
+
+    isEscaped = character == Marker.BACK_SLASH;
+    wasColon = character == Marker.COLON;
+  }
+
+  if (buffer.length > 0 && isPseudo) {
+    list.push(buffer.join(''));
+  }
+
+  return list;
+}
+
+function areMergeable(selector, matches, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) {
+  return areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements)
+    && needArguments(matches)
+    && (matches.length < 2 || !someIncorrectlyChained(selector, matches))
+    && (matches.length < 2 || multiplePseudoMerging && allMixable(matches));
+}
+
+function areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) {
+  var match;
+  var name;
+  var i, l;
+
+  for (i = 0, l = matches.length; i < l; i++) {
+    match = matches[i];
+    name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1
+      ? match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET))
+      : match;
+
+    if (mergeablePseudoClasses.indexOf(name) === -1 && mergeablePseudoElements.indexOf(name) === -1) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+function needArguments(matches) {
+  var match;
+  var name;
+  var bracketOpensAt;
+  var hasArguments;
+  var i, l;
+
+  for (i = 0, l = matches.length; i < l; i++) {
+    match = matches[i];
+
+    bracketOpensAt = match.indexOf(Marker.OPEN_ROUND_BRACKET);
+    hasArguments = bracketOpensAt > -1;
+    name = hasArguments
+      ? match.substring(0, bracketOpensAt)
+      : match;
+
+    if (hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) == -1) {
+      return false;
+    }
+
+    if (!hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) > -1) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+function someIncorrectlyChained(selector, matches) {
+  var positionInSelector = 0;
+  var match;
+  var matchAt;
+  var nextMatch;
+  var nextMatchAt;
+  var name;
+  var nextName;
+  var areChained;
+  var i, l;
+
+  for (i = 0, l = matches.length; i < l; i++) {
+    match = matches[i];
+    nextMatch = matches[i + 1];
+
+    if (!nextMatch) {
+      break;
+    }
+
+    matchAt = selector.indexOf(match, positionInSelector);
+    nextMatchAt = selector.indexOf(match, matchAt + 1);
+    positionInSelector = nextMatchAt;
+    areChained = matchAt + match.length == nextMatchAt;
+
+    if (areChained) {
+      name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1
+        ? match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET))
+        : match;
+      nextName = nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET) > -1
+        ? nextMatch.substring(0, nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET))
+        : nextMatch;
+
+      if (name != NOT_PSEUDO || nextName != NOT_PSEUDO) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+function allMixable(matches) {
+  var unmixableMatches = 0;
+  var match;
+  var i, l;
+
+  for (i = 0, l = matches.length; i < l; i++) {
+    match = matches[i];
+
+    if (isPseudoElement(match)) {
+      unmixableMatches += UNMIXABLE_PSEUDO_ELEMENTS.indexOf(match) > -1 ? 1 : 0;
+    } else {
+      unmixableMatches += UNMIXABLE_PSEUDO_CLASSES.indexOf(match) > -1 ? 1 : 0;
+    }
+
+    if (unmixableMatches > 1) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+function isPseudoElement(pseudo) {
+  return DOUBLE_COLON_PATTERN.test(pseudo);
+}
+
+module.exports = isMergeable;

+ 55 - 0
node_modules/clean-css/lib/optimizer/level-2/merge-adjacent.js

@@ -0,0 +1,55 @@
+var isMergeable = require('./is-mergeable');
+
+var optimizeProperties = require('./properties/optimize');
+
+var sortSelectors = require('../level-1/sort-selectors');
+var tidyRules = require('../level-1/tidy-rules');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+var Token = require('../../tokenizer/token');
+
+function mergeAdjacent(tokens, context) {
+  var lastToken = [null, [], []];
+  var options = context.options;
+  var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+  var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
+  var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+  var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+  var mergeLimit = options.compatibility.selectors.mergeLimit;
+  var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging;
+
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+
+    if (token[0] != Token.RULE) {
+      lastToken = [null, [], []];
+      continue;
+    }
+
+    if (lastToken[0] == Token.RULE && serializeRules(token[1]) == serializeRules(lastToken[1])) {
+      Array.prototype.push.apply(lastToken[2], token[2]);
+      optimizeProperties(lastToken[2], true, true, context);
+      token[2] = [];
+    } else if (lastToken[0] == Token.RULE && serializeBody(token[2]) == serializeBody(lastToken[2])
+        && isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging)
+        && isMergeable(
+          serializeRules(lastToken[1]),
+          mergeablePseudoClasses,
+          mergeablePseudoElements,
+          multiplePseudoMerging
+        )
+        && lastToken[1].length < mergeLimit) {
+      lastToken[1] = tidyRules(lastToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
+      lastToken[1] = lastToken.length > 1 ? sortSelectors(lastToken[1], selectorsSortingMethod) : lastToken[1];
+      token[2] = [];
+    } else {
+      lastToken = token;
+    }
+  }
+}
+
+module.exports = mergeAdjacent;

+ 105 - 0
node_modules/clean-css/lib/optimizer/level-2/merge-media-queries.js

@@ -0,0 +1,105 @@
+var canReorder = require('./reorderable').canReorder;
+var canReorderSingle = require('./reorderable').canReorderSingle;
+var extractProperties = require('./extract-properties');
+var rulesOverlap = require('./rules-overlap');
+
+var serializeRules = require('../../writer/one-time').rules;
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+var Token = require('../../tokenizer/token');
+
+function mergeMediaQueries(tokens, context) {
+  var mergeSemantically = context.options.level[OptimizationLevel.Two].mergeSemantically;
+  var specificityCache = context.cache.specificity;
+  var candidates = {};
+  var reduced = [];
+
+  for (var i = tokens.length - 1; i >= 0; i--) {
+    var token = tokens[i];
+    if (token[0] != Token.NESTED_BLOCK) {
+      continue;
+    }
+
+    var key = serializeRules(token[1]);
+    var candidate = candidates[key];
+    if (!candidate) {
+      candidate = [];
+      candidates[key] = candidate;
+    }
+
+    candidate.push(i);
+  }
+
+  for (var name in candidates) {
+    var positions = candidates[name];
+
+    positionLoop:
+    for (var j = positions.length - 1; j > 0; j--) {
+      var positionOne = positions[j];
+      var tokenOne = tokens[positionOne];
+      var positionTwo = positions[j - 1];
+      var tokenTwo = tokens[positionTwo];
+
+      directionLoop:
+      for (var direction = 1; direction >= -1; direction -= 2) {
+        var topToBottom = direction == 1;
+        var from = topToBottom ? positionOne + 1 : positionTwo - 1;
+        var to = topToBottom ? positionTwo : positionOne;
+        var delta = topToBottom ? 1 : -1;
+        var source = topToBottom ? tokenOne : tokenTwo;
+        var target = topToBottom ? tokenTwo : tokenOne;
+        var movedProperties = extractProperties(source);
+
+        while (from != to) {
+          var traversedProperties = extractProperties(tokens[from]);
+          from += delta;
+
+          if (mergeSemantically
+            && allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache)
+          ) {
+            continue;
+          }
+
+          if (!canReorder(movedProperties, traversedProperties, specificityCache)) { continue directionLoop; }
+        }
+
+        target[2] = topToBottom
+          ? source[2].concat(target[2])
+          : target[2].concat(source[2]);
+        source[2] = [];
+
+        reduced.push(target);
+        continue positionLoop;
+      }
+    }
+  }
+
+  return reduced;
+}
+
+function allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache) {
+  var movedProperty;
+  var movedRule;
+  var traversedProperty;
+  var traversedRule;
+  var i, l;
+  var j, m;
+
+  for (i = 0, l = movedProperties.length; i < l; i++) {
+    movedProperty = movedProperties[i];
+    movedRule = movedProperty[5];
+
+    for (j = 0, m = traversedProperties.length; j < m; j++) {
+      traversedProperty = traversedProperties[j];
+      traversedRule = traversedProperty[5];
+
+      if (rulesOverlap(movedRule, traversedRule, true)
+        && !canReorderSingle(movedProperty, traversedProperty, specificityCache)) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+module.exports = mergeMediaQueries;

+ 88 - 0
node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js

@@ -0,0 +1,88 @@
+var isMergeable = require('./is-mergeable');
+
+var sortSelectors = require('../level-1/sort-selectors');
+var tidyRules = require('../level-1/tidy-rules');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var serializeBody = require('../../writer/one-time').body;
+var serializeRules = require('../../writer/one-time').rules;
+
+var Token = require('../../tokenizer/token');
+
+function unsafeSelector(value) {
+  return /\.|\*| :/.test(value);
+}
+
+function isBemElement(token) {
+  var asString = serializeRules(token[1]);
+  return asString.indexOf('__') > -1 || asString.indexOf('--') > -1;
+}
+
+function withoutModifier(selector) {
+  return selector.replace(/--[^ ,>+~:]+/g, '');
+}
+
+function removeAnyUnsafeElements(left, candidates) {
+  var leftSelector = withoutModifier(serializeRules(left[1]));
+
+  for (var body in candidates) {
+    var right = candidates[body];
+    var rightSelector = withoutModifier(serializeRules(right[1]));
+
+    if (rightSelector.indexOf(leftSelector) > -1 || leftSelector.indexOf(rightSelector) > -1) {
+      delete candidates[body];
+    }
+  }
+}
+
+function mergeNonAdjacentByBody(tokens, context) {
+  var options = context.options;
+  var mergeSemantically = options.level[OptimizationLevel.Two].mergeSemantically;
+  var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+  var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
+  var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
+  var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
+  var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging;
+  var candidates = {};
+
+  for (var i = tokens.length - 1; i >= 0; i--) {
+    var token = tokens[i];
+    if (token[0] != Token.RULE) { continue; }
+
+    if (token[2].length > 0 && (!mergeSemantically && unsafeSelector(serializeRules(token[1])))) { candidates = {}; }
+
+    if (token[2].length > 0 && mergeSemantically && isBemElement(token)) { removeAnyUnsafeElements(token, candidates); }
+
+    var candidateBody = serializeBody(token[2]);
+    var oldToken = candidates[candidateBody];
+    if (oldToken
+        && isMergeable(
+          serializeRules(token[1]),
+          mergeablePseudoClasses,
+          mergeablePseudoElements,
+          multiplePseudoMerging
+        )
+        && isMergeable(
+          serializeRules(oldToken[1]),
+          mergeablePseudoClasses,
+          mergeablePseudoElements,
+          multiplePseudoMerging
+        )
+    ) {
+      if (token[2].length > 0) {
+        token[1] = tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
+        token[1] = token[1].length > 1 ? sortSelectors(token[1], selectorsSortingMethod) : token[1];
+      } else {
+        token[1] = oldToken[1].concat(token[1]);
+      }
+
+      oldToken[2] = [];
+      candidates[candidateBody] = null;
+    }
+
+    candidates[serializeBody(token[2])] = token;
+  }
+}
+
+module.exports = mergeNonAdjacentByBody;

+ 73 - 0
node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-selector.js

@@ -0,0 +1,73 @@
+var canReorder = require('./reorderable').canReorder;
+var extractProperties = require('./extract-properties');
+
+var optimizeProperties = require('./properties/optimize');
+
+var serializeRules = require('../../writer/one-time').rules;
+
+var Token = require('../../tokenizer/token');
+
+function mergeNonAdjacentBySelector(tokens, context) {
+  var specificityCache = context.cache.specificity;
+  var allSelectors = {};
+  var repeatedSelectors = [];
+  var i;
+
+  for (i = tokens.length - 1; i >= 0; i--) {
+    if (tokens[i][0] != Token.RULE) { continue; }
+    if (tokens[i][2].length === 0) { continue; }
+
+    var selector = serializeRules(tokens[i][1]);
+    allSelectors[selector] = [i].concat(allSelectors[selector] || []);
+
+    if (allSelectors[selector].length == 2) { repeatedSelectors.push(selector); }
+  }
+
+  for (i = repeatedSelectors.length - 1; i >= 0; i--) {
+    var positions = allSelectors[repeatedSelectors[i]];
+
+    selectorIterator:
+    for (var j = positions.length - 1; j > 0; j--) {
+      var positionOne = positions[j - 1];
+      var tokenOne = tokens[positionOne];
+      var positionTwo = positions[j];
+      var tokenTwo = tokens[positionTwo];
+
+      directionIterator:
+      for (var direction = 1; direction >= -1; direction -= 2) {
+        var topToBottom = direction == 1;
+        var from = topToBottom ? positionOne + 1 : positionTwo - 1;
+        var to = topToBottom ? positionTwo : positionOne;
+        var delta = topToBottom ? 1 : -1;
+        var moved = topToBottom ? tokenOne : tokenTwo;
+        var target = topToBottom ? tokenTwo : tokenOne;
+        var movedProperties = extractProperties(moved);
+
+        while (from != to) {
+          var traversedProperties = extractProperties(tokens[from]);
+          from += delta;
+
+          // traversed then moved as we move selectors towards the start
+          var reorderable = topToBottom
+            ? canReorder(movedProperties, traversedProperties, specificityCache)
+            : canReorder(traversedProperties, movedProperties, specificityCache);
+
+          if (!reorderable && !topToBottom) { continue selectorIterator; }
+          if (!reorderable && topToBottom) { continue directionIterator; }
+        }
+
+        if (topToBottom) {
+          Array.prototype.push.apply(moved[2], target[2]);
+          target[2] = moved[2];
+        } else {
+          Array.prototype.push.apply(target[2], moved[2]);
+        }
+
+        optimizeProperties(target[2], true, true, context);
+        moved[2] = [];
+      }
+    }
+  }
+}
+
+module.exports = mergeNonAdjacentBySelector;

+ 139 - 0
node_modules/clean-css/lib/optimizer/level-2/optimize.js

@@ -0,0 +1,139 @@
+var mergeAdjacent = require('./merge-adjacent');
+var mergeMediaQueries = require('./merge-media-queries');
+var mergeNonAdjacentByBody = require('./merge-non-adjacent-by-body');
+var mergeNonAdjacentBySelector = require('./merge-non-adjacent-by-selector');
+var reduceNonAdjacent = require('./reduce-non-adjacent');
+var removeDuplicateFontAtRules = require('./remove-duplicate-font-at-rules');
+var removeDuplicateMediaQueries = require('./remove-duplicate-media-queries');
+var removeDuplicates = require('./remove-duplicates');
+var removeUnusedAtRules = require('./remove-unused-at-rules');
+var restructure = require('./restructure');
+
+var optimizeProperties = require('./properties/optimize');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var Token = require('../../tokenizer/token');
+
+function removeEmpty(tokens) {
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+    var isEmpty = false;
+
+    switch (token[0]) {
+    case Token.RULE:
+      isEmpty = token[1].length === 0 || token[2].length === 0;
+      break;
+    case Token.NESTED_BLOCK:
+      removeEmpty(token[2]);
+      isEmpty = token[2].length === 0;
+      break;
+    case Token.AT_RULE:
+      isEmpty = token[1].length === 0;
+      break;
+    case Token.AT_RULE_BLOCK:
+      isEmpty = token[2].length === 0;
+    }
+
+    if (isEmpty) {
+      tokens.splice(i, 1);
+      i--;
+      l--;
+    }
+  }
+}
+
+function recursivelyOptimizeBlocks(tokens, context) {
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+
+    if (token[0] == Token.NESTED_BLOCK) {
+      var isKeyframes = /@(-moz-|-o-|-webkit-)?keyframes/.test(token[1][0][1]);
+      level2Optimize(token[2], context, !isKeyframes);
+    }
+  }
+}
+
+function recursivelyOptimizeProperties(tokens, context) {
+  for (var i = 0, l = tokens.length; i < l; i++) {
+    var token = tokens[i];
+
+    switch (token[0]) {
+    case Token.RULE:
+      optimizeProperties(token[2], true, true, context);
+      break;
+    case Token.NESTED_BLOCK:
+      recursivelyOptimizeProperties(token[2], context);
+    }
+  }
+}
+
+function level2Optimize(tokens, context, withRestructuring) {
+  var levelOptions = context.options.level[OptimizationLevel.Two];
+  var level2Plugins = context.options.plugins.level2Block;
+  var reduced;
+  var i;
+
+  recursivelyOptimizeBlocks(tokens, context);
+  recursivelyOptimizeProperties(tokens, context);
+
+  if (levelOptions.removeDuplicateRules) {
+    removeDuplicates(tokens, context);
+  }
+
+  if (levelOptions.mergeAdjacentRules) {
+    mergeAdjacent(tokens, context);
+  }
+
+  if (levelOptions.reduceNonAdjacentRules) {
+    reduceNonAdjacent(tokens, context);
+  }
+
+  if (levelOptions.mergeNonAdjacentRules && levelOptions.mergeNonAdjacentRules != 'body') {
+    mergeNonAdjacentBySelector(tokens, context);
+  }
+
+  if (levelOptions.mergeNonAdjacentRules && levelOptions.mergeNonAdjacentRules != 'selector') {
+    mergeNonAdjacentByBody(tokens, context);
+  }
+
+  if (levelOptions.restructureRules && levelOptions.mergeAdjacentRules && withRestructuring) {
+    restructure(tokens, context);
+    mergeAdjacent(tokens, context);
+  }
+
+  if (levelOptions.restructureRules && !levelOptions.mergeAdjacentRules && withRestructuring) {
+    restructure(tokens, context);
+  }
+
+  if (levelOptions.removeDuplicateFontRules) {
+    removeDuplicateFontAtRules(tokens, context);
+  }
+
+  if (levelOptions.removeDuplicateMediaBlocks) {
+    removeDuplicateMediaQueries(tokens, context);
+  }
+
+  if (levelOptions.removeUnusedAtRules) {
+    removeUnusedAtRules(tokens, context);
+  }
+
+  if (levelOptions.mergeMedia) {
+    reduced = mergeMediaQueries(tokens, context);
+    for (i = reduced.length - 1; i >= 0; i--) {
+      level2Optimize(reduced[i][2], context, false);
+    }
+  }
+
+  for (i = 0; i < level2Plugins.length; i++) {
+    level2Plugins[i](tokens);
+  }
+
+  if (levelOptions.removeEmpty) {
+    removeEmpty(tokens);
+  }
+
+  return tokens;
+}
+
+module.exports = level2Optimize;

+ 28 - 0
node_modules/clean-css/lib/optimizer/level-2/properties/every-values-pair.js

@@ -0,0 +1,28 @@
+var Marker = require('../../../tokenizer/marker');
+
+function everyValuesPair(fn, left, right) {
+  var leftSize = left.value.length;
+  var rightSize = right.value.length;
+  var total = Math.max(leftSize, rightSize);
+  var lowerBound = Math.min(leftSize, rightSize) - 1;
+  var leftValue;
+  var rightValue;
+  var position;
+
+  for (position = 0; position < total; position++) {
+    leftValue = left.value[position] && left.value[position][1] || leftValue;
+    rightValue = right.value[position] && right.value[position][1] || rightValue;
+
+    if (leftValue == Marker.COMMA || rightValue == Marker.COMMA) {
+      continue;
+    }
+
+    if (!fn(leftValue, rightValue, position, position <= lowerBound)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+module.exports = everyValuesPair;

Some files were not shown because too many files changed in this diff