Demo for query storing
Change-Id: I947bcac841992c3f6cfd01ab337c265b0d01cb70
diff --git a/node_modules/svgo/.svgo.yml b/node_modules/svgo/.svgo.yml
new file mode 100644
index 0000000..a9855db
--- /dev/null
+++ b/node_modules/svgo/.svgo.yml
@@ -0,0 +1,75 @@
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+ # - name
+ #
+ # or:
+ # - name: false
+ # - name: true
+ #
+ # or:
+ # - name:
+ # param1: 1
+ # param2: 2
+
+ - removeDoctype
+ - removeXMLProcInst
+ - removeComments
+ - removeMetadata
+ - removeXMLNS
+ - removeEditorsNSData
+ - cleanupAttrs
+ - inlineStyles
+ - minifyStyles
+ - convertStyleToAttrs
+ - cleanupIDs
+ - prefixIds
+ - removeRasterImages
+ - removeUselessDefs
+ - cleanupNumericValues
+ - cleanupListOfValues
+ - convertColors
+ - removeUnknownsAndDefaults
+ - removeNonInheritableGroupAttrs
+ - removeUselessStrokeAndFill
+ - removeViewBox
+ - cleanupEnableBackground
+ - removeHiddenElems
+ - removeEmptyText
+ - convertShapeToPath
+ - convertEllipseToCircle
+ - moveElemsAttrsToGroup
+ - moveGroupAttrsToElems
+ - collapseGroups
+ - convertPathData
+ - convertTransform
+ - removeEmptyAttrs
+ - removeEmptyContainers
+ - mergePaths
+ - removeUnusedNS
+ - sortAttrs
+ - sortDefsChildren
+ - removeTitle
+ - removeDesc
+ - removeDimensions
+ - removeAttrs
+ - removeAttributesBySelector
+ - removeElementsByAttr
+ - addClassesToSVGElement
+ - removeStyleElement
+ - removeScriptElement
+ - addAttributesToSVGElement
+ - removeOffCanvasPaths
+ - reusePaths
+
+# configure the indent (default 4 spaces) used by `--pretty` here:
+#
+# @see https://github.com/svg/svgo/blob/master/lib/svgo/js2svg.js#L6 for more config options
+#
+# js2svg:
+# pretty: true
+# indent: ' '
diff --git a/node_modules/svgo/CHANGELOG.md b/node_modules/svgo/CHANGELOG.md
new file mode 100644
index 0000000..ed12149
--- /dev/null
+++ b/node_modules/svgo/CHANGELOG.md
@@ -0,0 +1,533 @@
+### [ [>](https://github.com/svg/svgo/tree/v1.3.2) ] 1.3.2 / 30.10.2019
+* Fixed TypeError: Cannot set property 'multipassCount' of undefined
+
+### [ [>](https://github.com/svg/svgo/tree/v1.3.1) ] 1.3.1 / 29.10.2019
+* Updated CSSO version to 4.0.2 fixing the issue with empty semicolons ";;" in styles (thanks to @strarsis and @lahmatiy).
+* `prefixIds` plugin now runs only once with `--multipass` option (by @strarsis).
+* `cleanupIDs` plugin is prevented from producing a preserved ID, including one which matches a preserved prefix, when minifying (by @thomsj).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.3.0) ] 1.3.0 / 14.07.2019
+* Custom plugins now can be loaded from external js through `path` plugin param.
+* New plugin `convertEllipseToCircle` to convert ellipse with equal radius measures to circle (by @tigt).
+* New plugin `sortDefsChildren` for improved compression (by @davidleston).
+* SVGO now removes unnecessary spaces after `arcto` path command flags.
+* `removeDimensions` plugin now adds `viewBox` if it's missing (by @adipascu).
+* Fixed `removeUnusedNS` not counting attributes in `<svg>` tag itself.
+* Fixed an issue with incorrect processing multiple images (by @cyberalien).
+* Fixed an error with incorrect converting multiple segmented curve to an arc.
+* Fixed an error with matrix decomposition in `convertTransform` due to rounding error leading to illegal value.
+* Added `force` option for `mergePaths` plugin (by @goyney).
+* Added options to `prefixIds` plugin for selectively prefixing IDs and/or classes (by @strarsis).
+* Exported config function (by @1000ch).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.2.2) ] 1.2.2 / 16.04.2019
+* Update js-yaml for Code Injection warning (by @kaungst).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.2.1) ] 1.2.1 / 04.04.2019
+Some goodness from pull-requests.
+* Bump up js-yaml version to fix DoS vulnerability (by @eugestarr).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.2.0) ] 1.2.0 / 24.02.2019
+Some goodness from pull-requests.
+* Fixed extra blank lines when processing many files (by @panczarny).
+* Added `--recursive` option to process folders recursevely with option `-f` (by @dartess).
+* Added `removeAttributesBySelector` plugin to remove elements matching a css selector (by @bmease).
+* Added `removeOffCanvasPaths` plugin to remove elements outside of the viewbox (by @JoshyPHP).
+* `removeAttrs` plugin: added `preserveCurrentColor` color (by @roblevintennis) and 3rd optional filter for a value (by @Herman-Freund).
+* Added `reusePaths` plugin to replace duplicated elements with link (by @jhowcrof).
+* Added support of comma-separated plugins list in `--disable` and `--enable` options (by @jmwebservices).
+* Added option to preserve IDs based on prefix in `cleanupIDs` plugin (by @bkotzz).
+* Replaced `colors` dependency with `chalk` (by @xPaw).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.1.1) ] 1.1.1 / 17.09.2018
+* Fixed crash in `SVGO.optimize()` when ‘info’ is absent.
+* Removed extra space after `cleanupListOfValues` plugin.
+
+### [ [>](https://github.com/svg/svgo/tree/v1.1.0) ] 1.1.0 / 16.09.2018
+* Fixed `collapseGroups` plugin removing property with a child having `inherit` value.
+* `version` attribute value is not more being rounded.
+* Fixed jsAPI `clone` method with respect to the introduced CSS classes.
+* Fixed scaling strokes with `vector-effect="non-scaling-stroke"` (by @alexjlockwood).
+* Fixed passing properties from groups in `collapseGroups` plugin if child have a filter (by @stristr).
+* Fixed arc path commands parsing without separators after flags, effectively producing a JS error.
+* Fixed `viewBox` separators parsing.
+* Fixed `removeNonInheritableGroupAttrs` plugin to work as intended.
+* Fixed removing path segments without length in presence of `stroke-linecap`.
+* Fixed `removeUnknownsAndDefaults` plugin removing attributes from elements with `id`.
+* Fixed converting to large arcs from nearly straight lines curves.
+* Fixed `collapseGroups` plugin affecting `<switch>` and its subgroups.
+* Fixed `convertTransform` plugin converting to `rotate()` with wrong sign in some case.
+* Fixed `cleanupListOfValues` plugin not preserving non-numeric values.
+* Fixed `!important` being passed to attributes in `convertStyleToAttrs` plugin.
+* Added option `keepImportant` to `convertStyleToAttrs` plugin to preserve styles with `!important`.
+* `removeHiddenElems` plugin now also removes elements with `visibility="hidden"` attribute (by @mikolaj92).
+* Added `forceAbsolutePath` option to `convertPathData` plugin to always use absolute coordinates (by @cool).
+* Added `keepRoleAttr` for `removeUnknownsAndDefaults` plugin to preserve `role-` attributes (by @himedlooff).
+* Added `xmlns` order option in `sortAttrs` plugin (by @hellatan).
+* Added an option to `prefixIds` plugin to pass prefix as false or as a function that returns false (by @vzaidman).
+* `prefixIds` plugin now adds prefix to every class (by @vzaidman).
+* Updated and improved docs a bit (multiple authors).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.0.5) ] 1.0.5 / 26.02.2018
+* Fixed issue with prefixIDs plugin not replacing url() values correctly (by @harrisjose).
+
+### [ [>](https://github.com/svg/svgo/tree/v1.0.4) ] 1.0.4 / 30.01.2018
+* Fixed bug with removing groups that are direct child of "<switch>".
+* Fixed bug with shorthand path points counting (thanks @alexjlockwood for noticing).
+* Fixed crash on parsing invalid transform, e.g. without close parenthesis.
+
+### [ [>](https://github.com/svg/svgo/tree/v1.0.3) ] 1.0.3 / 08.11.2017
+* Fixed `removeViewBox` plugin to check for zero start coordinates.
+* Removed extra info from STDOUT when it set to output.
+
+### [ [>](https://github.com/svg/svgo/tree/v1.0.2) ] 1.0.2 / 03.11.2017
+* Fixed a couple of errors related to `inlineStyles` plugin.
+* Updated some lost details in documentation to reflect v1.0 changes.
+
+### [ [>](https://github.com/svg/svgo/tree/v1.0.1) ] 1.0.1 / 31.10.2017
+* Fixed error “Object.defineProperty called on non-object” in images with `<foreignObject/>`.
+
+### [ [>](https://github.com/svg/svgo/tree/v1.0.0) ] 1.0.0 / 30.10.2017
+* SVGO now requires Node 4 or higher.
+* Changed CLI syntax to treat filenames as input, thus allowing `svgo *.svg` syntax.
+* `SVGO.optimize()` now returns `Promise`.
+* Added `datauri` option to JS API.
+* Added support for SVG 2 `href` attribute.
+* `cleanupIDs` now don't removes IDs if an image consists only of `defs`.
+* New plugin `inlineStyles` for converting styles from `<style>` element to attributes if possible (by @strarsis).
+* `cleanupNumericValues` now rounds values in `viewBox` (by @caub).
+* New plugin: `removeScriptElement` (disabled by default) to align with `removeStyleElement` (by @pklingem).
+* `minifyStyles` now removes styles based on usage with controlling options (by @lahmatiy).
+* New option `except` in `cleanupIDs` to keep IDs (by @Velenir).
+* New option `force` in `cleanupIDs` to work even if SVG contains `style` or `script` elements (by @Velenir).
+* Fixed arcs transforming with different signed `scale` parameters (by @JoshyPHP).
+* Fixed `removeUselessStrokeAndFill` to check for `style` or `script` elements per file (by @caub).
+* New option `keepAriaAttrs` in `removeUnknownsAndDefaults` (by @davidtheclark).
+* Corrected parsing in `cleanupIDs` to account animation syntax (by @caub).
+* `#ff0000` now converts to `red` as well as `#f00` (by @davidleston).
+* Added “gray” variation to colors list per CSS Color Module Level 4 (by @ydaniv).
+* Fixed error on empty files.
+* A separator character in `removeAttrs` now can be changed per `elemSeparator` option (by @mikestreety).
+* `addAttributesToSVGElement` now can add values to attributes.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.7.2) ] 0.7.2 / 29.01.2017
+* Extended `currentColor` match conditions (string, rx, bool) (by @AlimovSV)
+* Fixed removing `<animate>` in `<stop>`.
+* Fixed removing same transform in inner element in `removeUnknownsAndDefaults`.
+* Fixed collapsing groups with same non-inheritable attribute.
+* Corrected removing of leading zero in case of exponential notation.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.7.1) ] 0.7.1 / 27.09.2016
+* Reverted the requirement of Node.js to version 0.10.
+* Added `addAttributesToSVGElement` to the default config to allow using it with `--enable` option.
+* Added korean translation of “How it works” doc (by @primeiros).
+
+### [ [>](https://github.com/svg/svgo/tree/v0.7.0) ] 0.7.0 / 25.08.2016
+* Required Node.js version has increased to 0.12.
+* New plugins: `removeElementsByAttr` (by IDs or classes) by @elidupuis,
+ `addAttributesToSVGElement` by @gjjones,
+ `removeXMLNS` (for SVG inlining) by @ricardobeat.
+* Tests now correctly pass in Windows with CRLF line endings. Pretty print now accounts system line endings.
+* Fixed bugs with collapsing groups with masks and transforms in `collapseGroups`.
+* Fixed bugs with erroneous removing IDs in `cleanupIDs`.
+* Improved attributes sorting in `sortAttrs` by @darktrojan.
+* `addClassesToSVGElement` no more repeats classes (by @ricardobeat).
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.6) ] 0.6.6 / 25.04.2016
+* Corrected CSSO API usage
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.5) ] 0.6.5 / 25.04.2016
+* Extra content inserted by editors are now being removed within `<foreignObject>` as well thus fixing bug “Namespace prefix … is not defined“ after applying SVGO.
+* Doctype with entities declaration is now also being removed since svgo correctly parses them starting from the version [0.6.2](https://github.com/svg/svgo/tree/v0.6.2).
+* Corrected `moveGroupAttrsToElems` not to move attributes to `g` content if it's referenced (has an `id`).
+* `collapseGroups` now don't collapse a group if it has an animated attribute (SMIL).
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.4) ] 0.6.4 / 05.04.2016
+* Fixed bug in “[convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js)” plugin with converting styling properties to non-existent attributes (which are normally removed later by `removeUnknownsAndDefaults`).
+* Added `--indent` option to style pretty-printed SVG. (e.g. `--indent 2`) (by @scurker).
+* Added `currentColor` param to `convertColors` plugin for converting values like `fill` and `stroke` to `currentColor` (by @scurker).
+* Bumped CSSO to the current version and used [its new shiny API](https://github.com/css/csso#api) (thanks to @lahmatiy).
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.3) ] 0.6.3 / 20.03.2016
+* Smart rounding (introduced in 0.4.5) now applies only when rounding is needed, thus making subsequent passes more stable.
+* Fixed regression in converting curves to arcs.
+* `xlink:href` references are now being checked by local name `href`, thus correctly working with another namespace prefix.
+* Fixed `id` removing with disabled `plugins/convertStyleToAttrs.js`.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.2) ] 0.6.2 / 08.03.2016
+* Better error handling and messaging improvements.
+* SVG files with XML entities (e.g. from Adobe Illustrator) are now correctly being parsed.
+* Fixed error on converting curves to arcs.
+* Corrected rounding in subsequent passes with `--multipass` option.
+* Data URI option now handles charset (by @holymonson)
+* Transformations are no longer moved to group if there is a mask (`plugins/moveElemsAttrsToGroup.js`).
+* Fixed matrix decomposition losing sign in case like `[1, 0, 0, -1, 0, 0]` (`scale(1 -1)`).
+* Fixed crash on uppercased color name.
+* Paths with `id` and without `stroke-width` aren't being transformed now since `stroke-width` may be applied later.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.1) ] 0.6.1 / 21.11.2015
+* Added option `--quiet` to suppress output (by @phihag).
+* Removed `lib-cov` folder from the package, which was erroneously included before.
+* Fixed errors in “[minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js)” when there are `<style>` elements with `CDATA` content or without content at all.
+* Amended transform functions parsing to prevent errors when there are no separators between numbers (which isn't allowed by syntax, but understood by browsers).
+
+### [ [>](https://github.com/svg/svgo/tree/v0.6.0) ] 0.6.0 / 08.11.2015
+* New optimization: circular curves now being converted to arcs. A notable improvement for circles within paths.
+* New plugin “[minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js)” which minifies `<style>` elments content with CSSO by @strarsis (svgo still doesn't understand its content)
+* New plugin “[removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js)” (disabled by default) by @betsydupuis.
+* Fixed issues with parsing numbers with exponent fraction (could happen with high precision >= 7).
+* Fixed rounding error due to incorrect preserving of precision in transformations.
+* Fixed shorthand curve distortion due to converted previous curve to not a curve.
+* Fixed interoperability issue with `precision` cli-option and `full` config.
+* Fixed an error produced by “[removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js)” by @thiakil
+* Another Inkscape prefix namespace is being removed.
+* Fixed an issue in [moveElemsAttrsToGroup“](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup“.js)” with transforms moved around `clip-path`.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.6) ] 0.5.6 / 13.08.2015
+* Fixed paths removing.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.5) ] 0.5.5 / 05.08.2015
+* Reverted debugging changes.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.4) ] 0.5.4 / 05.08.2015
+* New parameter `useShortTags` by @bradbarrow. Now svgo can produce correct non-selfclosing tags (useful in HTML in old browsers).
+* Fixed failing on empty transformation (which could be produced by two opposite).
+* Fixed removing paths which have numbers with exponent notation.
+* Fixed a bug with arc transformation.
+* Some typo fixes.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.3) ] 0.5.3 / 21.06.2015
+* Fixed breaking related to rounding functions in “[convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js)”.
+* Fixed a bug with ID in animations not being worked on by “[cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js)”.
+* Fixed a bug with quoted reference in `url()`.
+* Now, if there are several same IDs in the document, then the first one is used and others are being removed.
+* New command-line option `--show-plugins` displaying list of plugins.
+* Two new optional plugins: “[removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js)” (removes `width` and `height` if there is `viewBox`) and “[removeAttrsPlugin](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js)” (by @bennyschudel).
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.2) ] 0.5.2 / 24.05.2015
+* Introduced new `transformPrecision` option for better image quality (defaults to 5) in “[convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js)” and “[convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js)” (for the purpose of applying transformations) plugins.
+* Matrix transformations now can be decomposed into a combination of few simple transforms like `translate`, `rotate`, `scale`.
+* Arcs (paths `arcto` command) are now correctly being transformed into another arcs without being converting to Bezier curves.
+* Fixed an issue with “[mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js)” failing to detect paths intersection in some cases.
+* Fixed a bug with “[removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js)” removing some paths, which was introduced in [v0.5.1](https://github.com/svg/svgo/tree/v0.5.1).
+* Fixed a bug with transformation having `rotate()` with optional parameters.
+* Patterns with inherited attributes are no longer being removed.
+* Styles are no longer being removed from `<desc>` (by @dennari).
+* SVGO no longer breaks during parsing.
+* Added `clone()` method to JSAPI (by @jakearchibald)
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.1) ] 0.5.1 / 30.03.2015
+* added new command-line option to set precision in floating point numbers.
+* fixed all known image-disruptive bugs
+* Notably [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) plugin now checks for possible intersections to avoid side-effects
+* new plugin [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) to remove elements in ``<defs>`` and similar non-rendering elements without an ``id`` and thus cannot be used
+* fix for ``--multipass`` command line option (by @dfilatov)
+* improved [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) and [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) plugins (by @YetiOr)
+* new plugin for image manipulation [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) (by @kiyopikko)
+* fixed fail on comments after closing root ``</svg>`` tag
+* updated parsing to account meaningful spaces in ``<text>``
+* ``data-*`` attributes are now preserved in [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js)
+* prevented plugins from failing in ``<foreignObject>``
+* [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) plugin now converts other units to pixels (if it's better)
+* [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) plugin is enabled again with correct work in case of inherited attributes
+* fixed fail on images with incorrect paths like ``<path d="z"/>``
+* svgo now understands if an input is a folder (remember, you can set output to folder as well)
+* added support for some properties from SVG 2 like ``vector-effect="non-scaling-stroke"``
+* removed option to remove an ``id`` on root ``<svg>`` tag in [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) since it's already being done in [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js)
+
+### [ [>](https://github.com/svg/svgo/tree/v0.5.0) ] 0.5.0 / 05.11.2014
+* added ``--multipass`` command line option which repeatedly applies optimizations like collapsing groups (by @dfilatov)
+* exposed JSAPI as a factory method (by @mistakster)
+* added removeDesc plugin (by @dwabyick), disabled by default
+* [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) plugin is disabled by default since it's unable to check inherited properties
+* transformations now apply to paths with arcs in [plugins/convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js)
+* a lot of bug fixes mostly related to transformations
+
+### [ [>](https://github.com/svg/svgo/tree/v0.4.5) ] 0.4.5 / 02.08.2014
+* significally improved plugin [plugins/convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js):
+ - Now data is being written relative or absolute whichever is shorter. You can turn it off by setting ``utilizeAbsolute`` to ``false``.
+ - Smarter rounding: values like 2.499 now rounds to 2.5. Rounding now takes in account accumulutive error meaning that points will not be misplaced due to rounding more than it neccessary.
+ - Fixed couple bugs.
+* ``--output`` option now can be a folder along with ``--folder``, thanks to @mako-taco.
+* [plugins/cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) now have ``prefix`` option in case you want to combine multiple svg later (by @DanielMazurkiewicz).
+* Quotes now being escaped in attributes (by @ditesh).
+* Minor bugfixes.
+
+### [ [>](https://github.com/svg/svgo/tree/v0.4.4) ] 0.4.4 / 14.01.2014
+* new plugin [plugins/removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) (disabled by default, close [#159](https://github.com/svg/svgo/issues/159))
+* plugins/convertPathData: skip data concatenation for z instruction in collapseRepeated
+* plugins/removeUnknownsAndDefaults: do not remove overriden attributes with default values (fix [#161](https://github.com/svg/svgo/issues/161) and [#168](https://github.com/svg/svgo/issues/168))
+* plugins/removeViewBox: disable by default (fix [#139](https://github.com/svg/svgo/issues/139))
+* update README with [gulp task](https://github.com/ben-eb/gulp-svgmin)
+
+### [ [>](https://github.com/svg/svgo/tree/v0.4.3) ] 0.4.3 / 02.01.2014
+* new plugin [plugins/convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) (close [#96](https://github.com/svg/svgo/issues/96))
+* update sax version to fix [#140](https://github.com/svg/svgo/issues/140)
+* update deps
+
+### [ [>](https://github.com/svg/svgo/tree/v0.4.2) ] 0.4.2 / 19.12.2013
+* add `lcov.info` to npmignore
+* fix `js-yaml` version to suppress deprecation warning in stdout
+
+### [ [>](https://github.com/svg/svgo/tree/v0.4.1) ] 0.4.1 / 18.11.2013
+* node >=0.8.0
+
+### [ [>](https://github.com/svg/svgo/tree/v0.4.0) ] 0.4.0 / 18.11.2013
+* merge almost all pull-requests
+* update dependencies
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.7) ] 0.3.7 / 24.06.2013
+* do not remove `result` attribute from filter primitives (fix [#122](https://github.com/svg/svgo/issues/122))
+* plugins/cleanupAttrs: replace newline with space when needed (fix [#119](https://github.com/svg/svgo/issues/119))
+* lib/coa: look for config file in current folder
+* lib/coa: always traverse all files in the given folder
+* deprecate svgo-grunt in favor of [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin)
+* re-enable node-coveralls
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.6) ] 0.3.6 / 06.06.2013
+* plugins/removeNonInheritableGroupAttrs: more attrs groups to exclude (fix [#116](https://github.com/svg/svgo/issues/116) & [#118](https://github.com/svg/svgo/issues/118))
+* lib/coa: optimize folder file by file (temp fix [#114](https://github.com/svg/svgo/issues/114))
+* `.jshintrc`: JSHint 2.0
+* temporarily disable node-coveralls
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.5) ] 0.3.5 / 07.05.2013
+* plugins/transformsWithOnePath: fix curves bounding box calculation
+* plugins/transformsWithOnePath: fix possible c+t or q+s bug
+
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.4) ] 0.3.4 / 06.05.2013
+* plugins/convertPathData: fix m->M bug in some cases
+* plugins/transformsWithOnePath: fix last point calculation for C/S/Q/T
+* plugins/mergePaths: add space delimiter between z and m
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.3) ] 0.3.3 / 05.05.2013
+* plugins/convertPathData: convert very first m to M, fix applyTransforms with translate() (fix [#112](https://github.com/svg/svgo/issues/112))
+* plugins/transformsWithOnePath: fix real width/height rounding; fix scale transform origin; reorder transforms
+* plugins/transformsWithOnePath: ability to set new width or height independently with auto rescaling
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.2) ] 0.3.2 / 03.05.2013
+* new plugin [plugins/sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js)
+* plugins/transformsWithOnePath: buggy hcrop (fix [#111](https://github.com/svg/svgo/issues/111))
+* Impossible to set output presision to 0 (no fractional part) (fix [#110](https://github.com/svg/svgo/issues/110))
+* Istanbul + coveralls.io
+* update README with NPM version from badge.fury.io
+* update README with dependency status from gemnasium.com
+* npmignore unneeded files
+* reoptimized project logo
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.1) ] 0.3.1 / 15.04.2013
+* plugins/transformsWithOnePath: resize SVG and automatically rescale inner Path
+* better errors handling
+
+### [ [>](https://github.com/svg/svgo/tree/v0.3.0) ] 0.3.0 / 12.04.2013
+* global refactoring: getting rid of the many dependencies
+* new plugin [plugins/mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js)
+* new plugin [plugins/transformsWithOnePath](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) (renamed and featured `cropAndCenterAlongPath`)
+* config: replace default config with `full: true`
+* coa: JSON string as value of `--config`
+* coa: different types of Data URI strings (close [#105](https://github.com/svg/svgo/issues/105))
+* plugins/_transforms: allow spaces at the beginning of transform
+* Travis CI: Nodejs 0.10 & 0.11
+* `node.extend` → `whet.extend`
+* update `.gitignore`
+* update docs
+
+### [ [>](https://github.com/svg/svgo/tree/v0.2.4) ] 0.2.4 / 05.04.2013
+* new plugin [plugins/cropAndCenterAlongPath](https://github.com/svg/svgo/blob/master/plugins/cropAndCenterAlongPath.js) for the [Fontello](https://github.com/fontello) project
+
+### [ [>](https://github.com/svg/svgo/tree/v0.2.3) ] 0.2.3 / 22.02.2013
+* new plugin [plugins/removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) (fix [#101](https://github.com/svg/svgo/issues/101))
+* new plugin [plugins/removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) (close [#98](https://github.com/svg/svgo/issues/98))
+* plugins/convertTransform: bug with trailing spaces in transform value string (fix [#103](https://github.com/svg/svgo/issues/103))
+
+### [ [>](https://github.com/svg/svgo/tree/v0.2.2) ] 0.2.2 / 09.02.2013
+* plugins/convertTransforms: wrong translate() shorthand (fix [#94](https://github.com/svg/svgo/issues/94))
+* [yaml.js](https://github.com/jeremyfa/yaml.js) → [js-yaml](https://github.com/nodeca/js-yaml)
+* update outdated deps
+
+### [ [>](https://github.com/svg/svgo/tree/v0.2.1) ] 0.2.1 / 18.01.2013
+* plugins/moveElemsAttrsToGroup + plugins/moveGroupAttrsToElems: move or just leave transform attr from Group to the inner Path Elems (close [#86](https://github.com/svg/svgo/issues/86))
+* plugins/removeViewBox: doesn't catch floating-point numbers (fix [#88](https://github.com/svg/svgo/issues/88))
+* plugins/cleanupEnableBackground: doesn't catch floating-point numbers (fix [#89](https://github.com/svg/svgo/issues/89))
+* plugins/cleanupNumericValues: wrong floating-point numbers regexp (fix [#92](https://github.com/svg/svgo/issues/92))
+* SVG file generated by fontcustom.com not properly compressed (fix [#90](https://github.com/svg/svgo/issues/90))
+* `README.ru.md`: стилизация русского языка, улучшение языковых конструкций, правка ошибок (close [#91](https://github.com/svg/svgo/issues/91))
+* minor JSHint warning fix
+
+### [ [>](https://github.com/svg/svgo/tree/v0.2.0) ] 0.2.0 / 23.12.2012
+* plugins/convertPathData: apply transforms to Path pata (close [#33](https://github.com/svg/svgo/issues/33))
+* plugins/convertPathData: `-1.816-9.278.682-13.604` parsing error (fix [#85](https://github.com/svg/svgo/issues/85))
+* plugins/convertTransform: `translate(10, 0)` eq `translate(10)`, but not `translate(10, 10)` eq `translate(10)` (fix [#83](https://github.com/svg/svgo/issues/83))
+* run plugins/cleanupIDs before plugins/collapseGroups (fix [#84](https://github.com/svg/svgo/issues/84))
+* update `.gitignore`
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.9) ] 0.1.9 / 17.12.2012
+* plugins/cleanupIDs: renamed from removeUnusedIDs; minify used IDs (fix [#7](https://github.com/svg/svgo/issues/7))
+* lib/svgo/js2svg: restore HTML entities back (fix [#80](https://github.com/svg/svgo/issues/80) + [#81](https://github.com/svg/svgo/issues/81))
+* plugins/removeDoctype: do not remove if custom XML entities presents (fix [#77](https://github.com/svg/svgo/issues/77))
+* lib/svgo/coa: refactoring, colors and fix [#70](https://github.com/svg/svgo/issues/70)
+* lib/svgo: store elapsed time in result object
+* usage examples with SVGZ (close [#18](https://github.com/svg/svgo/issues/18))
+* more optimized logo
+* update `.gitignore`
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.8) ] 0.1.8 / 11.12.2012
+* new plugin [plugins/removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) (close [#75](https://github.com/svg/svgo/issues/75))
+* new plugin [plugins/removeUnusedIDs](https://github.com/svg/svgo/blob/master/plugins/removeUnusedIDs.js) (close [#76](https://github.com/svg/svgo/issues/76))
+* plugins/convertPathData: wrong M interpretation in some cases (fix [#73](https://github.com/svg/svgo/issues/73))
+* plugins/cleanupAttrs: use `isElem()` API
+* `.travis.yml`: check all branches
+
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.7) ] 0.1.7 / 08.12.2012
+* plugins/convertPathData: incorrect interpretation of `z + m` (fix [#69](https://github.com/svg/svgo/issues/69))
+* plugins/convertTransform: do a more accurate floating numbers rounding in `matrixToTransform()` (fix [#68](https://github.com/svg/svgo/issues/68))
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.6) ] 0.1.6 / 07.12.2012
+* plugins/convertPathData: collapse repeated instructions only after curveSmoothShorthands (fix [#64](https://github.com/svg/svgo/issues/64))
+* lib/svgo/coa: handle 'there is nothing to optimize' case and display a message about it (fix [#61](https://github.com/svg/svgo/issues/61))
+* plugins/cleanupSVGElem: delete as useless artefact
+
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.5) ] 0.1.5 / 06.12.2012
+* E-notated numbers in paths not recognised (fix [#63](https://github.com/svg/svgo/issues/63))
+* update README with `svgo-grunt` and `svgo-osx-folder-action`
+* fix `mocha-as-promised` plug in node 0.6
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.4) ] 0.1.4 / 05.12.2012
+* plugins/_collections: more defaults
+* `README.ru.md`
+* `docs/how-it-works/ru.md`
+* mocha + mocha-as-promised + chai + chai-as-promised + should + istanbul = <3
+* update dependencies semvers in `package.json`
+* `v0.1.x` and `v0.2.x` milestones
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.3) ] 0.1.3 / 30.11.2012
+* new plugin [plugins/cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) (close [#8](https://github.com/svg/svgo/issues/8))
+* plugins/removeDefaultPx functionality now included in plugins/removeUnknownsAndDefaults
+* plugins/removeUnknownsAndDefaults: refactoring and picking up the complete elems+attrs collection (close [#59](https://github.com/svg/svgo/issues/59))
+* plugins/convertTransform: error in matrices multiplication (fix [#58](https://github.com/svg/svgo/issues/58))
+* plugins/convertTransform: mark translate() and scale() as useless only with one param (fix [#57](https://github.com/svg/svgo/issues/57))
+* plugins/convertPathData: drastic speed improvement with huge Path data
+* plugins/convertPathData: fix the very first Mm with multiple points (fix [#56](https://github.com/svg/svgo/issues/56))
+* plugins/moveElemsAttrsToGroup: additional check for transform attr
+* brand-new project `logo.svg`
+* `.travis.yml`: build only master branch
+* global `'use strict'`
+* `.jshintignore`
+* README and CHANGELOG: minor corrections
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.2) ] 0.1.2 / 24.11.2012
+* lib/svgo/svg2js: correct 'onerror' failure (fix [#51](https://github.com/svg/svgo/issues/51))
+* config: disable sax-js position tracking by default (fix [#52](https://github.com/svg/svgo/issues/52))
+* lib/svgo: rename 'startBytes' to 'inBytes' and 'endBytes' to 'outBytes' (close [#53](https://github.com/svg/svgo/issues/53))
+* plugins/removeUnknownsAndDefaults: remove SVG id attr (close [#54](https://github.com/svg/svgo/issues/54))
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.1) ] 0.1.1 / 23.11.2012
+* plugins/moveElemsAttrsToGroup: fix inheitable only attrs array (fix [#47](https://github.com/svg/svgo/issues/47))
+* plugins/removeEmptyContainers: do not remove an empty 'svg' element (fix [#48](https://github.com/svg/svgo/issues/48))
+* plugins/removeDefaultPx: should also understand a floating-numbers too (fix [#49](https://github.com/svg/svgo/issues/49))
+* plugins/removeUnknownsAndDefaults: merge multiple groupDefaults attrs (close [#50](https://github.com/svg/svgo/issues/50))
+
+### [ [>](https://github.com/svg/svgo/tree/v0.1.0) ] 0.1.0 / 22.11.2012
+* new plugin [plugins/removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) (close [#6](https://github.com/svg/svgo/issues/6))
+* plugins/convertPathData: convert straight curves into lines segments (close [#17](https://github.com/svg/svgo/issues/17)); remove an absolute coords conversions
+* plugins/convertPathData: convert quadratic Bézier curveto into smooth shorthand (close [#31](https://github.com/svg/svgo/issues/31))
+* plugins/convertPathData: convert curveto into smooth shorthand (close [#30](https://github.com/svg/svgo/issues/30))
+* lib/svgo: global API refactoring (close [#37](https://github.com/svg/svgo/issues/37))
+* lib/svgo: fatal and stupid error in stream chunks concatenation (fix [#40](https://github.com/svg/svgo/issues/40))
+* lib/coa: batch folder optimization (close [#29](https://github.com/svg/svgo/issues/29))
+* lib/coa: support arguments as aliases to `--input` and `--output` (close [#28](https://github.com/svg/svgo/issues/28))
+* project logo by [Egor Bolhshakov](http://xizzzy.ru/)
+* move modules to `./lib/svgo/`
+* rename and convert `config.json` to `.svgo.yml`
+* add [./docs/](https://github.com/svg/svgo/tree/master/docs)
+* plugins/convertPathData: don't remove first `M` even if it's `0,0`
+* plugins/convertPathData: stronger defense from infinite loop
+* plugins/moveElemsAttrsToGroup: should affect only inheritable attributes (fix [#46](https://github.com/svg/svgo/issues/46))*
+* plugins/removeComments: ignore comments which starts with '!' (close [#43](https://github.com/svg/svgo/issues/43))
+* config: `cleanupAttrs` should be before `convertStyleToAttrs` (fix [#44](https://github.com/svg/svgo/issues/44))*
+* lib/svgo/jsAPI: add `eachAttr()` optional context param
+* temporarily remove PhantomJS and `--test` (close [#38](https://github.com/svg/svgo/issues/38))
+* q@0.8.10 compatibility: 'end is deprecated, use done instead' fix
+* add [Istanbul](https://github.com/gotwarlost/istanbul) code coverage
+* update dependencies versions and gitignore
+* README: add TODO section with versions milestones
+* update README with License section
+* update LICENSE with russian translation
+* `.editorconfig`: 2 spaces for YAML
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.9) ] 0.0.9 / 29.10.2012
+* [plugins how-to](https://github.com/svg/svgo/tree/master/plugins#readme) (close [#27](https://github.com/svg/svgo/issues/27))
+* allow any plugin of any type to go in any order (close [#14](https://github.com/svg/svgo/issues/14))
+* allow to do a multiple optimizations with one init (close [#25](https://github.com/svg/svgo/issues/25))
+* plugins/convertPathData: global refactoring
+* plugins/convertPathData: do all the tricks with absolute coords too (fix [#22](https://github.com/svg/svgo/issues/22))
+* plugins/convertPathData: accumulation of rounding errors (fix [#23](https://github.com/svg/svgo/issues/23))
+* plugins/convertPathData: prevent an infinity loop on invalid path data (fix [#26](https://github.com/svg/svgo/issues/26))
+* plugins/convertPathData: do not remove very first M from the path data (fix [#24](https://github.com/svg/svgo/issues/24))
+* plugins/convertPathData: optimize path data in <glyph> and <missing-glyph> (close [#20](https://github.com/svg/svgo/issues/20))
+* plugins/convertTransform: add patternTransform attribute to the process (close [#15](https://github.com/svg/svgo/issues/15))
+* plugins/convertTransform: Firefox: removing extra space in front of negative number is alowed only in path data, but not in transform (fix [#12](https://github.com/svg/svgo/issues/12))
+* plugins/removeXMLProcInst: remove only 'xml' but not 'xml-stylesheet' (fix [#21](https://github.com/svg/svgo/issues/15))
+* plugins/collapseGroups: merge split-level transforms (fix [#13](https://github.com/svg/svgo/issues/13))
+* jsdoc corrections
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.8) ] 0.0.8 / 20.10.2012
+* new plugin [convertTransform](plugins/convertTransform.js) (close [#5](https://github.com/svg/svgo/issues/5))
+* new plugin [removeUnusedNS](plugins/removeUnusedNS.js)
+* plugins/convertPathData: remove useless segments
+* plugins/convertPathData: a lot of refactoring
+* plugins/convertPathData: round numbers before conditions because of exponential notation (fix [#3](https://github.com/svg/svgo/issues/3))
+* plugins/moveElemsAttrsToGroup: merge split-level transforms instead of replacing (fix [#10](https://github.com/svg/svgo/issues/10))
+* lib/svg2js: catch and output xml parser errors (fix [#4](https://github.com/svg/svgo/issues/4))
+* lib/coa: open file for writing only when we are ready (fix [#2](https://github.com/svg/svgo/issues/2))
+* lib/tools: node.extend module
+* lib/plugins: refactoring
+* lib/js2svg: refactoring
+* lib/jsAPI: simplification and refactoring
+* absolute urls in README
+* update .editorconfig
+* update .travis.yml with nodejs 0.9
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.7) ] 0.0.7 / 14.10.2012
+* new plugin [convertPathData](plugins/convertPathData.js)
+* --input data now can be a Data URI base64 string
+* --output data now can be a Data URI base64 string with --datauri flag
+* Travis CI
+* JSHint corrections + .jshintrc
+* [.editorconfig](http://editorconfig.org/)
+* display time spent on optimization
+* .svgo → config.json
+* lib/phantom_wrapper.js → lib/phantom.js
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.6) ] 0.0.6 / 04.10.2012
+* add --test option to make a visual comparison of two files (PhantomJS pre-required)
+* update README and CHANGELOG with the correct relative urls
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.5) ] 0.0.5 / 03.10.2012
+* every plugin now has [at least one test](plugins)
+* removeViewBox, cleanupEnableBackground, removeEditorsNSData, convertStyleToAttrs and collapseGroups plugins fixes
+* new --pretty option for the pretty printed SVG
+* lib/config refactoring
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.4) ] 0.0.4 / 30.09.2012
+* new plugin [removeViewBox](plugins/removeViewBox.js)
+* new plugin [cleanupEnableBackground](plugins/cleanupEnableBackground.js)
+* display useful info after successful optimization
+* 'npm test' with 'spec' mocha output by default
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.3) ] 0.0.3 / 29.09.2012
+* plugins/collapseGroups bugfix
+* plugins/moveElemsAttrsToGroup bugfix
+* svgo now display --help if running w/o arguments
+* massive jsdoc updates
+* plugins engine main filter function optimization
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.2) ] 0.0.2 / 28.09.2012
+* add --disable and --enable command line options
+* add an empty values rejecting to coa.js
+* update README
+
+### [ [>](https://github.com/svg/svgo/tree/v0.0.1) ] 0.0.1 / 27.09.2012
+* initial public version
diff --git a/node_modules/svgo/LICENSE b/node_modules/svgo/LICENSE
new file mode 100644
index 0000000..cd8d500
--- /dev/null
+++ b/node_modules/svgo/LICENSE
@@ -0,0 +1,55 @@
+The MIT License
+
+Copyright © 2012–2016 Kir Belevich
+
+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.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Лицензия MIT
+
+Copyright © 2012–2016 Кир Белевич
+
+Данная лицензия разрешает лицам, получившим копию данного
+программного обеспечения и сопутствующей документации
+(в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно
+использовать Программное Обеспечение без ограничений, включая
+неограниченное право на использование, копирование, изменение,
+добавление, публикацию, распространение, сублицензирование
+и/или продажу копий Программного Обеспечения, также как и лицам,
+которым предоставляется данное Программное Обеспечение,
+при соблюдении следующих условий:
+
+Указанное выше уведомление об авторском праве и данные условия
+должны быть включены во все копии или значимые части данного
+Программного Обеспечения.
+
+ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ»,
+БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ,
+ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ ПРИГОДНОСТИ,
+СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ
+ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ
+ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ ИЛИ ДРУГИХ
+ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ ИНОМУ,
+ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С ПРОГРАММНЫМ
+ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ
+ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
diff --git a/node_modules/svgo/Makefile b/node_modules/svgo/Makefile
new file mode 100644
index 0000000..a757add
--- /dev/null
+++ b/node_modules/svgo/Makefile
@@ -0,0 +1,21 @@
+test:
+ @npm run test
+
+lib-cov:
+ @./node_modules/.bin/istanbul instrument --output lib-cov --no-compact --variable global.__coverage__ lib
+
+coverage: lib-cov
+ @COVERAGE=1 ISTANBUL_REPORTERS=text-summary ./node_modules/.bin/mocha --reporter mocha-istanbul
+ @rm -rf lib-cov
+
+coveralls: lib-cov
+ @COVERAGE=1 ISTANBUL_REPORTERS=lcovonly ./node_modules/.bin/mocha --reporter mocha-istanbul
+ @cat lcov.info | ./node_modules/.bin/coveralls
+ @rm -rf lib-cov lcov.info
+
+travis: lint test coveralls
+
+lint:
+ @npm run lint
+
+.PHONY: test
diff --git a/node_modules/svgo/README.md b/node_modules/svgo/README.md
new file mode 100644
index 0000000..3b676e0
--- /dev/null
+++ b/node_modules/svgo/README.md
@@ -0,0 +1,215 @@
+**english** | [русский](https://github.com/svg/svgo/blob/master/README.ru.md)
+- - -
+
+<img src="https://svg.github.io/svgo-logo.svg" width="200" height="200" alt="logo"/>
+
+## SVGO [](https://npmjs.org/package/svgo) [](https://travis-ci.org/svg/svgo) [](https://coveralls.io/r/svg/svgo?branch=master)
+
+**SVG O**ptimizer is a Nodejs-based tool for optimizing SVG vector graphics files.
+
+
+## Why?
+
+SVG files, especially those exported from various editors, usually contain a lot of redundant and useless information. This can include editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting the SVG rendering result.
+
+## What it can do
+
+SVGO has a plugin-based architecture, so almost every optimization is a separate plugin.
+
+Today we have:
+
+| Plugin | Description | Default |
+| ------ | ----------- | ------- |
+| [cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) | cleanup attributes from newlines, trailing, and repeating spaces | `enabled` |
+| [inlineStyles](https://github.com/svg/svgo/blob/master/plugins/inlineStyles.js) | move and merge styles from `<style>` elements to element `style` attributes | `enabled` |
+| [removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) | remove doctype declaration | `enabled` |
+| [removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) | remove XML processing instructions | `enabled` |
+| [removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) | remove comments | `enabled` |
+| [removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) | remove `<metadata>` | `enabled` |
+| [removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) | remove `<title>` | `enabled` |
+| [removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) | remove `<desc>` | `enabled` |
+| [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) | remove elements of `<defs>` without `id` | `enabled` |
+| [removeXMLNS](https://github.com/svg/svgo/blob/master/plugins/removeXMLNS.js) | removes `xmlns` attribute (for inline svg) | `disabled` |
+| [removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) | remove editors namespaces, elements, and attributes | `enabled` |
+| [removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) | remove empty attributes | `enabled` |
+| [removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) | remove hidden elements | `enabled` |
+| [removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) | remove empty Text elements | `enabled` |
+| [removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) | remove empty Container elements | `enabled` |
+| [removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) | remove `viewBox` attribute when possible | `enabled` |
+| [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) | remove or cleanup `enable-background` attribute when possible | `enabled` |
+| [minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js) | minify `<style>` elements content with [CSSO](https://github.com/css/csso) | `enabled` |
+| [convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) | convert styles into attributes | `enabled` |
+| [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) | convert colors (from `rgb()` to `#rrggbb`, from `#rrggbb` to `#rgb`) | `enabled` |
+| [convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) | convert Path data to relative or absolute (whichever is shorter), convert one segment to another, trim useless delimiters, smart rounding, and much more | `enabled` |
+| [convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) | collapse multiple transforms into one, convert matrices to the short aliases, and much more | `enabled` |
+| [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) | remove unknown elements content and attributes, remove attrs with default values | `enabled` |
+| [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | remove non-inheritable group's "presentation" attributes | `enabled` |
+| [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | remove useless `stroke` and `fill` attrs | `enabled` |
+| [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | remove unused namespaces declaration | `enabled` |
+| [prefixIds](https://github.com/svg/svgo/blob/master/plugins/prefixIds.js) | prefix IDs and classes with the SVG filename or an arbitrary string | `disabled` |
+| [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | remove unused and minify used IDs | `enabled` |
+| [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | round numeric values to the fixed precision, remove default `px` units | `enabled` |
+| [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) | round numeric values in attributes that take a list of numbers (like `viewBox` or `enable-background`) | `disabled` |
+| [moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) | move elements' attributes to their enclosing group | `enabled` |
+| [moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) | move some group attributes to the contained elements | `enabled` |
+| [collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) | collapse useless groups | `enabled` |
+| [removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) | remove raster images | `disabled` |
+| [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) | merge multiple Paths into one | `enabled` |
+| [convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) | convert some basic shapes to `<path>` | `enabled` |
+| [convertEllipseToCircle](https://github.com/svg/svgo/blob/master/plugins/convertEllipseToCircle.js) | convert non-eccentric `<ellipse>` to `<circle>` | `enabled` |
+| [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | sort element attributes for epic readability | `disabled` |
+| [sortDefsChildren](https://github.com/svg/svgo/blob/master/plugins/sortDefsChildren.js) | sort children of `<defs>` in order to improve compression | `enabled` |
+| [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | remove `width`/`height` and add `viewBox` if it's missing (opposite to removeViewBox, disable it first) | `disabled` |
+| [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | remove attributes by pattern | `disabled` |
+| [removeAttributesBySelector](https://github.com/svg/svgo/blob/master/plugins/removeAttributesBySelector.js) | removes attributes of elements that match a css selector | `disabled` |
+| [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | remove arbitrary elements by ID or className | `disabled` |
+| [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | add classnames to an outer `<svg>` element | `disabled` |
+| [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | adds attributes to an outer `<svg>` element | `disabled` |
+| [removeOffCanvasPaths](https://github.com/svg/svgo/blob/master/plugins/removeOffCanvasPaths.js) | removes elements that are drawn outside of the viewbox | `disabled` |
+| [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | remove `<style>` elements | `disabled` |
+| [removeScriptElement](https://github.com/svg/svgo/blob/master/plugins/removeScriptElement.js) | remove `<script>` elements | `disabled` |
+| [reusePaths](https://github.com/svg/svgo/blob/master/plugins/reusePaths.js) | Find duplicated <path> elements and replace them with <use> links | `disabled` |
+
+Want to know how it works and how to write your own plugin? [Of course you want to](https://github.com/svg/svgo/blob/master/docs/how-it-works/en.md). ([동작방법](https://github.com/svg/svgo/blob/master/docs/how-it-works/ko.md))
+
+
+## Installation
+
+```sh
+$ [sudo] npm install -g svgo
+```
+
+## Usage
+
+### <abbr title="Command Line Interface">CLI</abbr>
+
+```
+Usage:
+ svgo [OPTIONS] [ARGS]
+
+Options:
+ -h, --help : Help
+ -v, --version : Version
+ -i INPUT, --input=INPUT : Input file, "-" for STDIN
+ -s STRING, --string=STRING : Input SVG data string
+ -f FOLDER, --folder=FOLDER : Input folder, optimize and rewrite all *.svg files
+ -o OUTPUT, --output=OUTPUT : Output file or folder (by default the same as the input), "-" for STDOUT
+ -p PRECISION, --precision=PRECISION : Set number of digits in the fractional part, overrides plugins params
+ --config=CONFIG : Config file or JSON string to extend or replace default
+ --disable=PLUGIN : Disable plugin by name, "--disable=PLUGIN1,PLUGIN2" for multiple plugins
+ --enable=PLUGIN : Enable plugin by name, "--enable=PLUGIN3,PLUGIN4" for multiple plugins
+ --datauri=DATAURI : Output as Data URI string (base64, URI encoded or unencoded)
+ --multipass : Pass over SVGs multiple times to ensure all optimizations are applied
+ --pretty : Make SVG pretty printed
+ --indent=INDENT : Indent number when pretty printing SVGs
+ -r, --recursive : Use with '-f'. Optimizes *.svg files in folders recursively.
+ -q, --quiet : Only output error messages, not regular status messages
+ --show-plugins : Show available plugins and exit
+
+Arguments:
+ INPUT : Alias to --input
+```
+
+* with files:
+
+ ```sh
+ $ svgo test.svg
+ ```
+
+ or:
+
+ ```sh
+ $ svgo *.svg
+ ```
+
+ ```sh
+ $ svgo test.svg -o test.min.svg
+ ```
+
+ ```sh
+ $ svgo test.svg other.svg third.svg
+ ```
+
+ ```sh
+ $ svgo test.svg other.svg third.svg -o test.min.svg -o other.min.svg -o third.min.svg
+ ```
+
+* with STDIN / STDOUT:
+
+ ```sh
+ $ cat test.svg | svgo -i - -o - > test.min.svg
+ ```
+
+* with folder
+
+ ```sh
+ $ svgo -f ../path/to/folder/with/svg/files
+ ```
+
+ or:
+
+ ```sh
+ $ svgo -f ../path/to/folder/with/svg/files -o ../path/to/folder/with/svg/output
+ ```
+
+ ```sh
+ $ svgo *.svg -o ../path/to/folder/with/svg/output
+ ```
+
+* with strings:
+
+ ```sh
+ $ svgo -s '<svg version="1.1">test</svg>' -o test.min.svg
+ ```
+
+ or even with Data URI base64:
+
+ ```sh
+ $ svgo -s 'data:image/svg+xml;base64,...' -o test.min.svg
+ ```
+
+* with SVGZ:
+
+ from `.svgz` to `.svg`:
+
+ ```sh
+ $ gunzip -c test.svgz | svgo -i - -o test.min.svg
+ ```
+
+ from `.svg` to `.svgz`:
+
+ ```sh
+ $ svgo test.svg -o - | gzip -cfq9 > test.svgz
+ ```
+
+### Other Ways to Use SVGO
+
+* as a web app – [SVGOMG](https://jakearchibald.github.io/svgomg/)
+* as a Nodejs module – [examples](https://github.com/svg/svgo/tree/master/examples)
+* as a Grunt task – [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin)
+* as a Gulp task – [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin)
+* as a Mimosa module – [mimosa-minify-svg](https://github.com/dbashford/mimosa-minify-svg)
+* as an OSX Folder Action – [svgo-osx-folder-action](https://github.com/svg/svgo-osx-folder-action)
+* as a webpack loader – [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader)
+* as a Telegram Bot – [svgo_bot](https://github.com/maksugr/svgo_bot)
+* as a PostCSS plugin – [postcss-svgo](https://github.com/ben-eb/postcss-svgo)
+* as an Inkscape plugin – [inkscape-svgo](https://github.com/konsumer/inkscape-svgo)
+* as a Sketch plugin - [svgo-compressor](https://github.com/BohemianCoding/svgo-compressor)
+* as macOS app - [Image Shrinker](https://image-shrinker.com)
+* as a Rollup plugin - [rollup-plugin-svgo](https://github.com/porsager/rollup-plugin-svgo)
+
+## Backers
+
+| [<img src="https://sheetjs.com/sketch128.png" width="80">](https://sheetjs.com/) | [<img src="https://rawgithub.com/fontello/fontello/master/fontello-image.svg" width="80">](http://fontello.com/) |
+|:-:|:-:|
+| [SheetJS LLC](https://sheetjs.com/) | [Fontello](http://fontello.com/) |
+
+## Donations
+
+- PayPal: https://www.paypal.me/deepsweet
+
+## License and Copyright
+
+This software is released under the terms of the [MIT license](https://github.com/svg/svgo/blob/master/LICENSE).
+
+Logo by [Yegor Bolshakov](http://xizzzy.ru/).
diff --git a/node_modules/svgo/README.ru.md b/node_modules/svgo/README.ru.md
new file mode 100644
index 0000000..319e963
--- /dev/null
+++ b/node_modules/svgo/README.ru.md
@@ -0,0 +1,205 @@
+[english](https://github.com/svg/svgo/blob/master/README.md) | **русский**
+- - -
+
+<img src="https://svg.github.io/svgo-logo.svg" width="200" height="200" alt="logo"/>
+
+## SVGO [](https://npmjs.org/package/svgo) [](https://travis-ci.org/svg/svgo) [](https://coveralls.io/r/svg/svgo?branch=master)
+
+**SVG** **O**ptimizer – это инструмент для оптимизации векторной графики в формате SVG, написанный на Node.js.
+
+
+## Зачем?
+
+SVG-файлы, особенно экспортированные из редакторов, содержат много избыточной и бесполезной информации, комментариев, скрытых элементов, неоптимальные или стандартные значения и другой мусор, удаление которого безопасно и не влияет на конечный вид изображения.
+
+## Возможности
+
+SVGO имеет расширяемую архитектуру, в которой почти каждая оптимизация является отдельным расширением.
+
+Что у нас есть:
+
+| Plugin | Description | Default |
+| ------ | ----------- | ------- |
+| [cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) | удаление переносов строк и лишних пробелов | `включен` |
+| [inlineStyles](https://github.com/svg/svgo/blob/master/plugins/inlineStyles.js) | перенос стилей из элементов `<style>` в атрибуты `style` | `включен` |
+| [removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) | удаление doctype | `включен` |
+| [removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) | удаление XML-инструкций | `включен` |
+| [removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) | удаление комментариев | `включен` |
+| [removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) | удаление `<metadata>` | `включен` |
+| [removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) | удаление `<title>` | `включен` |
+| [removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) | удаление `<desc>` | `включен` |
+| [removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) | удаление элементов в `<defs>` без `id` | `включен` |
+| [removeXMLNS](https://github.com/svg/svgo/blob/master/plugins/removeXMLNS.js) | удаление атрибута xmlns (для заинлайненных svg) | `выключено` |
+| [removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) | удаление пространств имён различных редакторов, их элементов и атрибутов | `включен` |
+| [removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) | удаление пустых атрибутов | `включен` |
+| [removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) | удаление скрытых элементов | `включен` |
+| [removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) | удаление пустых текстовых элементов | `включен` |
+| [removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) | удаление пустых элементов-контейнеров | `включен` |
+| [removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) | удаление атрибута `viewBox`, когда это возможно | `включен` |
+| [cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) | удаление или оптимизация атрибута `enable-background`, когда это возможно | `включен` |
+| [minifyStyles](https://github.com/svg/svgo/blob/master/plugins/minifyStyles.js) | уменьшает содержимое элементов `<style>` с помощью [CSSO](https://github.com/css/csso). | `включен` |
+| [convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) | конвертирование стилей в атрибуте `style` в отдельные svg-атрибуты | `включен` |
+| [convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) | конвертирование цветовых значений: из `rgb()` в `#rrggbb`, из `#rrggbb` в `#rgb` | `включен` |
+| [convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) | конвертирование данных Path в относительные или абсолютные координаты, смотря что \|короче; конвертирование одних типов сегментов в другие; удаление ненужных разделителей; умное округление и тому подобное | `включен` |
+| [convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) | схлопывание нескольких трансформаций в одну, конвертирование матриц в короткие алиасы \|и многое другое | `включен` |
+| [removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) | удаление неизвестных элементов, контента и атрибутов | `включен` |
+| [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | удаление ненаследуемых "презентационных" атрибутов групп | `включен` |
+| [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | удаление неиспользуемых атрибутов stroke-* и fill-* | `включен` |
+| [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | удаление деклараций неиспользуемых пространств имён | `включен` |
+| [prefixIds](https://github.com/svg/svgo/blob/master/plugins/prefixIds.js) | добавляет префикс в ID или классы в виде имени файла или произвольной строки | `выключено` |
+| [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | удаление неиспользуемых и сокращение используемых ID | `включен` |
+| [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | округление дробных чисел до заданной точности, удаление `px` как единицы \|измерения по-умолчанию | `включен` |
+| [cleanupListOfValues](https://github.com/svg/svgo/blob/master/plugins/cleanupListOfValues.js) | округление числовых значений в атрибутах со списком чисел, таких как `viewBox` \|или `enableBackground` | `выключено` |
+| [moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) | перемещение совпадающих атрибутов у всех элементов внутри группы `<g>` | `включен` |
+| [moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) | перемещение некоторых атрибутов группы на элементы внутри | `включен` |
+| [collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) | схлопывание бесполезных групп `<g>` | `включен` |
+| [removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) | удаление растровых изображений | `выключено` |
+| [mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) | склеивание нескольких Path в одну кривую | `включен` |
+| [convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) | конвертирование простых форм в Path | `включен` |
+| [convertEllipseToCircle](https://github.com/svg/svgo/blob/master/plugins/convertEllipseToCircle.js) | конвертирование вырожденного эллипса `<ellipse>` в круг `<circle>` | `включен` |
+| [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | сортировка атрибутов элементов для удобочитаемости | `выключено` |
+| [sortDefsChildren](https://github.com/svg/svgo/blob/master/plugins/sortDefsChildren.js) | сортировка детей `<defs>` для лучшей компрессии | `включен` |
+| [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | удаляет атрибуты width/height при наличии viewBox (противоречит removeViewBox — плагин должен быть выключен) | `выключено` |
+| [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | удаляет атрибуты по указанному паттерну | `выключено` |
+| [removeAttributesBySelector](https://github.com/svg/svgo/blob/master/plugins/removeAttributesBySelector.js) | удаляет атрибуты по CSS-селектору | `выключено` |
+| [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | удаляет элементы по указанным ID или классам | `выключено` |
+| [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | добавляет имена классов корневому элементу `<svg>` | `выключено` |
+| [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | добавляет атрибуты корневому элементу `<svg>` | `выключено` |
+| [removeOffCanvasPaths](https://github.com/svg/svgo/blob/master/plugins/removeOffCanvasPaths.js) | удаляет элементы вне отрисовываемой области | `выключено` |
+| [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | удаляет элементы `<style>` | `выключено` |
+| [removeScriptElement](https://github.com/svg/svgo/blob/master/plugins/removeScriptElement.js) | удаляет элементы `<script>` | `выключено` |
+| [reusePaths](https://github.com/svg/svgo/blob/master/plugins/reusePaths.js) | Заменяет дублирующиеся элементы <path> ссылками <use> | `выключено` |
+
+Хотите узнать принципы работы и как написать свой плагин? [Конечно же, да!](https://github.com/svg/svgo/blob/master/docs/how-it-works/ru.md)
+
+
+## Как использовать
+
+```sh
+$ [sudo] npm install -g svgo
+```
+
+## Выполнение:
+
+### Командная строка
+
+```
+Запуск:
+ svgo [OPTIONS] [ARGS]
+
+Параметры:
+ -h, --help : Помощь
+ -v, --version : Версия программы
+ -i INPUT, --input=INPUT : Входной файл, "-" для STDIN
+ -s STRING, --string=STRING : Входная строка SVG
+ -f FOLDER, --folder=FOLDER : Входная папка, оптимизирует и перезаписывает все файлы *.svg
+ -o OUTPUT, --output=OUTPUT : Выходной файл или папка (совпадает с входным по умолчанию), "-" для STDOUT
+ -p PRECISION, --precision=PRECISION : Число цифр после запятой, переопределяет параметры плагинов
+ --config=CONFIG : Файл конфигурации (или строка JSON) для расширения и замены настроек
+ --disable=PLUGIN : Выключение плагина по имени, "--disable=PLUGIN1,PLUGIN2" для отключения нескольких плагинов
+ --enable=PLUGIN : Включение плагина по имени, "--enable=PLUGIN3,PLUGIN4" для отключения нескольких плагинов
+ --datauri=DATAURI : Результат в виде строки Data URI (base64, URI encoded или unencoded)
+ --multipass : Оптимизация в несколько проходов для применения всех возможных оптимизаций
+ --pretty : Удобочитаемое форматирование SVG
+ --indent=INDENT : Размер отступа для удобочитаемого форматирования
+ -r, --recursive : Совместно с '-f'. Рекурсивно обрабатывать *.svg файлы в папках.
+ -q, --quiet : Подавляет вывод информации, выводятся только сообщения об ошибках
+ --show-plugins : Доступные плагины
+
+Аргументы:
+ INPUT : Аналогично --input
+```
+
+* с файлами:
+
+ ```sh
+ $ svgo test.svg
+ ```
+
+ или:
+
+ ```sh
+ $ svgo *.svg
+ ```
+
+ ```sh
+ $ svgo test.svg -o test.min.svg
+ ```
+
+ ```sh
+ $ svgo test.svg other.svg third.svg
+ ```
+
+ ```sh
+ $ svgo test.svg other.svg third.svg -o test.min.svg -o other.min.svg -o third.min.svg
+ ```
+
+* со STDIN / STDOUT:
+
+ ```sh
+ $ cat test.svg | svgo -i - -o - > test.min.svg
+ ```
+
+* с папками
+
+ ```sh
+ $ svgo -f ../path/to/folder/with/svg/files
+ ```
+
+ или:
+
+ ```sh
+ $ svgo -f ../path/to/folder/with/svg/files -o ../path/to/folder/with/svg/output
+ ```
+
+ ```sh
+ $ svgo *.svg -o ../path/to/folder/with/svg/output
+ ```
+
+* со строками:
+
+ ```sh
+ $ svgo -s '<svg version="1.1">test</svg>' -o test.min.svg
+ ```
+
+ или даже с Data URI base64:
+
+ ```sh
+ $ svgo -s 'data:image/svg+xml;base64,…' -o test.min.svg
+ ```
+
+* с SVGZ:
+
+ из `.svgz` в `.svg`:
+
+ ```sh
+ $ gunzip -c test.svgz | svgo -i - -o test.min.svg
+ ```
+
+ из `.svg` в `.svgz`:
+
+ ```sh
+ $ svgo test.svg -o - | gzip -cfq9 > test.svgz
+ ```
+
+### Другие способы использования SVGO
+
+* в виде веб-приложения - [SVGOMG](https://jakearchibald.github.io/svgomg/)
+* как модуль Node.js – [examples](https://github.com/svg/svgo/tree/master/examples)
+* как таск для Grunt – [grunt-svgmin](https://github.com/sindresorhus/grunt-svgmin)
+* как таск для Gulp – [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin)
+* как таск для Mimosa – [mimosa-minify-svg](https://github.com/dbashford/mimosa-minify-svg)
+* как действие папки в OSX – [svgo-osx-folder-action](https://github.com/svg/svgo-osx-folder-action)
+* через загрузчик webpack – [image-webpack-loader](https://github.com/tcoopman/image-webpack-loader)
+* с помощью бота в Telegram – [svgo_bot](https://github.com/maksugr/svgo_bot)
+* как плагин PostCSS - [postcss-svgo](https://github.com/ben-eb/postcss-svgo)
+* как плагин для Inkscape – [inkscape-svgo](https://github.com/konsumer/inkscape-svgo)
+* как плагин для Sketch - [svgo-compressor](https://github.com/BohemianCoding/svgo-compressor)
+* в виде приложения macOS - [Image Shrinker](https://image-shrinker.com)
+* как плагин для Rollup - [rollup-plugin-svgo](https://github.com/porsager/rollup-plugin-svgo)
+
+## Лицензия и копирайты
+
+Данное программное обеспечение выпускается под [лицензией MIT](https://github.com/svg/svgo/blob/master/LICENSE).
+
+Логотип – [Егор Большаков](http://xizzzy.ru/).
diff --git a/node_modules/svgo/bin/svgo b/node_modules/svgo/bin/svgo
new file mode 100644
index 0000000..2fd77c0
--- /dev/null
+++ b/node_modules/svgo/bin/svgo
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+require('../lib/svgo/coa').run();
diff --git a/node_modules/svgo/lib/css-tools.js b/node_modules/svgo/lib/css-tools.js
new file mode 100644
index 0000000..6517892
--- /dev/null
+++ b/node_modules/svgo/lib/css-tools.js
@@ -0,0 +1,222 @@
+'use strict';
+
+var csstree = require('css-tree'),
+ List = csstree.List,
+ stable = require('stable'),
+ specificity = require('csso/lib/restructure/prepare/specificity');
+
+
+/**
+ * Flatten a CSS AST to a selectors list.
+ *
+ * @param {Object} cssAst css-tree AST to flatten
+ * @return {Array} selectors
+ */
+function flattenToSelectors(cssAst) {
+ var selectors = [];
+
+ csstree.walk(cssAst, {visit: 'Rule', enter: function(node) {
+ if (node.type !== 'Rule') {
+ return;
+ }
+
+ var atrule = this.atrule;
+ var rule = node;
+
+ node.prelude.children.each(function(selectorNode, selectorItem) {
+ var selector = {
+ item: selectorItem,
+ atrule: atrule,
+ rule: rule,
+ pseudos: []
+ };
+
+ selectorNode.children.each(function(selectorChildNode, selectorChildItem, selectorChildList) {
+ if (selectorChildNode.type === 'PseudoClassSelector' ||
+ selectorChildNode.type === 'PseudoElementSelector') {
+ selector.pseudos.push({
+ item: selectorChildItem,
+ list: selectorChildList
+ });
+ }
+ });
+
+ selectors.push(selector);
+ });
+ }});
+
+ return selectors;
+}
+
+/**
+ * Filter selectors by Media Query.
+ *
+ * @param {Array} selectors to filter
+ * @param {Array} useMqs Array with strings of media queries that should pass (<name> <expression>)
+ * @return {Array} Filtered selectors that match the passed media queries
+ */
+function filterByMqs(selectors, useMqs) {
+ return selectors.filter(function(selector) {
+ if (selector.atrule === null) {
+ return ~useMqs.indexOf('');
+ }
+
+ var mqName = selector.atrule.name;
+ var mqStr = mqName;
+ if (selector.atrule.expression &&
+ selector.atrule.expression.children.first().type === 'MediaQueryList') {
+ var mqExpr = csstree.generate(selector.atrule.expression);
+ mqStr = [mqName, mqExpr].join(' ');
+ }
+
+ return ~useMqs.indexOf(mqStr);
+ });
+}
+
+/**
+ * Filter selectors by the pseudo-elements and/or -classes they contain.
+ *
+ * @param {Array} selectors to filter
+ * @param {Array} usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass
+ * @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
+ */
+function filterByPseudos(selectors, usePseudos) {
+ return selectors.filter(function(selector) {
+ var pseudoSelectorsStr = csstree.generate({
+ type: 'Selector',
+ children: new List().fromArray(selector.pseudos.map(function(pseudo) {
+ return pseudo.item.data;
+ }))
+ });
+ return ~usePseudos.indexOf(pseudoSelectorsStr);
+ });
+}
+
+/**
+ * Remove pseudo-elements and/or -classes from the selectors for proper matching.
+ *
+ * @param {Array} selectors to clean
+ * @return {Array} Selectors without pseudo-elements and/or -classes
+ */
+function cleanPseudos(selectors) {
+ selectors.forEach(function(selector) {
+ selector.pseudos.forEach(function(pseudo) {
+ pseudo.list.remove(pseudo.item);
+ });
+ });
+}
+
+
+/**
+ * Compares two selector specificities.
+ * extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
+ *
+ * @param {Array} aSpecificity Specificity of selector A
+ * @param {Array} bSpecificity Specificity of selector B
+ * @return {Number} Score of selector specificity A compared to selector specificity B
+ */
+function compareSpecificity(aSpecificity, bSpecificity) {
+ for (var i = 0; i < 4; i += 1) {
+ if (aSpecificity[i] < bSpecificity[i]) {
+ return -1;
+ } else if (aSpecificity[i] > bSpecificity[i]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * Compare two simple selectors.
+ *
+ * @param {Object} aSimpleSelectorNode Simple selector A
+ * @param {Object} bSimpleSelectorNode Simple selector B
+ * @return {Number} Score of selector A compared to selector B
+ */
+function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) {
+ var aSpecificity = specificity(aSimpleSelectorNode),
+ bSpecificity = specificity(bSimpleSelectorNode);
+ return compareSpecificity(aSpecificity, bSpecificity);
+}
+
+function _bySelectorSpecificity(selectorA, selectorB) {
+ return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data);
+}
+
+
+/**
+ * Sort selectors stably by their specificity.
+ *
+ * @param {Array} selectors to be sorted
+ * @return {Array} Stable sorted selectors
+ */
+function sortSelectors(selectors) {
+ return stable(selectors, _bySelectorSpecificity);
+}
+
+
+/**
+ * Convert a css-tree AST style declaration to CSSStyleDeclaration property.
+ *
+ * @param {Object} declaration css-tree style declaration
+ * @return {Object} CSSStyleDeclaration property
+ */
+function csstreeToStyleDeclaration(declaration) {
+ var propertyName = declaration.property,
+ propertyValue = csstree.generate(declaration.value),
+ propertyPriority = (declaration.important ? 'important' : '');
+ return {
+ name: propertyName,
+ value: propertyValue,
+ priority: propertyPriority
+ };
+}
+
+
+/**
+ * Gets the CSS string of a style element
+ *
+ * @param {Object} element style element
+ * @return {String|Array} CSS string or empty array if no styles are set
+ */
+function getCssStr(elem) {
+ return elem.content[0].text || elem.content[0].cdata || [];
+}
+
+/**
+ * Sets the CSS string of a style element
+ *
+ * @param {Object} element style element
+ * @param {String} CSS string to be set
+ * @return {Object} reference to field with CSS
+ */
+function setCssStr(elem, css) {
+ // in case of cdata field
+ if(elem.content[0].cdata) {
+ elem.content[0].cdata = css;
+ return elem.content[0].cdata;
+ }
+
+ // in case of text field + if nothing was set yet
+ elem.content[0].text = css;
+ return elem.content[0].text;
+}
+
+
+module.exports.flattenToSelectors = flattenToSelectors;
+
+module.exports.filterByMqs = filterByMqs;
+module.exports.filterByPseudos = filterByPseudos;
+module.exports.cleanPseudos = cleanPseudos;
+
+module.exports.compareSpecificity = compareSpecificity;
+module.exports.compareSimpleSelectorNode = compareSimpleSelectorNode;
+
+module.exports.sortSelectors = sortSelectors;
+
+module.exports.csstreeToStyleDeclaration = csstreeToStyleDeclaration;
+
+module.exports.getCssStr = getCssStr;
+module.exports.setCssStr = setCssStr;
diff --git a/node_modules/svgo/lib/svgo.js b/node_modules/svgo/lib/svgo.js
new file mode 100644
index 0000000..cd1569f
--- /dev/null
+++ b/node_modules/svgo/lib/svgo.js
@@ -0,0 +1,90 @@
+'use strict';
+
+/**
+ * SVGO is a Nodejs-based tool for optimizing SVG vector graphics files.
+ *
+ * @see https://github.com/svg/svgo
+ *
+ * @author Kir Belevich <kir@soulshine.in> (https://github.com/deepsweet)
+ * @copyright © 2012 Kir Belevich
+ * @license MIT https://raw.githubusercontent.com/svg/svgo/master/LICENSE
+ */
+
+var CONFIG = require('./svgo/config.js'),
+ SVG2JS = require('./svgo/svg2js.js'),
+ PLUGINS = require('./svgo/plugins.js'),
+ JSAPI = require('./svgo/jsAPI.js'),
+ encodeSVGDatauri = require('./svgo/tools.js').encodeSVGDatauri,
+ JS2SVG = require('./svgo/js2svg.js');
+
+var SVGO = function(config) {
+ this.config = CONFIG(config);
+};
+
+SVGO.prototype.optimize = function(svgstr, info) {
+ info = info || {};
+ return new Promise((resolve, reject) => {
+ if (this.config.error) {
+ reject(this.config.error);
+ return;
+ }
+
+ var config = this.config,
+ maxPassCount = config.multipass ? 10 : 1,
+ counter = 0,
+ prevResultSize = Number.POSITIVE_INFINITY,
+ optimizeOnceCallback = (svgjs) => {
+ if (svgjs.error) {
+ reject(svgjs.error);
+ return;
+ }
+
+ info.multipassCount = counter;
+ if (++counter < maxPassCount && svgjs.data.length < prevResultSize) {
+ prevResultSize = svgjs.data.length;
+ this._optimizeOnce(svgjs.data, info, optimizeOnceCallback);
+ } else {
+ if (config.datauri) {
+ svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri);
+ }
+ if (info && info.path) {
+ svgjs.path = info.path;
+ }
+ resolve(svgjs);
+ }
+ };
+
+ this._optimizeOnce(svgstr, info, optimizeOnceCallback);
+ });
+};
+
+SVGO.prototype._optimizeOnce = function(svgstr, info, callback) {
+ var config = this.config;
+
+ SVG2JS(svgstr, function(svgjs) {
+ if (svgjs.error) {
+ callback(svgjs);
+ return;
+ }
+
+ svgjs = PLUGINS(svgjs, info, config.plugins);
+
+ callback(JS2SVG(svgjs, config.js2svg));
+ });
+};
+
+/**
+ * The factory that creates a content item with the helper methods.
+ *
+ * @param {Object} data which passed to jsAPI constructor
+ * @returns {JSAPI} content item
+ */
+SVGO.prototype.createContentItem = function(data) {
+ return new JSAPI(data);
+};
+
+SVGO.Config = CONFIG;
+
+module.exports = SVGO;
+// Offer ES module interop compatibility.
+module.exports.default = SVGO;
diff --git a/node_modules/svgo/lib/svgo/coa.js b/node_modules/svgo/lib/svgo/coa.js
new file mode 100644
index 0000000..1ac62ad
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/coa.js
@@ -0,0 +1,579 @@
+/* jshint quotmark: false */
+'use strict';
+
+var FS = require('fs'),
+ PATH = require('path'),
+ chalk = require('chalk'),
+ mkdirp = require('mkdirp'),
+ promisify = require('util.promisify'),
+ readdir = promisify(FS.readdir),
+ readFile = promisify(FS.readFile),
+ writeFile = promisify(FS.writeFile),
+ SVGO = require('../svgo.js'),
+ YAML = require('js-yaml'),
+ PKG = require('../../package.json'),
+ encodeSVGDatauri = require('./tools.js').encodeSVGDatauri,
+ decodeSVGDatauri = require('./tools.js').decodeSVGDatauri,
+ checkIsDir = require('./tools.js').checkIsDir,
+ regSVGFile = /\.svg$/,
+ noop = () => {},
+ svgo;
+
+/**
+ * Command-Option-Argument.
+ *
+ * @see https://github.com/veged/coa
+ */
+module.exports = require('coa').Cmd()
+ .helpful()
+ .name(PKG.name)
+ .title(PKG.description)
+ .opt()
+ .name('version').title('Version')
+ .short('v').long('version')
+ .only()
+ .flag()
+ .act(function() {
+ // output the version to stdout instead of stderr if returned
+ process.stdout.write(PKG.version + '\n');
+ // coa will run `.toString` on the returned value and send it to stderr
+ return '';
+ })
+ .end()
+ .opt()
+ .name('input').title('Input file, "-" for STDIN')
+ .short('i').long('input')
+ .arr()
+ .val(function(val) {
+ return val || this.reject("Option '--input' must have a value.");
+ })
+ .end()
+ .opt()
+ .name('string').title('Input SVG data string')
+ .short('s').long('string')
+ .end()
+ .opt()
+ .name('folder').title('Input folder, optimize and rewrite all *.svg files')
+ .short('f').long('folder')
+ .val(function(val) {
+ return val || this.reject("Option '--folder' must have a value.");
+ })
+ .end()
+ .opt()
+ .name('output').title('Output file or folder (by default the same as the input), "-" for STDOUT')
+ .short('o').long('output')
+ .arr()
+ .val(function(val) {
+ return val || this.reject("Option '--output' must have a value.");
+ })
+ .end()
+ .opt()
+ .name('precision').title('Set number of digits in the fractional part, overrides plugins params')
+ .short('p').long('precision')
+ .val(function(val) {
+ return !isNaN(val) ? val : this.reject("Option '--precision' must be an integer number");
+ })
+ .end()
+ .opt()
+ .name('config').title('Config file or JSON string to extend or replace default')
+ .long('config')
+ .val(function(val) {
+ return val || this.reject("Option '--config' must have a value.");
+ })
+ .end()
+ .opt()
+ .name('disable').title('Disable plugin by name, "--disable={PLUGIN1,PLUGIN2}" for multiple plugins (*nix)')
+ .long('disable')
+ .arr()
+ .val(function(val) {
+ return val || this.reject("Option '--disable' must have a value.");
+ })
+ .end()
+ .opt()
+ .name('enable').title('Enable plugin by name, "--enable={PLUGIN3,PLUGIN4}" for multiple plugins (*nix)')
+ .long('enable')
+ .arr()
+ .val(function(val) {
+ return val || this.reject("Option '--enable' must have a value.");
+ })
+ .end()
+ .opt()
+ .name('datauri').title('Output as Data URI string (base64, URI encoded or unencoded)')
+ .long('datauri')
+ .val(function(val) {
+ return val || this.reject("Option '--datauri' must have one of the following values: 'base64', 'enc' or 'unenc'");
+ })
+ .end()
+ .opt()
+ .name('multipass').title('Pass over SVGs multiple times to ensure all optimizations are applied')
+ .long('multipass')
+ .flag()
+ .end()
+ .opt()
+ .name('pretty').title('Make SVG pretty printed')
+ .long('pretty')
+ .flag()
+ .end()
+ .opt()
+ .name('indent').title('Indent number when pretty printing SVGs')
+ .long('indent')
+ .val(function(val) {
+ return !isNaN(val) ? val : this.reject("Option '--indent' must be an integer number");
+ })
+ .end()
+ .opt()
+ .name('recursive').title('Use with \'-f\'. Optimizes *.svg files in folders recursively.')
+ .short('r').long('recursive')
+ .flag()
+ .end()
+ .opt()
+ .name('quiet').title('Only output error messages, not regular status messages')
+ .short('q').long('quiet')
+ .flag()
+ .end()
+ .opt()
+ .name('show-plugins').title('Show available plugins and exit')
+ .long('show-plugins')
+ .flag()
+ .end()
+ .arg()
+ .name('input').title('Alias to --input')
+ .arr()
+ .end()
+ .act(function(opts, args) {
+ var input = opts.input || args.input,
+ output = opts.output,
+ config = {};
+
+ // --show-plugins
+ if (opts['show-plugins']) {
+ showAvailablePlugins();
+ return;
+ }
+
+ // w/o anything
+ if (
+ (!input || input[0] === '-') &&
+ !opts.string &&
+ !opts.stdin &&
+ !opts.folder &&
+ process.stdin.isTTY === true
+ ) return this.usage();
+
+ if (typeof process == 'object' && process.versions && process.versions.node && PKG && PKG.engines.node) {
+ var nodeVersion = String(PKG.engines.node).match(/\d*(\.\d+)*/)[0];
+ if (parseFloat(process.versions.node) < parseFloat(nodeVersion)) {
+ return printErrorAndExit(`Error: ${PKG.name} requires Node.js version ${nodeVersion} or higher.`);
+ }
+ }
+
+ // --config
+ if (opts.config) {
+ // string
+ if (opts.config.charAt(0) === '{') {
+ try {
+ config = JSON.parse(opts.config);
+ } catch (e) {
+ return printErrorAndExit(`Error: Couldn't parse config JSON.\n${String(e)}`);
+ }
+ // external file
+ } else {
+ var configPath = PATH.resolve(opts.config),
+ configData;
+ try {
+ // require() adds some weird output on YML files
+ configData = FS.readFileSync(configPath, 'utf8');
+ config = JSON.parse(configData);
+ } catch (err) {
+ if (err.code === 'ENOENT') {
+ return printErrorAndExit(`Error: couldn't find config file '${opts.config}'.`);
+ } else if (err.code === 'EISDIR') {
+ return printErrorAndExit(`Error: directory '${opts.config}' is not a config file.`);
+ }
+ config = YAML.safeLoad(configData);
+ config.__DIR = PATH.dirname(configPath); // will use it to resolve custom plugins defined via path
+
+ if (!config || Array.isArray(config)) {
+ return printErrorAndExit(`Error: invalid config file '${opts.config}'.`);
+ }
+ }
+ }
+ }
+
+ // --quiet
+ if (opts.quiet) {
+ config.quiet = opts.quiet;
+ }
+
+ // --recursive
+ if (opts.recursive) {
+ config.recursive = opts.recursive;
+ }
+
+ // --precision
+ if (opts.precision) {
+ var precision = Math.min(Math.max(0, parseInt(opts.precision)), 20);
+ if (!isNaN(precision)) {
+ config.floatPrecision = precision;
+ }
+ }
+
+ // --disable
+ if (opts.disable) {
+ changePluginsState(opts.disable, false, config);
+ }
+
+ // --enable
+ if (opts.enable) {
+ changePluginsState(opts.enable, true, config);
+ }
+
+ // --multipass
+ if (opts.multipass) {
+ config.multipass = true;
+ }
+
+ // --pretty
+ if (opts.pretty) {
+ config.js2svg = config.js2svg || {};
+ config.js2svg.pretty = true;
+ var indent;
+ if (opts.indent && !isNaN(indent = parseInt(opts.indent))) {
+ config.js2svg.indent = indent;
+ }
+ }
+
+ svgo = new SVGO(config);
+
+ // --output
+ if (output) {
+ if (input && input[0] != '-') {
+ if (output.length == 1 && checkIsDir(output[0])) {
+ var dir = output[0];
+ for (var i = 0; i < input.length; i++) {
+ output[i] = checkIsDir(input[i]) ? input[i] : PATH.resolve(dir, PATH.basename(input[i]));
+ }
+ } else if (output.length < input.length) {
+ output = output.concat(input.slice(output.length));
+ }
+ }
+ } else if (input) {
+ output = input;
+ } else if (opts.string) {
+ output = '-';
+ }
+
+ if (opts.datauri) {
+ config.datauri = opts.datauri;
+ }
+
+ // --folder
+ if (opts.folder) {
+ var ouputFolder = output && output[0] || opts.folder;
+ return optimizeFolder(config, opts.folder, ouputFolder).then(noop, printErrorAndExit);
+ }
+
+ // --input
+ if (input) {
+ // STDIN
+ if (input[0] === '-') {
+ return new Promise((resolve, reject) => {
+ var data = '',
+ file = output[0];
+
+ process.stdin
+ .on('data', chunk => data += chunk)
+ .once('end', () => processSVGData(config, {input: 'string'}, data, file).then(resolve, reject));
+ });
+ // file
+ } else {
+ return Promise.all(input.map((file, n) => optimizeFile(config, file, output[n])))
+ .then(noop, printErrorAndExit);
+ }
+
+ // --string
+ } else if (opts.string) {
+ var data = decodeSVGDatauri(opts.string);
+
+ return processSVGData(config, {input: 'string'}, data, output[0]);
+ }
+ });
+
+/**
+ * Change plugins state by names array.
+ *
+ * @param {Array} names plugins names
+ * @param {Boolean} state active state
+ * @param {Object} config original config
+ * @return {Object} changed config
+ */
+function changePluginsState(names, state, config) {
+ names.forEach(flattenPluginsCbk);
+
+ // extend config
+ if (config.plugins) {
+ for (var name of names) {
+ var matched = false,
+ key;
+
+ for (var plugin of config.plugins) {
+ // get plugin name
+ if (typeof plugin === 'object') {
+ key = Object.keys(plugin)[0];
+ } else {
+ key = plugin;
+ }
+
+ // if there is such a plugin name
+ if (key === name) {
+ // don't replace plugin's params with true
+ if (typeof plugin[key] !== 'object' || !state) {
+ plugin[key] = state;
+ }
+ // mark it as matched
+ matched = true;
+ }
+ }
+
+ // if not matched and current config is not full
+ if (!matched && !config.full) {
+ // push new plugin Object
+ config.plugins.push({ [name]: state });
+ matched = true;
+ }
+ }
+ // just push
+ } else {
+ config.plugins = names.map(name => ({ [name]: state }));
+ }
+ return config;
+}
+
+/**
+ * Flatten an array of plugins by invoking this callback on each element
+ * whose value may be a comma separated list of plugins.
+ *
+ * @param {String} name Plugin name
+ * @param {Number} index Plugin index
+ * @param {Array} names Plugins being traversed
+ */
+function flattenPluginsCbk(name, index, names)
+{
+ var split = name.split(',');
+
+ if(split.length > 1) {
+ names[index] = split.shift();
+ names.push.apply(names, split);
+ }
+
+}
+
+/**
+ * Optimize SVG files in a directory.
+ * @param {Object} config options
+ * @param {string} dir input directory
+ * @param {string} output output directory
+ * @return {Promise}
+ */
+function optimizeFolder(config, dir, output) {
+ if (!config.quiet) {
+ console.log(`Processing directory '${dir}':\n`);
+ }
+ return readdir(dir).then(files => processDirectory(config, dir, files, output));
+}
+
+/**
+ * Process given files, take only SVG.
+ * @param {Object} config options
+ * @param {string} dir input directory
+ * @param {Array} files list of file names in the directory
+ * @param {string} output output directory
+ * @return {Promise}
+ */
+function processDirectory(config, dir, files, output) {
+ // take only *.svg files, recursively if necessary
+ var svgFilesDescriptions = getFilesDescriptions(config, dir, files, output);
+
+ return svgFilesDescriptions.length ?
+ Promise.all(svgFilesDescriptions.map(fileDescription => optimizeFile(config, fileDescription.inputPath, fileDescription.outputPath))) :
+ Promise.reject(new Error(`No SVG files have been found in '${dir}' directory.`));
+}
+
+/**
+ * Get svg files descriptions
+ * @param {Object} config options
+ * @param {string} dir input directory
+ * @param {Array} files list of file names in the directory
+ * @param {string} output output directory
+ * @return {Array}
+ */
+function getFilesDescriptions(config, dir, files, output) {
+ const filesInThisFolder = files
+ .filter(name => regSVGFile.test(name))
+ .map(name => ({
+ inputPath: PATH.resolve(dir, name),
+ outputPath: PATH.resolve(output, name),
+ }));
+
+ return config.recursive ?
+ [].concat(
+ filesInThisFolder,
+ files
+ .filter(name => checkIsDir(PATH.resolve(dir, name)))
+ .map(subFolderName => {
+ const subFolderPath = PATH.resolve(dir, subFolderName);
+ const subFolderFiles = FS.readdirSync(subFolderPath);
+ const subFolderOutput = PATH.resolve(output, subFolderName);
+ return getFilesDescriptions(config, subFolderPath, subFolderFiles, subFolderOutput);
+ })
+ .reduce((a, b) => [].concat(a, b), [])
+ ) :
+ filesInThisFolder;
+}
+
+/**
+ * Read SVG file and pass to processing.
+ * @param {Object} config options
+ * @param {string} file
+ * @param {string} output
+ * @return {Promise}
+ */
+function optimizeFile(config, file, output) {
+ return readFile(file, 'utf8').then(
+ data => processSVGData(config, {input: 'file', path: file}, data, output, file),
+ error => checkOptimizeFileError(config, file, output, error)
+ );
+}
+
+/**
+ * Optimize SVG data.
+ * @param {Object} config options
+ * @param {string} data SVG content to optimize
+ * @param {string} output where to write optimized file
+ * @param {string} [input] input file name (being used if output is a directory)
+ * @return {Promise}
+ */
+function processSVGData(config, info, data, output, input) {
+ var startTime = Date.now(),
+ prevFileSize = Buffer.byteLength(data, 'utf8');
+
+ return svgo.optimize(data, info).then(function(result) {
+ if (config.datauri) {
+ result.data = encodeSVGDatauri(result.data, config.datauri);
+ }
+ var resultFileSize = Buffer.byteLength(result.data, 'utf8'),
+ processingTime = Date.now() - startTime;
+
+ return writeOutput(input, output, result.data).then(function() {
+ if (!config.quiet && output != '-') {
+ if (input) {
+ console.log(`\n${PATH.basename(input)}:`);
+ }
+ printTimeInfo(processingTime);
+ printProfitInfo(prevFileSize, resultFileSize);
+ }
+ },
+ error => Promise.reject(new Error(error.code === 'ENOTDIR' ? `Error: output '${output}' is not a directory.` : error)));
+ });
+}
+
+/**
+ * Write result of an optimization.
+ * @param {string} input
+ * @param {string} output output file name. '-' for stdout
+ * @param {string} data data to write
+ * @return {Promise}
+ */
+function writeOutput(input, output, data) {
+ if (output == '-') {
+ console.log(data);
+ return Promise.resolve();
+ }
+
+ mkdirp.sync(PATH.dirname(output));
+
+ return writeFile(output, data, 'utf8').catch(error => checkWriteFileError(input, output, data, error));
+}
+
+
+/**
+ * Write a time taken by optimization.
+ * @param {number} time time in milliseconds.
+ */
+function printTimeInfo(time) {
+ console.log(`Done in ${time} ms!`);
+}
+
+/**
+ * Write optimizing information in human readable format.
+ * @param {number} inBytes size before optimization.
+ * @param {number} outBytes size after optimization.
+ */
+function printProfitInfo(inBytes, outBytes) {
+ var profitPercents = 100 - outBytes * 100 / inBytes;
+
+ console.log(
+ (Math.round((inBytes / 1024) * 1000) / 1000) + ' KiB' +
+ (profitPercents < 0 ? ' + ' : ' - ') +
+ chalk.green(Math.abs((Math.round(profitPercents * 10) / 10)) + '%') + ' = ' +
+ (Math.round((outBytes / 1024) * 1000) / 1000) + ' KiB'
+ );
+}
+
+/**
+ * Check for errors, if it's a dir optimize the dir.
+ * @param {Object} config
+ * @param {string} input
+ * @param {string} output
+ * @param {Error} error
+ * @return {Promise}
+ */
+function checkOptimizeFileError(config, input, output, error) {
+ if (error.code == 'EISDIR') {
+ return optimizeFolder(config, input, output);
+ } else if (error.code == 'ENOENT') {
+ return Promise.reject(new Error(`Error: no such file or directory '${error.path}'.`));
+ }
+ return Promise.reject(error);
+}
+
+/**
+ * Check for saving file error. If the output is a dir, then write file there.
+ * @param {string} input
+ * @param {string} output
+ * @param {string} data
+ * @param {Error} error
+ * @return {Promise}
+ */
+function checkWriteFileError(input, output, data, error) {
+ if (error.code == 'EISDIR' && input) {
+ return writeFile(PATH.resolve(output, PATH.basename(input)), data, 'utf8');
+ } else {
+ return Promise.reject(error);
+ }
+}
+
+/**
+ * Show list of available plugins with short description.
+ */
+function showAvailablePlugins() {
+ console.log('Currently available plugins:');
+
+ // Flatten an array of plugins grouped per type, sort and write output
+ var list = [].concat.apply([], new SVGO().config.plugins)
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map(plugin => ` [ ${chalk.green(plugin.name)} ] ${plugin.description}`)
+ .join('\n');
+ console.log(list);
+}
+
+/**
+ * Write an error and exit.
+ * @param {Error} error
+ * @return {Promise} a promise for running tests
+ */
+function printErrorAndExit(error) {
+ console.error(chalk.red(error));
+ process.exit(1);
+ return Promise.reject(error); // for tests
+}
diff --git a/node_modules/svgo/lib/svgo/config.js b/node_modules/svgo/lib/svgo/config.js
new file mode 100644
index 0000000..a3d7b49
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/config.js
@@ -0,0 +1,250 @@
+'use strict';
+
+var FS = require('fs');
+var PATH = require('path');
+var yaml = require('js-yaml');
+
+/**
+ * Read and/or extend/replace default config file,
+ * prepare and optimize plugins array.
+ *
+ * @param {Object} [config] input config
+ * @return {Object} output config
+ */
+module.exports = function(config) {
+
+ var defaults;
+ config = typeof config == 'object' && config || {};
+
+ if (config.plugins && !Array.isArray(config.plugins)) {
+ return { error: 'Error: Invalid plugins list. Provided \'plugins\' in config should be an array.' };
+ }
+
+ if (config.full) {
+ defaults = config;
+
+ if (Array.isArray(defaults.plugins)) {
+ defaults.plugins = preparePluginsArray(config, defaults.plugins);
+ }
+ } else {
+ defaults = Object.assign({}, yaml.safeLoad(FS.readFileSync(__dirname + '/../../.svgo.yml', 'utf8')));
+ defaults.plugins = preparePluginsArray(config, defaults.plugins || []);
+ defaults = extendConfig(defaults, config);
+ }
+
+ if ('floatPrecision' in config && Array.isArray(defaults.plugins)) {
+ defaults.plugins.forEach(function(plugin) {
+ if (plugin.params && ('floatPrecision' in plugin.params)) {
+ // Don't touch default plugin params
+ plugin.params = Object.assign({}, plugin.params, { floatPrecision: config.floatPrecision });
+ }
+ });
+ }
+
+ if ('datauri' in config) {
+ defaults.datauri = config.datauri;
+ }
+
+ if (Array.isArray(defaults.plugins)) {
+ defaults.plugins = optimizePluginsArray(defaults.plugins);
+ }
+
+ return defaults;
+
+};
+
+/**
+ * Require() all plugins in array.
+ *
+ * @param {Object} config
+ * @param {Array} plugins input plugins array
+ * @return {Array} input plugins array of arrays
+ */
+function preparePluginsArray(config, plugins) {
+
+ var plugin,
+ key;
+
+ return plugins.map(function(item) {
+
+ // {}
+ if (typeof item === 'object') {
+
+ key = Object.keys(item)[0];
+
+ // custom
+ if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
+ plugin = setupCustomPlugin(key, item[key]);
+
+ } else {
+
+ plugin = setPluginActiveState(
+ loadPlugin(config, key, item[key].path),
+ item,
+ key
+ );
+ plugin.name = key;
+ }
+
+ // name
+ } else {
+
+ plugin = loadPlugin(config, item);
+ plugin.name = item;
+ if (typeof plugin.params === 'object') {
+ plugin.params = Object.assign({}, plugin.params);
+ }
+
+ }
+
+ return plugin;
+
+ });
+
+}
+
+/**
+ * Extend plugins with the custom config object.
+ *
+ * @param {Array} plugins input plugins
+ * @param {Object} config config
+ * @return {Array} output plugins
+ */
+function extendConfig(defaults, config) {
+
+ var key;
+
+ // plugins
+ if (config.plugins) {
+
+ config.plugins.forEach(function(item) {
+
+ // {}
+ if (typeof item === 'object') {
+
+ key = Object.keys(item)[0];
+
+ if (item[key] == null) {
+ console.error(`Error: '${key}' plugin is misconfigured! Have you padded its content in YML properly?\n`);
+ }
+
+ // custom
+ if (typeof item[key] === 'object' && item[key].fn && typeof item[key].fn === 'function') {
+ defaults.plugins.push(setupCustomPlugin(key, item[key]));
+
+ // plugin defined via path
+ } else if (typeof item[key] === 'object' && item[key].path) {
+ defaults.plugins.push(setPluginActiveState(loadPlugin(config, undefined, item[key].path), item, key));
+
+ } else {
+ defaults.plugins.forEach(function(plugin) {
+
+ if (plugin.name === key) {
+ plugin = setPluginActiveState(plugin, item, key);
+ }
+ });
+ }
+
+ }
+
+ });
+
+ }
+
+ defaults.multipass = config.multipass;
+
+ // svg2js
+ if (config.svg2js) {
+ defaults.svg2js = config.svg2js;
+ }
+
+ // js2svg
+ if (config.js2svg) {
+ defaults.js2svg = config.js2svg;
+ }
+
+ return defaults;
+
+}
+
+/**
+ * Setup and enable a custom plugin
+ *
+ * @param {String} plugin name
+ * @param {Object} custom plugin
+ * @return {Array} enabled plugin
+ */
+function setupCustomPlugin(name, plugin) {
+ plugin.active = true;
+ plugin.params = Object.assign({}, plugin.params || {});
+ plugin.name = name;
+
+ return plugin;
+}
+
+/**
+ * Try to group sequential elements of plugins array.
+ *
+ * @param {Object} plugins input plugins
+ * @return {Array} output plugins
+ */
+function optimizePluginsArray(plugins) {
+
+ var prev;
+
+ return plugins.reduce(function(plugins, item) {
+ if (prev && item.type == prev[0].type) {
+ prev.push(item);
+ } else {
+ plugins.push(prev = [item]);
+ }
+ return plugins;
+ }, []);
+
+}
+
+/**
+ * Sets plugin to active or inactive state.
+ *
+ * @param {Object} plugin
+ * @param {Object} item
+ * @param {Object} key
+ * @return {Object} plugin
+ */
+function setPluginActiveState(plugin, item, key) {
+ // name: {}
+ if (typeof item[key] === 'object') {
+ plugin.params = Object.assign({}, plugin.params || {}, item[key]);
+ plugin.active = true;
+
+ // name: false
+ } else if (item[key] === false) {
+ plugin.active = false;
+
+ // name: true
+ } else if (item[key] === true) {
+ plugin.active = true;
+ }
+
+ return plugin;
+}
+
+/**
+ * Loads default plugin using name or custom plugin defined via path in config.
+ *
+ * @param {Object} config
+ * @param {Object} name
+ * @param {Object} path
+ * @return {Object} plugin
+ */
+function loadPlugin(config, name, path) {
+ var plugin;
+
+ if (!path) {
+ plugin = require('../../plugins/' + name);
+ } else {
+ plugin = require(PATH.resolve(config.__DIR, path));
+ }
+
+ return Object.assign({}, plugin);
+}
diff --git a/node_modules/svgo/lib/svgo/css-class-list.js b/node_modules/svgo/lib/svgo/css-class-list.js
new file mode 100644
index 0000000..8401a9f
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/css-class-list.js
@@ -0,0 +1,138 @@
+'use strict';
+
+var values = require('object.values');
+if (!Object.values) {
+ values.shim();
+}
+
+
+var CSSClassList = function(node) {
+ this.parentNode = node;
+ this.classNames = new Set();
+ this.classAttr = null;
+ //this.classValue = null;
+};
+
+/**
+ * Performs a deep clone of this object.
+ *
+ * @param parentNode the parentNode to assign to the cloned result
+ */
+CSSClassList.prototype.clone = function(parentNode) {
+ var node = this;
+ var nodeData = {};
+
+ Object.keys(node).forEach(function(key) {
+ if (key !== 'parentNode') {
+ nodeData[key] = node[key];
+ }
+ });
+
+ // Deep-clone node data.
+ nodeData = JSON.parse(JSON.stringify(nodeData));
+
+ var clone = new CSSClassList(parentNode);
+ Object.assign(clone, nodeData);
+ return clone;
+};
+
+CSSClassList.prototype.hasClass = function() {
+ this.classAttr = { // empty class attr
+ 'name': 'class',
+ 'value': null
+ };
+
+ this.addClassHandler();
+};
+
+
+// attr.class
+
+CSSClassList.prototype.addClassHandler = function() {
+
+ Object.defineProperty(this.parentNode.attrs, 'class', {
+ get: this.getClassAttr.bind(this),
+ set: this.setClassAttr.bind(this),
+ enumerable: true,
+ configurable: true
+ });
+
+ this.addClassValueHandler();
+};
+
+// attr.class.value
+
+CSSClassList.prototype.addClassValueHandler = function() {
+
+ Object.defineProperty(this.classAttr, 'value', {
+ get: this.getClassValue.bind(this),
+ set: this.setClassValue.bind(this),
+ enumerable: true,
+ configurable: true
+ });
+};
+
+CSSClassList.prototype.getClassAttr = function() {
+ return this.classAttr;
+};
+
+CSSClassList.prototype.setClassAttr = function(newClassAttr) {
+ this.setClassValue(newClassAttr.value); // must before applying value handler!
+
+ this.classAttr = newClassAttr;
+ this.addClassValueHandler();
+};
+
+CSSClassList.prototype.getClassValue = function() {
+ var arrClassNames = Array.from(this.classNames);
+ return arrClassNames.join(' ');
+};
+
+CSSClassList.prototype.setClassValue = function(newValue) {
+ if(typeof newValue === 'undefined') {
+ this.classNames.clear();
+ return;
+ }
+ var arrClassNames = newValue.split(' ');
+ this.classNames = new Set(arrClassNames);
+};
+
+
+CSSClassList.prototype.add = function(/* variadic */) {
+ this.hasClass();
+ Object.values(arguments).forEach(this._addSingle.bind(this));
+};
+
+CSSClassList.prototype._addSingle = function(className) {
+ this.classNames.add(className);
+};
+
+
+CSSClassList.prototype.remove = function(/* variadic */) {
+ this.hasClass();
+ Object.values(arguments).forEach(this._removeSingle.bind(this));
+};
+
+CSSClassList.prototype._removeSingle = function(className) {
+ this.classNames.delete(className);
+};
+
+
+CSSClassList.prototype.item = function(index) {
+ var arrClassNames = Array.from(this.classNames);
+ return arrClassNames[index];
+};
+
+CSSClassList.prototype.toggle = function(className, force) {
+ if(this.contains(className) || force === false) {
+ this.classNames.delete(className);
+ }
+ this.classNames.add(className);
+};
+
+CSSClassList.prototype.contains = function(className) {
+ return this.classNames.has(className);
+};
+
+
+module.exports = CSSClassList;
\ No newline at end of file
diff --git a/node_modules/svgo/lib/svgo/css-select-adapter.js b/node_modules/svgo/lib/svgo/css-select-adapter.js
new file mode 100644
index 0000000..c37678c
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/css-select-adapter.js
@@ -0,0 +1,53 @@
+'use strict';
+
+var baseCssAdapter = require('css-select-base-adapter');
+
+/**
+ * DOMUtils API for SVGO AST (used by css-select)
+ */
+var svgoCssSelectAdapterMin = {
+
+ // is the node a tag?
+ // isTag: ( node:Node ) => isTag:Boolean
+ isTag: function(node) {
+ return node.isElem();
+ },
+
+ // get the parent of the node
+ // getParent: ( node:Node ) => parentNode:Node
+ // returns null when no parent exists
+ getParent: function(node) {
+ return node.parentNode || null;
+ },
+
+ // get the node's children
+ // getChildren: ( node:Node ) => children:[Node]
+ getChildren: function(node) {
+ return node.content || [];
+ },
+
+ // get the name of the tag
+ // getName: ( elem:ElementNode ) => tagName:String
+ getName: function(elemAst) {
+ return elemAst.elem;
+ },
+
+ // get the text content of the node, and its children if it has any
+ // getText: ( node:Node ) => text:String
+ // returns empty string when there is no text
+ getText: function(node) {
+ return node.content[0].text || node.content[0].cdata || '';
+ },
+
+ // get the attribute value
+ // getAttributeValue: ( elem:ElementNode, name:String ) => value:String
+ // returns null when attribute doesn't exist
+ getAttributeValue: function(elem, name) {
+ return elem.hasAttr(name) ? elem.attr(name).value : null;
+ }
+};
+
+// use base adapter for default implementation
+var svgoCssSelectAdapter = baseCssAdapter(svgoCssSelectAdapterMin);
+
+module.exports = svgoCssSelectAdapter;
diff --git a/node_modules/svgo/lib/svgo/css-style-declaration.js b/node_modules/svgo/lib/svgo/css-style-declaration.js
new file mode 100644
index 0000000..fb6d781
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/css-style-declaration.js
@@ -0,0 +1,285 @@
+'use strict';
+
+var csstree = require('css-tree'),
+ csstools = require('../css-tools');
+
+
+var CSSStyleDeclaration = function(node) {
+ this.parentNode = node;
+
+ this.properties = new Map();
+ this.hasSynced = false;
+
+ this.styleAttr = null;
+ this.styleValue = null;
+
+ this.parseError = false;
+};
+
+/**
+ * Performs a deep clone of this object.
+ *
+ * @param parentNode the parentNode to assign to the cloned result
+ */
+CSSStyleDeclaration.prototype.clone = function(parentNode) {
+ var node = this;
+ var nodeData = {};
+
+ Object.keys(node).forEach(function(key) {
+ if (key !== 'parentNode') {
+ nodeData[key] = node[key];
+ }
+ });
+
+ // Deep-clone node data.
+ nodeData = JSON.parse(JSON.stringify(nodeData));
+
+ var clone = new CSSStyleDeclaration(parentNode);
+ Object.assign(clone, nodeData);
+ return clone;
+};
+
+CSSStyleDeclaration.prototype.hasStyle = function() {
+ this.addStyleHandler();
+};
+
+
+
+
+// attr.style
+
+CSSStyleDeclaration.prototype.addStyleHandler = function() {
+
+ this.styleAttr = { // empty style attr
+ 'name': 'style',
+ 'value': null
+ };
+
+ Object.defineProperty(this.parentNode.attrs, 'style', {
+ get: this.getStyleAttr.bind(this),
+ set: this.setStyleAttr.bind(this),
+ enumerable: true,
+ configurable: true
+ });
+
+ this.addStyleValueHandler();
+};
+
+// attr.style.value
+
+CSSStyleDeclaration.prototype.addStyleValueHandler = function() {
+
+ Object.defineProperty(this.styleAttr, 'value', {
+ get: this.getStyleValue.bind(this),
+ set: this.setStyleValue.bind(this),
+ enumerable: true,
+ configurable: true
+ });
+};
+
+CSSStyleDeclaration.prototype.getStyleAttr = function() {
+ return this.styleAttr;
+};
+
+CSSStyleDeclaration.prototype.setStyleAttr = function(newStyleAttr) {
+ this.setStyleValue(newStyleAttr.value); // must before applying value handler!
+
+ this.styleAttr = newStyleAttr;
+ this.addStyleValueHandler();
+ this.hasSynced = false; // raw css changed
+};
+
+CSSStyleDeclaration.prototype.getStyleValue = function() {
+ return this.getCssText();
+};
+
+CSSStyleDeclaration.prototype.setStyleValue = function(newValue) {
+ this.properties.clear(); // reset all existing properties
+ this.styleValue = newValue;
+ this.hasSynced = false; // raw css changed
+};
+
+
+
+
+CSSStyleDeclaration.prototype._loadCssText = function() {
+ if (this.hasSynced) {
+ return;
+ }
+ this.hasSynced = true; // must be set here to prevent loop in setProperty(...)
+
+ if (!this.styleValue || this.styleValue.length === 0) {
+ return;
+ }
+ var inlineCssStr = this.styleValue;
+
+ var declarations = {};
+ try {
+ declarations = csstree.parse(inlineCssStr, {
+ context: 'declarationList',
+ parseValue: false
+ });
+ } catch (parseError) {
+ this.parseError = parseError;
+ return;
+ }
+ this.parseError = false;
+
+ var self = this;
+ declarations.children.each(function(declaration) {
+ try {
+ var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration);
+ self.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority);
+ } catch(styleError) {
+ if(styleError.message !== 'Unknown node type: undefined') {
+ self.parseError = styleError;
+ }
+ }
+ });
+};
+
+
+// only reads from properties
+
+/**
+ * Get the textual representation of the declaration block (equivalent to .cssText attribute).
+ *
+ * @return {String} Textual representation of the declaration block (empty string for no properties)
+ */
+CSSStyleDeclaration.prototype.getCssText = function() {
+ var properties = this.getProperties();
+
+ if (this.parseError) {
+ // in case of a parse error, pass through original styles
+ return this.styleValue;
+ }
+
+ var cssText = [];
+ properties.forEach(function(property, propertyName) {
+ var strImportant = property.priority === 'important' ? '!important' : '';
+ cssText.push(propertyName.trim() + ':' + property.value.trim() + strImportant);
+ });
+ return cssText.join(';');
+};
+
+CSSStyleDeclaration.prototype._handleParseError = function() {
+ if (this.parseError) {
+ console.warn('Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr(\'style\').value. Error details: ' + this.parseError);
+ }
+};
+
+
+CSSStyleDeclaration.prototype._getProperty = function(propertyName) {
+ if(typeof propertyName === 'undefined') {
+ throw Error('1 argument required, but only 0 present.');
+ }
+
+ var properties = this.getProperties();
+ this._handleParseError();
+
+ var property = properties.get(propertyName.trim());
+ return property;
+};
+
+/**
+ * Return the optional priority, "important".
+ *
+ * @param {String} propertyName representing the property name to be checked.
+ * @return {String} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string.
+ */
+CSSStyleDeclaration.prototype.getPropertyPriority = function(propertyName) {
+ var property = this._getProperty(propertyName);
+ return property ? property.priority : '';
+};
+
+/**
+ * Return the property value given a property name.
+ *
+ * @param {String} propertyName representing the property name to be checked.
+ * @return {String} value containing the value of the property. If not set, returns the empty string.
+ */
+CSSStyleDeclaration.prototype.getPropertyValue = function(propertyName) {
+ var property = this._getProperty(propertyName);
+ return property ? property.value : null;
+};
+
+/**
+ * Return a property name.
+ *
+ * @param {Number} index of the node to be fetched. The index is zero-based.
+ * @return {String} propertyName that is the name of the CSS property at the specified index.
+ */
+CSSStyleDeclaration.prototype.item = function(index) {
+ if(typeof index === 'undefined') {
+ throw Error('1 argument required, but only 0 present.');
+ }
+
+ var properties = this.getProperties();
+ this._handleParseError();
+
+ return Array.from(properties.keys())[index];
+};
+
+/**
+ * Return all properties of the node.
+ *
+ * @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value.
+ */
+CSSStyleDeclaration.prototype.getProperties = function() {
+ this._loadCssText();
+ return this.properties;
+};
+
+
+// writes to properties
+
+/**
+ * Remove a property from the CSS declaration block.
+ *
+ * @param {String} propertyName representing the property name to be removed.
+ * @return {String} oldValue equal to the value of the CSS property before it was removed.
+ */
+CSSStyleDeclaration.prototype.removeProperty = function(propertyName) {
+ if(typeof propertyName === 'undefined') {
+ throw Error('1 argument required, but only 0 present.');
+ }
+
+ this.hasStyle();
+
+ var properties = this.getProperties();
+ this._handleParseError();
+
+ var oldValue = this.getPropertyValue(propertyName);
+ properties.delete(propertyName.trim());
+ return oldValue;
+};
+
+/**
+ * Modify an existing CSS property or creates a new CSS property in the declaration block.
+ *
+ * @param {String} propertyName representing the CSS property name to be modified.
+ * @param {String} [value] containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter.
+ * @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
+ * @return {undefined}
+ */
+CSSStyleDeclaration.prototype.setProperty = function(propertyName, value, priority) {
+ if(typeof propertyName === 'undefined') {
+ throw Error('propertyName argument required, but only not present.');
+ }
+
+ this.hasStyle();
+
+ var properties = this.getProperties();
+ this._handleParseError();
+
+ var property = {
+ value: value.trim(),
+ priority: priority.trim()
+ };
+ properties.set(propertyName.trim(), property);
+
+ return property;
+};
+
+
+module.exports = CSSStyleDeclaration;
diff --git a/node_modules/svgo/lib/svgo/js2svg.js b/node_modules/svgo/lib/svgo/js2svg.js
new file mode 100644
index 0000000..0a52c6b
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/js2svg.js
@@ -0,0 +1,348 @@
+'use strict';
+
+var EOL = require('os').EOL,
+ textElem = require('../../plugins/_collections.js').elemsGroups.textContent.concat('title');
+
+var defaults = {
+ doctypeStart: '<!DOCTYPE',
+ doctypeEnd: '>',
+ procInstStart: '<?',
+ procInstEnd: '?>',
+ tagOpenStart: '<',
+ tagOpenEnd: '>',
+ tagCloseStart: '</',
+ tagCloseEnd: '>',
+ tagShortStart: '<',
+ tagShortEnd: '/>',
+ attrStart: '="',
+ attrEnd: '"',
+ commentStart: '<!--',
+ commentEnd: '-->',
+ cdataStart: '<![CDATA[',
+ cdataEnd: ']]>',
+ textStart: '',
+ textEnd: '',
+ indent: 4,
+ regEntities: /[&'"<>]/g,
+ regValEntities: /[&"<>]/g,
+ encodeEntity: encodeEntity,
+ pretty: false,
+ useShortTags: true
+};
+
+var entities = {
+ '&': '&',
+ '\'': ''',
+ '"': '"',
+ '>': '>',
+ '<': '<',
+ };
+
+/**
+ * Convert SVG-as-JS object to SVG (XML) string.
+ *
+ * @param {Object} data input data
+ * @param {Object} config config
+ *
+ * @return {Object} output data
+ */
+module.exports = function(data, config) {
+
+ return new JS2SVG(config).convert(data);
+
+};
+
+function JS2SVG(config) {
+
+ if (config) {
+ this.config = Object.assign({}, defaults, config);
+ } else {
+ this.config = Object.assign({}, defaults);
+ }
+
+ var indent = this.config.indent;
+ if (typeof indent == 'number' && !isNaN(indent)) {
+ this.config.indent = (indent < 0) ? '\t' : ' '.repeat(indent);
+ } else if (typeof indent != 'string') {
+ this.config.indent = ' ';
+ }
+
+ if (this.config.pretty) {
+ this.config.doctypeEnd += EOL;
+ this.config.procInstEnd += EOL;
+ this.config.commentEnd += EOL;
+ this.config.cdataEnd += EOL;
+ this.config.tagShortEnd += EOL;
+ this.config.tagOpenEnd += EOL;
+ this.config.tagCloseEnd += EOL;
+ this.config.textEnd += EOL;
+ }
+
+ this.indentLevel = 0;
+ this.textContext = null;
+
+}
+
+function encodeEntity(char) {
+ return entities[char];
+}
+
+/**
+ * Start conversion.
+ *
+ * @param {Object} data input data
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.convert = function(data) {
+
+ var svg = '';
+
+ if (data.content) {
+
+ this.indentLevel++;
+
+ data.content.forEach(function(item) {
+
+ if (item.elem) {
+ svg += this.createElem(item);
+ } else if (item.text) {
+ svg += this.createText(item.text);
+ } else if (item.doctype) {
+ svg += this.createDoctype(item.doctype);
+ } else if (item.processinginstruction) {
+ svg += this.createProcInst(item.processinginstruction);
+ } else if (item.comment) {
+ svg += this.createComment(item.comment);
+ } else if (item.cdata) {
+ svg += this.createCDATA(item.cdata);
+ }
+
+ }, this);
+
+ }
+
+ this.indentLevel--;
+
+ return {
+ data: svg,
+ info: {
+ width: this.width,
+ height: this.height
+ }
+ };
+
+};
+
+/**
+ * Create indent string in accordance with the current node level.
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createIndent = function() {
+
+ var indent = '';
+
+ if (this.config.pretty && !this.textContext) {
+ indent = this.config.indent.repeat(this.indentLevel - 1);
+ }
+
+ return indent;
+
+};
+
+/**
+ * Create doctype tag.
+ *
+ * @param {String} doctype doctype body string
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createDoctype = function(doctype) {
+
+ return this.config.doctypeStart +
+ doctype +
+ this.config.doctypeEnd;
+
+};
+
+/**
+ * Create XML Processing Instruction tag.
+ *
+ * @param {Object} instruction instruction object
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createProcInst = function(instruction) {
+
+ return this.config.procInstStart +
+ instruction.name +
+ ' ' +
+ instruction.body +
+ this.config.procInstEnd;
+
+};
+
+/**
+ * Create comment tag.
+ *
+ * @param {String} comment comment body
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createComment = function(comment) {
+
+ return this.config.commentStart +
+ comment +
+ this.config.commentEnd;
+
+};
+
+/**
+ * Create CDATA section.
+ *
+ * @param {String} cdata CDATA body
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createCDATA = function(cdata) {
+
+ return this.createIndent() +
+ this.config.cdataStart +
+ cdata +
+ this.config.cdataEnd;
+
+};
+
+/**
+ * Create element tag.
+ *
+ * @param {Object} data element object
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createElem = function(data) {
+
+ // beautiful injection for obtaining SVG information :)
+ if (
+ data.isElem('svg') &&
+ data.hasAttr('width') &&
+ data.hasAttr('height')
+ ) {
+ this.width = data.attr('width').value;
+ this.height = data.attr('height').value;
+ }
+
+ // empty element and short tag
+ if (data.isEmpty()) {
+ if (this.config.useShortTags) {
+ return this.createIndent() +
+ this.config.tagShortStart +
+ data.elem +
+ this.createAttrs(data) +
+ this.config.tagShortEnd;
+ } else {
+ return this.createIndent() +
+ this.config.tagShortStart +
+ data.elem +
+ this.createAttrs(data) +
+ this.config.tagOpenEnd +
+ this.config.tagCloseStart +
+ data.elem +
+ this.config.tagCloseEnd;
+ }
+ // non-empty element
+ } else {
+ var tagOpenStart = this.config.tagOpenStart,
+ tagOpenEnd = this.config.tagOpenEnd,
+ tagCloseStart = this.config.tagCloseStart,
+ tagCloseEnd = this.config.tagCloseEnd,
+ openIndent = this.createIndent(),
+ textIndent = '',
+ processedData = '',
+ dataEnd = '';
+
+ if (this.textContext) {
+ tagOpenStart = defaults.tagOpenStart;
+ tagOpenEnd = defaults.tagOpenEnd;
+ tagCloseStart = defaults.tagCloseStart;
+ tagCloseEnd = defaults.tagCloseEnd;
+ openIndent = '';
+ } else if (data.isElem(textElem)) {
+ if (this.config.pretty) {
+ textIndent += openIndent + this.config.indent;
+ }
+ this.textContext = data;
+ }
+
+ processedData += this.convert(data).data;
+
+ if (this.textContext == data) {
+ this.textContext = null;
+ if (this.config.pretty) dataEnd = EOL;
+ }
+
+ return openIndent +
+ tagOpenStart +
+ data.elem +
+ this.createAttrs(data) +
+ tagOpenEnd +
+ textIndent +
+ processedData +
+ dataEnd +
+ this.createIndent() +
+ tagCloseStart +
+ data.elem +
+ tagCloseEnd;
+
+ }
+
+};
+
+/**
+ * Create element attributes.
+ *
+ * @param {Object} elem attributes object
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createAttrs = function(elem) {
+
+ var attrs = '';
+
+ elem.eachAttr(function(attr) {
+
+ if (attr.value !== undefined) {
+ attrs += ' ' +
+ attr.name +
+ this.config.attrStart +
+ String(attr.value).replace(this.config.regValEntities, this.config.encodeEntity) +
+ this.config.attrEnd;
+ }
+ else {
+ attrs += ' ' +
+ attr.name;
+ }
+
+
+ }, this);
+
+ return attrs;
+
+};
+
+/**
+ * Create text node.
+ *
+ * @param {String} text text
+ *
+ * @return {String}
+ */
+JS2SVG.prototype.createText = function(text) {
+
+ return this.createIndent() +
+ this.config.textStart +
+ text.replace(this.config.regEntities, this.config.encodeEntity) +
+ (this.textContext ? '' : this.config.textEnd);
+
+};
diff --git a/node_modules/svgo/lib/svgo/jsAPI.js b/node_modules/svgo/lib/svgo/jsAPI.js
new file mode 100644
index 0000000..4cf958c
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/jsAPI.js
@@ -0,0 +1,372 @@
+'use strict';
+
+var cssSelect = require('css-select');
+
+var svgoCssSelectAdapter = require('./css-select-adapter');
+var cssSelectOpts = {
+ xmlMode: true,
+ adapter: svgoCssSelectAdapter
+};
+
+var JSAPI = module.exports = function(data, parentNode) {
+ Object.assign(this, data);
+ if (parentNode) {
+ Object.defineProperty(this, 'parentNode', {
+ writable: true,
+ value: parentNode
+ });
+ }
+};
+
+/**
+ * Perform a deep clone of this node.
+ *
+ * @return {Object} element
+ */
+JSAPI.prototype.clone = function() {
+ var node = this;
+ var nodeData = {};
+
+ Object.keys(node).forEach(function(key) {
+ if (key !== 'class' && key !== 'style' && key !== 'content') {
+ nodeData[key] = node[key];
+ }
+ });
+
+ // Deep-clone node data.
+ nodeData = JSON.parse(JSON.stringify(nodeData));
+
+ // parentNode gets set to a proper object by the parent clone,
+ // but it needs to be true/false now to do the right thing
+ // in the constructor.
+ var clonedNode = new JSAPI(nodeData, !!node.parentNode);
+
+ if (node.class) {
+ clonedNode.class = node.class.clone(clonedNode);
+ }
+ if (node.style) {
+ clonedNode.style = node.style.clone(clonedNode);
+ }
+ if (node.content) {
+ clonedNode.content = node.content.map(function(childNode) {
+ var clonedChild = childNode.clone();
+ clonedChild.parentNode = clonedNode;
+ return clonedChild;
+ });
+ }
+
+ return clonedNode;
+};
+
+/**
+ * Determine if item is an element
+ * (any, with a specific name or in a names array).
+ *
+ * @param {String|Array} [param] element name or names arrays
+ * @return {Boolean}
+ */
+JSAPI.prototype.isElem = function(param) {
+
+ if (!param) return !!this.elem;
+
+ if (Array.isArray(param)) return !!this.elem && (param.indexOf(this.elem) > -1);
+
+ return !!this.elem && this.elem === param;
+
+};
+
+/**
+ * Renames an element
+ *
+ * @param {String} name new element name
+ * @return {Object} element
+ */
+JSAPI.prototype.renameElem = function(name) {
+
+ if (name && typeof name === 'string')
+ this.elem = this.local = name;
+
+ return this;
+
+};
+
+/**
+ * Determine if element is empty.
+ *
+ * @return {Boolean}
+ */
+ JSAPI.prototype.isEmpty = function() {
+
+ return !this.content || !this.content.length;
+
+};
+
+/**
+ * Find the closest ancestor of the current element.
+ * @param elemName
+ *
+ * @return {?Object}
+ */
+ JSAPI.prototype.closestElem = function(elemName) {
+ var elem = this;
+
+ while ((elem = elem.parentNode) && !elem.isElem(elemName));
+
+ return elem;
+};
+
+/**
+ * Changes content by removing elements and/or adding new elements.
+ *
+ * @param {Number} start Index at which to start changing the content.
+ * @param {Number} n Number of elements to remove.
+ * @param {Array|Object} [insertion] Elements to add to the content.
+ * @return {Array} Removed elements.
+ */
+ JSAPI.prototype.spliceContent = function(start, n, insertion) {
+
+ if (arguments.length < 2) return [];
+
+ if (!Array.isArray(insertion))
+ insertion = Array.apply(null, arguments).slice(2);
+
+ insertion.forEach(function(inner) { inner.parentNode = this }, this);
+
+ return this.content.splice.apply(this.content, [start, n].concat(insertion));
+
+
+};
+
+/**
+ * Determine if element has an attribute
+ * (any, or by name or by name + value).
+ *
+ * @param {String} [name] attribute name
+ * @param {String} [val] attribute value (will be toString()'ed)
+ * @return {Boolean}
+ */
+ JSAPI.prototype.hasAttr = function(name, val) {
+
+ if (!this.attrs || !Object.keys(this.attrs).length) return false;
+
+ if (!arguments.length) return !!this.attrs;
+
+ if (val !== undefined) return !!this.attrs[name] && this.attrs[name].value === val.toString();
+
+ return !!this.attrs[name];
+
+};
+
+/**
+ * Determine if element has an attribute by local name
+ * (any, or by name or by name + value).
+ *
+ * @param {String} [localName] local attribute name
+ * @param {Number|String|RegExp|Function} [val] attribute value (will be toString()'ed or executed, otherwise ignored)
+ * @return {Boolean}
+ */
+ JSAPI.prototype.hasAttrLocal = function(localName, val) {
+
+ if (!this.attrs || !Object.keys(this.attrs).length) return false;
+
+ if (!arguments.length) return !!this.attrs;
+
+ var callback;
+
+ switch (val != null && val.constructor && val.constructor.name) {
+ case 'Number': // same as String
+ case 'String': callback = stringValueTest; break;
+ case 'RegExp': callback = regexpValueTest; break;
+ case 'Function': callback = funcValueTest; break;
+ default: callback = nameTest;
+ }
+ return this.someAttr(callback);
+
+ function nameTest(attr) {
+ return attr.local === localName;
+ }
+
+ function stringValueTest(attr) {
+ return attr.local === localName && val == attr.value;
+ }
+
+ function regexpValueTest(attr) {
+ return attr.local === localName && val.test(attr.value);
+ }
+
+ function funcValueTest(attr) {
+ return attr.local === localName && val(attr.value);
+ }
+
+};
+
+/**
+ * Get a specific attribute from an element
+ * (by name or name + value).
+ *
+ * @param {String} name attribute name
+ * @param {String} [val] attribute value (will be toString()'ed)
+ * @return {Object|Undefined}
+ */
+ JSAPI.prototype.attr = function(name, val) {
+
+ if (!this.hasAttr() || !arguments.length) return undefined;
+
+ if (val !== undefined) return this.hasAttr(name, val) ? this.attrs[name] : undefined;
+
+ return this.attrs[name];
+
+};
+
+/**
+ * Get computed attribute value from an element
+ *
+ * @param {String} name attribute name
+ * @return {Object|Undefined}
+ */
+ JSAPI.prototype.computedAttr = function(name, val) {
+ /* jshint eqnull: true */
+ if (!arguments.length) return;
+
+ for (var elem = this; elem && (!elem.hasAttr(name) || !elem.attr(name).value); elem = elem.parentNode);
+
+ if (val != null) {
+ return elem ? elem.hasAttr(name, val) : false;
+ } else if (elem && elem.hasAttr(name)) {
+ return elem.attrs[name].value;
+ }
+
+};
+
+/**
+ * Remove a specific attribute.
+ *
+ * @param {String|Array} name attribute name
+ * @param {String} [val] attribute value
+ * @return {Boolean}
+ */
+ JSAPI.prototype.removeAttr = function(name, val, recursive) {
+
+ if (!arguments.length) return false;
+
+ if (Array.isArray(name)) {
+ name.forEach(this.removeAttr, this);
+ return false;
+ }
+
+ if (!this.hasAttr(name)) return false;
+
+ if (!recursive && val && this.attrs[name].value !== val) return false;
+
+ delete this.attrs[name];
+
+ if (!Object.keys(this.attrs).length) delete this.attrs;
+
+ return true;
+
+};
+
+/**
+ * Add attribute.
+ *
+ * @param {Object} [attr={}] attribute object
+ * @return {Object|Boolean} created attribute or false if no attr was passed in
+ */
+ JSAPI.prototype.addAttr = function(attr) {
+ attr = attr || {};
+
+ if (attr.name === undefined ||
+ attr.prefix === undefined ||
+ attr.local === undefined
+ ) return false;
+
+ this.attrs = this.attrs || {};
+ this.attrs[attr.name] = attr;
+
+ if(attr.name === 'class') { // newly added class attribute
+ this.class.hasClass();
+ }
+
+ if(attr.name === 'style') { // newly added style attribute
+ this.style.hasStyle();
+ }
+
+ return this.attrs[attr.name];
+
+};
+
+/**
+ * Iterates over all attributes.
+ *
+ * @param {Function} callback callback
+ * @param {Object} [context] callback context
+ * @return {Boolean} false if there are no any attributes
+ */
+ JSAPI.prototype.eachAttr = function(callback, context) {
+
+ if (!this.hasAttr()) return false;
+
+ for (var name in this.attrs) {
+ callback.call(context, this.attrs[name]);
+ }
+
+ return true;
+
+};
+
+/**
+ * Tests whether some attribute passes the test.
+ *
+ * @param {Function} callback callback
+ * @param {Object} [context] callback context
+ * @return {Boolean} false if there are no any attributes
+ */
+ JSAPI.prototype.someAttr = function(callback, context) {
+
+ if (!this.hasAttr()) return false;
+
+ for (var name in this.attrs) {
+ if (callback.call(context, this.attrs[name])) return true;
+ }
+
+ return false;
+
+};
+
+/**
+ * Evaluate a string of CSS selectors against the element and returns matched elements.
+ *
+ * @param {String} selectors CSS selector(s) string
+ * @return {Array} null if no elements matched
+ */
+ JSAPI.prototype.querySelectorAll = function(selectors) {
+
+ var matchedEls = cssSelect(selectors, this, cssSelectOpts);
+
+ return matchedEls.length > 0 ? matchedEls : null;
+
+};
+
+/**
+ * Evaluate a string of CSS selectors against the element and returns only the first matched element.
+ *
+ * @param {String} selectors CSS selector(s) string
+ * @return {Array} null if no element matched
+ */
+ JSAPI.prototype.querySelector = function(selectors) {
+
+ return cssSelect.selectOne(selectors, this, cssSelectOpts);
+
+};
+
+/**
+ * Test if a selector matches a given element.
+ *
+ * @param {String} selector CSS selector string
+ * @return {Boolean} true if element would be selected by selector string, false if it does not
+ */
+ JSAPI.prototype.matches = function(selector) {
+
+ return cssSelect.is(this, selector, cssSelectOpts);
+
+};
diff --git a/node_modules/svgo/lib/svgo/plugins.js b/node_modules/svgo/lib/svgo/plugins.js
new file mode 100644
index 0000000..a317f5b
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/plugins.js
@@ -0,0 +1,101 @@
+'use strict';
+
+/**
+ * Plugins engine.
+ *
+ * @module plugins
+ *
+ * @param {Object} data input data
+ * @param {Object} info extra information
+ * @param {Object} plugins plugins object from config
+ * @return {Object} output data
+ */
+module.exports = function(data, info, plugins) {
+
+ plugins.forEach(function(group) {
+
+ switch(group[0].type) {
+ case 'perItem':
+ data = perItem(data, info, group);
+ break;
+ case 'perItemReverse':
+ data = perItem(data, info, group, true);
+ break;
+ case 'full':
+ data = full(data, info, group);
+ break;
+ }
+
+ });
+
+ return data;
+
+};
+
+/**
+ * Direct or reverse per-item loop.
+ *
+ * @param {Object} data input data
+ * @param {Object} info extra information
+ * @param {Array} plugins plugins list to process
+ * @param {Boolean} [reverse] reverse pass?
+ * @return {Object} output data
+ */
+function perItem(data, info, plugins, reverse) {
+
+ function monkeys(items) {
+
+ items.content = items.content.filter(function(item) {
+
+ // reverse pass
+ if (reverse && item.content) {
+ monkeys(item);
+ }
+
+ // main filter
+ var filter = true;
+
+ for (var i = 0; filter && i < plugins.length; i++) {
+ var plugin = plugins[i];
+
+ if (plugin.active && plugin.fn(item, plugin.params, info) === false) {
+ filter = false;
+ }
+ }
+
+ // direct pass
+ if (!reverse && item.content) {
+ monkeys(item);
+ }
+
+ return filter;
+
+ });
+
+ return items;
+
+ }
+
+ return monkeys(data);
+
+}
+
+/**
+ * "Full" plugins.
+ *
+ * @param {Object} data input data
+ * @param {Object} info extra information
+ * @param {Array} plugins plugins list to process
+ * @return {Object} output data
+ */
+function full(data, info, plugins) {
+
+ plugins.forEach(function(plugin) {
+ if (plugin.active) {
+ data = plugin.fn(data, plugin.params, info);
+ }
+ });
+
+ return data;
+
+}
diff --git a/node_modules/svgo/lib/svgo/svg2js.js b/node_modules/svgo/lib/svgo/svg2js.js
new file mode 100644
index 0000000..6bba13e
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/svg2js.js
@@ -0,0 +1,200 @@
+'use strict';
+
+var SAX = require('sax'),
+ JSAPI = require('./jsAPI.js'),
+ CSSClassList = require('./css-class-list'),
+ CSSStyleDeclaration = require('./css-style-declaration'),
+ entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^\']+)'|"([^\"]+)")\s*>/g;
+
+var config = {
+ strict: true,
+ trim: false,
+ normalize: true,
+ lowercase: true,
+ xmlns: true,
+ position: true
+};
+
+/**
+ * Convert SVG (XML) string to SVG-as-JS object.
+ *
+ * @param {String} data input data
+ * @param {Function} callback
+ */
+module.exports = function(data, callback) {
+
+ var sax = SAX.parser(config.strict, config),
+ root = new JSAPI({ elem: '#document', content: [] }),
+ current = root,
+ stack = [root],
+ textContext = null,
+ parsingError = false;
+
+ function pushToContent(content) {
+
+ content = new JSAPI(content, current);
+
+ (current.content = current.content || []).push(content);
+
+ return content;
+
+ }
+
+ sax.ondoctype = function(doctype) {
+
+ pushToContent({
+ doctype: doctype
+ });
+
+ var subsetStart = doctype.indexOf('['),
+ entityMatch;
+
+ if (subsetStart >= 0) {
+ entityDeclaration.lastIndex = subsetStart;
+
+ while ((entityMatch = entityDeclaration.exec(data)) != null) {
+ sax.ENTITIES[entityMatch[1]] = entityMatch[2] || entityMatch[3];
+ }
+ }
+ };
+
+ sax.onprocessinginstruction = function(data) {
+
+ pushToContent({
+ processinginstruction: data
+ });
+
+ };
+
+ sax.oncomment = function(comment) {
+
+ pushToContent({
+ comment: comment.trim()
+ });
+
+ };
+
+ sax.oncdata = function(cdata) {
+
+ pushToContent({
+ cdata: cdata
+ });
+
+ };
+
+ sax.onopentag = function(data) {
+
+ var elem = {
+ elem: data.name,
+ prefix: data.prefix,
+ local: data.local,
+ attrs: {}
+ };
+
+ elem.class = new CSSClassList(elem);
+ elem.style = new CSSStyleDeclaration(elem);
+
+ if (Object.keys(data.attributes).length) {
+ for (var name in data.attributes) {
+
+ if (name === 'class') { // has class attribute
+ elem.class.hasClass();
+ }
+
+ if (name === 'style') { // has style attribute
+ elem.style.hasStyle();
+ }
+
+ elem.attrs[name] = {
+ name: name,
+ value: data.attributes[name].value,
+ prefix: data.attributes[name].prefix,
+ local: data.attributes[name].local
+ };
+ }
+ }
+
+ elem = pushToContent(elem);
+ current = elem;
+
+ // Save info about <text> tag to prevent trimming of meaningful whitespace
+ if (data.name == 'text' && !data.prefix) {
+ textContext = current;
+ }
+
+ stack.push(elem);
+
+ };
+
+ sax.ontext = function(text) {
+
+ if (/\S/.test(text) || textContext) {
+
+ if (!textContext)
+ text = text.trim();
+
+ pushToContent({
+ text: text
+ });
+
+ }
+
+ };
+
+ sax.onclosetag = function() {
+
+ var last = stack.pop();
+
+ // Trim text inside <text> tag.
+ if (last == textContext) {
+ trim(textContext);
+ textContext = null;
+ }
+ current = stack[stack.length - 1];
+
+ };
+
+ sax.onerror = function(e) {
+
+ e.message = 'Error in parsing SVG: ' + e.message;
+ if (e.message.indexOf('Unexpected end') < 0) {
+ throw e;
+ }
+
+ };
+
+ sax.onend = function() {
+
+ if (!this.error) {
+ callback(root);
+ } else {
+ callback({ error: this.error.message });
+ }
+
+ };
+
+ try {
+ sax.write(data);
+ } catch (e) {
+ callback({ error: e.message });
+ parsingError = true;
+ }
+ if (!parsingError) sax.close();
+
+ function trim(elem) {
+ if (!elem.content) return elem;
+
+ var start = elem.content[0],
+ end = elem.content[elem.content.length - 1];
+
+ while (start && start.content && !start.text) start = start.content[0];
+ if (start && start.text) start.text = start.text.replace(/^\s+/, '');
+
+ while (end && end.content && !end.text) end = end.content[end.content.length - 1];
+ if (end && end.text) end.text = end.text.replace(/\s+$/, '');
+
+ return elem;
+
+ }
+
+};
diff --git a/node_modules/svgo/lib/svgo/tools.js b/node_modules/svgo/lib/svgo/tools.js
new file mode 100644
index 0000000..ed426d4
--- /dev/null
+++ b/node_modules/svgo/lib/svgo/tools.js
@@ -0,0 +1,155 @@
+'use strict';
+
+var FS = require('fs');
+
+/**
+ * Encode plain SVG data string into Data URI string.
+ *
+ * @param {String} str input string
+ * @param {String} type Data URI type
+ * @return {String} output string
+ */
+exports.encodeSVGDatauri = function(str, type) {
+ var prefix = 'data:image/svg+xml';
+ if (!type || type === 'base64') {
+ // base64
+ prefix += ';base64,';
+ if (Buffer.from) {
+ str = prefix + Buffer.from(str).toString('base64');
+ } else {
+ str = prefix + new Buffer(str).toString('base64');
+ }
+ } else if (type === 'enc') {
+ // URI encoded
+ str = prefix + ',' + encodeURIComponent(str);
+ } else if (type === 'unenc') {
+ // unencoded
+ str = prefix + ',' + str;
+ }
+ return str;
+};
+
+/**
+ * Decode SVG Data URI string into plain SVG string.
+ *
+ * @param {string} str input string
+ * @return {String} output string
+ */
+exports.decodeSVGDatauri = function(str) {
+ var regexp = /data:image\/svg\+xml(;charset=[^;,]*)?(;base64)?,(.*)/;
+ var match = regexp.exec(str);
+
+ // plain string
+ if (!match) return str;
+
+ var data = match[3];
+
+ if (match[2]) {
+ // base64
+ str = new Buffer(data, 'base64').toString('utf8');
+ } else if (data.charAt(0) === '%') {
+ // URI encoded
+ str = decodeURIComponent(data);
+ } else if (data.charAt(0) === '<') {
+ // unencoded
+ str = data;
+ }
+ return str;
+};
+
+exports.intersectArrays = function(a, b) {
+ return a.filter(function(n) {
+ return b.indexOf(n) > -1;
+ });
+};
+
+/**
+ * Convert a row of numbers to an optimized string view.
+ *
+ * @example
+ * [0, -1, .5, .5] → "0-1 .5.5"
+ *
+ * @param {number[]} data
+ * @param {Object} params
+ * @param {string?} command path data instruction
+ * @return {string}
+ */
+exports.cleanupOutData = function(data, params, command) {
+ var str = '',
+ delimiter,
+ prev;
+
+ data.forEach(function(item, i) {
+ // space delimiter by default
+ delimiter = ' ';
+
+ // no extra space in front of first number
+ if (i == 0) delimiter = '';
+
+ // no extra space after 'arcto' command flags
+ if (params.noSpaceAfterFlags && (command == 'A' || command == 'a')) {
+ var pos = i % 7;
+ if (pos == 4 || pos == 5) delimiter = '';
+ }
+
+ // remove floating-point numbers leading zeros
+ // 0.5 → .5
+ // -0.5 → -.5
+ if (params.leadingZero) {
+ item = removeLeadingZero(item);
+ }
+
+ // no extra space in front of negative number or
+ // in front of a floating number if a previous number is floating too
+ if (
+ params.negativeExtraSpace &&
+ delimiter != '' &&
+ (item < 0 ||
+ (String(item).charCodeAt(0) == 46 && prev % 1 !== 0)
+ )
+ ) {
+ delimiter = '';
+ }
+ // save prev item value
+ prev = item;
+ str += delimiter + item;
+ });
+ return str;
+};
+
+/**
+ * Remove floating-point numbers leading zero.
+ *
+ * @example
+ * 0.5 → .5
+ *
+ * @example
+ * -0.5 → -.5
+ *
+ * @param {Float} num input number
+ *
+ * @return {String} output number as string
+ */
+var removeLeadingZero = exports.removeLeadingZero = function(num) {
+ var strNum = num.toString();
+
+ if (0 < num && num < 1 && strNum.charCodeAt(0) == 48) {
+ strNum = strNum.slice(1);
+ } else if (-1 < num && num < 0 && strNum.charCodeAt(1) == 48) {
+ strNum = strNum.charAt(0) + strNum.slice(2);
+ }
+ return strNum;
+};
+
+
+/**
+ * Synchronously check if path is a directory. Tolerant to errors like ENOENT.
+ * @param {string} path
+ */
+exports.checkIsDir = function(path) {
+ try {
+ return FS.lstatSync(path).isDirectory();
+ } catch(e) {
+ return false;
+ }
+};
diff --git a/node_modules/svgo/node_modules/.bin/mkdirp b/node_modules/svgo/node_modules/.bin/mkdirp
new file mode 100644
index 0000000..bcd333f
--- /dev/null
+++ b/node_modules/svgo/node_modules/.bin/mkdirp
@@ -0,0 +1,15 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ "$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@"
+ ret=$?
+else
+ node "$basedir/../mkdirp/bin/cmd.js" "$@"
+ ret=$?
+fi
+exit $ret
diff --git a/node_modules/svgo/node_modules/.bin/mkdirp.cmd b/node_modules/svgo/node_modules/.bin/mkdirp.cmd
new file mode 100644
index 0000000..c2c9350
--- /dev/null
+++ b/node_modules/svgo/node_modules/.bin/mkdirp.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+"%_prog%" "%dp0%\..\mkdirp\bin\cmd.js" %*
+ENDLOCAL
+EXIT /b %errorlevel%
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
diff --git a/node_modules/svgo/node_modules/.bin/mkdirp.ps1 b/node_modules/svgo/node_modules/.bin/mkdirp.ps1
new file mode 100644
index 0000000..35ce690
--- /dev/null
+++ b/node_modules/svgo/node_modules/.bin/mkdirp.ps1
@@ -0,0 +1,18 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ & "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
+ $ret=$LASTEXITCODE
+} else {
+ & "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/node_modules/svgo/node_modules/ansi-styles/index.js b/node_modules/svgo/node_modules/ansi-styles/index.js
new file mode 100644
index 0000000..90a871c
--- /dev/null
+++ b/node_modules/svgo/node_modules/ansi-styles/index.js
@@ -0,0 +1,165 @@
+'use strict';
+const colorConvert = require('color-convert');
+
+const wrapAnsi16 = (fn, offset) => function () {
+ const code = fn.apply(colorConvert, arguments);
+ return `\u001B[${code + offset}m`;
+};
+
+const wrapAnsi256 = (fn, offset) => function () {
+ const code = fn.apply(colorConvert, arguments);
+ return `\u001B[${38 + offset};5;${code}m`;
+};
+
+const wrapAnsi16m = (fn, offset) => function () {
+ const rgb = fn.apply(colorConvert, arguments);
+ return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
+};
+
+function assembleStyles() {
+ const codes = new Map();
+ const styles = {
+ modifier: {
+ reset: [0, 0],
+ // 21 isn't widely supported and 22 does the same thing
+ bold: [1, 22],
+ dim: [2, 22],
+ italic: [3, 23],
+ underline: [4, 24],
+ inverse: [7, 27],
+ hidden: [8, 28],
+ strikethrough: [9, 29]
+ },
+ color: {
+ black: [30, 39],
+ red: [31, 39],
+ green: [32, 39],
+ yellow: [33, 39],
+ blue: [34, 39],
+ magenta: [35, 39],
+ cyan: [36, 39],
+ white: [37, 39],
+ gray: [90, 39],
+
+ // Bright color
+ redBright: [91, 39],
+ greenBright: [92, 39],
+ yellowBright: [93, 39],
+ blueBright: [94, 39],
+ magentaBright: [95, 39],
+ cyanBright: [96, 39],
+ whiteBright: [97, 39]
+ },
+ bgColor: {
+ bgBlack: [40, 49],
+ bgRed: [41, 49],
+ bgGreen: [42, 49],
+ bgYellow: [43, 49],
+ bgBlue: [44, 49],
+ bgMagenta: [45, 49],
+ bgCyan: [46, 49],
+ bgWhite: [47, 49],
+
+ // Bright color
+ bgBlackBright: [100, 49],
+ bgRedBright: [101, 49],
+ bgGreenBright: [102, 49],
+ bgYellowBright: [103, 49],
+ bgBlueBright: [104, 49],
+ bgMagentaBright: [105, 49],
+ bgCyanBright: [106, 49],
+ bgWhiteBright: [107, 49]
+ }
+ };
+
+ // Fix humans
+ styles.color.grey = styles.color.gray;
+
+ for (const groupName of Object.keys(styles)) {
+ const group = styles[groupName];
+
+ for (const styleName of Object.keys(group)) {
+ const style = group[styleName];
+
+ styles[styleName] = {
+ open: `\u001B[${style[0]}m`,
+ close: `\u001B[${style[1]}m`
+ };
+
+ group[styleName] = styles[styleName];
+
+ codes.set(style[0], style[1]);
+ }
+
+ Object.defineProperty(styles, groupName, {
+ value: group,
+ enumerable: false
+ });
+
+ Object.defineProperty(styles, 'codes', {
+ value: codes,
+ enumerable: false
+ });
+ }
+
+ const ansi2ansi = n => n;
+ const rgb2rgb = (r, g, b) => [r, g, b];
+
+ styles.color.close = '\u001B[39m';
+ styles.bgColor.close = '\u001B[49m';
+
+ styles.color.ansi = {
+ ansi: wrapAnsi16(ansi2ansi, 0)
+ };
+ styles.color.ansi256 = {
+ ansi256: wrapAnsi256(ansi2ansi, 0)
+ };
+ styles.color.ansi16m = {
+ rgb: wrapAnsi16m(rgb2rgb, 0)
+ };
+
+ styles.bgColor.ansi = {
+ ansi: wrapAnsi16(ansi2ansi, 10)
+ };
+ styles.bgColor.ansi256 = {
+ ansi256: wrapAnsi256(ansi2ansi, 10)
+ };
+ styles.bgColor.ansi16m = {
+ rgb: wrapAnsi16m(rgb2rgb, 10)
+ };
+
+ for (let key of Object.keys(colorConvert)) {
+ if (typeof colorConvert[key] !== 'object') {
+ continue;
+ }
+
+ const suite = colorConvert[key];
+
+ if (key === 'ansi16') {
+ key = 'ansi';
+ }
+
+ if ('ansi16' in suite) {
+ styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0);
+ styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10);
+ }
+
+ if ('ansi256' in suite) {
+ styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0);
+ styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10);
+ }
+
+ if ('rgb' in suite) {
+ styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0);
+ styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10);
+ }
+ }
+
+ return styles;
+}
+
+// Make the export immutable
+Object.defineProperty(module, 'exports', {
+ enumerable: true,
+ get: assembleStyles
+});
diff --git a/node_modules/svgo/node_modules/ansi-styles/license b/node_modules/svgo/node_modules/ansi-styles/license
new file mode 100644
index 0000000..e7af2f7
--- /dev/null
+++ b/node_modules/svgo/node_modules/ansi-styles/license
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
diff --git a/node_modules/svgo/node_modules/ansi-styles/package.json b/node_modules/svgo/node_modules/ansi-styles/package.json
new file mode 100644
index 0000000..bdf0795
--- /dev/null
+++ b/node_modules/svgo/node_modules/ansi-styles/package.json
@@ -0,0 +1,88 @@
+{
+ "_from": "ansi-styles@^3.2.1",
+ "_id": "ansi-styles@3.2.1",
+ "_inBundle": false,
+ "_integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "_location": "/svgo/ansi-styles",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "ansi-styles@^3.2.1",
+ "name": "ansi-styles",
+ "escapedName": "ansi-styles",
+ "rawSpec": "^3.2.1",
+ "saveSpec": null,
+ "fetchSpec": "^3.2.1"
+ },
+ "_requiredBy": [
+ "/svgo/chalk"
+ ],
+ "_resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "_shasum": "41fbb20243e50b12be0f04b8dedbf07520ce841d",
+ "_spec": "ansi-styles@^3.2.1",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo\\node_modules\\chalk",
+ "author": {
+ "name": "Sindre Sorhus",
+ "email": "sindresorhus@gmail.com",
+ "url": "sindresorhus.com"
+ },
+ "ava": {
+ "require": "babel-polyfill"
+ },
+ "bugs": {
+ "url": "https://github.com/chalk/ansi-styles/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "deprecated": false,
+ "description": "ANSI escape codes for styling strings in the terminal",
+ "devDependencies": {
+ "ava": "*",
+ "babel-polyfill": "^6.23.0",
+ "svg-term-cli": "^2.1.1",
+ "xo": "*"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "files": [
+ "index.js"
+ ],
+ "homepage": "https://github.com/chalk/ansi-styles#readme",
+ "keywords": [
+ "ansi",
+ "styles",
+ "color",
+ "colour",
+ "colors",
+ "terminal",
+ "console",
+ "cli",
+ "string",
+ "tty",
+ "escape",
+ "formatting",
+ "rgb",
+ "256",
+ "shell",
+ "xterm",
+ "log",
+ "logging",
+ "command-line",
+ "text"
+ ],
+ "license": "MIT",
+ "name": "ansi-styles",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/chalk/ansi-styles.git"
+ },
+ "scripts": {
+ "screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor",
+ "test": "xo && ava"
+ },
+ "version": "3.2.1"
+}
diff --git a/node_modules/svgo/node_modules/ansi-styles/readme.md b/node_modules/svgo/node_modules/ansi-styles/readme.md
new file mode 100644
index 0000000..3158e2d
--- /dev/null
+++ b/node_modules/svgo/node_modules/ansi-styles/readme.md
@@ -0,0 +1,147 @@
+# ansi-styles [](https://travis-ci.org/chalk/ansi-styles)
+
+> [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal
+
+You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.
+
+<img src="https://cdn.rawgit.com/chalk/ansi-styles/8261697c95bf34b6c7767e2cbe9941a851d59385/screenshot.svg" width="900">
+
+
+## Install
+
+```
+$ npm install ansi-styles
+```
+
+
+## Usage
+
+```js
+const style = require('ansi-styles');
+
+console.log(`${style.green.open}Hello world!${style.green.close}`);
+
+
+// Color conversion between 16/256/truecolor
+// NOTE: If conversion goes to 16 colors or 256 colors, the original color
+// may be degraded to fit that color palette. This means terminals
+// that do not support 16 million colors will best-match the
+// original color.
+console.log(style.bgColor.ansi.hsl(120, 80, 72) + 'Hello world!' + style.bgColor.close);
+console.log(style.color.ansi256.rgb(199, 20, 250) + 'Hello world!' + style.color.close);
+console.log(style.color.ansi16m.hex('#ABCDEF') + 'Hello world!' + style.color.close);
+```
+
+## API
+
+Each style has an `open` and `close` property.
+
+
+## Styles
+
+### Modifiers
+
+- `reset`
+- `bold`
+- `dim`
+- `italic` *(Not widely supported)*
+- `underline`
+- `inverse`
+- `hidden`
+- `strikethrough` *(Not widely supported)*
+
+### Colors
+
+- `black`
+- `red`
+- `green`
+- `yellow`
+- `blue`
+- `magenta`
+- `cyan`
+- `white`
+- `gray` ("bright black")
+- `redBright`
+- `greenBright`
+- `yellowBright`
+- `blueBright`
+- `magentaBright`
+- `cyanBright`
+- `whiteBright`
+
+### Background colors
+
+- `bgBlack`
+- `bgRed`
+- `bgGreen`
+- `bgYellow`
+- `bgBlue`
+- `bgMagenta`
+- `bgCyan`
+- `bgWhite`
+- `bgBlackBright`
+- `bgRedBright`
+- `bgGreenBright`
+- `bgYellowBright`
+- `bgBlueBright`
+- `bgMagentaBright`
+- `bgCyanBright`
+- `bgWhiteBright`
+
+
+## Advanced usage
+
+By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.
+
+- `style.modifier`
+- `style.color`
+- `style.bgColor`
+
+###### Example
+
+```js
+console.log(style.color.green.open);
+```
+
+Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values.
+
+###### Example
+
+```js
+console.log(style.codes.get(36));
+//=> 39
+```
+
+
+## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
+
+`ansi-styles` uses the [`color-convert`](https://github.com/Qix-/color-convert) package to allow for converting between various colors and ANSI escapes, with support for 256 and 16 million colors.
+
+To use these, call the associated conversion function with the intended output, for example:
+
+```js
+style.color.ansi.rgb(100, 200, 15); // RGB to 16 color ansi foreground code
+style.bgColor.ansi.rgb(100, 200, 15); // RGB to 16 color ansi background code
+
+style.color.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
+style.bgColor.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
+
+style.color.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color foreground code
+style.bgColor.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color background code
+```
+
+
+## Related
+
+- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal
+
+
+## Maintainers
+
+- [Sindre Sorhus](https://github.com/sindresorhus)
+- [Josh Junon](https://github.com/qix-)
+
+
+## License
+
+MIT
diff --git a/node_modules/svgo/node_modules/chalk/index.js b/node_modules/svgo/node_modules/chalk/index.js
new file mode 100644
index 0000000..1cc5fa8
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/index.js
@@ -0,0 +1,228 @@
+'use strict';
+const escapeStringRegexp = require('escape-string-regexp');
+const ansiStyles = require('ansi-styles');
+const stdoutColor = require('supports-color').stdout;
+
+const template = require('./templates.js');
+
+const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
+
+// `supportsColor.level` → `ansiStyles.color[name]` mapping
+const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];
+
+// `color-convert` models to exclude from the Chalk API due to conflicts and such
+const skipModels = new Set(['gray']);
+
+const styles = Object.create(null);
+
+function applyOptions(obj, options) {
+ options = options || {};
+
+ // Detect level if not set manually
+ const scLevel = stdoutColor ? stdoutColor.level : 0;
+ obj.level = options.level === undefined ? scLevel : options.level;
+ obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
+}
+
+function Chalk(options) {
+ // We check for this.template here since calling `chalk.constructor()`
+ // by itself will have a `this` of a previously constructed chalk object
+ if (!this || !(this instanceof Chalk) || this.template) {
+ const chalk = {};
+ applyOptions(chalk, options);
+
+ chalk.template = function () {
+ const args = [].slice.call(arguments);
+ return chalkTag.apply(null, [chalk.template].concat(args));
+ };
+
+ Object.setPrototypeOf(chalk, Chalk.prototype);
+ Object.setPrototypeOf(chalk.template, chalk);
+
+ chalk.template.constructor = Chalk;
+
+ return chalk.template;
+ }
+
+ applyOptions(this, options);
+}
+
+// Use bright blue on Windows as the normal blue color is illegible
+if (isSimpleWindowsTerm) {
+ ansiStyles.blue.open = '\u001B[94m';
+}
+
+for (const key of Object.keys(ansiStyles)) {
+ ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
+
+ styles[key] = {
+ get() {
+ const codes = ansiStyles[key];
+ return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key);
+ }
+ };
+}
+
+styles.visible = {
+ get() {
+ return build.call(this, this._styles || [], true, 'visible');
+ }
+};
+
+ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g');
+for (const model of Object.keys(ansiStyles.color.ansi)) {
+ if (skipModels.has(model)) {
+ continue;
+ }
+
+ styles[model] = {
+ get() {
+ const level = this.level;
+ return function () {
+ const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments);
+ const codes = {
+ open,
+ close: ansiStyles.color.close,
+ closeRe: ansiStyles.color.closeRe
+ };
+ return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
+ };
+ }
+ };
+}
+
+ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g');
+for (const model of Object.keys(ansiStyles.bgColor.ansi)) {
+ if (skipModels.has(model)) {
+ continue;
+ }
+
+ const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
+ styles[bgModel] = {
+ get() {
+ const level = this.level;
+ return function () {
+ const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments);
+ const codes = {
+ open,
+ close: ansiStyles.bgColor.close,
+ closeRe: ansiStyles.bgColor.closeRe
+ };
+ return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
+ };
+ }
+ };
+}
+
+const proto = Object.defineProperties(() => {}, styles);
+
+function build(_styles, _empty, key) {
+ const builder = function () {
+ return applyStyle.apply(builder, arguments);
+ };
+
+ builder._styles = _styles;
+ builder._empty = _empty;
+
+ const self = this;
+
+ Object.defineProperty(builder, 'level', {
+ enumerable: true,
+ get() {
+ return self.level;
+ },
+ set(level) {
+ self.level = level;
+ }
+ });
+
+ Object.defineProperty(builder, 'enabled', {
+ enumerable: true,
+ get() {
+ return self.enabled;
+ },
+ set(enabled) {
+ self.enabled = enabled;
+ }
+ });
+
+ // See below for fix regarding invisible grey/dim combination on Windows
+ builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey';
+
+ // `__proto__` is used because we must return a function, but there is
+ // no way to create a function with a different prototype
+ builder.__proto__ = proto; // eslint-disable-line no-proto
+
+ return builder;
+}
+
+function applyStyle() {
+ // Support varags, but simply cast to string in case there's only one arg
+ const args = arguments;
+ const argsLen = args.length;
+ let str = String(arguments[0]);
+
+ if (argsLen === 0) {
+ return '';
+ }
+
+ if (argsLen > 1) {
+ // Don't slice `arguments`, it prevents V8 optimizations
+ for (let a = 1; a < argsLen; a++) {
+ str += ' ' + args[a];
+ }
+ }
+
+ if (!this.enabled || this.level <= 0 || !str) {
+ return this._empty ? '' : str;
+ }
+
+ // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe,
+ // see https://github.com/chalk/chalk/issues/58
+ // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop.
+ const originalDim = ansiStyles.dim.open;
+ if (isSimpleWindowsTerm && this.hasGrey) {
+ ansiStyles.dim.open = '';
+ }
+
+ for (const code of this._styles.slice().reverse()) {
+ // Replace any instances already present with a re-opening code
+ // otherwise only the part of the string until said closing code
+ // will be colored, and the rest will simply be 'plain'.
+ str = code.open + str.replace(code.closeRe, code.open) + code.close;
+
+ // Close the styling before a linebreak and reopen
+ // after next line to fix a bleed issue on macOS
+ // https://github.com/chalk/chalk/pull/92
+ str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`);
+ }
+
+ // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue
+ ansiStyles.dim.open = originalDim;
+
+ return str;
+}
+
+function chalkTag(chalk, strings) {
+ if (!Array.isArray(strings)) {
+ // If chalk() was called by itself or with a string,
+ // return the string itself as a string.
+ return [].slice.call(arguments, 1).join(' ');
+ }
+
+ const args = [].slice.call(arguments, 2);
+ const parts = [strings.raw[0]];
+
+ for (let i = 1; i < strings.length; i++) {
+ parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&'));
+ parts.push(String(strings.raw[i]));
+ }
+
+ return template(chalk, parts.join(''));
+}
+
+Object.defineProperties(Chalk.prototype, styles);
+
+module.exports = Chalk(); // eslint-disable-line new-cap
+module.exports.supportsColor = stdoutColor;
+module.exports.default = module.exports; // For TypeScript
diff --git a/node_modules/svgo/node_modules/chalk/index.js.flow b/node_modules/svgo/node_modules/chalk/index.js.flow
new file mode 100644
index 0000000..622caaa
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/index.js.flow
@@ -0,0 +1,93 @@
+// @flow strict
+
+type TemplateStringsArray = $ReadOnlyArray<string>;
+
+export type Level = $Values<{
+ None: 0,
+ Basic: 1,
+ Ansi256: 2,
+ TrueColor: 3
+}>;
+
+export type ChalkOptions = {|
+ enabled?: boolean,
+ level?: Level
+|};
+
+export type ColorSupport = {|
+ level: Level,
+ hasBasic: boolean,
+ has256: boolean,
+ has16m: boolean
+|};
+
+export interface Chalk {
+ (...text: string[]): string,
+ (text: TemplateStringsArray, ...placeholders: string[]): string,
+ constructor(options?: ChalkOptions): Chalk,
+ enabled: boolean,
+ level: Level,
+ rgb(r: number, g: number, b: number): Chalk,
+ hsl(h: number, s: number, l: number): Chalk,
+ hsv(h: number, s: number, v: number): Chalk,
+ hwb(h: number, w: number, b: number): Chalk,
+ bgHex(color: string): Chalk,
+ bgKeyword(color: string): Chalk,
+ bgRgb(r: number, g: number, b: number): Chalk,
+ bgHsl(h: number, s: number, l: number): Chalk,
+ bgHsv(h: number, s: number, v: number): Chalk,
+ bgHwb(h: number, w: number, b: number): Chalk,
+ hex(color: string): Chalk,
+ keyword(color: string): Chalk,
+
+ +reset: Chalk,
+ +bold: Chalk,
+ +dim: Chalk,
+ +italic: Chalk,
+ +underline: Chalk,
+ +inverse: Chalk,
+ +hidden: Chalk,
+ +strikethrough: Chalk,
+
+ +visible: Chalk,
+
+ +black: Chalk,
+ +red: Chalk,
+ +green: Chalk,
+ +yellow: Chalk,
+ +blue: Chalk,
+ +magenta: Chalk,
+ +cyan: Chalk,
+ +white: Chalk,
+ +gray: Chalk,
+ +grey: Chalk,
+ +blackBright: Chalk,
+ +redBright: Chalk,
+ +greenBright: Chalk,
+ +yellowBright: Chalk,
+ +blueBright: Chalk,
+ +magentaBright: Chalk,
+ +cyanBright: Chalk,
+ +whiteBright: Chalk,
+
+ +bgBlack: Chalk,
+ +bgRed: Chalk,
+ +bgGreen: Chalk,
+ +bgYellow: Chalk,
+ +bgBlue: Chalk,
+ +bgMagenta: Chalk,
+ +bgCyan: Chalk,
+ +bgWhite: Chalk,
+ +bgBlackBright: Chalk,
+ +bgRedBright: Chalk,
+ +bgGreenBright: Chalk,
+ +bgYellowBright: Chalk,
+ +bgBlueBright: Chalk,
+ +bgMagentaBright: Chalk,
+ +bgCyanBright: Chalk,
+ +bgWhiteBrigh: Chalk,
+
+ supportsColor: ColorSupport
+};
+
+declare module.exports: Chalk;
diff --git a/node_modules/svgo/node_modules/chalk/license b/node_modules/svgo/node_modules/chalk/license
new file mode 100644
index 0000000..e7af2f7
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/license
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
diff --git a/node_modules/svgo/node_modules/chalk/package.json b/node_modules/svgo/node_modules/chalk/package.json
new file mode 100644
index 0000000..c8067bd
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/package.json
@@ -0,0 +1,103 @@
+{
+ "_from": "chalk@^2.4.1",
+ "_id": "chalk@2.4.2",
+ "_inBundle": false,
+ "_integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "_location": "/svgo/chalk",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "chalk@^2.4.1",
+ "name": "chalk",
+ "escapedName": "chalk",
+ "rawSpec": "^2.4.1",
+ "saveSpec": null,
+ "fetchSpec": "^2.4.1"
+ },
+ "_requiredBy": [
+ "/svgo"
+ ],
+ "_resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "_shasum": "cd42541677a54333cf541a49108c1432b44c9424",
+ "_spec": "chalk@^2.4.1",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo",
+ "bugs": {
+ "url": "https://github.com/chalk/chalk/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "deprecated": false,
+ "description": "Terminal string styling done right",
+ "devDependencies": {
+ "ava": "*",
+ "coveralls": "^3.0.0",
+ "execa": "^0.9.0",
+ "flow-bin": "^0.68.0",
+ "import-fresh": "^2.0.0",
+ "matcha": "^0.7.0",
+ "nyc": "^11.0.2",
+ "resolve-from": "^4.0.0",
+ "typescript": "^2.5.3",
+ "xo": "*"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "files": [
+ "index.js",
+ "templates.js",
+ "types/index.d.ts",
+ "index.js.flow"
+ ],
+ "homepage": "https://github.com/chalk/chalk#readme",
+ "keywords": [
+ "color",
+ "colour",
+ "colors",
+ "terminal",
+ "console",
+ "cli",
+ "string",
+ "str",
+ "ansi",
+ "style",
+ "styles",
+ "tty",
+ "formatting",
+ "rgb",
+ "256",
+ "shell",
+ "xterm",
+ "log",
+ "logging",
+ "command-line",
+ "text"
+ ],
+ "license": "MIT",
+ "name": "chalk",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/chalk/chalk.git"
+ },
+ "scripts": {
+ "bench": "matcha benchmark.js",
+ "coveralls": "nyc report --reporter=text-lcov | coveralls",
+ "test": "xo && tsc --project types && flow --max-warnings=0 && nyc ava"
+ },
+ "types": "types/index.d.ts",
+ "version": "2.4.2",
+ "xo": {
+ "envs": [
+ "node",
+ "mocha"
+ ],
+ "ignores": [
+ "test/_flow.js"
+ ]
+ }
+}
diff --git a/node_modules/svgo/node_modules/chalk/readme.md b/node_modules/svgo/node_modules/chalk/readme.md
new file mode 100644
index 0000000..d298e2c
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/readme.md
@@ -0,0 +1,314 @@
+<h1 align="center">
+ <br>
+ <br>
+ <img width="320" src="media/logo.svg" alt="Chalk">
+ <br>
+ <br>
+ <br>
+</h1>
+
+> Terminal string styling done right
+
+[](https://travis-ci.org/chalk/chalk) [](https://coveralls.io/github/chalk/chalk?branch=master) [](https://www.youtube.com/watch?v=9auOCbH5Ns4) [](https://github.com/xojs/xo) [](https://github.com/sindresorhus/awesome-nodejs)
+
+### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0)
+
+<img src="https://cdn.rawgit.com/chalk/ansi-styles/8261697c95bf34b6c7767e2cbe9941a851d59385/screenshot.svg" alt="" width="900">
+
+
+## Highlights
+
+- Expressive API
+- Highly performant
+- Ability to nest styles
+- [256/Truecolor color support](#256-and-truecolor-color-support)
+- Auto-detects color support
+- Doesn't extend `String.prototype`
+- Clean and focused
+- Actively maintained
+- [Used by ~23,000 packages](https://www.npmjs.com/browse/depended/chalk) as of December 31, 2017
+
+
+## Install
+
+```console
+$ npm install chalk
+```
+
+<a href="https://www.patreon.com/sindresorhus">
+ <img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
+</a>
+
+
+## Usage
+
+```js
+const chalk = require('chalk');
+
+console.log(chalk.blue('Hello world!'));
+```
+
+Chalk comes with an easy to use composable API where you just chain and nest the styles you want.
+
+```js
+const chalk = require('chalk');
+const log = console.log;
+
+// Combine styled and normal strings
+log(chalk.blue('Hello') + ' World' + chalk.red('!'));
+
+// Compose multiple styles using the chainable API
+log(chalk.blue.bgRed.bold('Hello world!'));
+
+// Pass in multiple arguments
+log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'));
+
+// Nest styles
+log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!'));
+
+// Nest styles of the same type even (color, underline, background)
+log(chalk.green(
+ 'I am a green line ' +
+ chalk.blue.underline.bold('with a blue substring') +
+ ' that becomes green again!'
+));
+
+// ES2015 template literal
+log(`
+CPU: ${chalk.red('90%')}
+RAM: ${chalk.green('40%')}
+DISK: ${chalk.yellow('70%')}
+`);
+
+// ES2015 tagged template literal
+log(chalk`
+CPU: {red ${cpu.totalPercent}%}
+RAM: {green ${ram.used / ram.total * 100}%}
+DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%}
+`);
+
+// Use RGB colors in terminal emulators that support it.
+log(chalk.keyword('orange')('Yay for orange colored text!'));
+log(chalk.rgb(123, 45, 67).underline('Underlined reddish color'));
+log(chalk.hex('#DEADED').bold('Bold gray!'));
+```
+
+Easily define your own themes:
+
+```js
+const chalk = require('chalk');
+
+const error = chalk.bold.red;
+const warning = chalk.keyword('orange');
+
+console.log(error('Error!'));
+console.log(warning('Warning!'));
+```
+
+Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args):
+
+```js
+const name = 'Sindre';
+console.log(chalk.green('Hello %s'), name);
+//=> 'Hello Sindre'
+```
+
+
+## API
+
+### chalk.`<style>[.<style>...](string, [string...])`
+
+Example: `chalk.red.bold.underline('Hello', 'world');`
+
+Chain [styles](#styles) and call the last one as a method with a string argument. Order doesn't matter, and later styles take precedent in case of a conflict. This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`.
+
+Multiple arguments will be separated by space.
+
+### chalk.enabled
+
+Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property.
+
+Chalk is enabled by default unless explicitly disabled via the constructor or `chalk.level` is `0`.
+
+If you need to change this in a reusable module, create a new instance:
+
+```js
+const ctx = new chalk.constructor({enabled: false});
+```
+
+### chalk.level
+
+Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers.
+
+If you need to change this in a reusable module, create a new instance:
+
+```js
+const ctx = new chalk.constructor({level: 0});
+```
+
+Levels are as follows:
+
+0. All colors disabled
+1. Basic color support (16 colors)
+2. 256 color support
+3. Truecolor support (16 million colors)
+
+### chalk.supportsColor
+
+Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience.
+
+Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add the environment variable `FORCE_COLOR=1` to forcefully enable color or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks.
+
+Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively.
+
+
+## Styles
+
+### Modifiers
+
+- `reset`
+- `bold`
+- `dim`
+- `italic` *(Not widely supported)*
+- `underline`
+- `inverse`
+- `hidden`
+- `strikethrough` *(Not widely supported)*
+- `visible` (Text is emitted only if enabled)
+
+### Colors
+
+- `black`
+- `red`
+- `green`
+- `yellow`
+- `blue` *(On Windows the bright version is used since normal blue is illegible)*
+- `magenta`
+- `cyan`
+- `white`
+- `gray` ("bright black")
+- `redBright`
+- `greenBright`
+- `yellowBright`
+- `blueBright`
+- `magentaBright`
+- `cyanBright`
+- `whiteBright`
+
+### Background colors
+
+- `bgBlack`
+- `bgRed`
+- `bgGreen`
+- `bgYellow`
+- `bgBlue`
+- `bgMagenta`
+- `bgCyan`
+- `bgWhite`
+- `bgBlackBright`
+- `bgRedBright`
+- `bgGreenBright`
+- `bgYellowBright`
+- `bgBlueBright`
+- `bgMagentaBright`
+- `bgCyanBright`
+- `bgWhiteBright`
+
+
+## Tagged template literal
+
+Chalk can be used as a [tagged template literal](http://exploringjs.com/es6/ch_template-literals.html#_tagged-template-literals).
+
+```js
+const chalk = require('chalk');
+
+const miles = 18;
+const calculateFeet = miles => miles * 5280;
+
+console.log(chalk`
+ There are {bold 5280 feet} in a mile.
+ In {bold ${miles} miles}, there are {green.bold ${calculateFeet(miles)} feet}.
+`);
+```
+
+Blocks are delimited by an opening curly brace (`{`), a style, some content, and a closing curly brace (`}`).
+
+Template styles are chained exactly like normal Chalk styles. The following two statements are equivalent:
+
+```js
+console.log(chalk.bold.rgb(10, 100, 200)('Hello!'));
+console.log(chalk`{bold.rgb(10,100,200) Hello!}`);
+```
+
+Note that function styles (`rgb()`, `hsl()`, `keyword()`, etc.) may not contain spaces between parameters.
+
+All interpolated values (`` chalk`${foo}` ``) are converted to strings via the `.toString()` method. All curly braces (`{` and `}`) in interpolated value strings are escaped.
+
+
+## 256 and Truecolor color support
+
+Chalk supports 256 colors and [Truecolor](https://gist.github.com/XVilka/8346728) (16 million colors) on supported terminal apps.
+
+Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying `{level: n}` as a Chalk option). For example, Chalk configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red).
+
+Examples:
+
+- `chalk.hex('#DEADED').underline('Hello, world!')`
+- `chalk.keyword('orange')('Some orange text')`
+- `chalk.rgb(15, 100, 204).inverse('Hello!')`
+
+Background versions of these models are prefixed with `bg` and the first level of the module capitalized (e.g. `keyword` for foreground colors and `bgKeyword` for background colors).
+
+- `chalk.bgHex('#DEADED').underline('Hello, world!')`
+- `chalk.bgKeyword('orange')('Some orange text')`
+- `chalk.bgRgb(15, 100, 204).inverse('Hello!')`
+
+The following color models can be used:
+
+- [`rgb`](https://en.wikipedia.org/wiki/RGB_color_model) - Example: `chalk.rgb(255, 136, 0).bold('Orange!')`
+- [`hex`](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet) - Example: `chalk.hex('#FF8800').bold('Orange!')`
+- [`keyword`](https://www.w3.org/wiki/CSS/Properties/color/keywords) (CSS keywords) - Example: `chalk.keyword('orange').bold('Orange!')`
+- [`hsl`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsl(32, 100, 50).bold('Orange!')`
+- [`hsv`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsv(32, 100, 100).bold('Orange!')`
+- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hwb(32, 0, 50).bold('Orange!')`
+- `ansi16`
+- `ansi256`
+
+
+## Windows
+
+If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) instead of `cmd.exe`.
+
+
+## Origin story
+
+[colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative.
+
+
+## Related
+
+- [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module
+- [ansi-styles](https://github.com/chalk/ansi-styles) - ANSI escape codes for styling strings in the terminal
+- [supports-color](https://github.com/chalk/supports-color) - Detect whether a terminal supports color
+- [strip-ansi](https://github.com/chalk/strip-ansi) - Strip ANSI escape codes
+- [strip-ansi-stream](https://github.com/chalk/strip-ansi-stream) - Strip ANSI escape codes from a stream
+- [has-ansi](https://github.com/chalk/has-ansi) - Check if a string has ANSI escape codes
+- [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes
+- [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes
+- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes
+- [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models
+- [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal
+- [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings
+- [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk style schemes with simpler style strings
+- [terminal-link](https://github.com/sindresorhus/terminal-link) - Create clickable links in the terminal
+
+
+## Maintainers
+
+- [Sindre Sorhus](https://github.com/sindresorhus)
+- [Josh Junon](https://github.com/qix-)
+
+
+## License
+
+MIT
diff --git a/node_modules/svgo/node_modules/chalk/templates.js b/node_modules/svgo/node_modules/chalk/templates.js
new file mode 100644
index 0000000..dbdf9b2
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/templates.js
@@ -0,0 +1,128 @@
+'use strict';
+const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi;
+const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g;
+const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/;
+const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi;
+
+const ESCAPES = new Map([
+ ['n', '\n'],
+ ['r', '\r'],
+ ['t', '\t'],
+ ['b', '\b'],
+ ['f', '\f'],
+ ['v', '\v'],
+ ['0', '\0'],
+ ['\\', '\\'],
+ ['e', '\u001B'],
+ ['a', '\u0007']
+]);
+
+function unescape(c) {
+ if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) {
+ return String.fromCharCode(parseInt(c.slice(1), 16));
+ }
+
+ return ESCAPES.get(c) || c;
+}
+
+function parseArguments(name, args) {
+ const results = [];
+ const chunks = args.trim().split(/\s*,\s*/g);
+ let matches;
+
+ for (const chunk of chunks) {
+ if (!isNaN(chunk)) {
+ results.push(Number(chunk));
+ } else if ((matches = chunk.match(STRING_REGEX))) {
+ results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr));
+ } else {
+ throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`);
+ }
+ }
+
+ return results;
+}
+
+function parseStyle(style) {
+ STYLE_REGEX.lastIndex = 0;
+
+ const results = [];
+ let matches;
+
+ while ((matches = STYLE_REGEX.exec(style)) !== null) {
+ const name = matches[1];
+
+ if (matches[2]) {
+ const args = parseArguments(name, matches[2]);
+ results.push([name].concat(args));
+ } else {
+ results.push([name]);
+ }
+ }
+
+ return results;
+}
+
+function buildStyle(chalk, styles) {
+ const enabled = {};
+
+ for (const layer of styles) {
+ for (const style of layer.styles) {
+ enabled[style[0]] = layer.inverse ? null : style.slice(1);
+ }
+ }
+
+ let current = chalk;
+ for (const styleName of Object.keys(enabled)) {
+ if (Array.isArray(enabled[styleName])) {
+ if (!(styleName in current)) {
+ throw new Error(`Unknown Chalk style: ${styleName}`);
+ }
+
+ if (enabled[styleName].length > 0) {
+ current = current[styleName].apply(current, enabled[styleName]);
+ } else {
+ current = current[styleName];
+ }
+ }
+ }
+
+ return current;
+}
+
+module.exports = (chalk, tmp) => {
+ const styles = [];
+ const chunks = [];
+ let chunk = [];
+
+ // eslint-disable-next-line max-params
+ tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => {
+ if (escapeChar) {
+ chunk.push(unescape(escapeChar));
+ } else if (style) {
+ const str = chunk.join('');
+ chunk = [];
+ chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str));
+ styles.push({inverse, styles: parseStyle(style)});
+ } else if (close) {
+ if (styles.length === 0) {
+ throw new Error('Found extraneous } in Chalk template literal');
+ }
+
+ chunks.push(buildStyle(chalk, styles)(chunk.join('')));
+ chunk = [];
+ styles.pop();
+ } else {
+ chunk.push(chr);
+ }
+ });
+
+ chunks.push(chunk.join(''));
+
+ if (styles.length > 0) {
+ const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`;
+ throw new Error(errMsg);
+ }
+
+ return chunks.join('');
+};
diff --git a/node_modules/svgo/node_modules/chalk/types/index.d.ts b/node_modules/svgo/node_modules/chalk/types/index.d.ts
new file mode 100644
index 0000000..b4e4dc5
--- /dev/null
+++ b/node_modules/svgo/node_modules/chalk/types/index.d.ts
@@ -0,0 +1,97 @@
+// Type definitions for Chalk
+// Definitions by: Thomas Sauer <https://github.com/t-sauer>
+
+export const enum Level {
+ None = 0,
+ Basic = 1,
+ Ansi256 = 2,
+ TrueColor = 3
+}
+
+export interface ChalkOptions {
+ enabled?: boolean;
+ level?: Level;
+}
+
+export interface ChalkConstructor {
+ new (options?: ChalkOptions): Chalk;
+ (options?: ChalkOptions): Chalk;
+}
+
+export interface ColorSupport {
+ level: Level;
+ hasBasic: boolean;
+ has256: boolean;
+ has16m: boolean;
+}
+
+export interface Chalk {
+ (...text: string[]): string;
+ (text: TemplateStringsArray, ...placeholders: string[]): string;
+ constructor: ChalkConstructor;
+ enabled: boolean;
+ level: Level;
+ rgb(r: number, g: number, b: number): this;
+ hsl(h: number, s: number, l: number): this;
+ hsv(h: number, s: number, v: number): this;
+ hwb(h: number, w: number, b: number): this;
+ bgHex(color: string): this;
+ bgKeyword(color: string): this;
+ bgRgb(r: number, g: number, b: number): this;
+ bgHsl(h: number, s: number, l: number): this;
+ bgHsv(h: number, s: number, v: number): this;
+ bgHwb(h: number, w: number, b: number): this;
+ hex(color: string): this;
+ keyword(color: string): this;
+
+ readonly reset: this;
+ readonly bold: this;
+ readonly dim: this;
+ readonly italic: this;
+ readonly underline: this;
+ readonly inverse: this;
+ readonly hidden: this;
+ readonly strikethrough: this;
+
+ readonly visible: this;
+
+ readonly black: this;
+ readonly red: this;
+ readonly green: this;
+ readonly yellow: this;
+ readonly blue: this;
+ readonly magenta: this;
+ readonly cyan: this;
+ readonly white: this;
+ readonly gray: this;
+ readonly grey: this;
+ readonly blackBright: this;
+ readonly redBright: this;
+ readonly greenBright: this;
+ readonly yellowBright: this;
+ readonly blueBright: this;
+ readonly magentaBright: this;
+ readonly cyanBright: this;
+ readonly whiteBright: this;
+
+ readonly bgBlack: this;
+ readonly bgRed: this;
+ readonly bgGreen: this;
+ readonly bgYellow: this;
+ readonly bgBlue: this;
+ readonly bgMagenta: this;
+ readonly bgCyan: this;
+ readonly bgWhite: this;
+ readonly bgBlackBright: this;
+ readonly bgRedBright: this;
+ readonly bgGreenBright: this;
+ readonly bgYellowBright: this;
+ readonly bgBlueBright: this;
+ readonly bgMagentaBright: this;
+ readonly bgCyanBright: this;
+ readonly bgWhiteBright: this;
+}
+
+declare const chalk: Chalk & { supportsColor: ColorSupport };
+
+export default chalk
diff --git a/node_modules/svgo/node_modules/color-convert/CHANGELOG.md b/node_modules/svgo/node_modules/color-convert/CHANGELOG.md
new file mode 100644
index 0000000..0a7bce4
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/CHANGELOG.md
@@ -0,0 +1,54 @@
+# 1.0.0 - 2016-01-07
+
+- Removed: unused speed test
+- Added: Automatic routing between previously unsupported conversions
+([#27](https://github.com/Qix-/color-convert/pull/27))
+- Removed: `xxx2xxx()` and `xxx2xxxRaw()` functions
+([#27](https://github.com/Qix-/color-convert/pull/27))
+- Removed: `convert()` class
+([#27](https://github.com/Qix-/color-convert/pull/27))
+- Changed: all functions to lookup dictionary
+([#27](https://github.com/Qix-/color-convert/pull/27))
+- Changed: `ansi` to `ansi256`
+([#27](https://github.com/Qix-/color-convert/pull/27))
+- Fixed: argument grouping for functions requiring only one argument
+([#27](https://github.com/Qix-/color-convert/pull/27))
+
+# 0.6.0 - 2015-07-23
+
+- Added: methods to handle
+[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 16/256 colors:
+ - rgb2ansi16
+ - rgb2ansi
+ - hsl2ansi16
+ - hsl2ansi
+ - hsv2ansi16
+ - hsv2ansi
+ - hwb2ansi16
+ - hwb2ansi
+ - cmyk2ansi16
+ - cmyk2ansi
+ - keyword2ansi16
+ - keyword2ansi
+ - ansi162rgb
+ - ansi162hsl
+ - ansi162hsv
+ - ansi162hwb
+ - ansi162cmyk
+ - ansi162keyword
+ - ansi2rgb
+ - ansi2hsl
+ - ansi2hsv
+ - ansi2hwb
+ - ansi2cmyk
+ - ansi2keyword
+([#18](https://github.com/harthur/color-convert/pull/18))
+
+# 0.5.3 - 2015-06-02
+
+- Fixed: hsl2hsv does not return `NaN` anymore when using `[0,0,0]`
+([#15](https://github.com/harthur/color-convert/issues/15))
+
+---
+
+Check out commit logs for older releases
diff --git a/node_modules/svgo/node_modules/color-convert/LICENSE b/node_modules/svgo/node_modules/color-convert/LICENSE
new file mode 100644
index 0000000..5b4c386
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2011-2016 Heather Arthur <fayearthur@gmail.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.
+
diff --git a/node_modules/svgo/node_modules/color-convert/README.md b/node_modules/svgo/node_modules/color-convert/README.md
new file mode 100644
index 0000000..d4b08fc
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/README.md
@@ -0,0 +1,68 @@
+# color-convert
+
+[](https://travis-ci.org/Qix-/color-convert)
+
+Color-convert is a color conversion library for JavaScript and node.
+It converts all ways between `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `ansi`, `ansi16`, `hex` strings, and CSS `keyword`s (will round to closest):
+
+```js
+var convert = require('color-convert');
+
+convert.rgb.hsl(140, 200, 100); // [96, 48, 59]
+convert.keyword.rgb('blue'); // [0, 0, 255]
+
+var rgbChannels = convert.rgb.channels; // 3
+var cmykChannels = convert.cmyk.channels; // 4
+var ansiChannels = convert.ansi16.channels; // 1
+```
+
+# Install
+
+```console
+$ npm install color-convert
+```
+
+# API
+
+Simply get the property of the _from_ and _to_ conversion that you're looking for.
+
+All functions have a rounded and unrounded variant. By default, return values are rounded. To get the unrounded (raw) results, simply tack on `.raw` to the function.
+
+All 'from' functions have a hidden property called `.channels` that indicates the number of channels the function expects (not including alpha).
+
+```js
+var convert = require('color-convert');
+
+// Hex to LAB
+convert.hex.lab('DEADBF'); // [ 76, 21, -2 ]
+convert.hex.lab.raw('DEADBF'); // [ 75.56213190997677, 20.653827952644754, -2.290532499330533 ]
+
+// RGB to CMYK
+convert.rgb.cmyk(167, 255, 4); // [ 35, 0, 98, 0 ]
+convert.rgb.cmyk.raw(167, 255, 4); // [ 34.509803921568626, 0, 98.43137254901961, 0 ]
+```
+
+### Arrays
+All functions that accept multiple arguments also support passing an array.
+
+Note that this does **not** apply to functions that convert from a color that only requires one value (e.g. `keyword`, `ansi256`, `hex`, etc.)
+
+```js
+var convert = require('color-convert');
+
+convert.rgb.hex(123, 45, 67); // '7B2D43'
+convert.rgb.hex([123, 45, 67]); // '7B2D43'
+```
+
+## Routing
+
+Conversions that don't have an _explicitly_ defined conversion (in [conversions.js](conversions.js)), but can be converted by means of sub-conversions (e.g. XYZ -> **RGB** -> CMYK), are automatically routed together. This allows just about any color model supported by `color-convert` to be converted to any other model, so long as a sub-conversion path exists. This is also true for conversions requiring more than one step in between (e.g. LCH -> **LAB** -> **XYZ** -> **RGB** -> Hex).
+
+Keep in mind that extensive conversions _may_ result in a loss of precision, and exist only to be complete. For a list of "direct" (single-step) conversions, see [conversions.js](conversions.js).
+
+# Contribute
+
+If there is a new model you would like to support, or want to add a direct conversion between two existing models, please send us a pull request.
+
+# License
+Copyright © 2011-2016, Heather Arthur and Josh Junon. Licensed under the [MIT License](LICENSE).
diff --git a/node_modules/svgo/node_modules/color-convert/conversions.js b/node_modules/svgo/node_modules/color-convert/conversions.js
new file mode 100644
index 0000000..3217200
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/conversions.js
@@ -0,0 +1,868 @@
+/* MIT license */
+var cssKeywords = require('color-name');
+
+// NOTE: conversions should only return primitive values (i.e. arrays, or
+// values that give correct `typeof` results).
+// do not use box values types (i.e. Number(), String(), etc.)
+
+var reverseKeywords = {};
+for (var key in cssKeywords) {
+ if (cssKeywords.hasOwnProperty(key)) {
+ reverseKeywords[cssKeywords[key]] = key;
+ }
+}
+
+var convert = module.exports = {
+ rgb: {channels: 3, labels: 'rgb'},
+ hsl: {channels: 3, labels: 'hsl'},
+ hsv: {channels: 3, labels: 'hsv'},
+ hwb: {channels: 3, labels: 'hwb'},
+ cmyk: {channels: 4, labels: 'cmyk'},
+ xyz: {channels: 3, labels: 'xyz'},
+ lab: {channels: 3, labels: 'lab'},
+ lch: {channels: 3, labels: 'lch'},
+ hex: {channels: 1, labels: ['hex']},
+ keyword: {channels: 1, labels: ['keyword']},
+ ansi16: {channels: 1, labels: ['ansi16']},
+ ansi256: {channels: 1, labels: ['ansi256']},
+ hcg: {channels: 3, labels: ['h', 'c', 'g']},
+ apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
+ gray: {channels: 1, labels: ['gray']}
+};
+
+// hide .channels and .labels properties
+for (var model in convert) {
+ if (convert.hasOwnProperty(model)) {
+ if (!('channels' in convert[model])) {
+ throw new Error('missing channels property: ' + model);
+ }
+
+ if (!('labels' in convert[model])) {
+ throw new Error('missing channel labels property: ' + model);
+ }
+
+ if (convert[model].labels.length !== convert[model].channels) {
+ throw new Error('channel and label counts mismatch: ' + model);
+ }
+
+ var channels = convert[model].channels;
+ var labels = convert[model].labels;
+ delete convert[model].channels;
+ delete convert[model].labels;
+ Object.defineProperty(convert[model], 'channels', {value: channels});
+ Object.defineProperty(convert[model], 'labels', {value: labels});
+ }
+}
+
+convert.rgb.hsl = function (rgb) {
+ var r = rgb[0] / 255;
+ var g = rgb[1] / 255;
+ var b = rgb[2] / 255;
+ var min = Math.min(r, g, b);
+ var max = Math.max(r, g, b);
+ var delta = max - min;
+ var h;
+ var s;
+ var l;
+
+ if (max === min) {
+ h = 0;
+ } else if (r === max) {
+ h = (g - b) / delta;
+ } else if (g === max) {
+ h = 2 + (b - r) / delta;
+ } else if (b === max) {
+ h = 4 + (r - g) / delta;
+ }
+
+ h = Math.min(h * 60, 360);
+
+ if (h < 0) {
+ h += 360;
+ }
+
+ l = (min + max) / 2;
+
+ if (max === min) {
+ s = 0;
+ } else if (l <= 0.5) {
+ s = delta / (max + min);
+ } else {
+ s = delta / (2 - max - min);
+ }
+
+ return [h, s * 100, l * 100];
+};
+
+convert.rgb.hsv = function (rgb) {
+ var rdif;
+ var gdif;
+ var bdif;
+ var h;
+ var s;
+
+ var r = rgb[0] / 255;
+ var g = rgb[1] / 255;
+ var b = rgb[2] / 255;
+ var v = Math.max(r, g, b);
+ var diff = v - Math.min(r, g, b);
+ var diffc = function (c) {
+ return (v - c) / 6 / diff + 1 / 2;
+ };
+
+ if (diff === 0) {
+ h = s = 0;
+ } else {
+ s = diff / v;
+ rdif = diffc(r);
+ gdif = diffc(g);
+ bdif = diffc(b);
+
+ if (r === v) {
+ h = bdif - gdif;
+ } else if (g === v) {
+ h = (1 / 3) + rdif - bdif;
+ } else if (b === v) {
+ h = (2 / 3) + gdif - rdif;
+ }
+ if (h < 0) {
+ h += 1;
+ } else if (h > 1) {
+ h -= 1;
+ }
+ }
+
+ return [
+ h * 360,
+ s * 100,
+ v * 100
+ ];
+};
+
+convert.rgb.hwb = function (rgb) {
+ var r = rgb[0];
+ var g = rgb[1];
+ var b = rgb[2];
+ var h = convert.rgb.hsl(rgb)[0];
+ var w = 1 / 255 * Math.min(r, Math.min(g, b));
+
+ b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
+
+ return [h, w * 100, b * 100];
+};
+
+convert.rgb.cmyk = function (rgb) {
+ var r = rgb[0] / 255;
+ var g = rgb[1] / 255;
+ var b = rgb[2] / 255;
+ var c;
+ var m;
+ var y;
+ var k;
+
+ k = Math.min(1 - r, 1 - g, 1 - b);
+ c = (1 - r - k) / (1 - k) || 0;
+ m = (1 - g - k) / (1 - k) || 0;
+ y = (1 - b - k) / (1 - k) || 0;
+
+ return [c * 100, m * 100, y * 100, k * 100];
+};
+
+/**
+ * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
+ * */
+function comparativeDistance(x, y) {
+ return (
+ Math.pow(x[0] - y[0], 2) +
+ Math.pow(x[1] - y[1], 2) +
+ Math.pow(x[2] - y[2], 2)
+ );
+}
+
+convert.rgb.keyword = function (rgb) {
+ var reversed = reverseKeywords[rgb];
+ if (reversed) {
+ return reversed;
+ }
+
+ var currentClosestDistance = Infinity;
+ var currentClosestKeyword;
+
+ for (var keyword in cssKeywords) {
+ if (cssKeywords.hasOwnProperty(keyword)) {
+ var value = cssKeywords[keyword];
+
+ // Compute comparative distance
+ var distance = comparativeDistance(rgb, value);
+
+ // Check if its less, if so set as closest
+ if (distance < currentClosestDistance) {
+ currentClosestDistance = distance;
+ currentClosestKeyword = keyword;
+ }
+ }
+ }
+
+ return currentClosestKeyword;
+};
+
+convert.keyword.rgb = function (keyword) {
+ return cssKeywords[keyword];
+};
+
+convert.rgb.xyz = function (rgb) {
+ var r = rgb[0] / 255;
+ var g = rgb[1] / 255;
+ var b = rgb[2] / 255;
+
+ // assume sRGB
+ r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
+ g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
+ b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
+
+ var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
+ var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
+ var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
+
+ return [x * 100, y * 100, z * 100];
+};
+
+convert.rgb.lab = function (rgb) {
+ var xyz = convert.rgb.xyz(rgb);
+ var x = xyz[0];
+ var y = xyz[1];
+ var z = xyz[2];
+ var l;
+ var a;
+ var b;
+
+ x /= 95.047;
+ y /= 100;
+ z /= 108.883;
+
+ x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
+ y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
+ z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
+
+ l = (116 * y) - 16;
+ a = 500 * (x - y);
+ b = 200 * (y - z);
+
+ return [l, a, b];
+};
+
+convert.hsl.rgb = function (hsl) {
+ var h = hsl[0] / 360;
+ var s = hsl[1] / 100;
+ var l = hsl[2] / 100;
+ var t1;
+ var t2;
+ var t3;
+ var rgb;
+ var val;
+
+ if (s === 0) {
+ val = l * 255;
+ return [val, val, val];
+ }
+
+ if (l < 0.5) {
+ t2 = l * (1 + s);
+ } else {
+ t2 = l + s - l * s;
+ }
+
+ t1 = 2 * l - t2;
+
+ rgb = [0, 0, 0];
+ for (var i = 0; i < 3; i++) {
+ t3 = h + 1 / 3 * -(i - 1);
+ if (t3 < 0) {
+ t3++;
+ }
+ if (t3 > 1) {
+ t3--;
+ }
+
+ if (6 * t3 < 1) {
+ val = t1 + (t2 - t1) * 6 * t3;
+ } else if (2 * t3 < 1) {
+ val = t2;
+ } else if (3 * t3 < 2) {
+ val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
+ } else {
+ val = t1;
+ }
+
+ rgb[i] = val * 255;
+ }
+
+ return rgb;
+};
+
+convert.hsl.hsv = function (hsl) {
+ var h = hsl[0];
+ var s = hsl[1] / 100;
+ var l = hsl[2] / 100;
+ var smin = s;
+ var lmin = Math.max(l, 0.01);
+ var sv;
+ var v;
+
+ l *= 2;
+ s *= (l <= 1) ? l : 2 - l;
+ smin *= lmin <= 1 ? lmin : 2 - lmin;
+ v = (l + s) / 2;
+ sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
+
+ return [h, sv * 100, v * 100];
+};
+
+convert.hsv.rgb = function (hsv) {
+ var h = hsv[0] / 60;
+ var s = hsv[1] / 100;
+ var v = hsv[2] / 100;
+ var hi = Math.floor(h) % 6;
+
+ var f = h - Math.floor(h);
+ var p = 255 * v * (1 - s);
+ var q = 255 * v * (1 - (s * f));
+ var t = 255 * v * (1 - (s * (1 - f)));
+ v *= 255;
+
+ switch (hi) {
+ case 0:
+ return [v, t, p];
+ case 1:
+ return [q, v, p];
+ case 2:
+ return [p, v, t];
+ case 3:
+ return [p, q, v];
+ case 4:
+ return [t, p, v];
+ case 5:
+ return [v, p, q];
+ }
+};
+
+convert.hsv.hsl = function (hsv) {
+ var h = hsv[0];
+ var s = hsv[1] / 100;
+ var v = hsv[2] / 100;
+ var vmin = Math.max(v, 0.01);
+ var lmin;
+ var sl;
+ var l;
+
+ l = (2 - s) * v;
+ lmin = (2 - s) * vmin;
+ sl = s * vmin;
+ sl /= (lmin <= 1) ? lmin : 2 - lmin;
+ sl = sl || 0;
+ l /= 2;
+
+ return [h, sl * 100, l * 100];
+};
+
+// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
+convert.hwb.rgb = function (hwb) {
+ var h = hwb[0] / 360;
+ var wh = hwb[1] / 100;
+ var bl = hwb[2] / 100;
+ var ratio = wh + bl;
+ var i;
+ var v;
+ var f;
+ var n;
+
+ // wh + bl cant be > 1
+ if (ratio > 1) {
+ wh /= ratio;
+ bl /= ratio;
+ }
+
+ i = Math.floor(6 * h);
+ v = 1 - bl;
+ f = 6 * h - i;
+
+ if ((i & 0x01) !== 0) {
+ f = 1 - f;
+ }
+
+ n = wh + f * (v - wh); // linear interpolation
+
+ var r;
+ var g;
+ var b;
+ switch (i) {
+ default:
+ case 6:
+ case 0: r = v; g = n; b = wh; break;
+ case 1: r = n; g = v; b = wh; break;
+ case 2: r = wh; g = v; b = n; break;
+ case 3: r = wh; g = n; b = v; break;
+ case 4: r = n; g = wh; b = v; break;
+ case 5: r = v; g = wh; b = n; break;
+ }
+
+ return [r * 255, g * 255, b * 255];
+};
+
+convert.cmyk.rgb = function (cmyk) {
+ var c = cmyk[0] / 100;
+ var m = cmyk[1] / 100;
+ var y = cmyk[2] / 100;
+ var k = cmyk[3] / 100;
+ var r;
+ var g;
+ var b;
+
+ r = 1 - Math.min(1, c * (1 - k) + k);
+ g = 1 - Math.min(1, m * (1 - k) + k);
+ b = 1 - Math.min(1, y * (1 - k) + k);
+
+ return [r * 255, g * 255, b * 255];
+};
+
+convert.xyz.rgb = function (xyz) {
+ var x = xyz[0] / 100;
+ var y = xyz[1] / 100;
+ var z = xyz[2] / 100;
+ var r;
+ var g;
+ var b;
+
+ r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
+ g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
+ b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
+
+ // assume sRGB
+ r = r > 0.0031308
+ ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
+ : r * 12.92;
+
+ g = g > 0.0031308
+ ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
+ : g * 12.92;
+
+ b = b > 0.0031308
+ ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
+ : b * 12.92;
+
+ r = Math.min(Math.max(0, r), 1);
+ g = Math.min(Math.max(0, g), 1);
+ b = Math.min(Math.max(0, b), 1);
+
+ return [r * 255, g * 255, b * 255];
+};
+
+convert.xyz.lab = function (xyz) {
+ var x = xyz[0];
+ var y = xyz[1];
+ var z = xyz[2];
+ var l;
+ var a;
+ var b;
+
+ x /= 95.047;
+ y /= 100;
+ z /= 108.883;
+
+ x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
+ y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
+ z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
+
+ l = (116 * y) - 16;
+ a = 500 * (x - y);
+ b = 200 * (y - z);
+
+ return [l, a, b];
+};
+
+convert.lab.xyz = function (lab) {
+ var l = lab[0];
+ var a = lab[1];
+ var b = lab[2];
+ var x;
+ var y;
+ var z;
+
+ y = (l + 16) / 116;
+ x = a / 500 + y;
+ z = y - b / 200;
+
+ var y2 = Math.pow(y, 3);
+ var x2 = Math.pow(x, 3);
+ var z2 = Math.pow(z, 3);
+ y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
+ x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
+ z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
+
+ x *= 95.047;
+ y *= 100;
+ z *= 108.883;
+
+ return [x, y, z];
+};
+
+convert.lab.lch = function (lab) {
+ var l = lab[0];
+ var a = lab[1];
+ var b = lab[2];
+ var hr;
+ var h;
+ var c;
+
+ hr = Math.atan2(b, a);
+ h = hr * 360 / 2 / Math.PI;
+
+ if (h < 0) {
+ h += 360;
+ }
+
+ c = Math.sqrt(a * a + b * b);
+
+ return [l, c, h];
+};
+
+convert.lch.lab = function (lch) {
+ var l = lch[0];
+ var c = lch[1];
+ var h = lch[2];
+ var a;
+ var b;
+ var hr;
+
+ hr = h / 360 * 2 * Math.PI;
+ a = c * Math.cos(hr);
+ b = c * Math.sin(hr);
+
+ return [l, a, b];
+};
+
+convert.rgb.ansi16 = function (args) {
+ var r = args[0];
+ var g = args[1];
+ var b = args[2];
+ var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization
+
+ value = Math.round(value / 50);
+
+ if (value === 0) {
+ return 30;
+ }
+
+ var ansi = 30
+ + ((Math.round(b / 255) << 2)
+ | (Math.round(g / 255) << 1)
+ | Math.round(r / 255));
+
+ if (value === 2) {
+ ansi += 60;
+ }
+
+ return ansi;
+};
+
+convert.hsv.ansi16 = function (args) {
+ // optimization here; we already know the value and don't need to get
+ // it converted for us.
+ return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
+};
+
+convert.rgb.ansi256 = function (args) {
+ var r = args[0];
+ var g = args[1];
+ var b = args[2];
+
+ // we use the extended greyscale palette here, with the exception of
+ // black and white. normal palette only has 4 greyscale shades.
+ if (r === g && g === b) {
+ if (r < 8) {
+ return 16;
+ }
+
+ if (r > 248) {
+ return 231;
+ }
+
+ return Math.round(((r - 8) / 247) * 24) + 232;
+ }
+
+ var ansi = 16
+ + (36 * Math.round(r / 255 * 5))
+ + (6 * Math.round(g / 255 * 5))
+ + Math.round(b / 255 * 5);
+
+ return ansi;
+};
+
+convert.ansi16.rgb = function (args) {
+ var color = args % 10;
+
+ // handle greyscale
+ if (color === 0 || color === 7) {
+ if (args > 50) {
+ color += 3.5;
+ }
+
+ color = color / 10.5 * 255;
+
+ return [color, color, color];
+ }
+
+ var mult = (~~(args > 50) + 1) * 0.5;
+ var r = ((color & 1) * mult) * 255;
+ var g = (((color >> 1) & 1) * mult) * 255;
+ var b = (((color >> 2) & 1) * mult) * 255;
+
+ return [r, g, b];
+};
+
+convert.ansi256.rgb = function (args) {
+ // handle greyscale
+ if (args >= 232) {
+ var c = (args - 232) * 10 + 8;
+ return [c, c, c];
+ }
+
+ args -= 16;
+
+ var rem;
+ var r = Math.floor(args / 36) / 5 * 255;
+ var g = Math.floor((rem = args % 36) / 6) / 5 * 255;
+ var b = (rem % 6) / 5 * 255;
+
+ return [r, g, b];
+};
+
+convert.rgb.hex = function (args) {
+ var integer = ((Math.round(args[0]) & 0xFF) << 16)
+ + ((Math.round(args[1]) & 0xFF) << 8)
+ + (Math.round(args[2]) & 0xFF);
+
+ var string = integer.toString(16).toUpperCase();
+ return '000000'.substring(string.length) + string;
+};
+
+convert.hex.rgb = function (args) {
+ var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
+ if (!match) {
+ return [0, 0, 0];
+ }
+
+ var colorString = match[0];
+
+ if (match[0].length === 3) {
+ colorString = colorString.split('').map(function (char) {
+ return char + char;
+ }).join('');
+ }
+
+ var integer = parseInt(colorString, 16);
+ var r = (integer >> 16) & 0xFF;
+ var g = (integer >> 8) & 0xFF;
+ var b = integer & 0xFF;
+
+ return [r, g, b];
+};
+
+convert.rgb.hcg = function (rgb) {
+ var r = rgb[0] / 255;
+ var g = rgb[1] / 255;
+ var b = rgb[2] / 255;
+ var max = Math.max(Math.max(r, g), b);
+ var min = Math.min(Math.min(r, g), b);
+ var chroma = (max - min);
+ var grayscale;
+ var hue;
+
+ if (chroma < 1) {
+ grayscale = min / (1 - chroma);
+ } else {
+ grayscale = 0;
+ }
+
+ if (chroma <= 0) {
+ hue = 0;
+ } else
+ if (max === r) {
+ hue = ((g - b) / chroma) % 6;
+ } else
+ if (max === g) {
+ hue = 2 + (b - r) / chroma;
+ } else {
+ hue = 4 + (r - g) / chroma + 4;
+ }
+
+ hue /= 6;
+ hue %= 1;
+
+ return [hue * 360, chroma * 100, grayscale * 100];
+};
+
+convert.hsl.hcg = function (hsl) {
+ var s = hsl[1] / 100;
+ var l = hsl[2] / 100;
+ var c = 1;
+ var f = 0;
+
+ if (l < 0.5) {
+ c = 2.0 * s * l;
+ } else {
+ c = 2.0 * s * (1.0 - l);
+ }
+
+ if (c < 1.0) {
+ f = (l - 0.5 * c) / (1.0 - c);
+ }
+
+ return [hsl[0], c * 100, f * 100];
+};
+
+convert.hsv.hcg = function (hsv) {
+ var s = hsv[1] / 100;
+ var v = hsv[2] / 100;
+
+ var c = s * v;
+ var f = 0;
+
+ if (c < 1.0) {
+ f = (v - c) / (1 - c);
+ }
+
+ return [hsv[0], c * 100, f * 100];
+};
+
+convert.hcg.rgb = function (hcg) {
+ var h = hcg[0] / 360;
+ var c = hcg[1] / 100;
+ var g = hcg[2] / 100;
+
+ if (c === 0.0) {
+ return [g * 255, g * 255, g * 255];
+ }
+
+ var pure = [0, 0, 0];
+ var hi = (h % 1) * 6;
+ var v = hi % 1;
+ var w = 1 - v;
+ var mg = 0;
+
+ switch (Math.floor(hi)) {
+ case 0:
+ pure[0] = 1; pure[1] = v; pure[2] = 0; break;
+ case 1:
+ pure[0] = w; pure[1] = 1; pure[2] = 0; break;
+ case 2:
+ pure[0] = 0; pure[1] = 1; pure[2] = v; break;
+ case 3:
+ pure[0] = 0; pure[1] = w; pure[2] = 1; break;
+ case 4:
+ pure[0] = v; pure[1] = 0; pure[2] = 1; break;
+ default:
+ pure[0] = 1; pure[1] = 0; pure[2] = w;
+ }
+
+ mg = (1.0 - c) * g;
+
+ return [
+ (c * pure[0] + mg) * 255,
+ (c * pure[1] + mg) * 255,
+ (c * pure[2] + mg) * 255
+ ];
+};
+
+convert.hcg.hsv = function (hcg) {
+ var c = hcg[1] / 100;
+ var g = hcg[2] / 100;
+
+ var v = c + g * (1.0 - c);
+ var f = 0;
+
+ if (v > 0.0) {
+ f = c / v;
+ }
+
+ return [hcg[0], f * 100, v * 100];
+};
+
+convert.hcg.hsl = function (hcg) {
+ var c = hcg[1] / 100;
+ var g = hcg[2] / 100;
+
+ var l = g * (1.0 - c) + 0.5 * c;
+ var s = 0;
+
+ if (l > 0.0 && l < 0.5) {
+ s = c / (2 * l);
+ } else
+ if (l >= 0.5 && l < 1.0) {
+ s = c / (2 * (1 - l));
+ }
+
+ return [hcg[0], s * 100, l * 100];
+};
+
+convert.hcg.hwb = function (hcg) {
+ var c = hcg[1] / 100;
+ var g = hcg[2] / 100;
+ var v = c + g * (1.0 - c);
+ return [hcg[0], (v - c) * 100, (1 - v) * 100];
+};
+
+convert.hwb.hcg = function (hwb) {
+ var w = hwb[1] / 100;
+ var b = hwb[2] / 100;
+ var v = 1 - b;
+ var c = v - w;
+ var g = 0;
+
+ if (c < 1) {
+ g = (v - c) / (1 - c);
+ }
+
+ return [hwb[0], c * 100, g * 100];
+};
+
+convert.apple.rgb = function (apple) {
+ return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
+};
+
+convert.rgb.apple = function (rgb) {
+ return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
+};
+
+convert.gray.rgb = function (args) {
+ return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
+};
+
+convert.gray.hsl = convert.gray.hsv = function (args) {
+ return [0, 0, args[0]];
+};
+
+convert.gray.hwb = function (gray) {
+ return [0, 100, gray[0]];
+};
+
+convert.gray.cmyk = function (gray) {
+ return [0, 0, 0, gray[0]];
+};
+
+convert.gray.lab = function (gray) {
+ return [gray[0], 0, 0];
+};
+
+convert.gray.hex = function (gray) {
+ var val = Math.round(gray[0] / 100 * 255) & 0xFF;
+ var integer = (val << 16) + (val << 8) + val;
+
+ var string = integer.toString(16).toUpperCase();
+ return '000000'.substring(string.length) + string;
+};
+
+convert.rgb.gray = function (rgb) {
+ var val = (rgb[0] + rgb[1] + rgb[2]) / 3;
+ return [val / 255 * 100];
+};
diff --git a/node_modules/svgo/node_modules/color-convert/index.js b/node_modules/svgo/node_modules/color-convert/index.js
new file mode 100644
index 0000000..e65b5d7
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/index.js
@@ -0,0 +1,78 @@
+var conversions = require('./conversions');
+var route = require('./route');
+
+var convert = {};
+
+var models = Object.keys(conversions);
+
+function wrapRaw(fn) {
+ var wrappedFn = function (args) {
+ if (args === undefined || args === null) {
+ return args;
+ }
+
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ }
+
+ return fn(args);
+ };
+
+ // preserve .conversion property if there is one
+ if ('conversion' in fn) {
+ wrappedFn.conversion = fn.conversion;
+ }
+
+ return wrappedFn;
+}
+
+function wrapRounded(fn) {
+ var wrappedFn = function (args) {
+ if (args === undefined || args === null) {
+ return args;
+ }
+
+ if (arguments.length > 1) {
+ args = Array.prototype.slice.call(arguments);
+ }
+
+ var result = fn(args);
+
+ // we're assuming the result is an array here.
+ // see notice in conversions.js; don't use box types
+ // in conversion functions.
+ if (typeof result === 'object') {
+ for (var len = result.length, i = 0; i < len; i++) {
+ result[i] = Math.round(result[i]);
+ }
+ }
+
+ return result;
+ };
+
+ // preserve .conversion property if there is one
+ if ('conversion' in fn) {
+ wrappedFn.conversion = fn.conversion;
+ }
+
+ return wrappedFn;
+}
+
+models.forEach(function (fromModel) {
+ convert[fromModel] = {};
+
+ Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
+ Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
+
+ var routes = route(fromModel);
+ var routeModels = Object.keys(routes);
+
+ routeModels.forEach(function (toModel) {
+ var fn = routes[toModel];
+
+ convert[fromModel][toModel] = wrapRounded(fn);
+ convert[fromModel][toModel].raw = wrapRaw(fn);
+ });
+});
+
+module.exports = convert;
diff --git a/node_modules/svgo/node_modules/color-convert/package.json b/node_modules/svgo/node_modules/color-convert/package.json
new file mode 100644
index 0000000..4a653df
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/package.json
@@ -0,0 +1,81 @@
+{
+ "_from": "color-convert@^1.9.0",
+ "_id": "color-convert@1.9.3",
+ "_inBundle": false,
+ "_integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "_location": "/svgo/color-convert",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "color-convert@^1.9.0",
+ "name": "color-convert",
+ "escapedName": "color-convert",
+ "rawSpec": "^1.9.0",
+ "saveSpec": null,
+ "fetchSpec": "^1.9.0"
+ },
+ "_requiredBy": [
+ "/svgo/ansi-styles"
+ ],
+ "_resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "_shasum": "bb71850690e1f136567de629d2d5471deda4c1e8",
+ "_spec": "color-convert@^1.9.0",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo\\node_modules\\ansi-styles",
+ "author": {
+ "name": "Heather Arthur",
+ "email": "fayearthur@gmail.com"
+ },
+ "bugs": {
+ "url": "https://github.com/Qix-/color-convert/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "color-name": "1.1.3"
+ },
+ "deprecated": false,
+ "description": "Plain color conversion functions",
+ "devDependencies": {
+ "chalk": "1.1.1",
+ "xo": "0.11.2"
+ },
+ "files": [
+ "index.js",
+ "conversions.js",
+ "css-keywords.js",
+ "route.js"
+ ],
+ "homepage": "https://github.com/Qix-/color-convert#readme",
+ "keywords": [
+ "color",
+ "colour",
+ "convert",
+ "converter",
+ "conversion",
+ "rgb",
+ "hsl",
+ "hsv",
+ "hwb",
+ "cmyk",
+ "ansi",
+ "ansi16"
+ ],
+ "license": "MIT",
+ "name": "color-convert",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Qix-/color-convert.git"
+ },
+ "scripts": {
+ "pretest": "xo",
+ "test": "node test/basic.js"
+ },
+ "version": "1.9.3",
+ "xo": {
+ "rules": {
+ "default-case": 0,
+ "no-inline-comments": 0,
+ "operator-linebreak": 0
+ }
+ }
+}
diff --git a/node_modules/svgo/node_modules/color-convert/route.js b/node_modules/svgo/node_modules/color-convert/route.js
new file mode 100644
index 0000000..0a1fdea
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-convert/route.js
@@ -0,0 +1,97 @@
+var conversions = require('./conversions');
+
+/*
+ this function routes a model to all other models.
+
+ all functions that are routed have a property `.conversion` attached
+ to the returned synthetic function. This property is an array
+ of strings, each with the steps in between the 'from' and 'to'
+ color models (inclusive).
+
+ conversions that are not possible simply are not included.
+*/
+
+function buildGraph() {
+ var graph = {};
+ // https://jsperf.com/object-keys-vs-for-in-with-closure/3
+ var models = Object.keys(conversions);
+
+ for (var len = models.length, i = 0; i < len; i++) {
+ graph[models[i]] = {
+ // http://jsperf.com/1-vs-infinity
+ // micro-opt, but this is simple.
+ distance: -1,
+ parent: null
+ };
+ }
+
+ return graph;
+}
+
+// https://en.wikipedia.org/wiki/Breadth-first_search
+function deriveBFS(fromModel) {
+ var graph = buildGraph();
+ var queue = [fromModel]; // unshift -> queue -> pop
+
+ graph[fromModel].distance = 0;
+
+ while (queue.length) {
+ var current = queue.pop();
+ var adjacents = Object.keys(conversions[current]);
+
+ for (var len = adjacents.length, i = 0; i < len; i++) {
+ var adjacent = adjacents[i];
+ var node = graph[adjacent];
+
+ if (node.distance === -1) {
+ node.distance = graph[current].distance + 1;
+ node.parent = current;
+ queue.unshift(adjacent);
+ }
+ }
+ }
+
+ return graph;
+}
+
+function link(from, to) {
+ return function (args) {
+ return to(from(args));
+ };
+}
+
+function wrapConversion(toModel, graph) {
+ var path = [graph[toModel].parent, toModel];
+ var fn = conversions[graph[toModel].parent][toModel];
+
+ var cur = graph[toModel].parent;
+ while (graph[cur].parent) {
+ path.unshift(graph[cur].parent);
+ fn = link(conversions[graph[cur].parent][cur], fn);
+ cur = graph[cur].parent;
+ }
+
+ fn.conversion = path;
+ return fn;
+}
+
+module.exports = function (fromModel) {
+ var graph = deriveBFS(fromModel);
+ var conversion = {};
+
+ var models = Object.keys(graph);
+ for (var len = models.length, i = 0; i < len; i++) {
+ var toModel = models[i];
+ var node = graph[toModel];
+
+ if (node.parent === null) {
+ // no possible conversion, or this node is the source model.
+ continue;
+ }
+
+ conversion[toModel] = wrapConversion(toModel, graph);
+ }
+
+ return conversion;
+};
+
diff --git a/node_modules/svgo/node_modules/color-name/.eslintrc.json b/node_modules/svgo/node_modules/color-name/.eslintrc.json
new file mode 100644
index 0000000..c50c250
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/.eslintrc.json
@@ -0,0 +1,43 @@
+{
+ "env": {
+ "browser": true,
+ "node": true,
+ "commonjs": true,
+ "es6": true
+ },
+ "extends": "eslint:recommended",
+ "rules": {
+ "strict": 2,
+ "indent": 0,
+ "linebreak-style": 0,
+ "quotes": 0,
+ "semi": 0,
+ "no-cond-assign": 1,
+ "no-constant-condition": 1,
+ "no-duplicate-case": 1,
+ "no-empty": 1,
+ "no-ex-assign": 1,
+ "no-extra-boolean-cast": 1,
+ "no-extra-semi": 1,
+ "no-fallthrough": 1,
+ "no-func-assign": 1,
+ "no-global-assign": 1,
+ "no-implicit-globals": 2,
+ "no-inner-declarations": ["error", "functions"],
+ "no-irregular-whitespace": 2,
+ "no-loop-func": 1,
+ "no-multi-str": 1,
+ "no-mixed-spaces-and-tabs": 1,
+ "no-proto": 1,
+ "no-sequences": 1,
+ "no-throw-literal": 1,
+ "no-unmodified-loop-condition": 1,
+ "no-useless-call": 1,
+ "no-void": 1,
+ "no-with": 2,
+ "wrap-iife": 1,
+ "no-redeclare": 1,
+ "no-unused-vars": ["error", { "vars": "all", "args": "none" }],
+ "no-sparse-arrays": 1
+ }
+}
diff --git a/node_modules/svgo/node_modules/color-name/.npmignore b/node_modules/svgo/node_modules/color-name/.npmignore
new file mode 100644
index 0000000..3854c07
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/.npmignore
@@ -0,0 +1,107 @@
+//this will affect all the git repos
+git config --global core.excludesfile ~/.gitignore
+
+
+//update files since .ignore won't if already tracked
+git rm --cached <file>
+
+# Compiled source #
+###################
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Logs and databases #
+######################
+*.log
+*.sql
+*.sqlite
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+# Icon?
+ehthumbs.db
+Thumbs.db
+.cache
+.project
+.settings
+.tmproj
+*.esproj
+nbproject
+
+# Numerous always-ignore extensions #
+#####################################
+*.diff
+*.err
+*.orig
+*.rej
+*.swn
+*.swo
+*.swp
+*.vi
+*~
+*.sass-cache
+*.grunt
+*.tmp
+
+# Dreamweaver added files #
+###########################
+_notes
+dwsync.xml
+
+# Komodo #
+###########################
+*.komodoproject
+.komodotools
+
+# Node #
+#####################
+node_modules
+
+# Bower #
+#####################
+bower_components
+
+# Folders to ignore #
+#####################
+.hg
+.svn
+.CVS
+intermediate
+publish
+.idea
+.graphics
+_test
+_archive
+uploads
+tmp
+
+# Vim files to ignore #
+#######################
+.VimballRecord
+.netrwhist
+
+bundle.*
+
+_demo
\ No newline at end of file
diff --git a/node_modules/svgo/node_modules/color-name/LICENSE b/node_modules/svgo/node_modules/color-name/LICENSE
new file mode 100644
index 0000000..4d9802a
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/LICENSE
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2015 Dmitry Ivanov
+
+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.
\ No newline at end of file
diff --git a/node_modules/svgo/node_modules/color-name/README.md b/node_modules/svgo/node_modules/color-name/README.md
new file mode 100644
index 0000000..3611a6b
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/README.md
@@ -0,0 +1,11 @@
+A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
+
+[](https://nodei.co/npm/color-name/)
+
+
+```js
+var colors = require('color-name');
+colors.red //[255,0,0]
+```
+
+<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
diff --git a/node_modules/svgo/node_modules/color-name/index.js b/node_modules/svgo/node_modules/color-name/index.js
new file mode 100644
index 0000000..e42aa68
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/index.js
@@ -0,0 +1,152 @@
+'use strict'
+
+module.exports = {
+ "aliceblue": [240, 248, 255],
+ "antiquewhite": [250, 235, 215],
+ "aqua": [0, 255, 255],
+ "aquamarine": [127, 255, 212],
+ "azure": [240, 255, 255],
+ "beige": [245, 245, 220],
+ "bisque": [255, 228, 196],
+ "black": [0, 0, 0],
+ "blanchedalmond": [255, 235, 205],
+ "blue": [0, 0, 255],
+ "blueviolet": [138, 43, 226],
+ "brown": [165, 42, 42],
+ "burlywood": [222, 184, 135],
+ "cadetblue": [95, 158, 160],
+ "chartreuse": [127, 255, 0],
+ "chocolate": [210, 105, 30],
+ "coral": [255, 127, 80],
+ "cornflowerblue": [100, 149, 237],
+ "cornsilk": [255, 248, 220],
+ "crimson": [220, 20, 60],
+ "cyan": [0, 255, 255],
+ "darkblue": [0, 0, 139],
+ "darkcyan": [0, 139, 139],
+ "darkgoldenrod": [184, 134, 11],
+ "darkgray": [169, 169, 169],
+ "darkgreen": [0, 100, 0],
+ "darkgrey": [169, 169, 169],
+ "darkkhaki": [189, 183, 107],
+ "darkmagenta": [139, 0, 139],
+ "darkolivegreen": [85, 107, 47],
+ "darkorange": [255, 140, 0],
+ "darkorchid": [153, 50, 204],
+ "darkred": [139, 0, 0],
+ "darksalmon": [233, 150, 122],
+ "darkseagreen": [143, 188, 143],
+ "darkslateblue": [72, 61, 139],
+ "darkslategray": [47, 79, 79],
+ "darkslategrey": [47, 79, 79],
+ "darkturquoise": [0, 206, 209],
+ "darkviolet": [148, 0, 211],
+ "deeppink": [255, 20, 147],
+ "deepskyblue": [0, 191, 255],
+ "dimgray": [105, 105, 105],
+ "dimgrey": [105, 105, 105],
+ "dodgerblue": [30, 144, 255],
+ "firebrick": [178, 34, 34],
+ "floralwhite": [255, 250, 240],
+ "forestgreen": [34, 139, 34],
+ "fuchsia": [255, 0, 255],
+ "gainsboro": [220, 220, 220],
+ "ghostwhite": [248, 248, 255],
+ "gold": [255, 215, 0],
+ "goldenrod": [218, 165, 32],
+ "gray": [128, 128, 128],
+ "green": [0, 128, 0],
+ "greenyellow": [173, 255, 47],
+ "grey": [128, 128, 128],
+ "honeydew": [240, 255, 240],
+ "hotpink": [255, 105, 180],
+ "indianred": [205, 92, 92],
+ "indigo": [75, 0, 130],
+ "ivory": [255, 255, 240],
+ "khaki": [240, 230, 140],
+ "lavender": [230, 230, 250],
+ "lavenderblush": [255, 240, 245],
+ "lawngreen": [124, 252, 0],
+ "lemonchiffon": [255, 250, 205],
+ "lightblue": [173, 216, 230],
+ "lightcoral": [240, 128, 128],
+ "lightcyan": [224, 255, 255],
+ "lightgoldenrodyellow": [250, 250, 210],
+ "lightgray": [211, 211, 211],
+ "lightgreen": [144, 238, 144],
+ "lightgrey": [211, 211, 211],
+ "lightpink": [255, 182, 193],
+ "lightsalmon": [255, 160, 122],
+ "lightseagreen": [32, 178, 170],
+ "lightskyblue": [135, 206, 250],
+ "lightslategray": [119, 136, 153],
+ "lightslategrey": [119, 136, 153],
+ "lightsteelblue": [176, 196, 222],
+ "lightyellow": [255, 255, 224],
+ "lime": [0, 255, 0],
+ "limegreen": [50, 205, 50],
+ "linen": [250, 240, 230],
+ "magenta": [255, 0, 255],
+ "maroon": [128, 0, 0],
+ "mediumaquamarine": [102, 205, 170],
+ "mediumblue": [0, 0, 205],
+ "mediumorchid": [186, 85, 211],
+ "mediumpurple": [147, 112, 219],
+ "mediumseagreen": [60, 179, 113],
+ "mediumslateblue": [123, 104, 238],
+ "mediumspringgreen": [0, 250, 154],
+ "mediumturquoise": [72, 209, 204],
+ "mediumvioletred": [199, 21, 133],
+ "midnightblue": [25, 25, 112],
+ "mintcream": [245, 255, 250],
+ "mistyrose": [255, 228, 225],
+ "moccasin": [255, 228, 181],
+ "navajowhite": [255, 222, 173],
+ "navy": [0, 0, 128],
+ "oldlace": [253, 245, 230],
+ "olive": [128, 128, 0],
+ "olivedrab": [107, 142, 35],
+ "orange": [255, 165, 0],
+ "orangered": [255, 69, 0],
+ "orchid": [218, 112, 214],
+ "palegoldenrod": [238, 232, 170],
+ "palegreen": [152, 251, 152],
+ "paleturquoise": [175, 238, 238],
+ "palevioletred": [219, 112, 147],
+ "papayawhip": [255, 239, 213],
+ "peachpuff": [255, 218, 185],
+ "peru": [205, 133, 63],
+ "pink": [255, 192, 203],
+ "plum": [221, 160, 221],
+ "powderblue": [176, 224, 230],
+ "purple": [128, 0, 128],
+ "rebeccapurple": [102, 51, 153],
+ "red": [255, 0, 0],
+ "rosybrown": [188, 143, 143],
+ "royalblue": [65, 105, 225],
+ "saddlebrown": [139, 69, 19],
+ "salmon": [250, 128, 114],
+ "sandybrown": [244, 164, 96],
+ "seagreen": [46, 139, 87],
+ "seashell": [255, 245, 238],
+ "sienna": [160, 82, 45],
+ "silver": [192, 192, 192],
+ "skyblue": [135, 206, 235],
+ "slateblue": [106, 90, 205],
+ "slategray": [112, 128, 144],
+ "slategrey": [112, 128, 144],
+ "snow": [255, 250, 250],
+ "springgreen": [0, 255, 127],
+ "steelblue": [70, 130, 180],
+ "tan": [210, 180, 140],
+ "teal": [0, 128, 128],
+ "thistle": [216, 191, 216],
+ "tomato": [255, 99, 71],
+ "turquoise": [64, 224, 208],
+ "violet": [238, 130, 238],
+ "wheat": [245, 222, 179],
+ "white": [255, 255, 255],
+ "whitesmoke": [245, 245, 245],
+ "yellow": [255, 255, 0],
+ "yellowgreen": [154, 205, 50]
+};
diff --git a/node_modules/svgo/node_modules/color-name/package.json b/node_modules/svgo/node_modules/color-name/package.json
new file mode 100644
index 0000000..6011c26
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/package.json
@@ -0,0 +1,53 @@
+{
+ "_from": "color-name@1.1.3",
+ "_id": "color-name@1.1.3",
+ "_inBundle": false,
+ "_integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "_location": "/svgo/color-name",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "version",
+ "registry": true,
+ "raw": "color-name@1.1.3",
+ "name": "color-name",
+ "escapedName": "color-name",
+ "rawSpec": "1.1.3",
+ "saveSpec": null,
+ "fetchSpec": "1.1.3"
+ },
+ "_requiredBy": [
+ "/svgo/color-convert"
+ ],
+ "_resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "_shasum": "a7d0558bd89c42f795dd42328f740831ca53bc25",
+ "_spec": "color-name@1.1.3",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo\\node_modules\\color-convert",
+ "author": {
+ "name": "DY",
+ "email": "dfcreative@gmail.com"
+ },
+ "bugs": {
+ "url": "https://github.com/dfcreative/color-name/issues"
+ },
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "A list of color names and its values",
+ "homepage": "https://github.com/dfcreative/color-name",
+ "keywords": [
+ "color-name",
+ "color",
+ "color-keyword",
+ "keyword"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "name": "color-name",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/dfcreative/color-name.git"
+ },
+ "scripts": {
+ "test": "node test.js"
+ },
+ "version": "1.1.3"
+}
diff --git a/node_modules/svgo/node_modules/color-name/test.js b/node_modules/svgo/node_modules/color-name/test.js
new file mode 100644
index 0000000..7a08746
--- /dev/null
+++ b/node_modules/svgo/node_modules/color-name/test.js
@@ -0,0 +1,7 @@
+'use strict'
+
+var names = require('./');
+var assert = require('assert');
+
+assert.deepEqual(names.red, [255,0,0]);
+assert.deepEqual(names.aliceblue, [240,248,255]);
diff --git a/node_modules/svgo/node_modules/has-flag/index.js b/node_modules/svgo/node_modules/has-flag/index.js
new file mode 100644
index 0000000..5139728
--- /dev/null
+++ b/node_modules/svgo/node_modules/has-flag/index.js
@@ -0,0 +1,8 @@
+'use strict';
+module.exports = (flag, argv) => {
+ argv = argv || process.argv;
+ const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
+ const pos = argv.indexOf(prefix + flag);
+ const terminatorPos = argv.indexOf('--');
+ return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos);
+};
diff --git a/node_modules/svgo/node_modules/has-flag/license b/node_modules/svgo/node_modules/has-flag/license
new file mode 100644
index 0000000..e7af2f7
--- /dev/null
+++ b/node_modules/svgo/node_modules/has-flag/license
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
diff --git a/node_modules/svgo/node_modules/has-flag/package.json b/node_modules/svgo/node_modules/has-flag/package.json
new file mode 100644
index 0000000..9ab76e8
--- /dev/null
+++ b/node_modules/svgo/node_modules/has-flag/package.json
@@ -0,0 +1,76 @@
+{
+ "_from": "has-flag@^3.0.0",
+ "_id": "has-flag@3.0.0",
+ "_inBundle": false,
+ "_integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "_location": "/svgo/has-flag",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "has-flag@^3.0.0",
+ "name": "has-flag",
+ "escapedName": "has-flag",
+ "rawSpec": "^3.0.0",
+ "saveSpec": null,
+ "fetchSpec": "^3.0.0"
+ },
+ "_requiredBy": [
+ "/svgo/supports-color"
+ ],
+ "_resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "_shasum": "b5d454dc2199ae225699f3467e5a07f3b955bafd",
+ "_spec": "has-flag@^3.0.0",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo\\node_modules\\supports-color",
+ "author": {
+ "name": "Sindre Sorhus",
+ "email": "sindresorhus@gmail.com",
+ "url": "sindresorhus.com"
+ },
+ "bugs": {
+ "url": "https://github.com/sindresorhus/has-flag/issues"
+ },
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "Check if argv has a specific flag",
+ "devDependencies": {
+ "ava": "*",
+ "xo": "*"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "files": [
+ "index.js"
+ ],
+ "homepage": "https://github.com/sindresorhus/has-flag#readme",
+ "keywords": [
+ "has",
+ "check",
+ "detect",
+ "contains",
+ "find",
+ "flag",
+ "cli",
+ "command-line",
+ "argv",
+ "process",
+ "arg",
+ "args",
+ "argument",
+ "arguments",
+ "getopt",
+ "minimist",
+ "optimist"
+ ],
+ "license": "MIT",
+ "name": "has-flag",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/sindresorhus/has-flag.git"
+ },
+ "scripts": {
+ "test": "xo && ava"
+ },
+ "version": "3.0.0"
+}
diff --git a/node_modules/svgo/node_modules/has-flag/readme.md b/node_modules/svgo/node_modules/has-flag/readme.md
new file mode 100644
index 0000000..677893c
--- /dev/null
+++ b/node_modules/svgo/node_modules/has-flag/readme.md
@@ -0,0 +1,70 @@
+# has-flag [](https://travis-ci.org/sindresorhus/has-flag)
+
+> Check if [`argv`](https://nodejs.org/docs/latest/api/process.html#process_process_argv) has a specific flag
+
+Correctly stops looking after an `--` argument terminator.
+
+
+## Install
+
+```
+$ npm install has-flag
+```
+
+
+## Usage
+
+```js
+// foo.js
+const hasFlag = require('has-flag');
+
+hasFlag('unicorn');
+//=> true
+
+hasFlag('--unicorn');
+//=> true
+
+hasFlag('f');
+//=> true
+
+hasFlag('-f');
+//=> true
+
+hasFlag('foo=bar');
+//=> true
+
+hasFlag('foo');
+//=> false
+
+hasFlag('rainbow');
+//=> false
+```
+
+```
+$ node foo.js -f --unicorn --foo=bar -- --rainbow
+```
+
+
+## API
+
+### hasFlag(flag, [argv])
+
+Returns a boolean for whether the flag exists.
+
+#### flag
+
+Type: `string`
+
+CLI flag to look for. The `--` prefix is optional.
+
+#### argv
+
+Type: `string[]`<br>
+Default: `process.argv`
+
+CLI arguments.
+
+
+## License
+
+MIT © [Sindre Sorhus](https://sindresorhus.com)
diff --git a/node_modules/svgo/node_modules/mkdirp/LICENSE b/node_modules/svgo/node_modules/mkdirp/LICENSE
new file mode 100644
index 0000000..432d1ae
--- /dev/null
+++ b/node_modules/svgo/node_modules/mkdirp/LICENSE
@@ -0,0 +1,21 @@
+Copyright 2010 James Halliday (mail@substack.net)
+
+This project is free software released under the MIT/X11 license:
+
+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.
diff --git a/node_modules/svgo/node_modules/mkdirp/bin/cmd.js b/node_modules/svgo/node_modules/mkdirp/bin/cmd.js
new file mode 100644
index 0000000..d95de15
--- /dev/null
+++ b/node_modules/svgo/node_modules/mkdirp/bin/cmd.js
@@ -0,0 +1,33 @@
+#!/usr/bin/env node
+
+var mkdirp = require('../');
+var minimist = require('minimist');
+var fs = require('fs');
+
+var argv = minimist(process.argv.slice(2), {
+ alias: { m: 'mode', h: 'help' },
+ string: [ 'mode' ]
+});
+if (argv.help) {
+ fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
+ return;
+}
+
+var paths = argv._.slice();
+var mode = argv.mode ? parseInt(argv.mode, 8) : undefined;
+
+(function next () {
+ if (paths.length === 0) return;
+ var p = paths.shift();
+
+ if (mode === undefined) mkdirp(p, cb)
+ else mkdirp(p, mode, cb)
+
+ function cb (err) {
+ if (err) {
+ console.error(err.message);
+ process.exit(1);
+ }
+ else next();
+ }
+})();
diff --git a/node_modules/svgo/node_modules/mkdirp/bin/usage.txt b/node_modules/svgo/node_modules/mkdirp/bin/usage.txt
new file mode 100644
index 0000000..f952aa2
--- /dev/null
+++ b/node_modules/svgo/node_modules/mkdirp/bin/usage.txt
@@ -0,0 +1,12 @@
+usage: mkdirp [DIR1,DIR2..] {OPTIONS}
+
+ Create each supplied directory including any necessary parent directories that
+ don't yet exist.
+
+ If the directory already exists, do nothing.
+
+OPTIONS are:
+
+ -m, --mode If a directory needs to be created, set the mode as an octal
+ permission string.
+
diff --git a/node_modules/svgo/node_modules/mkdirp/index.js b/node_modules/svgo/node_modules/mkdirp/index.js
new file mode 100644
index 0000000..468d7cd
--- /dev/null
+++ b/node_modules/svgo/node_modules/mkdirp/index.js
@@ -0,0 +1,99 @@
+var path = require('path');
+var fs = require('fs');
+var _0777 = parseInt('0777', 8);
+
+module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;
+
+function mkdirP (p, opts, f, made) {
+ if (typeof opts === 'function') {
+ f = opts;
+ opts = {};
+ }
+ else if (!opts || typeof opts !== 'object') {
+ opts = { mode: opts };
+ }
+
+ var mode = opts.mode;
+ var xfs = opts.fs || fs;
+
+ if (mode === undefined) {
+ mode = _0777
+ }
+ if (!made) made = null;
+
+ var cb = f || function () {};
+ p = path.resolve(p);
+
+ xfs.mkdir(p, mode, function (er) {
+ if (!er) {
+ made = made || p;
+ return cb(null, made);
+ }
+ switch (er.code) {
+ case 'ENOENT':
+ if (path.dirname(p) === p) return cb(er);
+ mkdirP(path.dirname(p), opts, function (er, made) {
+ if (er) cb(er, made);
+ else mkdirP(p, opts, cb, made);
+ });
+ break;
+
+ // In the case of any other error, just see if there's a dir
+ // there already. If so, then hooray! If not, then something
+ // is borked.
+ default:
+ xfs.stat(p, function (er2, stat) {
+ // if the stat fails, then that's super weird.
+ // let the original error be the failure reason.
+ if (er2 || !stat.isDirectory()) cb(er, made)
+ else cb(null, made);
+ });
+ break;
+ }
+ });
+}
+
+mkdirP.sync = function sync (p, opts, made) {
+ if (!opts || typeof opts !== 'object') {
+ opts = { mode: opts };
+ }
+
+ var mode = opts.mode;
+ var xfs = opts.fs || fs;
+
+ if (mode === undefined) {
+ mode = _0777
+ }
+ if (!made) made = null;
+
+ p = path.resolve(p);
+
+ try {
+ xfs.mkdirSync(p, mode);
+ made = made || p;
+ }
+ catch (err0) {
+ switch (err0.code) {
+ case 'ENOENT' :
+ made = sync(path.dirname(p), opts, made);
+ sync(p, opts, made);
+ break;
+
+ // In the case of any other error, just see if there's a dir
+ // there already. If so, then hooray! If not, then something
+ // is borked.
+ default:
+ var stat;
+ try {
+ stat = xfs.statSync(p);
+ }
+ catch (err1) {
+ throw err0;
+ }
+ if (!stat.isDirectory()) throw err0;
+ break;
+ }
+ }
+
+ return made;
+};
diff --git a/node_modules/svgo/node_modules/mkdirp/package.json b/node_modules/svgo/node_modules/mkdirp/package.json
new file mode 100644
index 0000000..1ce5d4b
--- /dev/null
+++ b/node_modules/svgo/node_modules/mkdirp/package.json
@@ -0,0 +1,69 @@
+{
+ "_from": "mkdirp@~0.5.1",
+ "_id": "mkdirp@0.5.5",
+ "_inBundle": false,
+ "_integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "_location": "/svgo/mkdirp",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "mkdirp@~0.5.1",
+ "name": "mkdirp",
+ "escapedName": "mkdirp",
+ "rawSpec": "~0.5.1",
+ "saveSpec": null,
+ "fetchSpec": "~0.5.1"
+ },
+ "_requiredBy": [
+ "/svgo"
+ ],
+ "_resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "_shasum": "d91cefd62d1436ca0f41620e251288d420099def",
+ "_spec": "mkdirp@~0.5.1",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo",
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "bugs": {
+ "url": "https://github.com/substack/node-mkdirp/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "deprecated": false,
+ "description": "Recursively mkdir, like `mkdir -p`",
+ "devDependencies": {
+ "mock-fs": "^3.7.0",
+ "tap": "^5.4.2"
+ },
+ "files": [
+ "bin",
+ "index.js"
+ ],
+ "homepage": "https://github.com/substack/node-mkdirp#readme",
+ "keywords": [
+ "mkdir",
+ "directory"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "name": "mkdirp",
+ "publishConfig": {
+ "tag": "legacy"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/substack/node-mkdirp.git"
+ },
+ "scripts": {
+ "test": "tap test/*.js"
+ },
+ "version": "0.5.5"
+}
diff --git a/node_modules/svgo/node_modules/mkdirp/readme.markdown b/node_modules/svgo/node_modules/mkdirp/readme.markdown
new file mode 100644
index 0000000..fc314bf
--- /dev/null
+++ b/node_modules/svgo/node_modules/mkdirp/readme.markdown
@@ -0,0 +1,100 @@
+# mkdirp
+
+Like `mkdir -p`, but in node.js!
+
+[](http://travis-ci.org/substack/node-mkdirp)
+
+# example
+
+## pow.js
+
+```js
+var mkdirp = require('mkdirp');
+
+mkdirp('/tmp/foo/bar/baz', function (err) {
+ if (err) console.error(err)
+ else console.log('pow!')
+});
+```
+
+Output
+
+```
+pow!
+```
+
+And now /tmp/foo/bar/baz exists, huzzah!
+
+# methods
+
+```js
+var mkdirp = require('mkdirp');
+```
+
+## mkdirp(dir, opts, cb)
+
+Create a new directory and any necessary subdirectories at `dir` with octal
+permission string `opts.mode`. If `opts` is a non-object, it will be treated as
+the `opts.mode`.
+
+If `opts.mode` isn't specified, it defaults to `0777`.
+
+`cb(err, made)` fires with the error or the first directory `made`
+that had to be created, if any.
+
+You can optionally pass in an alternate `fs` implementation by passing in
+`opts.fs`. Your implementation should have `opts.fs.mkdir(path, mode, cb)` and
+`opts.fs.stat(path, cb)`.
+
+## mkdirp.sync(dir, opts)
+
+Synchronously create a new directory and any necessary subdirectories at `dir`
+with octal permission string `opts.mode`. If `opts` is a non-object, it will be
+treated as the `opts.mode`.
+
+If `opts.mode` isn't specified, it defaults to `0777`.
+
+Returns the first directory that had to be created, if any.
+
+You can optionally pass in an alternate `fs` implementation by passing in
+`opts.fs`. Your implementation should have `opts.fs.mkdirSync(path, mode)` and
+`opts.fs.statSync(path)`.
+
+# usage
+
+This package also ships with a `mkdirp` command.
+
+```
+usage: mkdirp [DIR1,DIR2..] {OPTIONS}
+
+ Create each supplied directory including any necessary parent directories that
+ don't yet exist.
+
+ If the directory already exists, do nothing.
+
+OPTIONS are:
+
+ -m, --mode If a directory needs to be created, set the mode as an octal
+ permission string.
+
+```
+
+# install
+
+With [npm](http://npmjs.org) do:
+
+```
+npm install mkdirp
+```
+
+to get the library, or
+
+```
+npm install -g mkdirp
+```
+
+to get the command.
+
+# license
+
+MIT
diff --git a/node_modules/svgo/node_modules/supports-color/browser.js b/node_modules/svgo/node_modules/supports-color/browser.js
new file mode 100644
index 0000000..62afa3a
--- /dev/null
+++ b/node_modules/svgo/node_modules/supports-color/browser.js
@@ -0,0 +1,5 @@
+'use strict';
+module.exports = {
+ stdout: false,
+ stderr: false
+};
diff --git a/node_modules/svgo/node_modules/supports-color/index.js b/node_modules/svgo/node_modules/supports-color/index.js
new file mode 100644
index 0000000..1704131
--- /dev/null
+++ b/node_modules/svgo/node_modules/supports-color/index.js
@@ -0,0 +1,131 @@
+'use strict';
+const os = require('os');
+const hasFlag = require('has-flag');
+
+const env = process.env;
+
+let forceColor;
+if (hasFlag('no-color') ||
+ hasFlag('no-colors') ||
+ hasFlag('color=false')) {
+ forceColor = false;
+} else if (hasFlag('color') ||
+ hasFlag('colors') ||
+ hasFlag('color=true') ||
+ hasFlag('color=always')) {
+ forceColor = true;
+}
+if ('FORCE_COLOR' in env) {
+ forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0;
+}
+
+function translateLevel(level) {
+ if (level === 0) {
+ return false;
+ }
+
+ return {
+ level,
+ hasBasic: true,
+ has256: level >= 2,
+ has16m: level >= 3
+ };
+}
+
+function supportsColor(stream) {
+ if (forceColor === false) {
+ return 0;
+ }
+
+ if (hasFlag('color=16m') ||
+ hasFlag('color=full') ||
+ hasFlag('color=truecolor')) {
+ return 3;
+ }
+
+ if (hasFlag('color=256')) {
+ return 2;
+ }
+
+ if (stream && !stream.isTTY && forceColor !== true) {
+ return 0;
+ }
+
+ const min = forceColor ? 1 : 0;
+
+ if (process.platform === 'win32') {
+ // Node.js 7.5.0 is the first version of Node.js to include a patch to
+ // libuv that enables 256 color output on Windows. Anything earlier and it
+ // won't work. However, here we target Node.js 8 at minimum as it is an LTS
+ // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows
+ // release that supports 256 colors. Windows 10 build 14931 is the first release
+ // that supports 16m/TrueColor.
+ const osRelease = os.release().split('.');
+ if (
+ Number(process.versions.node.split('.')[0]) >= 8 &&
+ Number(osRelease[0]) >= 10 &&
+ Number(osRelease[2]) >= 10586
+ ) {
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
+ }
+
+ return 1;
+ }
+
+ if ('CI' in env) {
+ if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
+ return 1;
+ }
+
+ return min;
+ }
+
+ if ('TEAMCITY_VERSION' in env) {
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
+ }
+
+ if (env.COLORTERM === 'truecolor') {
+ return 3;
+ }
+
+ if ('TERM_PROGRAM' in env) {
+ const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
+
+ switch (env.TERM_PROGRAM) {
+ case 'iTerm.app':
+ return version >= 3 ? 3 : 2;
+ case 'Apple_Terminal':
+ return 2;
+ // No default
+ }
+ }
+
+ if (/-256(color)?$/i.test(env.TERM)) {
+ return 2;
+ }
+
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
+ return 1;
+ }
+
+ if ('COLORTERM' in env) {
+ return 1;
+ }
+
+ if (env.TERM === 'dumb') {
+ return min;
+ }
+
+ return min;
+}
+
+function getSupportLevel(stream) {
+ const level = supportsColor(stream);
+ return translateLevel(level);
+}
+
+module.exports = {
+ supportsColor: getSupportLevel,
+ stdout: getSupportLevel(process.stdout),
+ stderr: getSupportLevel(process.stderr)
+};
diff --git a/node_modules/svgo/node_modules/supports-color/license b/node_modules/svgo/node_modules/supports-color/license
new file mode 100644
index 0000000..e7af2f7
--- /dev/null
+++ b/node_modules/svgo/node_modules/supports-color/license
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
diff --git a/node_modules/svgo/node_modules/supports-color/package.json b/node_modules/svgo/node_modules/supports-color/package.json
new file mode 100644
index 0000000..6008076
--- /dev/null
+++ b/node_modules/svgo/node_modules/supports-color/package.json
@@ -0,0 +1,85 @@
+{
+ "_from": "supports-color@^5.3.0",
+ "_id": "supports-color@5.5.0",
+ "_inBundle": false,
+ "_integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "_location": "/svgo/supports-color",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "supports-color@^5.3.0",
+ "name": "supports-color",
+ "escapedName": "supports-color",
+ "rawSpec": "^5.3.0",
+ "saveSpec": null,
+ "fetchSpec": "^5.3.0"
+ },
+ "_requiredBy": [
+ "/svgo/chalk"
+ ],
+ "_resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "_shasum": "e2e69a44ac8772f78a1ec0b35b689df6530efc8f",
+ "_spec": "supports-color@^5.3.0",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\svgo\\node_modules\\chalk",
+ "author": {
+ "name": "Sindre Sorhus",
+ "email": "sindresorhus@gmail.com",
+ "url": "sindresorhus.com"
+ },
+ "browser": "browser.js",
+ "bugs": {
+ "url": "https://github.com/chalk/supports-color/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "deprecated": false,
+ "description": "Detect whether a terminal supports color",
+ "devDependencies": {
+ "ava": "^0.25.0",
+ "import-fresh": "^2.0.0",
+ "xo": "^0.20.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "files": [
+ "index.js",
+ "browser.js"
+ ],
+ "homepage": "https://github.com/chalk/supports-color#readme",
+ "keywords": [
+ "color",
+ "colour",
+ "colors",
+ "terminal",
+ "console",
+ "cli",
+ "ansi",
+ "styles",
+ "tty",
+ "rgb",
+ "256",
+ "shell",
+ "xterm",
+ "command-line",
+ "support",
+ "supports",
+ "capability",
+ "detect",
+ "truecolor",
+ "16m"
+ ],
+ "license": "MIT",
+ "name": "supports-color",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/chalk/supports-color.git"
+ },
+ "scripts": {
+ "test": "xo && ava"
+ },
+ "version": "5.5.0"
+}
diff --git a/node_modules/svgo/node_modules/supports-color/readme.md b/node_modules/svgo/node_modules/supports-color/readme.md
new file mode 100644
index 0000000..f6e4019
--- /dev/null
+++ b/node_modules/svgo/node_modules/supports-color/readme.md
@@ -0,0 +1,66 @@
+# supports-color [](https://travis-ci.org/chalk/supports-color)
+
+> Detect whether a terminal supports color
+
+
+## Install
+
+```
+$ npm install supports-color
+```
+
+
+## Usage
+
+```js
+const supportsColor = require('supports-color');
+
+if (supportsColor.stdout) {
+ console.log('Terminal stdout supports color');
+}
+
+if (supportsColor.stdout.has256) {
+ console.log('Terminal stdout supports 256 colors');
+}
+
+if (supportsColor.stderr.has16m) {
+ console.log('Terminal stderr supports 16 million colors (truecolor)');
+}
+```
+
+
+## API
+
+Returns an `Object` with a `stdout` and `stderr` property for testing either streams. Each property is an `Object`, or `false` if color is not supported.
+
+The `stdout`/`stderr` objects specifies a level of support for color through a `.level` property and a corresponding flag:
+
+- `.level = 1` and `.hasBasic = true`: Basic color support (16 colors)
+- `.level = 2` and `.has256 = true`: 256 color support
+- `.level = 3` and `.has16m = true`: Truecolor support (16 million colors)
+
+
+## Info
+
+It obeys the `--color` and `--no-color` CLI flags.
+
+Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add the environment variable `FORCE_COLOR=1` to forcefully enable color or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks.
+
+Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively.
+
+
+## Related
+
+- [supports-color-cli](https://github.com/chalk/supports-color-cli) - CLI for this module
+- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right
+
+
+## Maintainers
+
+- [Sindre Sorhus](https://github.com/sindresorhus)
+- [Josh Junon](https://github.com/qix-)
+
+
+## License
+
+MIT
diff --git a/node_modules/svgo/package.json b/node_modules/svgo/package.json
new file mode 100644
index 0000000..3cb7405
--- /dev/null
+++ b/node_modules/svgo/package.json
@@ -0,0 +1,107 @@
+{
+ "_from": "svgo@^1.3.2",
+ "_id": "svgo@1.3.2",
+ "_inBundle": false,
+ "_integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
+ "_location": "/svgo",
+ "_phantomChildren": {
+ "escape-string-regexp": "1.0.5",
+ "minimist": "1.2.5"
+ },
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "svgo@^1.3.2",
+ "name": "svgo",
+ "escapedName": "svgo",
+ "rawSpec": "^1.3.2",
+ "saveSpec": null,
+ "fetchSpec": "^1.3.2"
+ },
+ "_requiredBy": [
+ "/imagemin-svgo"
+ ],
+ "_resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
+ "_shasum": "b6dc511c063346c9e415b81e43401145b96d4167",
+ "_spec": "svgo@^1.3.2",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\imagemin-svgo",
+ "author": {
+ "name": "Kir Belevich",
+ "email": "kir@belevi.ch",
+ "url": "https://github.com/deepsweet"
+ },
+ "bin": {
+ "svgo": "bin/svgo"
+ },
+ "bugs": {
+ "url": "https://github.com/svg/svgo/issues"
+ },
+ "bundleDependencies": false,
+ "contributors": [
+ {
+ "name": "Sergey Belov",
+ "email": "peimei@ya.ru",
+ "url": "http://github.com/arikon"
+ },
+ {
+ "name": "Lev Solntsev",
+ "email": "lev.sun@ya.ru",
+ "url": "http://github.com/GreLI"
+ }
+ ],
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "coa": "^2.0.2",
+ "css-select": "^2.0.0",
+ "css-select-base-adapter": "^0.1.1",
+ "css-tree": "1.0.0-alpha.37",
+ "csso": "^4.0.2",
+ "js-yaml": "^3.13.1",
+ "mkdirp": "~0.5.1",
+ "object.values": "^1.1.0",
+ "sax": "~1.2.4",
+ "stable": "^0.1.8",
+ "unquote": "~1.1.1",
+ "util.promisify": "~1.0.0"
+ },
+ "deprecated": false,
+ "description": "Nodejs-based tool for optimizing SVG vector graphics files",
+ "devDependencies": {
+ "coveralls": "^3.0.7",
+ "fs-extra": "~8.1.0",
+ "istanbul": "~0.4.5",
+ "jshint": "~2.10.2",
+ "mocha": "~6.2.2",
+ "mocha-istanbul": "~0.3.0",
+ "mock-stdin": "~0.3.1",
+ "should": "~13.2.3"
+ },
+ "directories": {
+ "bin": "./bin",
+ "lib": "./lib",
+ "example": "./examples"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ },
+ "homepage": "https://github.com/svg/svgo",
+ "keywords": [
+ "svgo",
+ "svg",
+ "optimize",
+ "minify"
+ ],
+ "license": "MIT",
+ "main": "./lib/svgo.js",
+ "name": "svgo",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/svg/svgo.git"
+ },
+ "scripts": {
+ "jshint": "npm run lint",
+ "lint": "jshint --show-non-errors .",
+ "test": "set NODE_ENV=test && mocha"
+ },
+ "version": "1.3.2"
+}
diff --git a/node_modules/svgo/plugins/_collections.js b/node_modules/svgo/plugins/_collections.js
new file mode 100644
index 0000000..8179f30
--- /dev/null
+++ b/node_modules/svgo/plugins/_collections.js
@@ -0,0 +1,2558 @@
+'use strict';
+
+// http://www.w3.org/TR/SVG11/intro.html#Definitions
+exports.elemsGroups = {
+ animation: ['animate', 'animateColor', 'animateMotion', 'animateTransform', 'set'],
+ descriptive: ['desc', 'metadata', 'title'],
+ shape: ['circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect'],
+ structural: ['defs', 'g', 'svg', 'symbol', 'use'],
+ paintServer: ['solidColor', 'linearGradient', 'radialGradient', 'meshGradient', 'pattern', 'hatch'],
+ nonRendering: ['linearGradient', 'radialGradient', 'pattern', 'clipPath', 'mask', 'marker', 'symbol', 'filter', 'solidColor'],
+ container: ['a', 'defs', 'g', 'marker', 'mask', 'missing-glyph', 'pattern', 'svg', 'switch', 'symbol', 'foreignObject'],
+ textContent: ['altGlyph', 'altGlyphDef', 'altGlyphItem', 'glyph', 'glyphRef', 'textPath', 'text', 'tref', 'tspan'],
+ textContentChild: ['altGlyph', 'textPath', 'tref', 'tspan'],
+ lightSource: ['feDiffuseLighting', 'feSpecularLighting', 'feDistantLight', 'fePointLight', 'feSpotLight'],
+ filterPrimitive: ['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feFlood', 'feGaussianBlur', 'feImage', 'feMerge', 'feMorphology', 'feOffset', 'feSpecularLighting', 'feTile', 'feTurbulence']
+};
+
+exports.pathElems = ['path', 'glyph', 'missing-glyph'];
+
+// http://www.w3.org/TR/SVG11/intro.html#Definitions
+exports.attrsGroups = {
+ animationAddition: ['additive', 'accumulate'],
+ animationAttributeTarget: ['attributeType', 'attributeName'],
+ animationEvent: ['onbegin', 'onend', 'onrepeat', 'onload'],
+ animationTiming: ['begin', 'dur', 'end', 'min', 'max', 'restart', 'repeatCount', 'repeatDur', 'fill'],
+ animationValue: ['calcMode', 'values', 'keyTimes', 'keySplines', 'from', 'to', 'by'],
+ conditionalProcessing: ['requiredFeatures', 'requiredExtensions', 'systemLanguage'],
+ core: ['id', 'tabindex', 'xml:base', 'xml:lang', 'xml:space'],
+ graphicalEvent: ['onfocusin', 'onfocusout', 'onactivate', 'onclick', 'onmousedown', 'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onload'],
+ presentation: [
+ 'alignment-baseline',
+ 'baseline-shift',
+ 'clip',
+ 'clip-path',
+ 'clip-rule',
+ 'color',
+ 'color-interpolation',
+ 'color-interpolation-filters',
+ 'color-profile',
+ 'color-rendering',
+ 'cursor',
+ 'direction',
+ 'display',
+ 'dominant-baseline',
+ 'enable-background',
+ 'fill',
+ 'fill-opacity',
+ 'fill-rule',
+ 'filter',
+ 'flood-color',
+ 'flood-opacity',
+ 'font-family',
+ 'font-size',
+ 'font-size-adjust',
+ 'font-stretch',
+ 'font-style',
+ 'font-variant',
+ 'font-weight',
+ 'glyph-orientation-horizontal',
+ 'glyph-orientation-vertical',
+ 'image-rendering',
+ 'letter-spacing',
+ 'lighting-color',
+ 'marker-end',
+ 'marker-mid',
+ 'marker-start',
+ 'mask',
+ 'opacity',
+ 'overflow',
+ 'paint-order',
+ 'pointer-events',
+ 'shape-rendering',
+ 'stop-color',
+ 'stop-opacity',
+ 'stroke',
+ 'stroke-dasharray',
+ 'stroke-dashoffset',
+ 'stroke-linecap',
+ 'stroke-linejoin',
+ 'stroke-miterlimit',
+ 'stroke-opacity',
+ 'stroke-width',
+ 'text-anchor',
+ 'text-decoration',
+ 'text-overflow',
+ 'text-rendering',
+ 'transform',
+ 'unicode-bidi',
+ 'vector-effect',
+ 'visibility',
+ 'word-spacing',
+ 'writing-mode'
+ ],
+ xlink: ['xlink:href', 'xlink:show', 'xlink:actuate', 'xlink:type', 'xlink:role', 'xlink:arcrole', 'xlink:title'],
+ documentEvent: ['onunload', 'onabort', 'onerror', 'onresize', 'onscroll', 'onzoom'],
+ filterPrimitive: ['x', 'y', 'width', 'height', 'result'],
+ transferFunction: ['type', 'tableValues', 'slope', 'intercept', 'amplitude', 'exponent', 'offset']
+};
+
+exports.attrsGroupsDefaults = {
+ core: {'xml:space': 'preserve'},
+ filterPrimitive: {x: '0', y: '0', width: '100%', height: '100%'},
+ presentation: {
+ clip: 'auto',
+ 'clip-path': 'none',
+ 'clip-rule': 'nonzero',
+ mask: 'none',
+ opacity: '1',
+ 'stop-color': '#000',
+ 'stop-opacity': '1',
+ 'fill-opacity': '1',
+ 'fill-rule': 'nonzero',
+ fill: '#000',
+ stroke: 'none',
+ 'stroke-width': '1',
+ 'stroke-linecap': 'butt',
+ 'stroke-linejoin': 'miter',
+ 'stroke-miterlimit': '4',
+ 'stroke-dasharray': 'none',
+ 'stroke-dashoffset': '0',
+ 'stroke-opacity': '1',
+ 'paint-order': 'normal',
+ 'vector-effect': 'none',
+ display: 'inline',
+ visibility: 'visible',
+ 'marker-start': 'none',
+ 'marker-mid': 'none',
+ 'marker-end': 'none',
+ 'color-interpolation': 'sRGB',
+ 'color-interpolation-filters': 'linearRGB',
+ 'color-rendering': 'auto',
+ 'shape-rendering': 'auto',
+ 'text-rendering': 'auto',
+ 'image-rendering': 'auto',
+ 'font-style': 'normal',
+ 'font-variant': 'normal',
+ 'font-weight': 'normal',
+ 'font-stretch': 'normal',
+ 'font-size': 'medium',
+ 'font-size-adjust': 'none',
+ kerning: 'auto',
+ 'letter-spacing': 'normal',
+ 'word-spacing': 'normal',
+ 'text-decoration': 'none',
+ 'text-anchor': 'start',
+ 'text-overflow': 'clip',
+ 'writing-mode': 'lr-tb',
+ 'glyph-orientation-vertical': 'auto',
+ 'glyph-orientation-horizontal': '0deg',
+ direction: 'ltr',
+ 'unicode-bidi': 'normal',
+ 'dominant-baseline': 'auto',
+ 'alignment-baseline': 'baseline',
+ 'baseline-shift': 'baseline'
+ },
+ transferFunction: {slope: '1', intercept: '0', amplitude: '1', exponent: '1', offset: '0'}
+};
+
+// http://www.w3.org/TR/SVG11/eltindex.html
+exports.elems = {
+ a: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'target'
+ ],
+ defaults: {
+ target: '_self'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ altGlyph: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'x',
+ 'y',
+ 'dx',
+ 'dy',
+ 'glyphRef',
+ 'format',
+ 'rotate'
+ ]
+ },
+ altGlyphDef: {
+ attrsGroups: [
+ 'core'
+ ],
+ content: [
+ 'glyphRef'
+ ]
+ },
+ altGlyphItem: {
+ attrsGroups: [
+ 'core'
+ ],
+ content: [
+ 'glyphRef',
+ 'altGlyphItem'
+ ]
+ },
+ animate: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'animationAddition',
+ 'animationAttributeTarget',
+ 'animationEvent',
+ 'animationTiming',
+ 'animationValue',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'externalResourcesRequired'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ animateColor: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'animationEvent',
+ 'xlink',
+ 'animationAttributeTarget',
+ 'animationTiming',
+ 'animationValue',
+ 'animationAddition',
+ 'presentation'
+ ],
+ attrs: [
+ 'externalResourcesRequired'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ animateMotion: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'animationEvent',
+ 'xlink',
+ 'animationTiming',
+ 'animationValue',
+ 'animationAddition'
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'path',
+ 'keyPoints',
+ 'rotate',
+ 'origin'
+ ],
+ defaults: {
+ 'rotate': '0'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'mpath'
+ ]
+ },
+ animateTransform: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'animationEvent',
+ 'xlink',
+ 'animationAttributeTarget',
+ 'animationTiming',
+ 'animationValue',
+ 'animationAddition'
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'type'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ circle: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'cx',
+ 'cy',
+ 'r'
+ ],
+ defaults: {
+ cx: '0',
+ cy: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ clipPath: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'clipPathUnits'
+ ],
+ defaults: {
+ clipPathUnits: 'userSpaceOnUse'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape'
+ ],
+ content: [
+ 'text',
+ 'use'
+ ]
+ },
+ 'color-profile': {
+ attrsGroups: [
+ 'core',
+ 'xlink'
+ ],
+ attrs: [
+ 'local',
+ 'name',
+ 'rendering-intent'
+ ],
+ defaults: {
+ name: 'sRGB',
+ 'rendering-intent': 'auto'
+ },
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ cursor: {
+ attrsGroups: [
+ 'core',
+ 'conditionalProcessing',
+ 'xlink'
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'x',
+ 'y'
+ ],
+ defaults: {
+ x: '0',
+ y: '0'
+ },
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ defs: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ desc: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ]
+ },
+ ellipse: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'cx',
+ 'cy',
+ 'rx',
+ 'ry'
+ ],
+ defaults: {
+ cx: '0',
+ cy: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ feBlend: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ // TODO: in - 'If no value is provided and this is the first filter primitive,
+ // then this filter primitive will use SourceGraphic as its input'
+ 'in',
+ 'in2',
+ 'mode'
+ ],
+ defaults: {
+ mode: 'normal'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feColorMatrix: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'type',
+ 'values'
+ ],
+ defaults: {
+ type: 'matrix'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feComponentTransfer: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in'
+ ],
+ content: [
+ 'feFuncA',
+ 'feFuncB',
+ 'feFuncG',
+ 'feFuncR'
+ ]
+ },
+ feComposite: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'in2',
+ 'operator',
+ 'k1',
+ 'k2',
+ 'k3',
+ 'k4'
+ ],
+ defaults: {
+ operator: 'over',
+ k1: '0',
+ k2: '0',
+ k3: '0',
+ k4: '0'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feConvolveMatrix: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'order',
+ 'kernelMatrix',
+ // TODO: divisor - 'The default value is the sum of all values in kernelMatrix,
+ // with the exception that if the sum is zero, then the divisor is set to 1'
+ 'divisor',
+ 'bias',
+ // TODO: targetX - 'By default, the convolution matrix is centered in X over each
+ // pixel of the input image (i.e., targetX = floor ( orderX / 2 ))'
+ 'targetX',
+ 'targetY',
+ 'edgeMode',
+ // TODO: kernelUnitLength - 'The first number is the <dx> value. The second number
+ // is the <dy> value. If the <dy> value is not specified, it defaults to the same value as <dx>'
+ 'kernelUnitLength',
+ 'preserveAlpha'
+ ],
+ defaults: {
+ order: '3',
+ bias: '0',
+ edgeMode: 'duplicate',
+ preserveAlpha: 'false'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feDiffuseLighting: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'surfaceScale',
+ 'diffuseConstant',
+ 'kernelUnitLength'
+ ],
+ defaults: {
+ surfaceScale: '1',
+ diffuseConstant: '1'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ // TODO: 'exactly one light source element, in any order'
+ 'feDistantLight',
+ 'fePointLight',
+ 'feSpotLight'
+ ]
+ },
+ feDisplacementMap: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'in2',
+ 'scale',
+ 'xChannelSelector',
+ 'yChannelSelector'
+ ],
+ defaults: {
+ scale: '0',
+ xChannelSelector: 'A',
+ yChannelSelector: 'A'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feDistantLight: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'azimuth',
+ 'elevation'
+ ],
+ defaults: {
+ azimuth: '0',
+ elevation: '0'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feFlood: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ],
+ content: [
+ 'animate',
+ 'animateColor',
+ 'set'
+ ]
+ },
+ feFuncA: {
+ attrsGroups: [
+ 'core',
+ 'transferFunction'
+ ],
+ content: [
+ 'set',
+ 'animate'
+ ]
+ },
+ feFuncB: {
+ attrsGroups: [
+ 'core',
+ 'transferFunction'
+ ],
+ content: [
+ 'set',
+ 'animate'
+ ]
+ },
+ feFuncG: {
+ attrsGroups: [
+ 'core',
+ 'transferFunction'
+ ],
+ content: [
+ 'set',
+ 'animate'
+ ]
+ },
+ feFuncR: {
+ attrsGroups: [
+ 'core',
+ 'transferFunction'
+ ],
+ content: [
+ 'set',
+ 'animate'
+ ]
+ },
+ feGaussianBlur: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'stdDeviation'
+ ],
+ defaults: {
+ stdDeviation: '0'
+ },
+ content: [
+ 'set',
+ 'animate'
+ ]
+ },
+ feImage: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'preserveAspectRatio',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ preserveAspectRatio: 'xMidYMid meet'
+ },
+ content: [
+ 'animate',
+ 'animateTransform',
+ 'set'
+ ]
+ },
+ feMerge: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ],
+ content: [
+ 'feMergeNode'
+ ]
+ },
+ feMergeNode: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'in'
+ ],
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feMorphology: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'operator',
+ 'radius'
+ ],
+ defaults: {
+ operator: 'erode',
+ radius: '0'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feOffset: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'dx',
+ 'dy'
+ ],
+ defaults: {
+ dx: '0',
+ dy: '0'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ fePointLight: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'x',
+ 'y',
+ 'z'
+ ],
+ defaults: {
+ x: '0',
+ y: '0',
+ z: '0'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feSpecularLighting: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in',
+ 'surfaceScale',
+ 'specularConstant',
+ 'specularExponent',
+ 'kernelUnitLength'
+ ],
+ defaults: {
+ surfaceScale: '1',
+ specularConstant: '1',
+ specularExponent: '1'
+ },
+ contentGroups: [
+ 'descriptive',
+ // TODO: exactly one 'light source element'
+ 'lightSource'
+ ]
+ },
+ feSpotLight: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'x',
+ 'y',
+ 'z',
+ 'pointsAtX',
+ 'pointsAtY',
+ 'pointsAtZ',
+ 'specularExponent',
+ 'limitingConeAngle'
+ ],
+ defaults: {
+ x: '0',
+ y: '0',
+ z: '0',
+ pointsAtX: '0',
+ pointsAtY: '0',
+ pointsAtZ: '0',
+ specularExponent: '1'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feTile: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'in'
+ ],
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ feTurbulence: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'filterPrimitive'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'baseFrequency',
+ 'numOctaves',
+ 'seed',
+ 'stitchTiles',
+ 'type'
+ ],
+ defaults: {
+ baseFrequency: '0',
+ numOctaves: '1',
+ seed: '0',
+ stitchTiles: 'noStitch',
+ type: 'turbulence'
+ },
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ filter: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'filterRes',
+ 'filterUnits',
+ 'primitiveUnits',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ primitiveUnits: 'userSpaceOnUse',
+ x: '-10%',
+ y: '-10%',
+ width: '120%',
+ height: '120%'
+ },
+ contentGroups: [
+ 'descriptive',
+ 'filterPrimitive'
+ ],
+ content: [
+ 'animate',
+ 'set'
+ ]
+ },
+ font: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'horiz-origin-x',
+ 'horiz-origin-y',
+ 'horiz-adv-x',
+ 'vert-origin-x',
+ 'vert-origin-y',
+ 'vert-adv-y'
+ ],
+ defaults: {
+ 'horiz-origin-x': '0',
+ 'horiz-origin-y': '0'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'font-face',
+ 'glyph',
+ 'hkern',
+ 'missing-glyph',
+ 'vkern'
+ ]
+ },
+ 'font-face': {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'font-family',
+ 'font-style',
+ 'font-variant',
+ 'font-weight',
+ 'font-stretch',
+ 'font-size',
+ 'unicode-range',
+ 'units-per-em',
+ 'panose-1',
+ 'stemv',
+ 'stemh',
+ 'slope',
+ 'cap-height',
+ 'x-height',
+ 'accent-height',
+ 'ascent',
+ 'descent',
+ 'widths',
+ 'bbox',
+ 'ideographic',
+ 'alphabetic',
+ 'mathematical',
+ 'hanging',
+ 'v-ideographic',
+ 'v-alphabetic',
+ 'v-mathematical',
+ 'v-hanging',
+ 'underline-position',
+ 'underline-thickness',
+ 'strikethrough-position',
+ 'strikethrough-thickness',
+ 'overline-position',
+ 'overline-thickness'
+ ],
+ defaults: {
+ 'font-style': 'all',
+ 'font-variant': 'normal',
+ 'font-weight': 'all',
+ 'font-stretch': 'normal',
+ 'unicode-range': 'U+0-10FFFF',
+ 'units-per-em': '1000',
+ 'panose-1': '0 0 0 0 0 0 0 0 0 0',
+ 'slope': '0'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ // TODO: "at most one 'font-face-src' element"
+ 'font-face-src'
+ ]
+ },
+ // TODO: empty content
+ 'font-face-format': {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'string'
+ ]
+ },
+ 'font-face-name': {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'name'
+ ]
+ },
+ 'font-face-src': {
+ attrsGroups: [
+ 'core'
+ ],
+ content: [
+ 'font-face-name',
+ 'font-face-uri'
+ ]
+ },
+ 'font-face-uri': {
+ attrsGroups: [
+ 'core',
+ 'xlink'
+ ],
+ attrs: [
+ 'href',
+ 'xlink:href'
+ ],
+ content: [
+ 'font-face-format'
+ ]
+ },
+ foreignObject: {
+ attrsGroups: [
+ 'core',
+ 'conditionalProcessing',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'x',
+ 'y',
+ 'width',
+ 'height'
+ ],
+ defaults: {
+ x: 0,
+ y: 0
+ }
+ },
+ g: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ glyph: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'd',
+ 'horiz-adv-x',
+ 'vert-origin-x',
+ 'vert-origin-y',
+ 'vert-adv-y',
+ 'unicode',
+ 'glyph-name',
+ 'orientation',
+ 'arabic-form',
+ 'lang'
+ ],
+ defaults: {
+ 'arabic-form': 'initial'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ],
+ },
+ glyphRef: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'd',
+ 'horiz-adv-x',
+ 'vert-origin-x',
+ 'vert-origin-y',
+ 'vert-adv-y'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ hatch: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'x',
+ 'y',
+ 'pitch',
+ 'rotate',
+ 'hatchUnits',
+ 'hatchContentUnits',
+ 'transform'
+ ],
+ defaults: {
+ hatchUnits: 'objectBoundingBox',
+ hatchContentUnits: 'userSpaceOnUse',
+ x: '0',
+ y: '0',
+ pitch: '0',
+ rotate: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ],
+ content: [
+ 'hatchPath'
+ ]
+ },
+ hatchPath: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'd',
+ 'offset'
+ ],
+ defaults: {
+ offset: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ hkern: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'u1',
+ 'g1',
+ 'u2',
+ 'g2',
+ 'k'
+ ]
+ },
+ image: {
+ attrsGroups: [
+ 'core',
+ 'conditionalProcessing',
+ 'graphicalEvent',
+ 'xlink',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'preserveAspectRatio',
+ 'transform',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ x: '0',
+ y: '0',
+ preserveAspectRatio: 'xMidYMid meet'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ line: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'x1',
+ 'y1',
+ 'x2',
+ 'y2'
+ ],
+ defaults: {
+ x1: '0',
+ y1: '0',
+ x2: '0',
+ y2: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ linearGradient: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'x1',
+ 'y1',
+ 'x2',
+ 'y2',
+ 'gradientUnits',
+ 'gradientTransform',
+ 'spreadMethod',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ x1: '0',
+ y1: '0',
+ x2: '100%',
+ y2: '0',
+ spreadMethod: 'pad'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'animate',
+ 'animateTransform',
+ 'set',
+ 'stop'
+ ]
+ },
+ marker: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'viewBox',
+ 'preserveAspectRatio',
+ 'refX',
+ 'refY',
+ 'markerUnits',
+ 'markerWidth',
+ 'markerHeight',
+ 'orient'
+ ],
+ defaults: {
+ markerUnits: 'strokeWidth',
+ refX: '0',
+ refY: '0',
+ markerWidth: '3',
+ markerHeight: '3'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ mask: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'maskUnits',
+ 'maskContentUnits'
+ ],
+ defaults: {
+ maskUnits: 'objectBoundingBox',
+ maskContentUnits: 'userSpaceOnUse',
+ x: '-10%',
+ y: '-10%',
+ width: '120%',
+ height: '120%'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ metadata: {
+ attrsGroups: [
+ 'core'
+ ]
+ },
+ 'missing-glyph': {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'd',
+ 'horiz-adv-x',
+ 'vert-origin-x',
+ 'vert-origin-y',
+ 'vert-adv-y'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ mpath: {
+ attrsGroups: [
+ 'core',
+ 'xlink'
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'href',
+ 'xlink:href'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ path: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'd',
+ 'pathLength'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ pattern: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'viewBox',
+ 'preserveAspectRatio',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'patternUnits',
+ 'patternContentUnits',
+ 'patternTransform',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ patternUnits: 'objectBoundingBox',
+ patternContentUnits: 'userSpaceOnUse',
+ x: '0',
+ y: '0',
+ width: '0',
+ height: '0',
+ preserveAspectRatio: 'xMidYMid meet'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'paintServer',
+ 'shape',
+ 'structural'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ polygon: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'points'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ polyline: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'points'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ radialGradient: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'cx',
+ 'cy',
+ 'r',
+ 'fx',
+ 'fy',
+ 'fr',
+ 'gradientUnits',
+ 'gradientTransform',
+ 'spreadMethod',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ gradientUnits: 'objectBoundingBox',
+ cx: '50%',
+ cy: '50%',
+ r: '50%'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'animate',
+ 'animateTransform',
+ 'set',
+ 'stop'
+ ]
+ },
+ meshGradient: {
+ attrsGroups: [
+ 'core',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'x',
+ 'y',
+ 'gradientUnits',
+ 'transform'
+ ],
+ contentGroups: [
+ 'descriptive',
+ 'paintServer',
+ 'animation',
+ ],
+ content: [
+ 'meshRow'
+ ]
+ },
+ meshRow: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'meshPatch'
+ ]
+ },
+ meshPatch: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'stop'
+ ]
+ },
+ rect: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'rx',
+ 'ry'
+ ],
+ defaults: {
+ x: '0',
+ y: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ script: {
+ attrsGroups: [
+ 'core',
+ 'xlink'
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'type',
+ 'href',
+ 'xlink:href'
+ ]
+ },
+ set: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'animation',
+ 'xlink',
+ 'animationAttributeTarget',
+ 'animationTiming',
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'to'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ solidColor: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ],
+ contentGroups: [
+ 'paintServer'
+ ]
+ },
+ stop: {
+ attrsGroups: [
+ 'core',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'offset',
+ 'path'
+ ],
+ content: [
+ 'animate',
+ 'animateColor',
+ 'set'
+ ]
+ },
+ style: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'type',
+ 'media',
+ 'title'
+ ],
+ defaults: {
+ type: 'text/css'
+ }
+ },
+ svg: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'documentEvent',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'viewBox',
+ 'preserveAspectRatio',
+ 'zoomAndPan',
+ 'version',
+ 'baseProfile',
+ 'contentScriptType',
+ 'contentStyleType'
+ ],
+ defaults: {
+ x: '0',
+ y: '0',
+ width: '100%',
+ height: '100%',
+ preserveAspectRatio: 'xMidYMid meet',
+ zoomAndPan: 'magnify',
+ version: '1.1',
+ baseProfile: 'none',
+ contentScriptType: 'application/ecmascript',
+ contentStyleType: 'text/css'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ switch: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform'
+ ],
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape'
+ ],
+ content: [
+ 'a',
+ 'foreignObject',
+ 'g',
+ 'image',
+ 'svg',
+ 'switch',
+ 'text',
+ 'use'
+ ]
+ },
+ symbol: {
+ attrsGroups: [
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'preserveAspectRatio',
+ 'viewBox',
+ 'refX',
+ 'refY'
+ ],
+ defaults: {
+ refX: 0,
+ refY: 0
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'shape',
+ 'structural',
+ 'paintServer'
+ ],
+ content: [
+ 'a',
+ 'altGlyphDef',
+ 'clipPath',
+ 'color-profile',
+ 'cursor',
+ 'filter',
+ 'font',
+ 'font-face',
+ 'foreignObject',
+ 'image',
+ 'marker',
+ 'mask',
+ 'pattern',
+ 'script',
+ 'style',
+ 'switch',
+ 'text',
+ 'view'
+ ]
+ },
+ text: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'lengthAdjust',
+ 'x',
+ 'y',
+ 'dx',
+ 'dy',
+ 'rotate',
+ 'textLength'
+ ],
+ defaults: {
+ x: '0',
+ y: '0',
+ lengthAdjust: 'spacing'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive',
+ 'textContentChild'
+ ],
+ content: [
+ 'a'
+ ]
+ },
+ textPath: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'href',
+ 'xlink:href',
+ 'startOffset',
+ 'method',
+ 'spacing',
+ 'd'
+ ],
+ defaults: {
+ startOffset: '0',
+ method: 'align',
+ spacing: 'exact'
+ },
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'a',
+ 'altGlyph',
+ 'animate',
+ 'animateColor',
+ 'set',
+ 'tref',
+ 'tspan'
+ ]
+ },
+ title: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'class',
+ 'style'
+ ]
+ },
+ tref: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'href',
+ 'xlink:href'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'animate',
+ 'animateColor',
+ 'set'
+ ]
+ },
+ tspan: {
+ attrsGroups: [
+ 'conditionalProcessing',
+ 'core',
+ 'graphicalEvent',
+ 'presentation'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'x',
+ 'y',
+ 'dx',
+ 'dy',
+ 'rotate',
+ 'textLength',
+ 'lengthAdjust'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ],
+ content: [
+ 'a',
+ 'altGlyph',
+ 'animate',
+ 'animateColor',
+ 'set',
+ 'tref',
+ 'tspan'
+ ]
+ },
+ use: {
+ attrsGroups: [
+ 'core',
+ 'conditionalProcessing',
+ 'graphicalEvent',
+ 'presentation',
+ 'xlink'
+ ],
+ attrs: [
+ 'class',
+ 'style',
+ 'externalResourcesRequired',
+ 'transform',
+ 'x',
+ 'y',
+ 'width',
+ 'height',
+ 'href',
+ 'xlink:href'
+ ],
+ defaults: {
+ x: '0',
+ y: '0'
+ },
+ contentGroups: [
+ 'animation',
+ 'descriptive'
+ ]
+ },
+ view: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'externalResourcesRequired',
+ 'viewBox',
+ 'preserveAspectRatio',
+ 'zoomAndPan',
+ 'viewTarget'
+ ],
+ contentGroups: [
+ 'descriptive'
+ ]
+ },
+ vkern: {
+ attrsGroups: [
+ 'core'
+ ],
+ attrs: [
+ 'u1',
+ 'g1',
+ 'u2',
+ 'g2',
+ 'k'
+ ]
+ }
+};
+
+// http://wiki.inkscape.org/wiki/index.php/Inkscape-specific_XML_attributes
+exports.editorNamespaces = [
+ 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd',
+ 'http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd',
+ 'http://www.inkscape.org/namespaces/inkscape',
+ 'http://www.bohemiancoding.com/sketch/ns',
+ 'http://ns.adobe.com/AdobeIllustrator/10.0/',
+ 'http://ns.adobe.com/Graphs/1.0/',
+ 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/',
+ 'http://ns.adobe.com/Variables/1.0/',
+ 'http://ns.adobe.com/SaveForWeb/1.0/',
+ 'http://ns.adobe.com/Extensibility/1.0/',
+ 'http://ns.adobe.com/Flows/1.0/',
+ 'http://ns.adobe.com/ImageReplacement/1.0/',
+ 'http://ns.adobe.com/GenericCustomNamespace/1.0/',
+ 'http://ns.adobe.com/XPath/1.0/',
+ 'http://schemas.microsoft.com/visio/2003/SVGExtensions/',
+ 'http://taptrix.com/vectorillustrator/svg_extensions',
+ 'http://www.figma.com/figma/ns',
+ 'http://purl.org/dc/elements/1.1/',
+ 'http://creativecommons.org/ns#',
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+ 'http://www.serif.com/',
+ 'http://www.vector.evaxdesign.sk'
+];
+
+// http://www.w3.org/TR/SVG11/linking.html#processingIRI
+exports.referencesProps = [
+ 'clip-path',
+ 'color-profile',
+ 'fill',
+ 'filter',
+ 'marker-start',
+ 'marker-mid',
+ 'marker-end',
+ 'mask',
+ 'stroke',
+ 'style'
+];
+
+// http://www.w3.org/TR/SVG11/propidx.html
+exports.inheritableAttrs = [
+ 'clip-rule',
+ 'color',
+ 'color-interpolation',
+ 'color-interpolation-filters',
+ 'color-profile',
+ 'color-rendering',
+ 'cursor',
+ 'direction',
+ 'dominant-baseline',
+ 'fill',
+ 'fill-opacity',
+ 'fill-rule',
+ 'font',
+ 'font-family',
+ 'font-size',
+ 'font-size-adjust',
+ 'font-stretch',
+ 'font-style',
+ 'font-variant',
+ 'font-weight',
+ 'glyph-orientation-horizontal',
+ 'glyph-orientation-vertical',
+ 'image-rendering',
+ 'letter-spacing',
+ 'marker',
+ 'marker-end',
+ 'marker-mid',
+ 'marker-start',
+ 'paint-order',
+ 'pointer-events',
+ 'shape-rendering',
+ 'stroke',
+ 'stroke-dasharray',
+ 'stroke-dashoffset',
+ 'stroke-linecap',
+ 'stroke-linejoin',
+ 'stroke-miterlimit',
+ 'stroke-opacity',
+ 'stroke-width',
+ 'text-anchor',
+ 'text-rendering',
+ 'transform',
+ 'visibility',
+ 'word-spacing',
+ 'writing-mode'
+];
+
+exports.presentationNonInheritableGroupAttrs = [
+ 'display',
+ 'clip-path',
+ 'filter',
+ 'mask',
+ 'opacity',
+ 'text-decoration',
+ 'transform',
+ 'unicode-bidi',
+ 'visibility'
+];
+
+// http://www.w3.org/TR/SVG11/single-page.html#types-ColorKeywords
+exports.colorsNames = {
+ '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': '#789',
+ 'lightslategrey': '#789',
+ 'lightsteelblue': '#b0c4de',
+ 'lightyellow': '#ffffe0',
+ 'lime': '#0f0',
+ 'limegreen': '#32cd32',
+ 'linen': '#faf0e6',
+ 'magenta': '#f0f',
+ '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': '#639',
+ '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'
+};
+
+exports.colorsShortNames = {
+ '#f0ffff': 'azure',
+ '#f5f5dc': 'beige',
+ '#ffe4c4': 'bisque',
+ '#a52a2a': 'brown',
+ '#ff7f50': 'coral',
+ '#ffd700': 'gold',
+ '#808080': 'gray',
+ '#008000': 'green',
+ '#4b0082': 'indigo',
+ '#fffff0': 'ivory',
+ '#f0e68c': 'khaki',
+ '#faf0e6': 'linen',
+ '#800000': 'maroon',
+ '#000080': 'navy',
+ '#808000': 'olive',
+ '#ffa500': 'orange',
+ '#da70d6': 'orchid',
+ '#cd853f': 'peru',
+ '#ffc0cb': 'pink',
+ '#dda0dd': 'plum',
+ '#800080': 'purple',
+ '#f00': 'red',
+ '#ff0000': 'red',
+ '#fa8072': 'salmon',
+ '#a0522d': 'sienna',
+ '#c0c0c0': 'silver',
+ '#fffafa': 'snow',
+ '#d2b48c': 'tan',
+ '#008080': 'teal',
+ '#ff6347': 'tomato',
+ '#ee82ee': 'violet',
+ '#f5deb3': 'wheat'
+};
+
+// http://www.w3.org/TR/SVG11/single-page.html#types-DataTypeColor
+exports.colorsProps = [
+ 'color', 'fill', 'stroke', 'stop-color', 'flood-color', 'lighting-color'
+];
diff --git a/node_modules/svgo/plugins/_path.js b/node_modules/svgo/plugins/_path.js
new file mode 100644
index 0000000..bb613c6
--- /dev/null
+++ b/node_modules/svgo/plugins/_path.js
@@ -0,0 +1,988 @@
+/* global a2c */
+'use strict';
+
+var rNumber = String.raw`[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?\s*`,
+ rCommaWsp = String.raw`(?:\s,?\s*|,\s*)`,
+ rNumberCommaWsp = `(${rNumber})` + rCommaWsp,
+ rFlagCommaWsp = `([01])${rCommaWsp}?`,
+ rCoordinatePair = String.raw`(${rNumber})${rCommaWsp}?(${rNumber})`,
+ rArcSeq = (rNumberCommaWsp + '?').repeat(2) + rNumberCommaWsp + rFlagCommaWsp.repeat(2) + rCoordinatePair;
+
+var regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/,
+ regCoordinateSequence = new RegExp(rNumber, 'g'),
+ regArcArgumentSequence = new RegExp(rArcSeq, 'g'),
+ regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/,
+ transform2js = require('./_transforms').transform2js,
+ transformsMultiply = require('./_transforms').transformsMultiply,
+ transformArc = require('./_transforms').transformArc,
+ collections = require('./_collections.js'),
+ referencesProps = collections.referencesProps,
+ defaultStrokeWidth = collections.attrsGroupsDefaults.presentation['stroke-width'],
+ cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
+ removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
+ prevCtrlPoint;
+
+/**
+ * Convert path string to JS representation.
+ *
+ * @param {String} pathString input string
+ * @param {Object} params plugin params
+ * @return {Array} output array
+ */
+exports.path2js = function(path) {
+ if (path.pathJS) return path.pathJS;
+
+ var paramsLength = { // Number of parameters of every path command
+ H: 1, V: 1, M: 2, L: 2, T: 2, Q: 4, S: 4, C: 6, A: 7,
+ h: 1, v: 1, m: 2, l: 2, t: 2, q: 4, s: 4, c: 6, a: 7
+ },
+ pathData = [], // JS representation of the path data
+ instruction, // current instruction context
+ startMoveto = false;
+
+ // splitting path string into array like ['M', '10 50', 'L', '20 30']
+ path.attr('d').value.split(regPathInstructions).forEach(function(data) {
+ if (!data) return;
+ if (!startMoveto) {
+ if (data == 'M' || data == 'm') {
+ startMoveto = true;
+ } else return;
+ }
+
+ // instruction item
+ if (regPathInstructions.test(data)) {
+ instruction = data;
+
+ // z - instruction w/o data
+ if (instruction == 'Z' || instruction == 'z') {
+ pathData.push({
+ instruction: 'z'
+ });
+ }
+ // data item
+ } else {
+ /* jshint boss: true */
+ if (instruction == 'A' || instruction == 'a') {
+ var newData = [];
+ for (var args; (args = regArcArgumentSequence.exec(data));) {
+ for (var i = 1; i < args.length; i++) {
+ newData.push(args[i]);
+ }
+ }
+ data = newData;
+ } else {
+ data = data.match(regCoordinateSequence);
+ }
+ if (!data) return;
+
+ data = data.map(Number);
+ // Subsequent moveto pairs of coordinates are threated as implicit lineto commands
+ // http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
+ if (instruction == 'M' || instruction == 'm') {
+ pathData.push({
+ instruction: pathData.length == 0 ? 'M' : instruction,
+ data: data.splice(0, 2)
+ });
+ instruction = instruction == 'M' ? 'L' : 'l';
+ }
+
+ for (var pair = paramsLength[instruction]; data.length;) {
+ pathData.push({
+ instruction: instruction,
+ data: data.splice(0, pair)
+ });
+ }
+ }
+ });
+
+ // First moveto is actually absolute. Subsequent coordinates were separated above.
+ if (pathData.length && pathData[0].instruction == 'm') {
+ pathData[0].instruction = 'M';
+ }
+ path.pathJS = pathData;
+
+ return pathData;
+};
+
+/**
+ * Convert relative Path data to absolute.
+ *
+ * @param {Array} data input data
+ * @return {Array} output data
+ */
+var relative2absolute = exports.relative2absolute = function(data) {
+ var currentPoint = [0, 0],
+ subpathPoint = [0, 0],
+ i;
+
+ return data.map(function(item) {
+
+ var instruction = item.instruction,
+ itemData = item.data && item.data.slice();
+
+ if (instruction == 'M') {
+
+ set(currentPoint, itemData);
+ set(subpathPoint, itemData);
+
+ } else if ('mlcsqt'.indexOf(instruction) > -1) {
+
+ for (i = 0; i < itemData.length; i++) {
+ itemData[i] += currentPoint[i % 2];
+ }
+ set(currentPoint, itemData);
+
+ if (instruction == 'm') {
+ set(subpathPoint, itemData);
+ }
+
+ } else if (instruction == 'a') {
+
+ itemData[5] += currentPoint[0];
+ itemData[6] += currentPoint[1];
+ set(currentPoint, itemData);
+
+ } else if (instruction == 'h') {
+
+ itemData[0] += currentPoint[0];
+ currentPoint[0] = itemData[0];
+
+ } else if (instruction == 'v') {
+
+ itemData[0] += currentPoint[1];
+ currentPoint[1] = itemData[0];
+
+ } else if ('MZLCSQTA'.indexOf(instruction) > -1) {
+
+ set(currentPoint, itemData);
+
+ } else if (instruction == 'H') {
+
+ currentPoint[0] = itemData[0];
+
+ } else if (instruction == 'V') {
+
+ currentPoint[1] = itemData[0];
+
+ } else if (instruction == 'z') {
+
+ set(currentPoint, subpathPoint);
+
+ }
+
+ return instruction == 'z' ?
+ { instruction: 'z' } :
+ {
+ instruction: instruction.toUpperCase(),
+ data: itemData
+ };
+
+ });
+};
+
+/**
+ * Apply transformation(s) to the Path data.
+ *
+ * @param {Object} elem current element
+ * @param {Array} path input path data
+ * @param {Object} params whether to apply transforms to stroked lines and transform precision (used for stroke width)
+ * @return {Array} output path data
+ */
+exports.applyTransforms = function(elem, path, params) {
+ // if there are no 'stroke' attr and references to other objects such as
+ // gradiends or clip-path which are also subjects to transform.
+ if (!elem.hasAttr('transform') || !elem.attr('transform').value ||
+ elem.someAttr(function(attr) {
+ return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
+ }))
+ return path;
+
+ var matrix = transformsMultiply(transform2js(elem.attr('transform').value)),
+ stroke = elem.computedAttr('stroke'),
+ id = elem.computedAttr('id'),
+ transformPrecision = params.transformPrecision,
+ newPoint, scale;
+
+ if (stroke && stroke != 'none') {
+ if (!params.applyTransformsStroked ||
+ (matrix.data[0] != matrix.data[3] || matrix.data[1] != -matrix.data[2]) &&
+ (matrix.data[0] != -matrix.data[3] || matrix.data[1] != matrix.data[2]))
+ return path;
+
+ // "stroke-width" should be inside the part with ID, otherwise it can be overrided in <use>
+ if (id) {
+ var idElem = elem,
+ hasStrokeWidth = false;
+
+ do {
+ if (idElem.hasAttr('stroke-width')) hasStrokeWidth = true;
+ } while (!idElem.hasAttr('id', id) && !hasStrokeWidth && (idElem = idElem.parentNode));
+
+ if (!hasStrokeWidth) return path;
+ }
+
+ scale = +Math.sqrt(matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]).toFixed(transformPrecision);
+
+ if (scale !== 1) {
+ var strokeWidth = elem.computedAttr('stroke-width') || defaultStrokeWidth;
+
+ if (!elem.hasAttr('vector-effect') || elem.attr('vector-effect').value !== 'non-scaling-stroke') {
+ if (elem.hasAttr('stroke-width')) {
+ elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value.trim()
+ .replace(regNumericValues, function(num) {
+ return removeLeadingZero(num * scale);
+ });
+ } else {
+ elem.addAttr({
+ name: 'stroke-width',
+ prefix: '',
+ local: 'stroke-width',
+ value: strokeWidth.replace(regNumericValues, function(num) {
+ return removeLeadingZero(num * scale);
+ })
+ });
+ }
+ }
+ }
+ } else if (id) { // Stroke and stroke-width can be redefined with <use>
+ return path;
+ }
+
+ path.forEach(function(pathItem) {
+
+ if (pathItem.data) {
+
+ // h -> l
+ if (pathItem.instruction === 'h') {
+
+ pathItem.instruction = 'l';
+ pathItem.data[1] = 0;
+
+ // v -> l
+ } else if (pathItem.instruction === 'v') {
+
+ pathItem.instruction = 'l';
+ pathItem.data[1] = pathItem.data[0];
+ pathItem.data[0] = 0;
+
+ }
+
+ // if there is a translate() transform
+ if (pathItem.instruction === 'M' &&
+ (matrix.data[4] !== 0 ||
+ matrix.data[5] !== 0)
+ ) {
+
+ // then apply it only to the first absoluted M
+ newPoint = transformPoint(matrix.data, pathItem.data[0], pathItem.data[1]);
+ set(pathItem.data, newPoint);
+ set(pathItem.coords, newPoint);
+
+ // clear translate() data from transform matrix
+ matrix.data[4] = 0;
+ matrix.data[5] = 0;
+
+ } else {
+
+ if (pathItem.instruction == 'a') {
+
+ transformArc(pathItem.data, matrix.data);
+
+ // reduce number of digits in rotation angle
+ if (Math.abs(pathItem.data[2]) > 80) {
+ var a = pathItem.data[0],
+ rotation = pathItem.data[2];
+ pathItem.data[0] = pathItem.data[1];
+ pathItem.data[1] = a;
+ pathItem.data[2] = rotation + (rotation > 0 ? -90 : 90);
+ }
+
+ newPoint = transformPoint(matrix.data, pathItem.data[5], pathItem.data[6]);
+ pathItem.data[5] = newPoint[0];
+ pathItem.data[6] = newPoint[1];
+
+ } else {
+
+ for (var i = 0; i < pathItem.data.length; i += 2) {
+ newPoint = transformPoint(matrix.data, pathItem.data[i], pathItem.data[i + 1]);
+ pathItem.data[i] = newPoint[0];
+ pathItem.data[i + 1] = newPoint[1];
+ }
+ }
+
+ pathItem.coords[0] = pathItem.base[0] + pathItem.data[pathItem.data.length - 2];
+ pathItem.coords[1] = pathItem.base[1] + pathItem.data[pathItem.data.length - 1];
+
+ }
+
+ }
+
+ });
+
+ // remove transform attr
+ elem.removeAttr('transform');
+
+ return path;
+};
+
+/**
+ * Apply transform 3x3 matrix to x-y point.
+ *
+ * @param {Array} matrix transform 3x3 matrix
+ * @param {Array} point x-y point
+ * @return {Array} point with new coordinates
+ */
+function transformPoint(matrix, x, y) {
+
+ return [
+ matrix[0] * x + matrix[2] * y + matrix[4],
+ matrix[1] * x + matrix[3] * y + matrix[5]
+ ];
+
+}
+
+/**
+ * Compute Cubic Bézie bounding box.
+ *
+ * @see http://processingjs.nihongoresources.com/bezierinfo/
+ *
+ * @param {Float} xa
+ * @param {Float} ya
+ * @param {Float} xb
+ * @param {Float} yb
+ * @param {Float} xc
+ * @param {Float} yc
+ * @param {Float} xd
+ * @param {Float} yd
+ *
+ * @return {Object}
+ */
+exports.computeCubicBoundingBox = function(xa, ya, xb, yb, xc, yc, xd, yd) {
+
+ var minx = Number.POSITIVE_INFINITY,
+ miny = Number.POSITIVE_INFINITY,
+ maxx = Number.NEGATIVE_INFINITY,
+ maxy = Number.NEGATIVE_INFINITY,
+ ts,
+ t,
+ x,
+ y,
+ i;
+
+ // X
+ if (xa < minx) { minx = xa; }
+ if (xa > maxx) { maxx = xa; }
+ if (xd < minx) { minx= xd; }
+ if (xd > maxx) { maxx = xd; }
+
+ ts = computeCubicFirstDerivativeRoots(xa, xb, xc, xd);
+
+ for (i = 0; i < ts.length; i++) {
+
+ t = ts[i];
+
+ if (t >= 0 && t <= 1) {
+ x = computeCubicBaseValue(t, xa, xb, xc, xd);
+ // y = computeCubicBaseValue(t, ya, yb, yc, yd);
+
+ if (x < minx) { minx = x; }
+ if (x > maxx) { maxx = x; }
+ }
+
+ }
+
+ // Y
+ if (ya < miny) { miny = ya; }
+ if (ya > maxy) { maxy = ya; }
+ if (yd < miny) { miny = yd; }
+ if (yd > maxy) { maxy = yd; }
+
+ ts = computeCubicFirstDerivativeRoots(ya, yb, yc, yd);
+
+ for (i = 0; i < ts.length; i++) {
+
+ t = ts[i];
+
+ if (t >= 0 && t <= 1) {
+ // x = computeCubicBaseValue(t, xa, xb, xc, xd);
+ y = computeCubicBaseValue(t, ya, yb, yc, yd);
+
+ if (y < miny) { miny = y; }
+ if (y > maxy) { maxy = y; }
+ }
+
+ }
+
+ return {
+ minx: minx,
+ miny: miny,
+ maxx: maxx,
+ maxy: maxy
+ };
+
+};
+
+// compute the value for the cubic bezier function at time=t
+function computeCubicBaseValue(t, a, b, c, d) {
+
+ var mt = 1 - t;
+
+ return mt * mt * mt * a + 3 * mt * mt * t * b + 3 * mt * t * t * c + t * t * t * d;
+
+}
+
+// compute the value for the first derivative of the cubic bezier function at time=t
+function computeCubicFirstDerivativeRoots(a, b, c, d) {
+
+ var result = [-1, -1],
+ tl = -a + 2 * b - c,
+ tr = -Math.sqrt(-a * (c - d) + b * b - b * (c + d) + c * c),
+ dn = -a + 3 * b - 3 * c + d;
+
+ if (dn !== 0) {
+ result[0] = (tl + tr) / dn;
+ result[1] = (tl - tr) / dn;
+ }
+
+ return result;
+
+}
+
+/**
+ * Compute Quadratic Bézier bounding box.
+ *
+ * @see http://processingjs.nihongoresources.com/bezierinfo/
+ *
+ * @param {Float} xa
+ * @param {Float} ya
+ * @param {Float} xb
+ * @param {Float} yb
+ * @param {Float} xc
+ * @param {Float} yc
+ *
+ * @return {Object}
+ */
+exports.computeQuadraticBoundingBox = function(xa, ya, xb, yb, xc, yc) {
+
+ var minx = Number.POSITIVE_INFINITY,
+ miny = Number.POSITIVE_INFINITY,
+ maxx = Number.NEGATIVE_INFINITY,
+ maxy = Number.NEGATIVE_INFINITY,
+ t,
+ x,
+ y;
+
+ // X
+ if (xa < minx) { minx = xa; }
+ if (xa > maxx) { maxx = xa; }
+ if (xc < minx) { minx = xc; }
+ if (xc > maxx) { maxx = xc; }
+
+ t = computeQuadraticFirstDerivativeRoot(xa, xb, xc);
+
+ if (t >= 0 && t <= 1) {
+ x = computeQuadraticBaseValue(t, xa, xb, xc);
+ // y = computeQuadraticBaseValue(t, ya, yb, yc);
+
+ if (x < minx) { minx = x; }
+ if (x > maxx) { maxx = x; }
+ }
+
+ // Y
+ if (ya < miny) { miny = ya; }
+ if (ya > maxy) { maxy = ya; }
+ if (yc < miny) { miny = yc; }
+ if (yc > maxy) { maxy = yc; }
+
+ t = computeQuadraticFirstDerivativeRoot(ya, yb, yc);
+
+ if (t >= 0 && t <=1 ) {
+ // x = computeQuadraticBaseValue(t, xa, xb, xc);
+ y = computeQuadraticBaseValue(t, ya, yb, yc);
+
+ if (y < miny) { miny = y; }
+ if (y > maxy) { maxy = y ; }
+
+ }
+
+ return {
+ minx: minx,
+ miny: miny,
+ maxx: maxx,
+ maxy: maxy
+ };
+
+};
+
+// compute the value for the quadratic bezier function at time=t
+function computeQuadraticBaseValue(t, a, b, c) {
+
+ var mt = 1 - t;
+
+ return mt * mt * a + 2 * mt * t * b + t * t * c;
+
+}
+
+// compute the value for the first derivative of the quadratic bezier function at time=t
+function computeQuadraticFirstDerivativeRoot(a, b, c) {
+
+ var t = -1,
+ denominator = a - 2 * b + c;
+
+ if (denominator !== 0) {
+ t = (a - b) / denominator;
+ }
+
+ return t;
+
+}
+
+/**
+ * Convert path array to string.
+ *
+ * @param {Array} path input path data
+ * @param {Object} params plugin params
+ * @return {String} output path string
+ */
+exports.js2path = function(path, data, params) {
+
+ path.pathJS = data;
+
+ if (params.collapseRepeated) {
+ data = collapseRepeated(data);
+ }
+
+ path.attr('d').value = data.reduce(function(pathString, item) {
+ var strData = '';
+ if (item.data) {
+ strData = cleanupOutData(item.data, params, item.instruction);
+ }
+ return pathString += item.instruction + strData;
+ }, '');
+
+};
+
+/**
+ * Collapse repeated instructions data
+ *
+ * @param {Array} path input path data
+ * @return {Array} output path data
+ */
+function collapseRepeated(data) {
+
+ var prev,
+ prevIndex;
+
+ // copy an array and modifieds item to keep original data untouched
+ data = data.reduce(function(newPath, item) {
+ if (
+ prev && item.data &&
+ item.instruction == prev.instruction
+ ) {
+ // concat previous data with current
+ if (item.instruction != 'M') {
+ prev = newPath[prevIndex] = {
+ instruction: prev.instruction,
+ data: prev.data.concat(item.data),
+ coords: item.coords,
+ base: prev.base
+ };
+ } else {
+ prev.data = item.data;
+ prev.coords = item.coords;
+ }
+ } else {
+ newPath.push(item);
+ prev = item;
+ prevIndex = newPath.length - 1;
+ }
+
+ return newPath;
+ }, []);
+
+ return data;
+
+}
+
+function set(dest, source) {
+ dest[0] = source[source.length - 2];
+ dest[1] = source[source.length - 1];
+ return dest;
+}
+
+/**
+ * Checks if two paths have an intersection by checking convex hulls
+ * collision using Gilbert-Johnson-Keerthi distance algorithm
+ * http://entropyinteractive.com/2011/04/gjk-algorithm/
+ *
+ * @param {Array} path1 JS path representation
+ * @param {Array} path2 JS path representation
+ * @return {Boolean}
+ */
+exports.intersects = function(path1, path2) {
+ if (path1.length < 3 || path2.length < 3) return false; // nothing to fill
+
+ // Collect points of every subpath.
+ var points1 = relative2absolute(path1).reduce(gatherPoints, []),
+ points2 = relative2absolute(path2).reduce(gatherPoints, []);
+
+ // Axis-aligned bounding box check.
+ if (points1.maxX <= points2.minX || points2.maxX <= points1.minX ||
+ points1.maxY <= points2.minY || points2.maxY <= points1.minY ||
+ points1.every(function (set1) {
+ return points2.every(function (set2) {
+ return set1[set1.maxX][0] <= set2[set2.minX][0] ||
+ set2[set2.maxX][0] <= set1[set1.minX][0] ||
+ set1[set1.maxY][1] <= set2[set2.minY][1] ||
+ set2[set2.maxY][1] <= set1[set1.minY][1];
+ });
+ })
+ ) return false;
+
+ // Get a convex hull from points of each subpath. Has the most complexity O(n·log n).
+ var hullNest1 = points1.map(convexHull),
+ hullNest2 = points2.map(convexHull);
+
+ // Check intersection of every subpath of the first path with every subpath of the second.
+ return hullNest1.some(function(hull1) {
+ if (hull1.length < 3) return false;
+
+ return hullNest2.some(function(hull2) {
+ if (hull2.length < 3) return false;
+
+ var simplex = [getSupport(hull1, hull2, [1, 0])], // create the initial simplex
+ direction = minus(simplex[0]); // set the direction to point towards the origin
+
+ var iterations = 1e4; // infinite loop protection, 10 000 iterations is more than enough
+ while (true) {
+ if (iterations-- == 0) {
+ console.error('Error: infinite loop while processing mergePaths plugin.');
+ return true; // true is the safe value that means “do nothing with paths”
+ }
+ // add a new point
+ simplex.push(getSupport(hull1, hull2, direction));
+ // see if the new point was on the correct side of the origin
+ if (dot(direction, simplex[simplex.length - 1]) <= 0) return false;
+ // process the simplex
+ if (processSimplex(simplex, direction)) return true;
+ }
+ });
+ });
+
+ function getSupport(a, b, direction) {
+ return sub(supportPoint(a, direction), supportPoint(b, minus(direction)));
+ }
+
+ // Computes farthest polygon point in particular direction.
+ // Thanks to knowledge of min/max x and y coordinates we can choose a quadrant to search in.
+ // Since we're working on convex hull, the dot product is increasing until we find the farthest point.
+ function supportPoint(polygon, direction) {
+ var index = direction[1] >= 0 ?
+ direction[0] < 0 ? polygon.maxY : polygon.maxX :
+ direction[0] < 0 ? polygon.minX : polygon.minY,
+ max = -Infinity,
+ value;
+ while ((value = dot(polygon[index], direction)) > max) {
+ max = value;
+ index = ++index % polygon.length;
+ }
+ return polygon[(index || polygon.length) - 1];
+ }
+};
+
+function processSimplex(simplex, direction) {
+ /* jshint -W004 */
+
+ // we only need to handle to 1-simplex and 2-simplex
+ if (simplex.length == 2) { // 1-simplex
+ var a = simplex[1],
+ b = simplex[0],
+ AO = minus(simplex[1]),
+ AB = sub(b, a);
+ // AO is in the same direction as AB
+ if (dot(AO, AB) > 0) {
+ // get the vector perpendicular to AB facing O
+ set(direction, orth(AB, a));
+ } else {
+ set(direction, AO);
+ // only A remains in the simplex
+ simplex.shift();
+ }
+ } else { // 2-simplex
+ var a = simplex[2], // [a, b, c] = simplex
+ b = simplex[1],
+ c = simplex[0],
+ AB = sub(b, a),
+ AC = sub(c, a),
+ AO = minus(a),
+ ACB = orth(AB, AC), // the vector perpendicular to AB facing away from C
+ ABC = orth(AC, AB); // the vector perpendicular to AC facing away from B
+
+ if (dot(ACB, AO) > 0) {
+ if (dot(AB, AO) > 0) { // region 4
+ set(direction, ACB);
+ simplex.shift(); // simplex = [b, a]
+ } else { // region 5
+ set(direction, AO);
+ simplex.splice(0, 2); // simplex = [a]
+ }
+ } else if (dot(ABC, AO) > 0) {
+ if (dot(AC, AO) > 0) { // region 6
+ set(direction, ABC);
+ simplex.splice(1, 1); // simplex = [c, a]
+ } else { // region 5 (again)
+ set(direction, AO);
+ simplex.splice(0, 2); // simplex = [a]
+ }
+ } else // region 7
+ return true;
+ }
+ return false;
+}
+
+function minus(v) {
+ return [-v[0], -v[1]];
+}
+
+function sub(v1, v2) {
+ return [v1[0] - v2[0], v1[1] - v2[1]];
+}
+
+function dot(v1, v2) {
+ return v1[0] * v2[0] + v1[1] * v2[1];
+}
+
+function orth(v, from) {
+ var o = [-v[1], v[0]];
+ return dot(o, minus(from)) < 0 ? minus(o) : o;
+}
+
+function gatherPoints(points, item, index, path) {
+
+ var subPath = points.length && points[points.length - 1],
+ prev = index && path[index - 1],
+ basePoint = subPath.length && subPath[subPath.length - 1],
+ data = item.data,
+ ctrlPoint = basePoint;
+
+ switch (item.instruction) {
+ case 'M':
+ points.push(subPath = []);
+ break;
+ case 'H':
+ addPoint(subPath, [data[0], basePoint[1]]);
+ break;
+ case 'V':
+ addPoint(subPath, [basePoint[0], data[0]]);
+ break;
+ case 'Q':
+ addPoint(subPath, data.slice(0, 2));
+ prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; // Save control point for shorthand
+ break;
+ case 'T':
+ if (prev.instruction == 'Q' || prev.instruction == 'T') {
+ ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]];
+ addPoint(subPath, ctrlPoint);
+ prevCtrlPoint = [data[0] - ctrlPoint[0], data[1] - ctrlPoint[1]];
+ }
+ break;
+ case 'C':
+ // Approximate quibic Bezier curve with middle points between control points
+ addPoint(subPath, [.5 * (basePoint[0] + data[0]), .5 * (basePoint[1] + data[1])]);
+ addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]);
+ addPoint(subPath, [.5 * (data[2] + data[4]), .5 * (data[3] + data[5])]);
+ prevCtrlPoint = [data[4] - data[2], data[5] - data[3]]; // Save control point for shorthand
+ break;
+ case 'S':
+ if (prev.instruction == 'C' || prev.instruction == 'S') {
+ addPoint(subPath, [basePoint[0] + .5 * prevCtrlPoint[0], basePoint[1] + .5 * prevCtrlPoint[1]]);
+ ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]];
+ }
+ addPoint(subPath, [.5 * (ctrlPoint[0] + data[0]), .5 * (ctrlPoint[1]+ data[1])]);
+ addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]);
+ prevCtrlPoint = [data[2] - data[0], data[3] - data[1]];
+ break;
+ case 'A':
+ // Convert the arc to bezier curves and use the same approximation
+ var curves = a2c.apply(0, basePoint.concat(data));
+ for (var cData; (cData = curves.splice(0,6).map(toAbsolute)).length;) {
+ addPoint(subPath, [.5 * (basePoint[0] + cData[0]), .5 * (basePoint[1] + cData[1])]);
+ addPoint(subPath, [.5 * (cData[0] + cData[2]), .5 * (cData[1] + cData[3])]);
+ addPoint(subPath, [.5 * (cData[2] + cData[4]), .5 * (cData[3] + cData[5])]);
+ if (curves.length) addPoint(subPath, basePoint = cData.slice(-2));
+ }
+ break;
+ }
+ // Save final command coordinates
+ if (data && data.length >= 2) addPoint(subPath, data.slice(-2));
+ return points;
+
+ function toAbsolute(n, i) { return n + basePoint[i % 2] }
+
+ // Writes data about the extreme points on each axle
+ function addPoint(path, point) {
+ if (!path.length || point[1] > path[path.maxY][1]) {
+ path.maxY = path.length;
+ points.maxY = points.length ? Math.max(point[1], points.maxY) : point[1];
+ }
+ if (!path.length || point[0] > path[path.maxX][0]) {
+ path.maxX = path.length;
+ points.maxX = points.length ? Math.max(point[0], points.maxX) : point[0];
+ }
+ if (!path.length || point[1] < path[path.minY][1]) {
+ path.minY = path.length;
+ points.minY = points.length ? Math.min(point[1], points.minY) : point[1];
+ }
+ if (!path.length || point[0] < path[path.minX][0]) {
+ path.minX = path.length;
+ points.minX = points.length ? Math.min(point[0], points.minX) : point[0];
+ }
+ path.push(point);
+ }
+}
+
+/**
+ * Forms a convex hull from set of points of every subpath using monotone chain convex hull algorithm.
+ * http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
+ *
+ * @param points An array of [X, Y] coordinates
+ */
+function convexHull(points) {
+ /* jshint -W004 */
+
+ points.sort(function(a, b) {
+ return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
+ });
+
+ var lower = [],
+ minY = 0,
+ bottom = 0;
+ for (var i = 0; i < points.length; i++) {
+ while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) {
+ lower.pop();
+ }
+ if (points[i][1] < points[minY][1]) {
+ minY = i;
+ bottom = lower.length;
+ }
+ lower.push(points[i]);
+ }
+
+ var upper = [],
+ maxY = points.length - 1,
+ top = 0;
+ for (var i = points.length; i--;) {
+ while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) {
+ upper.pop();
+ }
+ if (points[i][1] > points[maxY][1]) {
+ maxY = i;
+ top = upper.length;
+ }
+ upper.push(points[i]);
+ }
+
+ // last points are equal to starting points of the other part
+ upper.pop();
+ lower.pop();
+
+ var hull = lower.concat(upper);
+
+ hull.minX = 0; // by sorting
+ hull.maxX = lower.length;
+ hull.minY = bottom;
+ hull.maxY = (lower.length + top) % hull.length;
+
+ return hull;
+}
+
+function cross(o, a, b) {
+ return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
+}
+
+/* Based on code from Snap.svg (Apache 2 license). http://snapsvg.io/
+ * Thanks to Dmitry Baranovskiy for his great work!
+ */
+
+// jshint ignore: start
+function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
+ // for more information of where this Math came from visit:
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ var _120 = Math.PI * 120 / 180,
+ rad = Math.PI / 180 * (+angle || 0),
+ res = [],
+ rotateX = function(x, y, rad) { return x * Math.cos(rad) - y * Math.sin(rad) },
+ rotateY = function(x, y, rad) { return x * Math.sin(rad) + y * Math.cos(rad) };
+ if (!recursive) {
+ x1 = rotateX(x1, y1, -rad);
+ y1 = rotateY(x1, y1, -rad);
+ x2 = rotateX(x2, y2, -rad);
+ y2 = rotateY(x2, y2, -rad);
+ var x = (x1 - x2) / 2,
+ y = (y1 - y2) / 2;
+ var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
+ if (h > 1) {
+ h = Math.sqrt(h);
+ rx = h * rx;
+ ry = h * ry;
+ }
+ var rx2 = rx * rx,
+ ry2 = ry * ry,
+ k = (large_arc_flag == sweep_flag ? -1 : 1) *
+ Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
+ cx = k * rx * y / ry + (x1 + x2) / 2,
+ cy = k * -ry * x / rx + (y1 + y2) / 2,
+ f1 = Math.asin(((y1 - cy) / ry).toFixed(9)),
+ f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
+
+ f1 = x1 < cx ? Math.PI - f1 : f1;
+ f2 = x2 < cx ? Math.PI - f2 : f2;
+ f1 < 0 && (f1 = Math.PI * 2 + f1);
+ f2 < 0 && (f2 = Math.PI * 2 + f2);
+ if (sweep_flag && f1 > f2) {
+ f1 = f1 - Math.PI * 2;
+ }
+ if (!sweep_flag && f2 > f1) {
+ f2 = f2 - Math.PI * 2;
+ }
+ } else {
+ f1 = recursive[0];
+ f2 = recursive[1];
+ cx = recursive[2];
+ cy = recursive[3];
+ }
+ var df = f2 - f1;
+ if (Math.abs(df) > _120) {
+ var f2old = f2,
+ x2old = x2,
+ y2old = y2;
+ f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
+ x2 = cx + rx * Math.cos(f2);
+ y2 = cy + ry * Math.sin(f2);
+ res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
+ }
+ df = f2 - f1;
+ var c1 = Math.cos(f1),
+ s1 = Math.sin(f1),
+ c2 = Math.cos(f2),
+ s2 = Math.sin(f2),
+ t = Math.tan(df / 4),
+ hx = 4 / 3 * rx * t,
+ hy = 4 / 3 * ry * t,
+ m = [
+ - hx * s1, hy * c1,
+ x2 + hx * s2 - x1, y2 - hy * c2 - y1,
+ x2 - x1, y2 - y1
+ ];
+ if (recursive) {
+ return m.concat(res);
+ } else {
+ res = m.concat(res);
+ var newres = [];
+ for (var i = 0, n = res.length; i < n; i++) {
+ newres[i] = i % 2 ? rotateY(res[i - 1], res[i], rad) : rotateX(res[i], res[i + 1], rad);
+ }
+ return newres;
+ }
+}
+// jshint ignore: end
diff --git a/node_modules/svgo/plugins/_transforms.js b/node_modules/svgo/plugins/_transforms.js
new file mode 100644
index 0000000..a516083
--- /dev/null
+++ b/node_modules/svgo/plugins/_transforms.js
@@ -0,0 +1,310 @@
+'use strict';
+
+var regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/,
+ regTransformSplit = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/,
+ regNumericValues = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
+
+/**
+ * Convert transform string to JS representation.
+ *
+ * @param {String} transformString input string
+ * @param {Object} params plugin params
+ * @return {Array} output array
+ */
+exports.transform2js = function(transformString) {
+
+ // JS representation of the transform data
+ var transforms = [],
+ // current transform context
+ current;
+
+ // split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
+ transformString.split(regTransformSplit).forEach(function(item) {
+ /*jshint -W084 */
+ var num;
+
+ if (item) {
+ // if item is a translate function
+ if (regTransformTypes.test(item)) {
+ // then collect it and change current context
+ transforms.push(current = { name: item });
+ // else if item is data
+ } else {
+ // then split it into [10, 50] and collect as context.data
+ while (num = regNumericValues.exec(item)) {
+ num = Number(num);
+ if (current.data)
+ current.data.push(num);
+ else
+ current.data = [num];
+ }
+ }
+ }
+ });
+
+ // return empty array if broken transform (no data)
+ return current && current.data ? transforms : [];
+};
+
+/**
+ * Multiply transforms into one.
+ *
+ * @param {Array} input transforms array
+ * @return {Array} output matrix array
+ */
+exports.transformsMultiply = function(transforms) {
+
+ // convert transforms objects to the matrices
+ transforms = transforms.map(function(transform) {
+ if (transform.name === 'matrix') {
+ return transform.data;
+ }
+ return transformToMatrix(transform);
+ });
+
+ // multiply all matrices into one
+ transforms = {
+ name: 'matrix',
+ data: transforms.length > 0 ? transforms.reduce(multiplyTransformMatrices) : []
+ };
+
+ return transforms;
+
+};
+
+/**
+ * Do math like a schoolgirl.
+ *
+ * @type {Object}
+ */
+var mth = exports.mth = {
+
+ rad: function(deg) {
+ return deg * Math.PI / 180;
+ },
+
+ deg: function(rad) {
+ return rad * 180 / Math.PI;
+ },
+
+ cos: function(deg) {
+ return Math.cos(this.rad(deg));
+ },
+
+ acos: function(val, floatPrecision) {
+ return +(this.deg(Math.acos(val)).toFixed(floatPrecision));
+ },
+
+ sin: function(deg) {
+ return Math.sin(this.rad(deg));
+ },
+
+ asin: function(val, floatPrecision) {
+ return +(this.deg(Math.asin(val)).toFixed(floatPrecision));
+ },
+
+ tan: function(deg) {
+ return Math.tan(this.rad(deg));
+ },
+
+ atan: function(val, floatPrecision) {
+ return +(this.deg(Math.atan(val)).toFixed(floatPrecision));
+ }
+
+};
+
+/**
+ * Decompose matrix into simple transforms. See
+ * http://frederic-wang.fr/decomposition-of-2d-transform-matrices.html
+ *
+ * @param {Object} data matrix transform object
+ * @return {Object|Array} transforms array or original transform object
+ */
+exports.matrixToTransform = function(transform, params) {
+ var floatPrecision = params.floatPrecision,
+ data = transform.data,
+ transforms = [],
+ sx = +Math.hypot(data[0], data[1]).toFixed(params.transformPrecision),
+ sy = +((data[0] * data[3] - data[1] * data[2]) / sx).toFixed(params.transformPrecision),
+ colsSum = data[0] * data[2] + data[1] * data[3],
+ rowsSum = data[0] * data[1] + data[2] * data[3],
+ scaleBefore = rowsSum != 0 || sx == sy;
+
+ // [..., ..., ..., ..., tx, ty] → translate(tx, ty)
+ if (data[4] || data[5]) {
+ transforms.push({ name: 'translate', data: data.slice(4, data[5] ? 6 : 5) });
+ }
+
+ // [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy)
+ if (!data[1] && data[2]) {
+ transforms.push({ name: 'skewX', data: [mth.atan(data[2] / sy, floatPrecision)] });
+
+ // [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy)
+ } else if (data[1] && !data[2]) {
+ transforms.push({ name: 'skewY', data: [mth.atan(data[1] / data[0], floatPrecision)] });
+ sx = data[0];
+ sy = data[3];
+
+ // [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or
+ // [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore)
+ } else if (!colsSum || (sx == 1 && sy == 1) || !scaleBefore) {
+ if (!scaleBefore) {
+ sx = (data[0] < 0 ? -1 : 1) * Math.hypot(data[0], data[2]);
+ sy = (data[3] < 0 ? -1 : 1) * Math.hypot(data[1], data[3]);
+ transforms.push({ name: 'scale', data: [sx, sy] });
+ }
+ var angle = Math.min(Math.max(-1, data[0] / sx), 1),
+ rotate = [mth.acos(angle, floatPrecision) * ((scaleBefore ? 1 : sy) * data[1] < 0 ? -1 : 1)];
+
+ if (rotate[0]) transforms.push({ name: 'rotate', data: rotate });
+
+ if (rowsSum && colsSum) transforms.push({
+ name: 'skewX',
+ data: [mth.atan(colsSum / (sx * sx), floatPrecision)]
+ });
+
+ // rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point)
+ if (rotate[0] && (data[4] || data[5])) {
+ transforms.shift();
+ var cos = data[0] / sx,
+ sin = data[1] / (scaleBefore ? sx : sy),
+ x = data[4] * (scaleBefore || sy),
+ y = data[5] * (scaleBefore || sx),
+ denom = (Math.pow(1 - cos, 2) + Math.pow(sin, 2)) * (scaleBefore || sx * sy);
+ rotate.push(((1 - cos) * x - sin * y) / denom);
+ rotate.push(((1 - cos) * y + sin * x) / denom);
+ }
+
+ // Too many transformations, return original matrix if it isn't just a scale/translate
+ } else if (data[1] || data[2]) {
+ return transform;
+ }
+
+ if (scaleBefore && (sx != 1 || sy != 1) || !transforms.length) transforms.push({
+ name: 'scale',
+ data: sx == sy ? [sx] : [sx, sy]
+ });
+
+ return transforms;
+};
+
+/**
+ * Convert transform to the matrix data.
+ *
+ * @param {Object} transform transform object
+ * @return {Array} matrix data
+ */
+function transformToMatrix(transform) {
+
+ if (transform.name === 'matrix') return transform.data;
+
+ var matrix;
+
+ switch (transform.name) {
+ case 'translate':
+ // [1, 0, 0, 1, tx, ty]
+ matrix = [1, 0, 0, 1, transform.data[0], transform.data[1] || 0];
+ break;
+ case 'scale':
+ // [sx, 0, 0, sy, 0, 0]
+ matrix = [transform.data[0], 0, 0, transform.data[1] || transform.data[0], 0, 0];
+ break;
+ case 'rotate':
+ // [cos(a), sin(a), -sin(a), cos(a), x, y]
+ var cos = mth.cos(transform.data[0]),
+ sin = mth.sin(transform.data[0]),
+ cx = transform.data[1] || 0,
+ cy = transform.data[2] || 0;
+
+ matrix = [cos, sin, -sin, cos, (1 - cos) * cx + sin * cy, (1 - cos) * cy - sin * cx];
+ break;
+ case 'skewX':
+ // [1, 0, tan(a), 1, 0, 0]
+ matrix = [1, 0, mth.tan(transform.data[0]), 1, 0, 0];
+ break;
+ case 'skewY':
+ // [1, tan(a), 0, 1, 0, 0]
+ matrix = [1, mth.tan(transform.data[0]), 0, 1, 0, 0];
+ break;
+ }
+
+ return matrix;
+
+}
+
+/**
+ * Applies transformation to an arc. To do so, we represent ellipse as a matrix, multiply it
+ * by the transformation matrix and use a singular value decomposition to represent in a form
+ * rotate(θ)·scale(a b)·rotate(φ). This gives us new ellipse params a, b and θ.
+ * SVD is being done with the formulae provided by Wolffram|Alpha (svd {{m0, m2}, {m1, m3}})
+ *
+ * @param {Array} arc [a, b, rotation in deg]
+ * @param {Array} transform transformation matrix
+ * @return {Array} arc transformed input arc
+ */
+exports.transformArc = function(arc, transform) {
+
+ var a = arc[0],
+ b = arc[1],
+ rot = arc[2] * Math.PI / 180,
+ cos = Math.cos(rot),
+ sin = Math.sin(rot),
+ h = Math.pow(arc[5] * cos + arc[6] * sin, 2) / (4 * a * a) +
+ Math.pow(arc[6] * cos - arc[5] * sin, 2) / (4 * b * b);
+ if (h > 1) {
+ h = Math.sqrt(h);
+ a *= h;
+ b *= h;
+ }
+ var ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0],
+ m = multiplyTransformMatrices(transform, ellipse),
+ // Decompose the new ellipse matrix
+ lastCol = m[2] * m[2] + m[3] * m[3],
+ squareSum = m[0] * m[0] + m[1] * m[1] + lastCol,
+ root = Math.hypot(m[0] - m[3], m[1] + m[2]) * Math.hypot(m[0] + m[3], m[1] - m[2]);
+
+ if (!root) { // circle
+ arc[0] = arc[1] = Math.sqrt(squareSum / 2);
+ arc[2] = 0;
+ } else {
+ var majorAxisSqr = (squareSum + root) / 2,
+ minorAxisSqr = (squareSum - root) / 2,
+ major = Math.abs(majorAxisSqr - lastCol) > 1e-6,
+ sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol,
+ rowsSum = m[0] * m[2] + m[1] * m[3],
+ term1 = m[0] * sub + m[2] * rowsSum,
+ term2 = m[1] * sub + m[3] * rowsSum;
+ arc[0] = Math.sqrt(majorAxisSqr);
+ arc[1] = Math.sqrt(minorAxisSqr);
+ arc[2] = ((major ? term2 < 0 : term1 > 0) ? -1 : 1) *
+ Math.acos((major ? term1 : term2) / Math.hypot(term1, term2)) * 180 / Math.PI;
+ }
+
+ if ((transform[0] < 0) !== (transform[3] < 0)) {
+ // Flip the sweep flag if coordinates are being flipped horizontally XOR vertically
+ arc[4] = 1 - arc[4];
+ }
+
+ return arc;
+
+};
+
+/**
+ * Multiply transformation matrices.
+ *
+ * @param {Array} a matrix A data
+ * @param {Array} b matrix B data
+ * @return {Array} result
+ */
+function multiplyTransformMatrices(a, b) {
+
+ return [
+ a[0] * b[0] + a[2] * b[1],
+ a[1] * b[0] + a[3] * b[1],
+ a[0] * b[2] + a[2] * b[3],
+ a[1] * b[2] + a[3] * b[3],
+ a[0] * b[4] + a[2] * b[5] + a[4],
+ a[1] * b[4] + a[3] * b[5] + a[5]
+ ];
+
+}
diff --git a/node_modules/svgo/plugins/addAttributesToSVGElement.js b/node_modules/svgo/plugins/addAttributesToSVGElement.js
new file mode 100644
index 0000000..da2448b
--- /dev/null
+++ b/node_modules/svgo/plugins/addAttributesToSVGElement.js
@@ -0,0 +1,82 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = false;
+
+exports.description = 'adds attributes to an outer <svg> element';
+
+var ENOCLS = `Error in plugin "addAttributesToSVGElement": absent parameters.
+It should have a list of "attributes" or one "attribute".
+Config example:
+
+plugins:
+- addAttributesToSVGElement:
+ attribute: "mySvg"
+
+plugins:
+- addAttributesToSVGElement:
+ attributes: ["mySvg", "size-big"]
+
+plugins:
+- addAttributesToSVGElement:
+ attributes:
+ - focusable: false
+ - data-image: icon`;
+
+/**
+ * Add attributes to an outer <svg> element. Example config:
+ *
+ * plugins:
+ * - addAttributesToSVGElement:
+ * attribute: 'data-icon'
+ *
+ * plugins:
+ * - addAttributesToSVGElement:
+ * attributes: ['data-icon', 'data-disabled']
+ *
+ * plugins:
+ * - addAttributesToSVGElement:
+ * attributes:
+ * - focusable: false
+ * - data-image: icon
+ *
+ * @author April Arcus
+ */
+exports.fn = function(data, params) {
+ if (!params || !(Array.isArray(params.attributes) || params.attribute)) {
+ console.error(ENOCLS);
+ return data;
+ }
+
+ var attributes = params.attributes || [ params.attribute ],
+ svg = data.content[0];
+
+ if (svg.isElem('svg')) {
+ attributes.forEach(function (attribute) {
+ if (typeof attribute === 'string') {
+ if (!svg.hasAttr(attribute)) {
+ svg.addAttr({
+ name: attribute,
+ prefix: '',
+ local: attribute
+ });
+ }
+ } else if (typeof attribute === 'object') {
+ Object.keys(attribute).forEach(function (key) {
+ if (!svg.hasAttr(key)) {
+ svg.addAttr({
+ name: key,
+ value: attribute[key],
+ prefix: '',
+ local: key
+ });
+ }
+ });
+ }
+ });
+ }
+
+ return data;
+
+};
diff --git a/node_modules/svgo/plugins/addClassesToSVGElement.js b/node_modules/svgo/plugins/addClassesToSVGElement.js
new file mode 100644
index 0000000..ef215fc
--- /dev/null
+++ b/node_modules/svgo/plugins/addClassesToSVGElement.js
@@ -0,0 +1,50 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = false;
+
+exports.description = 'adds classnames to an outer <svg> element';
+
+var ENOCLS = `Error in plugin "addClassesToSVGElement": absent parameters.
+It should have a list of classes in "classNames" or one "className".
+Config example:
+
+plugins:
+- addClassesToSVGElement:
+ className: "mySvg"
+
+plugins:
+- addClassesToSVGElement:
+ classNames: ["mySvg", "size-big"]
+`;
+
+/**
+ * Add classnames to an outer <svg> element. Example config:
+ *
+ * plugins:
+ * - addClassesToSVGElement:
+ * className: 'mySvg'
+ *
+ * plugins:
+ * - addClassesToSVGElement:
+ * classNames: ['mySvg', 'size-big']
+ *
+ * @author April Arcus
+ */
+exports.fn = function(data, params) {
+ if (!params || !(Array.isArray(params.classNames) && params.classNames.some(String) || params.className)) {
+ console.error(ENOCLS);
+ return data;
+ }
+
+ var classNames = params.classNames || [ params.className ],
+ svg = data.content[0];
+
+ if (svg.isElem('svg')) {
+ svg.class.add.apply(svg.class, classNames);
+ }
+
+ return data;
+
+};
diff --git a/node_modules/svgo/plugins/cleanupAttrs.js b/node_modules/svgo/plugins/cleanupAttrs.js
new file mode 100644
index 0000000..47e77ac
--- /dev/null
+++ b/node_modules/svgo/plugins/cleanupAttrs.js
@@ -0,0 +1,56 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'cleanups attributes from newlines, trailing and repeating spaces';
+
+exports.params = {
+ newlines: true,
+ trim: true,
+ spaces: true
+};
+
+var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
+ regNewlines = /\r?\n/g,
+ regSpaces = /\s{2,}/g;
+
+/**
+ * Cleanup attributes values from newlines, trailing and repeating spaces.
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (item.isElem()) {
+
+ item.eachAttr(function(attr) {
+
+ if (params.newlines) {
+ // new line which requires a space instead of themselve
+ attr.value = attr.value.replace(regNewlinesNeedSpace, function(match, p1, p2) {
+ return p1 + ' ' + p2;
+ });
+
+ // simple new line
+ attr.value = attr.value.replace(regNewlines, '');
+ }
+
+ if (params.trim) {
+ attr.value = attr.value.trim();
+ }
+
+ if (params.spaces) {
+ attr.value = attr.value.replace(regSpaces, ' ');
+ }
+
+ });
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/cleanupEnableBackground.js b/node_modules/svgo/plugins/cleanupEnableBackground.js
new file mode 100644
index 0000000..e6384ab
--- /dev/null
+++ b/node_modules/svgo/plugins/cleanupEnableBackground.js
@@ -0,0 +1,84 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = true;
+
+exports.description = 'remove or cleanup enable-background attribute when possible';
+
+/**
+ * Remove or cleanup enable-background attr which coincides with a width/height box.
+ *
+ * @see http://www.w3.org/TR/SVG/filters.html#EnableBackgroundProperty
+ *
+ * @example
+ * <svg width="100" height="50" enable-background="new 0 0 100 50">
+ * ⬇
+ * <svg width="100" height="50">
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(data) {
+
+ var regEnableBackground = /^new\s0\s0\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)\s([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)$/,
+ hasFilter = false,
+ elems = ['svg', 'mask', 'pattern'];
+
+ function checkEnableBackground(item) {
+ if (
+ item.isElem(elems) &&
+ item.hasAttr('enable-background') &&
+ item.hasAttr('width') &&
+ item.hasAttr('height')
+ ) {
+
+ var match = item.attr('enable-background').value.match(regEnableBackground);
+
+ if (match) {
+ if (
+ item.attr('width').value === match[1] &&
+ item.attr('height').value === match[3]
+ ) {
+ if (item.isElem('svg')) {
+ item.removeAttr('enable-background');
+ } else {
+ item.attr('enable-background').value = 'new';
+ }
+ }
+ }
+
+ }
+ }
+
+ function checkForFilter(item) {
+ if (item.isElem('filter')) {
+ hasFilter = true;
+ }
+ }
+
+ function monkeys(items, fn) {
+ items.content.forEach(function(item) {
+ fn(item);
+
+ if (item.content) {
+ monkeys(item, fn);
+ }
+ });
+ return items;
+ }
+
+ var firstStep = monkeys(data, function(item) {
+ checkEnableBackground(item);
+ if (!hasFilter) {
+ checkForFilter(item);
+ }
+ });
+
+ return hasFilter ? firstStep : monkeys(firstStep, function(item) {
+ //we don't need 'enable-background' if we have no filters
+ item.removeAttr('enable-background');
+ });
+};
diff --git a/node_modules/svgo/plugins/cleanupIDs.js b/node_modules/svgo/plugins/cleanupIDs.js
new file mode 100644
index 0000000..918474a
--- /dev/null
+++ b/node_modules/svgo/plugins/cleanupIDs.js
@@ -0,0 +1,209 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = true;
+
+exports.description = 'removes unused IDs and minifies used';
+
+exports.params = {
+ remove: true,
+ minify: true,
+ prefix: '',
+ preserve: [],
+ preservePrefixes: [],
+ force: false
+};
+
+var referencesProps = new Set(require('./_collections').referencesProps),
+ regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/,
+ regReferencesHref = /^#(.+?)$/,
+ regReferencesBegin = /(\w+)\./,
+ styleOrScript = ['style', 'script'],
+ generateIDchars = [
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
+ ],
+ maxIDindex = generateIDchars.length - 1;
+
+/**
+ * Remove unused and minify used IDs
+ * (only if there are no any <style> or <script>).
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(data, params) {
+ var currentID,
+ currentIDstring,
+ IDs = new Map(),
+ referencesIDs = new Map(),
+ hasStyleOrScript = false,
+ preserveIDs = new Set(Array.isArray(params.preserve) ? params.preserve : params.preserve ? [params.preserve] : []),
+ preserveIDPrefixes = new Set(Array.isArray(params.preservePrefixes) ? params.preservePrefixes : (params.preservePrefixes ? [params.preservePrefixes] : [])),
+ idValuePrefix = '#',
+ idValuePostfix = '.';
+
+ /**
+ * Bananas!
+ *
+ * @param {Array} items input items
+ * @return {Array} output items
+ */
+ function monkeys(items) {
+ for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
+ var item = items.content[i];
+
+ // quit if <style> or <script> present ('force' param prevents quitting)
+ if (!params.force) {
+ if (item.isElem(styleOrScript)) {
+ hasStyleOrScript = true;
+ continue;
+ }
+ // Don't remove IDs if the whole SVG consists only of defs.
+ if (item.isElem('defs') && item.parentNode.isElem('svg')) {
+ var hasDefsOnly = true;
+ for (var j = i + 1; j < items.content.length; j++) {
+ if (items.content[j].isElem()) {
+ hasDefsOnly = false;
+ break;
+ }
+ }
+ if (hasDefsOnly) {
+ break;
+ }
+ }
+ }
+ // …and don't remove any ID if yes
+ if (item.isElem()) {
+ item.eachAttr(function(attr) {
+ var key, match;
+
+ // save IDs
+ if (attr.name === 'id') {
+ key = attr.value;
+ if (IDs.has(key)) {
+ item.removeAttr('id'); // remove repeated id
+ } else {
+ IDs.set(key, item);
+ }
+ return;
+ }
+ // save references
+ if (referencesProps.has(attr.name) && (match = attr.value.match(regReferencesUrl))) {
+ key = match[2]; // url() reference
+ } else if (
+ attr.local === 'href' && (match = attr.value.match(regReferencesHref)) ||
+ attr.name === 'begin' && (match = attr.value.match(regReferencesBegin))
+ ) {
+ key = match[1]; // href reference
+ }
+ if (key) {
+ var ref = referencesIDs.get(key) || [];
+ ref.push(attr);
+ referencesIDs.set(key, ref);
+ }
+ });
+ }
+ // go deeper
+ if (item.content) {
+ monkeys(item);
+ }
+ }
+ return items;
+ }
+
+ data = monkeys(data);
+
+ if (hasStyleOrScript) {
+ return data;
+ }
+
+ const idPreserved = id => preserveIDs.has(id) || idMatchesPrefix(preserveIDPrefixes, id);
+
+ for (var ref of referencesIDs) {
+ var key = ref[0];
+
+ if (IDs.has(key)) {
+ // replace referenced IDs with the minified ones
+ if (params.minify && !idPreserved(key)) {
+ do {
+ currentIDstring = getIDstring(currentID = generateID(currentID), params);
+ } while (idPreserved(currentIDstring));
+
+ IDs.get(key).attr('id').value = currentIDstring;
+
+ for (var attr of ref[1]) {
+ attr.value = attr.value.includes(idValuePrefix) ?
+ attr.value.replace(idValuePrefix + key, idValuePrefix + currentIDstring) :
+ attr.value.replace(key + idValuePostfix, currentIDstring + idValuePostfix);
+ }
+ }
+ // don't remove referenced IDs
+ IDs.delete(key);
+ }
+ }
+ // remove non-referenced IDs attributes from elements
+ if (params.remove) {
+ for(var keyElem of IDs) {
+ if (!idPreserved(keyElem[0])) {
+ keyElem[1].removeAttr('id');
+ }
+ }
+ }
+ return data;
+};
+
+/**
+ * Check if an ID starts with any one of a list of strings.
+ *
+ * @param {Array} of prefix strings
+ * @param {String} current ID
+ * @return {Boolean} if currentID starts with one of the strings in prefixArray
+ */
+function idMatchesPrefix(prefixArray, currentID) {
+ if (!currentID) return false;
+
+ for (var prefix of prefixArray) if (currentID.startsWith(prefix)) return true;
+ return false;
+}
+
+/**
+ * Generate unique minimal ID.
+ *
+ * @param {Array} [currentID] current ID
+ * @return {Array} generated ID array
+ */
+function generateID(currentID) {
+ if (!currentID) return [0];
+
+ currentID[currentID.length - 1]++;
+
+ for(var i = currentID.length - 1; i > 0; i--) {
+ if (currentID[i] > maxIDindex) {
+ currentID[i] = 0;
+
+ if (currentID[i - 1] !== undefined) {
+ currentID[i - 1]++;
+ }
+ }
+ }
+ if (currentID[0] > maxIDindex) {
+ currentID[0] = 0;
+ currentID.unshift(0);
+ }
+ return currentID;
+}
+
+/**
+ * Get string from generated ID array.
+ *
+ * @param {Array} arr input ID array
+ * @return {String} output ID string
+ */
+function getIDstring(arr, params) {
+ var str = params.prefix;
+ return str + arr.map(i => generateIDchars[i]).join('');
+}
diff --git a/node_modules/svgo/plugins/cleanupListOfValues.js b/node_modules/svgo/plugins/cleanupListOfValues.js
new file mode 100644
index 0000000..e4aa980
--- /dev/null
+++ b/node_modules/svgo/plugins/cleanupListOfValues.js
@@ -0,0 +1,139 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'rounds list of values to the fixed precision';
+
+exports.params = {
+ floatPrecision: 3,
+ leadingZero: true,
+ defaultPx: true,
+ convertToPx: true
+};
+
+var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
+ regSeparator = /\s+,?\s*|,\s*/,
+ removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
+ absoluteLengths = { // relative to px
+ cm: 96/2.54,
+ mm: 96/25.4,
+ in: 96,
+ pt: 4/3,
+ pc: 16
+ };
+
+/**
+ * Round list of values to the fixed precision.
+ *
+ * @example
+ * <svg viewBox="0 0 200.28423 200.28423" enable-background="new 0 0 200.28423 200.28423">
+ * ⬇
+ * <svg viewBox="0 0 200.284 200.284" enable-background="new 0 0 200.284 200.284">
+ *
+ *
+ * <polygon points="208.250977 77.1308594 223.069336 ... "/>
+ * ⬇
+ * <polygon points="208.251 77.131 223.069 ... "/>
+ *
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author kiyopikko
+ */
+exports.fn = function(item, params) {
+
+
+ if ( item.hasAttr('points') ) {
+ roundValues(item.attrs.points);
+ }
+
+ if ( item.hasAttr('enable-background') ) {
+ roundValues(item.attrs['enable-background']);
+ }
+
+ if ( item.hasAttr('viewBox') ) {
+ roundValues(item.attrs.viewBox);
+ }
+
+ if ( item.hasAttr('stroke-dasharray') ) {
+ roundValues(item.attrs['stroke-dasharray']);
+ }
+
+ if ( item.hasAttr('dx') ) {
+ roundValues(item.attrs.dx);
+ }
+
+ if ( item.hasAttr('dy') ) {
+ roundValues(item.attrs.dy);
+ }
+
+ if ( item.hasAttr('x') ) {
+ roundValues(item.attrs.x);
+ }
+
+ if ( item.hasAttr('y') ) {
+ roundValues(item.attrs.y);
+ }
+
+
+ function roundValues($prop){
+
+ var num, units,
+ match,
+ matchNew,
+ lists = $prop.value,
+ listsArr = lists.split(regSeparator),
+ roundedListArr = [],
+ roundedList;
+
+ listsArr.forEach(function(elem){
+
+ match = elem.match(regNumericValues);
+ matchNew = elem.match(/new/);
+
+ // if attribute value matches regNumericValues
+ if (match) {
+ // round it to the fixed precision
+ num = +(+match[1]).toFixed(params.floatPrecision),
+ units = match[3] || '';
+
+ // convert absolute values to pixels
+ if (params.convertToPx && units && (units in absoluteLengths)) {
+ var pxNum = +(absoluteLengths[units] * match[1]).toFixed(params.floatPrecision);
+
+ if (String(pxNum).length < match[0].length)
+ num = pxNum,
+ units = 'px';
+ }
+
+ // and remove leading zero
+ if (params.leadingZero) {
+ num = removeLeadingZero(num);
+ }
+
+ // remove default 'px' units
+ if (params.defaultPx && units === 'px') {
+ units = '';
+ }
+
+ roundedListArr.push(num+units);
+ }
+ // if attribute value is "new"(only enable-background).
+ else if (matchNew) {
+ roundedListArr.push('new');
+ } else if (elem) {
+ roundedListArr.push(elem);
+ }
+
+ });
+
+ roundedList = roundedListArr.join(' ');
+ $prop.value = roundedList;
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/cleanupNumericValues.js b/node_modules/svgo/plugins/cleanupNumericValues.js
new file mode 100644
index 0000000..e37a053
--- /dev/null
+++ b/node_modules/svgo/plugins/cleanupNumericValues.js
@@ -0,0 +1,88 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'rounds numeric values to the fixed precision, removes default ‘px’ units';
+
+exports.params = {
+ floatPrecision: 3,
+ leadingZero: true,
+ defaultPx: true,
+ convertToPx: true
+};
+
+var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
+ removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
+ absoluteLengths = { // relative to px
+ cm: 96/2.54,
+ mm: 96/25.4,
+ in: 96,
+ pt: 4/3,
+ pc: 16
+ };
+
+/**
+ * Round numeric values to the fixed precision,
+ * remove default 'px' units.
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (item.isElem()) {
+
+ var floatPrecision = params.floatPrecision;
+
+ if (item.hasAttr('viewBox')) {
+ var nums = item.attr('viewBox').value.split(/\s,?\s*|,\s*/g);
+ item.attr('viewBox').value = nums.map(function(value) {
+ var num = +value;
+ return isNaN(num) ? value : +num.toFixed(floatPrecision);
+ }).join(' ');
+ }
+
+ item.eachAttr(function(attr) {
+ // The `version` attribute is a text string and cannot be rounded
+ if (attr.name === 'version') { return }
+
+ var match = attr.value.match(regNumericValues);
+
+ // if attribute value matches regNumericValues
+ if (match) {
+ // round it to the fixed precision
+ var num = +(+match[1]).toFixed(floatPrecision),
+ units = match[3] || '';
+
+ // convert absolute values to pixels
+ if (params.convertToPx && units && (units in absoluteLengths)) {
+ var pxNum = +(absoluteLengths[units] * match[1]).toFixed(floatPrecision);
+
+ if (String(pxNum).length < match[0].length) {
+ num = pxNum;
+ units = 'px';
+ }
+ }
+
+ // and remove leading zero
+ if (params.leadingZero) {
+ num = removeLeadingZero(num);
+ }
+
+ // remove default 'px' units
+ if (params.defaultPx && units === 'px') {
+ units = '';
+ }
+
+ attr.value = num + units;
+ }
+ });
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/collapseGroups.js b/node_modules/svgo/plugins/collapseGroups.js
new file mode 100644
index 0000000..3daa5a8
--- /dev/null
+++ b/node_modules/svgo/plugins/collapseGroups.js
@@ -0,0 +1,87 @@
+'use strict';
+
+exports.type = 'perItemReverse';
+
+exports.active = true;
+
+exports.description = 'collapses useless groups';
+
+var collections = require('./_collections'),
+ attrsInheritable = collections.inheritableAttrs,
+ animationElems = collections.elemsGroups.animation;
+
+function hasAnimatedAttr(item) {
+ /* jshint validthis:true */
+ return item.isElem(animationElems) && item.hasAttr('attributeName', this) ||
+ !item.isEmpty() && item.content.some(hasAnimatedAttr, this);
+}
+
+/*
+ * Collapse useless groups.
+ *
+ * @example
+ * <g>
+ * <g attr1="val1">
+ * <path d="..."/>
+ * </g>
+ * </g>
+ * ⬇
+ * <g>
+ * <g>
+ * <path attr1="val1" d="..."/>
+ * </g>
+ * </g>
+ * ⬇
+ * <path attr1="val1" d="..."/>
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ // non-empty elements
+ if (item.isElem() && !item.isElem('switch') && !item.isEmpty()) {
+ item.content.forEach(function(g, i) {
+ // non-empty groups
+ if (g.isElem('g') && !g.isEmpty()) {
+ // move group attibutes to the single content element
+ if (g.hasAttr() && g.content.length === 1) {
+ var inner = g.content[0];
+
+ if (inner.isElem() && !inner.hasAttr('id') && !g.hasAttr('filter') &&
+ !(g.hasAttr('class') && inner.hasAttr('class')) && (
+ !g.hasAttr('clip-path') && !g.hasAttr('mask') ||
+ inner.isElem('g') && !g.hasAttr('transform') && !inner.hasAttr('transform')
+ )
+ ) {
+ g.eachAttr(function(attr) {
+ if (g.content.some(hasAnimatedAttr, attr.name)) return;
+
+ if (!inner.hasAttr(attr.name)) {
+ inner.addAttr(attr);
+ } else if (attr.name == 'transform') {
+ inner.attr(attr.name).value = attr.value + ' ' + inner.attr(attr.name).value;
+ } else if (inner.hasAttr(attr.name, 'inherit')) {
+ inner.attr(attr.name).value = attr.value;
+ } else if (
+ attrsInheritable.indexOf(attr.name) < 0 &&
+ !inner.hasAttr(attr.name, attr.value)
+ ) {
+ return;
+ }
+
+ g.removeAttr(attr.name);
+ });
+ }
+ }
+
+ // collapse groups without attributes
+ if (!g.hasAttr() && !g.content.some(function(item) { return item.isElem(animationElems) })) {
+ item.spliceContent(i, 1, g.content);
+ }
+ }
+ });
+ }
+};
diff --git a/node_modules/svgo/plugins/convertColors.js b/node_modules/svgo/plugins/convertColors.js
new file mode 100644
index 0000000..77279e9
--- /dev/null
+++ b/node_modules/svgo/plugins/convertColors.js
@@ -0,0 +1,130 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
+
+exports.params = {
+ currentColor: false,
+ names2hex: true,
+ rgb2hex: true,
+ shorthex: true,
+ shortname: true
+};
+
+var collections = require('./_collections'),
+ rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)',
+ rComma = '\\s*,\\s*',
+ regRGB = new RegExp('^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'),
+ regHEX = /^\#(([a-fA-F0-9])\2){3}$/,
+ none = /\bnone\b/i;
+
+/**
+ * Convert different colors formats in element attributes to hex.
+ *
+ * @see http://www.w3.org/TR/SVG/types.html#DataTypeColor
+ * @see http://www.w3.org/TR/SVG/single-page.html#types-ColorKeywords
+ *
+ * @example
+ * Convert color name keyword to long hex:
+ * fuchsia ➡ #ff00ff
+ *
+ * Convert rgb() to long hex:
+ * rgb(255, 0, 255) ➡ #ff00ff
+ * rgb(50%, 100, 100%) ➡ #7f64ff
+ *
+ * Convert long hex to short hex:
+ * #aabbcc ➡ #abc
+ *
+ * Convert hex to short name
+ * #000080 ➡ navy
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (item.elem) {
+
+ item.eachAttr(function(attr) {
+
+ if (collections.colorsProps.indexOf(attr.name) > -1) {
+
+ var val = attr.value,
+ match;
+
+ // Convert colors to currentColor
+ if (params.currentColor) {
+ if (typeof params.currentColor === 'string') {
+ match = val === params.currentColor;
+ } else if (params.currentColor.exec) {
+ match = params.currentColor.exec(val);
+ } else {
+ match = !val.match(none);
+ }
+ if (match) {
+ val = 'currentColor';
+ }
+ }
+
+ // Convert color name keyword to long hex
+ if (params.names2hex && val.toLowerCase() in collections.colorsNames) {
+ val = collections.colorsNames[val.toLowerCase()];
+ }
+
+ // Convert rgb() to long hex
+ if (params.rgb2hex && (match = val.match(regRGB))) {
+ match = match.slice(1, 4).map(function(m) {
+ if (m.indexOf('%') > -1)
+ m = Math.round(parseFloat(m) * 2.55);
+
+ return Math.max(0, Math.min(m, 255));
+ });
+
+ val = rgb2hex(match);
+ }
+
+ // Convert long hex to short hex
+ if (params.shorthex && (match = val.match(regHEX))) {
+ val = '#' + match[0][1] + match[0][3] + match[0][5];
+ }
+
+ // Convert hex to short name
+ if (params.shortname) {
+ var lowerVal = val.toLowerCase();
+ if (lowerVal in collections.colorsShortNames) {
+ val = collections.colorsShortNames[lowerVal];
+ }
+ }
+
+ attr.value = val;
+
+ }
+
+ });
+
+ }
+
+};
+
+/**
+ * Convert [r, g, b] to #rrggbb.
+ *
+ * @see https://gist.github.com/983535
+ *
+ * @example
+ * rgb2hex([255, 255, 255]) // '#ffffff'
+ *
+ * @param {Array} rgb [r, g, b]
+ * @return {String} #rrggbb
+ *
+ * @author Jed Schmidt
+ */
+function rgb2hex(rgb) {
+ return '#' + ('00000' + (rgb[0] << 16 | rgb[1] << 8 | rgb[2]).toString(16)).slice(-6).toUpperCase();
+}
diff --git a/node_modules/svgo/plugins/convertEllipseToCircle.js b/node_modules/svgo/plugins/convertEllipseToCircle.js
new file mode 100644
index 0000000..f1af11a
--- /dev/null
+++ b/node_modules/svgo/plugins/convertEllipseToCircle.js
@@ -0,0 +1,39 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'converts non-eccentric <ellipse>s to <circle>s';
+
+/**
+ * Converts non-eccentric <ellipse>s to <circle>s.
+ *
+ * @see http://www.w3.org/TR/SVG/shapes.html
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Taylor Hunt
+ */
+exports.fn = function(item) {
+ if (item.isElem('ellipse')) {
+ var rx = item.attr('rx').value || 0;
+ var ry = item.attr('ry').value || 0;
+
+ if (rx === ry ||
+ rx === 'auto' || ry === 'auto' // SVG2
+ ) {
+ var radius = rx !== 'auto' ? rx : ry;
+ item.renameElem('circle');
+ item.removeAttr(['rx', 'ry']);
+ item.addAttr({
+ name: 'r',
+ value: radius,
+ prefix: '',
+ local: 'r',
+ });
+ }
+ }
+ return;
+};
diff --git a/node_modules/svgo/plugins/convertPathData.js b/node_modules/svgo/plugins/convertPathData.js
new file mode 100644
index 0000000..e0bcf8d
--- /dev/null
+++ b/node_modules/svgo/plugins/convertPathData.js
@@ -0,0 +1,971 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'optimizes path data: writes in shorter form, applies transformations';
+
+exports.params = {
+ applyTransforms: true,
+ applyTransformsStroked: true,
+ makeArcs: {
+ threshold: 2.5, // coefficient of rounding error
+ tolerance: 0.5 // percentage of radius
+ },
+ straightCurves: true,
+ lineShorthands: true,
+ curveSmoothShorthands: true,
+ floatPrecision: 3,
+ transformPrecision: 5,
+ removeUseless: true,
+ collapseRepeated: true,
+ utilizeAbsolute: true,
+ leadingZero: true,
+ negativeExtraSpace: true,
+ noSpaceAfterFlags: true,
+ forceAbsolutePath: false
+};
+
+var pathElems = require('./_collections.js').pathElems,
+ path2js = require('./_path.js').path2js,
+ js2path = require('./_path.js').js2path,
+ applyTransforms = require('./_path.js').applyTransforms,
+ cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
+ roundData,
+ precision,
+ error,
+ arcThreshold,
+ arcTolerance,
+ hasMarkerMid,
+ hasStrokeLinecap;
+
+/**
+ * Convert absolute Path to relative,
+ * collapse repeated instructions,
+ * detect and convert Lineto shorthands,
+ * remove useless instructions like "l0,0",
+ * trim useless delimiters and leading zeros,
+ * decrease accuracy of floating-point numbers.
+ *
+ * @see http://www.w3.org/TR/SVG/paths.html#PathData
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (item.isElem(pathElems) && item.hasAttr('d')) {
+
+ precision = params.floatPrecision;
+ error = precision !== false ? +Math.pow(.1, precision).toFixed(precision) : 1e-2;
+ roundData = precision > 0 && precision < 20 ? strongRound : round;
+ if (params.makeArcs) {
+ arcThreshold = params.makeArcs.threshold;
+ arcTolerance = params.makeArcs.tolerance;
+ }
+ hasMarkerMid = item.hasAttr('marker-mid');
+
+ var stroke = item.computedAttr('stroke'),
+ strokeLinecap = item.computedAttr('stroke');
+ hasStrokeLinecap = stroke && stroke != 'none' && strokeLinecap && strokeLinecap != 'butt';
+
+ var data = path2js(item);
+
+ // TODO: get rid of functions returns
+ if (data.length) {
+ convertToRelative(data);
+
+ if (params.applyTransforms) {
+ data = applyTransforms(item, data, params);
+ }
+
+ data = filters(data, params);
+
+ if (params.utilizeAbsolute) {
+ data = convertToMixed(data, params);
+ }
+
+ js2path(item, data, params);
+ }
+
+ }
+
+};
+
+/**
+ * Convert absolute path data coordinates to relative.
+ *
+ * @param {Array} path input path data
+ * @param {Object} params plugin params
+ * @return {Array} output path data
+ */
+function convertToRelative(path) {
+
+ var point = [0, 0],
+ subpathPoint = [0, 0],
+ baseItem;
+
+ path.forEach(function(item, index) {
+
+ var instruction = item.instruction,
+ data = item.data;
+
+ // data !== !z
+ if (data) {
+
+ // already relative
+ // recalculate current point
+ if ('mcslqta'.indexOf(instruction) > -1) {
+
+ point[0] += data[data.length - 2];
+ point[1] += data[data.length - 1];
+
+ if (instruction === 'm') {
+ subpathPoint[0] = point[0];
+ subpathPoint[1] = point[1];
+ baseItem = item;
+ }
+
+ } else if (instruction === 'h') {
+
+ point[0] += data[0];
+
+ } else if (instruction === 'v') {
+
+ point[1] += data[0];
+
+ }
+
+ // convert absolute path data coordinates to relative
+ // if "M" was not transformed from "m"
+ // M → m
+ if (instruction === 'M') {
+
+ if (index > 0) instruction = 'm';
+
+ data[0] -= point[0];
+ data[1] -= point[1];
+
+ subpathPoint[0] = point[0] += data[0];
+ subpathPoint[1] = point[1] += data[1];
+
+ baseItem = item;
+
+ }
+
+ // L → l
+ // T → t
+ else if ('LT'.indexOf(instruction) > -1) {
+
+ instruction = instruction.toLowerCase();
+
+ // x y
+ // 0 1
+ data[0] -= point[0];
+ data[1] -= point[1];
+
+ point[0] += data[0];
+ point[1] += data[1];
+
+ // C → c
+ } else if (instruction === 'C') {
+
+ instruction = 'c';
+
+ // x1 y1 x2 y2 x y
+ // 0 1 2 3 4 5
+ data[0] -= point[0];
+ data[1] -= point[1];
+ data[2] -= point[0];
+ data[3] -= point[1];
+ data[4] -= point[0];
+ data[5] -= point[1];
+
+ point[0] += data[4];
+ point[1] += data[5];
+
+ // S → s
+ // Q → q
+ } else if ('SQ'.indexOf(instruction) > -1) {
+
+ instruction = instruction.toLowerCase();
+
+ // x1 y1 x y
+ // 0 1 2 3
+ data[0] -= point[0];
+ data[1] -= point[1];
+ data[2] -= point[0];
+ data[3] -= point[1];
+
+ point[0] += data[2];
+ point[1] += data[3];
+
+ // A → a
+ } else if (instruction === 'A') {
+
+ instruction = 'a';
+
+ // rx ry x-axis-rotation large-arc-flag sweep-flag x y
+ // 0 1 2 3 4 5 6
+ data[5] -= point[0];
+ data[6] -= point[1];
+
+ point[0] += data[5];
+ point[1] += data[6];
+
+ // H → h
+ } else if (instruction === 'H') {
+
+ instruction = 'h';
+
+ data[0] -= point[0];
+
+ point[0] += data[0];
+
+ // V → v
+ } else if (instruction === 'V') {
+
+ instruction = 'v';
+
+ data[0] -= point[1];
+
+ point[1] += data[0];
+
+ }
+
+ item.instruction = instruction;
+ item.data = data;
+
+ // store absolute coordinates for later use
+ item.coords = point.slice(-2);
+
+ }
+
+ // !data === z, reset current point
+ else if (instruction == 'z') {
+ if (baseItem) {
+ item.coords = baseItem.coords;
+ }
+ point[0] = subpathPoint[0];
+ point[1] = subpathPoint[1];
+ }
+
+ item.base = index > 0 ? path[index - 1].coords : [0, 0];
+
+ });
+
+ return path;
+
+}
+
+/**
+ * Main filters loop.
+ *
+ * @param {Array} path input path data
+ * @param {Object} params plugin params
+ * @return {Array} output path data
+ */
+function filters(path, params) {
+
+ var stringify = data2Path.bind(null, params),
+ relSubpoint = [0, 0],
+ pathBase = [0, 0],
+ prev = {};
+
+ path = path.filter(function(item, index, path) {
+
+ var instruction = item.instruction,
+ data = item.data,
+ next = path[index + 1];
+
+ if (data) {
+
+ var sdata = data,
+ circle;
+
+ if (instruction === 's') {
+ sdata = [0, 0].concat(data);
+
+ if ('cs'.indexOf(prev.instruction) > -1) {
+ var pdata = prev.data,
+ n = pdata.length;
+
+ // (-x, -y) of the prev tangent point relative to the current point
+ sdata[0] = pdata[n - 2] - pdata[n - 4];
+ sdata[1] = pdata[n - 1] - pdata[n - 3];
+ }
+
+ }
+
+ // convert curves to arcs if possible
+ if (
+ params.makeArcs &&
+ (instruction == 'c' || instruction == 's') &&
+ isConvex(sdata) &&
+ (circle = findCircle(sdata))
+ ) {
+ var r = roundData([circle.radius])[0],
+ angle = findArcAngle(sdata, circle),
+ sweep = sdata[5] * sdata[0] - sdata[4] * sdata[1] > 0 ? 1 : 0,
+ arc = {
+ instruction: 'a',
+ data: [r, r, 0, 0, sweep, sdata[4], sdata[5]],
+ coords: item.coords.slice(),
+ base: item.base
+ },
+ output = [arc],
+ // relative coordinates to adjust the found circle
+ relCenter = [circle.center[0] - sdata[4], circle.center[1] - sdata[5]],
+ relCircle = { center: relCenter, radius: circle.radius },
+ arcCurves = [item],
+ hasPrev = 0,
+ suffix = '',
+ nextLonghand;
+
+ if (
+ prev.instruction == 'c' && isConvex(prev.data) && isArcPrev(prev.data, circle) ||
+ prev.instruction == 'a' && prev.sdata && isArcPrev(prev.sdata, circle)
+ ) {
+ arcCurves.unshift(prev);
+ arc.base = prev.base;
+ arc.data[5] = arc.coords[0] - arc.base[0];
+ arc.data[6] = arc.coords[1] - arc.base[1];
+ var prevData = prev.instruction == 'a' ? prev.sdata : prev.data;
+ var prevAngle = findArcAngle(prevData,
+ {
+ center: [prevData[4] + circle.center[0], prevData[5] + circle.center[1]],
+ radius: circle.radius
+ }
+ );
+ angle += prevAngle;
+ if (angle > Math.PI) arc.data[3] = 1;
+ hasPrev = 1;
+ }
+
+ // check if next curves are fitting the arc
+ for (var j = index; (next = path[++j]) && ~'cs'.indexOf(next.instruction);) {
+ var nextData = next.data;
+ if (next.instruction == 's') {
+ nextLonghand = makeLonghand({instruction: 's', data: next.data.slice() },
+ path[j - 1].data);
+ nextData = nextLonghand.data;
+ nextLonghand.data = nextData.slice(0, 2);
+ suffix = stringify([nextLonghand]);
+ }
+ if (isConvex(nextData) && isArc(nextData, relCircle)) {
+ angle += findArcAngle(nextData, relCircle);
+ if (angle - 2 * Math.PI > 1e-3) break; // more than 360°
+ if (angle > Math.PI) arc.data[3] = 1;
+ arcCurves.push(next);
+ if (2 * Math.PI - angle > 1e-3) { // less than 360°
+ arc.coords = next.coords;
+ arc.data[5] = arc.coords[0] - arc.base[0];
+ arc.data[6] = arc.coords[1] - arc.base[1];
+ } else {
+ // full circle, make a half-circle arc and add a second one
+ arc.data[5] = 2 * (relCircle.center[0] - nextData[4]);
+ arc.data[6] = 2 * (relCircle.center[1] - nextData[5]);
+ arc.coords = [arc.base[0] + arc.data[5], arc.base[1] + arc.data[6]];
+ arc = {
+ instruction: 'a',
+ data: [r, r, 0, 0, sweep,
+ next.coords[0] - arc.coords[0], next.coords[1] - arc.coords[1]],
+ coords: next.coords,
+ base: arc.coords
+ };
+ output.push(arc);
+ j++;
+ break;
+ }
+ relCenter[0] -= nextData[4];
+ relCenter[1] -= nextData[5];
+ } else break;
+ }
+
+ if ((stringify(output) + suffix).length < stringify(arcCurves).length) {
+ if (path[j] && path[j].instruction == 's') {
+ makeLonghand(path[j], path[j - 1].data);
+ }
+ if (hasPrev) {
+ var prevArc = output.shift();
+ roundData(prevArc.data);
+ relSubpoint[0] += prevArc.data[5] - prev.data[prev.data.length - 2];
+ relSubpoint[1] += prevArc.data[6] - prev.data[prev.data.length - 1];
+ prev.instruction = 'a';
+ prev.data = prevArc.data;
+ item.base = prev.coords = prevArc.coords;
+ }
+ arc = output.shift();
+ if (arcCurves.length == 1) {
+ item.sdata = sdata.slice(); // preserve curve data for future checks
+ } else if (arcCurves.length - 1 - hasPrev > 0) {
+ // filter out consumed next items
+ path.splice.apply(path, [index + 1, arcCurves.length - 1 - hasPrev].concat(output));
+ }
+ if (!arc) return false;
+ instruction = 'a';
+ data = arc.data;
+ item.coords = arc.coords;
+ }
+ }
+
+ // Rounding relative coordinates, taking in account accummulating error
+ // to get closer to absolute coordinates. Sum of rounded value remains same:
+ // l .25 3 .25 2 .25 3 .25 2 -> l .3 3 .2 2 .3 3 .2 2
+ if (precision !== false) {
+ if ('mltqsc'.indexOf(instruction) > -1) {
+ for (var i = data.length; i--;) {
+ data[i] += item.base[i % 2] - relSubpoint[i % 2];
+ }
+ } else if (instruction == 'h') {
+ data[0] += item.base[0] - relSubpoint[0];
+ } else if (instruction == 'v') {
+ data[0] += item.base[1] - relSubpoint[1];
+ } else if (instruction == 'a') {
+ data[5] += item.base[0] - relSubpoint[0];
+ data[6] += item.base[1] - relSubpoint[1];
+ }
+ roundData(data);
+
+ if (instruction == 'h') relSubpoint[0] += data[0];
+ else if (instruction == 'v') relSubpoint[1] += data[0];
+ else {
+ relSubpoint[0] += data[data.length - 2];
+ relSubpoint[1] += data[data.length - 1];
+ }
+ roundData(relSubpoint);
+
+ if (instruction.toLowerCase() == 'm') {
+ pathBase[0] = relSubpoint[0];
+ pathBase[1] = relSubpoint[1];
+ }
+ }
+
+ // convert straight curves into lines segments
+ if (params.straightCurves) {
+
+ if (
+ instruction === 'c' &&
+ isCurveStraightLine(data) ||
+ instruction === 's' &&
+ isCurveStraightLine(sdata)
+ ) {
+ if (next && next.instruction == 's')
+ makeLonghand(next, data); // fix up next curve
+ instruction = 'l';
+ data = data.slice(-2);
+ }
+
+ else if (
+ instruction === 'q' &&
+ isCurveStraightLine(data)
+ ) {
+ if (next && next.instruction == 't')
+ makeLonghand(next, data); // fix up next curve
+ instruction = 'l';
+ data = data.slice(-2);
+ }
+
+ else if (
+ instruction === 't' &&
+ prev.instruction !== 'q' &&
+ prev.instruction !== 't'
+ ) {
+ instruction = 'l';
+ data = data.slice(-2);
+ }
+
+ else if (
+ instruction === 'a' &&
+ (data[0] === 0 || data[1] === 0)
+ ) {
+ instruction = 'l';
+ data = data.slice(-2);
+ }
+ }
+
+ // horizontal and vertical line shorthands
+ // l 50 0 → h 50
+ // l 0 50 → v 50
+ if (
+ params.lineShorthands &&
+ instruction === 'l'
+ ) {
+ if (data[1] === 0) {
+ instruction = 'h';
+ data.pop();
+ } else if (data[0] === 0) {
+ instruction = 'v';
+ data.shift();
+ }
+ }
+
+ // collapse repeated commands
+ // h 20 h 30 -> h 50
+ if (
+ params.collapseRepeated &&
+ !hasMarkerMid &&
+ ('mhv'.indexOf(instruction) > -1) &&
+ prev.instruction &&
+ instruction == prev.instruction.toLowerCase() &&
+ (
+ (instruction != 'h' && instruction != 'v') ||
+ (prev.data[0] >= 0) == (item.data[0] >= 0)
+ )) {
+ prev.data[0] += data[0];
+ if (instruction != 'h' && instruction != 'v') {
+ prev.data[1] += data[1];
+ }
+ prev.coords = item.coords;
+ path[index] = prev;
+ return false;
+ }
+
+ // convert curves into smooth shorthands
+ if (params.curveSmoothShorthands && prev.instruction) {
+
+ // curveto
+ if (instruction === 'c') {
+
+ // c + c → c + s
+ if (
+ prev.instruction === 'c' &&
+ data[0] === -(prev.data[2] - prev.data[4]) &&
+ data[1] === -(prev.data[3] - prev.data[5])
+ ) {
+ instruction = 's';
+ data = data.slice(2);
+ }
+
+ // s + c → s + s
+ else if (
+ prev.instruction === 's' &&
+ data[0] === -(prev.data[0] - prev.data[2]) &&
+ data[1] === -(prev.data[1] - prev.data[3])
+ ) {
+ instruction = 's';
+ data = data.slice(2);
+ }
+
+ // [^cs] + c → [^cs] + s
+ else if (
+ 'cs'.indexOf(prev.instruction) === -1 &&
+ data[0] === 0 &&
+ data[1] === 0
+ ) {
+ instruction = 's';
+ data = data.slice(2);
+ }
+
+ }
+
+ // quadratic Bézier curveto
+ else if (instruction === 'q') {
+
+ // q + q → q + t
+ if (
+ prev.instruction === 'q' &&
+ data[0] === (prev.data[2] - prev.data[0]) &&
+ data[1] === (prev.data[3] - prev.data[1])
+ ) {
+ instruction = 't';
+ data = data.slice(2);
+ }
+
+ // t + q → t + t
+ else if (
+ prev.instruction === 't' &&
+ data[2] === prev.data[0] &&
+ data[3] === prev.data[1]
+ ) {
+ instruction = 't';
+ data = data.slice(2);
+ }
+
+ }
+
+ }
+
+ // remove useless non-first path segments
+ if (params.removeUseless && !hasStrokeLinecap) {
+
+ // l 0,0 / h 0 / v 0 / q 0,0 0,0 / t 0,0 / c 0,0 0,0 0,0 / s 0,0 0,0
+ if (
+ (
+ 'lhvqtcs'.indexOf(instruction) > -1
+ ) &&
+ data.every(function(i) { return i === 0; })
+ ) {
+ path[index] = prev;
+ return false;
+ }
+
+ // a 25,25 -30 0,1 0,0
+ if (
+ instruction === 'a' &&
+ data[5] === 0 &&
+ data[6] === 0
+ ) {
+ path[index] = prev;
+ return false;
+ }
+
+ }
+
+ item.instruction = instruction;
+ item.data = data;
+
+ prev = item;
+
+ } else {
+
+ // z resets coordinates
+ relSubpoint[0] = pathBase[0];
+ relSubpoint[1] = pathBase[1];
+ if (prev.instruction == 'z') return false;
+ prev = item;
+
+ }
+
+ return true;
+
+ });
+
+ return path;
+
+}
+
+/**
+ * Writes data in shortest form using absolute or relative coordinates.
+ *
+ * @param {Array} data input path data
+ * @return {Boolean} output
+ */
+function convertToMixed(path, params) {
+
+ var prev = path[0];
+
+ path = path.filter(function(item, index) {
+
+ if (index == 0) return true;
+ if (!item.data) {
+ prev = item;
+ return true;
+ }
+
+ var instruction = item.instruction,
+ data = item.data,
+ adata = data && data.slice(0);
+
+ if ('mltqsc'.indexOf(instruction) > -1) {
+ for (var i = adata.length; i--;) {
+ adata[i] += item.base[i % 2];
+ }
+ } else if (instruction == 'h') {
+ adata[0] += item.base[0];
+ } else if (instruction == 'v') {
+ adata[0] += item.base[1];
+ } else if (instruction == 'a') {
+ adata[5] += item.base[0];
+ adata[6] += item.base[1];
+ }
+
+ roundData(adata);
+
+ var absoluteDataStr = cleanupOutData(adata, params),
+ relativeDataStr = cleanupOutData(data, params);
+
+ // Convert to absolute coordinates if it's shorter or forceAbsolutePath is true.
+ // v-20 -> V0
+ // Don't convert if it fits following previous instruction.
+ // l20 30-10-50 instead of l20 30L20 30
+ if (
+ params.forceAbsolutePath || (
+ absoluteDataStr.length < relativeDataStr.length &&
+ !(
+ params.negativeExtraSpace &&
+ instruction == prev.instruction &&
+ prev.instruction.charCodeAt(0) > 96 &&
+ absoluteDataStr.length == relativeDataStr.length - 1 &&
+ (data[0] < 0 || /^0\./.test(data[0]) && prev.data[prev.data.length - 1] % 1)
+ ))
+ ) {
+ item.instruction = instruction.toUpperCase();
+ item.data = adata;
+ }
+
+ prev = item;
+
+ return true;
+
+ });
+
+ return path;
+
+}
+
+/**
+ * Checks if curve is convex. Control points of such a curve must form
+ * a convex quadrilateral with diagonals crosspoint inside of it.
+ *
+ * @param {Array} data input path data
+ * @return {Boolean} output
+ */
+function isConvex(data) {
+
+ var center = getIntersection([0, 0, data[2], data[3], data[0], data[1], data[4], data[5]]);
+
+ return center &&
+ (data[2] < center[0] == center[0] < 0) &&
+ (data[3] < center[1] == center[1] < 0) &&
+ (data[4] < center[0] == center[0] < data[0]) &&
+ (data[5] < center[1] == center[1] < data[1]);
+
+}
+
+/**
+ * Computes lines equations by two points and returns their intersection point.
+ *
+ * @param {Array} coords 8 numbers for 4 pairs of coordinates (x,y)
+ * @return {Array|undefined} output coordinate of lines' crosspoint
+ */
+function getIntersection(coords) {
+
+ // Prev line equation parameters.
+ var a1 = coords[1] - coords[3], // y1 - y2
+ b1 = coords[2] - coords[0], // x2 - x1
+ c1 = coords[0] * coords[3] - coords[2] * coords[1], // x1 * y2 - x2 * y1
+
+ // Next line equation parameters
+ a2 = coords[5] - coords[7], // y1 - y2
+ b2 = coords[6] - coords[4], // x2 - x1
+ c2 = coords[4] * coords[7] - coords[5] * coords[6], // x1 * y2 - x2 * y1
+ denom = (a1 * b2 - a2 * b1);
+
+ if (!denom) return; // parallel lines havn't an intersection
+
+ var cross = [
+ (b1 * c2 - b2 * c1) / denom,
+ (a1 * c2 - a2 * c1) / -denom
+ ];
+ if (
+ !isNaN(cross[0]) && !isNaN(cross[1]) &&
+ isFinite(cross[0]) && isFinite(cross[1])
+ ) {
+ return cross;
+ }
+
+}
+
+/**
+ * Decrease accuracy of floating-point numbers
+ * in path data keeping a specified number of decimals.
+ * Smart rounds values like 2.3491 to 2.35 instead of 2.349.
+ * Doesn't apply "smartness" if the number precision fits already.
+ *
+ * @param {Array} data input data array
+ * @return {Array} output data array
+ */
+function strongRound(data) {
+ for (var i = data.length; i-- > 0;) {
+ if (data[i].toFixed(precision) != data[i]) {
+ var rounded = +data[i].toFixed(precision - 1);
+ data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= error ?
+ +data[i].toFixed(precision) :
+ rounded;
+ }
+ }
+ return data;
+}
+
+/**
+ * Simple rounding function if precision is 0.
+ *
+ * @param {Array} data input data array
+ * @return {Array} output data array
+ */
+function round(data) {
+ for (var i = data.length; i-- > 0;) {
+ data[i] = Math.round(data[i]);
+ }
+ return data;
+}
+
+/**
+ * Checks if a curve is a straight line by measuring distance
+ * from middle points to the line formed by end points.
+ *
+ * @param {Array} xs array of curve points x-coordinates
+ * @param {Array} ys array of curve points y-coordinates
+ * @return {Boolean}
+ */
+
+function isCurveStraightLine(data) {
+
+ // Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points.
+ var i = data.length - 2,
+ a = -data[i + 1], // y1 − y2 (y1 = 0)
+ b = data[i], // x2 − x1 (x1 = 0)
+ d = 1 / (a * a + b * b); // same part for all points
+
+ if (i <= 1 || !isFinite(d)) return false; // curve that ends at start point isn't the case
+
+ // Distance from point (x0, y0) to the line is sqrt((c − a·x0 − b·y0)² / (a² + b²))
+ while ((i -= 2) >= 0) {
+ if (Math.sqrt(Math.pow(a * data[i] + b * data[i + 1], 2) * d) > error)
+ return false;
+ }
+
+ return true;
+
+}
+
+/**
+ * Converts next curve from shorthand to full form using the current curve data.
+ *
+ * @param {Object} item curve to convert
+ * @param {Array} data current curve data
+ */
+
+function makeLonghand(item, data) {
+ switch (item.instruction) {
+ case 's': item.instruction = 'c'; break;
+ case 't': item.instruction = 'q'; break;
+ }
+ item.data.unshift(data[data.length - 2] - data[data.length - 4], data[data.length - 1] - data[data.length - 3]);
+ return item;
+}
+
+/**
+ * Returns distance between two points
+ *
+ * @param {Array} point1 first point coordinates
+ * @param {Array} point2 second point coordinates
+ * @return {Number} distance
+ */
+
+function getDistance(point1, point2) {
+ return Math.hypot(point1[0] - point2[0], point1[1] - point2[1]);
+}
+
+/**
+ * Returns coordinates of the curve point corresponding to the certain t
+ * a·(1 - t)³·p1 + b·(1 - t)²·t·p2 + c·(1 - t)·t²·p3 + d·t³·p4,
+ * where pN are control points and p1 is zero due to relative coordinates.
+ *
+ * @param {Array} curve array of curve points coordinates
+ * @param {Number} t parametric position from 0 to 1
+ * @return {Array} Point coordinates
+ */
+
+function getCubicBezierPoint(curve, t) {
+ var sqrT = t * t,
+ cubT = sqrT * t,
+ mt = 1 - t,
+ sqrMt = mt * mt;
+
+ return [
+ 3 * sqrMt * t * curve[0] + 3 * mt * sqrT * curve[2] + cubT * curve[4],
+ 3 * sqrMt * t * curve[1] + 3 * mt * sqrT * curve[3] + cubT * curve[5]
+ ];
+}
+
+/**
+ * Finds circle by 3 points of the curve and checks if the curve fits the found circle.
+ *
+ * @param {Array} curve
+ * @return {Object|undefined} circle
+ */
+
+function findCircle(curve) {
+ var midPoint = getCubicBezierPoint(curve, 1/2),
+ m1 = [midPoint[0] / 2, midPoint[1] / 2],
+ m2 = [(midPoint[0] + curve[4]) / 2, (midPoint[1] + curve[5]) / 2],
+ center = getIntersection([
+ m1[0], m1[1],
+ m1[0] + m1[1], m1[1] - m1[0],
+ m2[0], m2[1],
+ m2[0] + (m2[1] - midPoint[1]), m2[1] - (m2[0] - midPoint[0])
+ ]),
+ radius = center && getDistance([0, 0], center),
+ tolerance = Math.min(arcThreshold * error, arcTolerance * radius / 100);
+
+ if (center && radius < 1e15 &&
+ [1/4, 3/4].every(function(point) {
+ return Math.abs(getDistance(getCubicBezierPoint(curve, point), center) - radius) <= tolerance;
+ }))
+ return { center: center, radius: radius};
+}
+
+/**
+ * Checks if a curve fits the given circle.
+ *
+ * @param {Object} circle
+ * @param {Array} curve
+ * @return {Boolean}
+ */
+
+function isArc(curve, circle) {
+ var tolerance = Math.min(arcThreshold * error, arcTolerance * circle.radius / 100);
+
+ return [0, 1/4, 1/2, 3/4, 1].every(function(point) {
+ return Math.abs(getDistance(getCubicBezierPoint(curve, point), circle.center) - circle.radius) <= tolerance;
+ });
+}
+
+/**
+ * Checks if a previous curve fits the given circle.
+ *
+ * @param {Object} circle
+ * @param {Array} curve
+ * @return {Boolean}
+ */
+
+function isArcPrev(curve, circle) {
+ return isArc(curve, {
+ center: [circle.center[0] + curve[4], circle.center[1] + curve[5]],
+ radius: circle.radius
+ });
+}
+
+/**
+ * Finds angle of a curve fitting the given arc.
+
+ * @param {Array} curve
+ * @param {Object} relCircle
+ * @return {Number} angle
+ */
+
+function findArcAngle(curve, relCircle) {
+ var x1 = -relCircle.center[0],
+ y1 = -relCircle.center[1],
+ x2 = curve[4] - relCircle.center[0],
+ y2 = curve[5] - relCircle.center[1];
+
+ return Math.acos(
+ (x1 * x2 + y1 * y2) /
+ Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2))
+ );
+}
+
+/**
+ * Converts given path data to string.
+ *
+ * @param {Object} params
+ * @param {Array} pathData
+ * @return {String}
+ */
+
+function data2Path(params, pathData) {
+ return pathData.reduce(function(pathString, item) {
+ var strData = '';
+ if (item.data) {
+ strData = cleanupOutData(roundData(item.data.slice()), params);
+ }
+ return pathString + item.instruction + strData;
+ }, '');
+}
diff --git a/node_modules/svgo/plugins/convertShapeToPath.js b/node_modules/svgo/plugins/convertShapeToPath.js
new file mode 100644
index 0000000..9072461
--- /dev/null
+++ b/node_modules/svgo/plugins/convertShapeToPath.js
@@ -0,0 +1,149 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'converts basic shapes to more compact path form';
+
+exports.params = {
+ convertArcs: false
+};
+
+var none = { value: 0 },
+ regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
+
+/**
+ * Converts basic shape to more compact path.
+ * It also allows further optimizations like
+ * combining paths with similar attributes.
+ *
+ * @see http://www.w3.org/TR/SVG/shapes.html
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Lev Solntsev
+ */
+exports.fn = function(item, params) {
+ var convertArcs = params && params.convertArcs;
+
+ if (
+ item.isElem('rect') &&
+ item.hasAttr('width') &&
+ item.hasAttr('height') &&
+ !item.hasAttr('rx') &&
+ !item.hasAttr('ry')
+ ) {
+
+ var x = +(item.attr('x') || none).value,
+ y = +(item.attr('y') || none).value,
+ width = +item.attr('width').value,
+ height = +item.attr('height').value;
+
+ // Values like '100%' compute to NaN, thus running after
+ // cleanupNumericValues when 'px' units has already been removed.
+ // TODO: Calculate sizes from % and non-px units if possible.
+ if (isNaN(x - y + width - height)) return;
+
+ var pathData =
+ 'M' + x + ' ' + y +
+ 'H' + (x + width) +
+ 'V' + (y + height) +
+ 'H' + x +
+ 'z';
+
+ item.addAttr({
+ name: 'd',
+ value: pathData,
+ prefix: '',
+ local: 'd'
+ });
+
+ item.renameElem('path')
+ .removeAttr(['x', 'y', 'width', 'height']);
+
+ } else if (item.isElem('line')) {
+
+ var x1 = +(item.attr('x1') || none).value,
+ y1 = +(item.attr('y1') || none).value,
+ x2 = +(item.attr('x2') || none).value,
+ y2 = +(item.attr('y2') || none).value;
+ if (isNaN(x1 - y1 + x2 - y2)) return;
+
+ item.addAttr({
+ name: 'd',
+ value: 'M' + x1 + ' ' + y1 + 'L' + x2 + ' ' + y2,
+ prefix: '',
+ local: 'd'
+ });
+
+ item.renameElem('path')
+ .removeAttr(['x1', 'y1', 'x2', 'y2']);
+
+ } else if ((
+ item.isElem('polyline') ||
+ item.isElem('polygon')
+ ) &&
+ item.hasAttr('points')
+ ) {
+
+ var coords = (item.attr('points').value.match(regNumber) || []).map(Number);
+ if (coords.length < 4) return false;
+
+ item.addAttr({
+ name: 'd',
+ value: 'M' + coords.slice(0,2).join(' ') +
+ 'L' + coords.slice(2).join(' ') +
+ (item.isElem('polygon') ? 'z' : ''),
+ prefix: '',
+ local: 'd'
+ });
+
+ item.renameElem('path')
+ .removeAttr('points');
+ } else if (item.isElem('circle') && convertArcs) {
+
+ var cx = +(item.attr('cx') || none).value;
+ var cy = +(item.attr('cy') || none).value;
+ var r = +(item.attr('r') || none).value;
+ if (isNaN(cx - cy + r)) {
+ return;
+ }
+ var cPathData =
+ 'M' + cx + ' ' + (cy - r) +
+ 'A' + r + ' ' + r + ' 0 1 0 ' + cx + ' ' + (cy + r) +
+ 'A' + r + ' ' + r + ' 0 1 0 ' + cx + ' ' + (cy - r) +
+ 'Z';
+ item.addAttr({
+ name: 'd',
+ value: cPathData,
+ prefix: '',
+ local: 'd',
+ });
+ item.renameElem('path').removeAttr(['cx', 'cy', 'r']);
+
+ } else if (item.isElem('ellipse') && convertArcs) {
+
+ var ecx = +(item.attr('cx') || none).value;
+ var ecy = +(item.attr('cy') || none).value;
+ var rx = +(item.attr('rx') || none).value;
+ var ry = +(item.attr('ry') || none).value;
+ if (isNaN(ecx - ecy + rx - ry)) {
+ return;
+ }
+ var ePathData =
+ 'M' + ecx + ' ' + (ecy - ry) +
+ 'A' + rx + ' ' + ry + ' 0 1 0 ' + ecx + ' ' + (ecy + ry) +
+ 'A' + rx + ' ' + ry + ' 0 1 0 ' + ecx + ' ' + (ecy - ry) +
+ 'Z';
+ item.addAttr({
+ name: 'd',
+ value: ePathData,
+ prefix: '',
+ local: 'd',
+ });
+ item.renameElem('path').removeAttr(['cx', 'cy', 'rx', 'ry']);
+ }
+};
diff --git a/node_modules/svgo/plugins/convertStyleToAttrs.js b/node_modules/svgo/plugins/convertStyleToAttrs.js
new file mode 100644
index 0000000..29d69a7
--- /dev/null
+++ b/node_modules/svgo/plugins/convertStyleToAttrs.js
@@ -0,0 +1,125 @@
+/* jshint quotmark: false */
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'converts style to attributes';
+
+exports.params = {
+ keepImportant: false
+};
+
+var stylingProps = require('./_collections').attrsGroups.presentation,
+ rEscape = '\\\\(?:[0-9a-f]{1,6}\\s?|\\r\\n|.)', // Like \" or \2051. Code points consume one space.
+ rAttr = '\\s*(' + g('[^:;\\\\]', rEscape) + '*?)\\s*', // attribute name like ‘fill’
+ rSingleQuotes = "'(?:[^'\\n\\r\\\\]|" + rEscape + ")*?(?:'|$)", // string in single quotes: 'smth'
+ rQuotes = '"(?:[^"\\n\\r\\\\]|' + rEscape + ')*?(?:"|$)', // string in double quotes: "smth"
+ rQuotedString = new RegExp('^' + g(rSingleQuotes, rQuotes) + '$'),
+
+ // Parentheses, E.g.: url(data:image/png;base64,iVBO...).
+ // ':' and ';' inside of it should be threated as is. (Just like in strings.)
+ rParenthesis = '\\(' + g('[^\'"()\\\\]+', rEscape, rSingleQuotes, rQuotes) + '*?' + '\\)',
+
+ // The value. It can have strings and parentheses (see above). Fallbacks to anything in case of unexpected input.
+ rValue = '\\s*(' + g('[^!\'"();\\\\]+?', rEscape, rSingleQuotes, rQuotes, rParenthesis, '[^;]*?') + '*?' + ')',
+
+ // End of declaration. Spaces outside of capturing groups help to do natural trimming.
+ rDeclEnd = '\\s*(?:;\\s*|$)',
+
+ // Important rule
+ rImportant = '(\\s*!important(?![-(\w]))?',
+
+ // Final RegExp to parse CSS declarations.
+ regDeclarationBlock = new RegExp(rAttr + ':' + rValue + rImportant + rDeclEnd, 'ig'),
+
+ // Comments expression. Honors escape sequences and strings.
+ regStripComments = new RegExp(g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'), 'ig');
+
+/**
+ * Convert style in attributes. Cleanups comments and illegal declarations (without colon) as a side effect.
+ *
+ * @example
+ * <g style="fill:#000; color: #fff;">
+ * ⬇
+ * <g fill="#000" color="#fff">
+ *
+ * @example
+ * <g style="fill:#000; color: #fff; -webkit-blah: blah">
+ * ⬇
+ * <g fill="#000" color="#fff" style="-webkit-blah: blah">
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+ /* jshint boss: true */
+
+ if (item.elem && item.hasAttr('style')) {
+ // ['opacity: 1', 'color: #000']
+ var styleValue = item.attr('style').value,
+ styles = [],
+ attrs = {};
+
+ // Strip CSS comments preserving escape sequences and strings.
+ styleValue = styleValue.replace(regStripComments, function(match) {
+ return match[0] == '/' ? '' :
+ match[0] == '\\' && /[-g-z]/i.test(match[1]) ? match[1] : match;
+ });
+
+ regDeclarationBlock.lastIndex = 0;
+ for (var rule; rule = regDeclarationBlock.exec(styleValue);) {
+ if (!params.keepImportant || !rule[3]) {
+ styles.push([rule[1], rule[2]]);
+ }
+ }
+
+ if (styles.length) {
+
+ styles = styles.filter(function(style) {
+ if (style[0]) {
+ var prop = style[0].toLowerCase(),
+ val = style[1];
+
+ if (rQuotedString.test(val)) {
+ val = val.slice(1, -1);
+ }
+
+ if (stylingProps.indexOf(prop) > -1) {
+
+ attrs[prop] = {
+ name: prop,
+ value: val,
+ local: prop,
+ prefix: ''
+ };
+
+ return false;
+ }
+ }
+
+ return true;
+ });
+
+ Object.assign(item.attrs, attrs);
+
+ if (styles.length) {
+ item.attr('style').value = styles
+ .map(function(declaration) { return declaration.join(':') })
+ .join(';');
+ } else {
+ item.removeAttr('style');
+ }
+
+ }
+
+ }
+
+};
+
+function g() {
+ return '(?:' + Array.prototype.join.call(arguments, '|') + ')';
+}
diff --git a/node_modules/svgo/plugins/convertTransform.js b/node_modules/svgo/plugins/convertTransform.js
new file mode 100644
index 0000000..ea5969c
--- /dev/null
+++ b/node_modules/svgo/plugins/convertTransform.js
@@ -0,0 +1,363 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'collapses multiple transformations and optimizes it';
+
+exports.params = {
+ convertToShorts: true,
+ // degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default
+ floatPrecision: 3,
+ transformPrecision: 5,
+ matrixToTransform: true,
+ shortTranslate: true,
+ shortScale: true,
+ shortRotate: true,
+ removeUseless: true,
+ collapseIntoOne: true,
+ leadingZero: true,
+ negativeExtraSpace: false
+};
+
+var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
+ transform2js = require('./_transforms.js').transform2js,
+ transformsMultiply = require('./_transforms.js').transformsMultiply,
+ matrixToTransform = require('./_transforms.js').matrixToTransform,
+ degRound,
+ floatRound,
+ transformRound;
+
+/**
+ * Convert matrices to the short aliases,
+ * convert long translate, scale or rotate transform notations to the shorts ones,
+ * convert transforms to the matrices and multiply them all into one,
+ * remove useless transforms.
+ *
+ * @see http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (item.elem) {
+
+ // transform
+ if (item.hasAttr('transform')) {
+ convertTransform(item, 'transform', params);
+ }
+
+ // gradientTransform
+ if (item.hasAttr('gradientTransform')) {
+ convertTransform(item, 'gradientTransform', params);
+ }
+
+ // patternTransform
+ if (item.hasAttr('patternTransform')) {
+ convertTransform(item, 'patternTransform', params);
+ }
+
+ }
+
+};
+
+/**
+ * Main function.
+ *
+ * @param {Object} item input item
+ * @param {String} attrName attribute name
+ * @param {Object} params plugin params
+ */
+function convertTransform(item, attrName, params) {
+ var data = transform2js(item.attr(attrName).value);
+ params = definePrecision(data, params);
+
+ if (params.collapseIntoOne && data.length > 1) {
+ data = [transformsMultiply(data)];
+ }
+
+ if (params.convertToShorts) {
+ data = convertToShorts(data, params);
+ } else {
+ data.forEach(roundTransform);
+ }
+
+ if (params.removeUseless) {
+ data = removeUseless(data);
+ }
+
+ if (data.length) {
+ item.attr(attrName).value = js2transform(data, params);
+ } else {
+ item.removeAttr(attrName);
+ }
+}
+
+/**
+ * Defines precision to work with certain parts.
+ * transformPrecision - for scale and four first matrix parameters (needs a better precision due to multiplying),
+ * floatPrecision - for translate including two last matrix and rotate parameters,
+ * degPrecision - for rotate and skew. By default it's equal to (rougly)
+ * transformPrecision - 2 or floatPrecision whichever is lower. Can be set in params.
+ *
+ * @param {Array} transforms input array
+ * @param {Object} params plugin params
+ * @return {Array} output array
+ */
+function definePrecision(data, params) {
+ /* jshint validthis: true */
+ var matrixData = data.reduce(getMatrixData, []),
+ significantDigits = params.transformPrecision;
+
+ // Clone params so it don't affect other elements transformations.
+ params = Object.assign({}, params);
+
+ // Limit transform precision with matrix one. Calculating with larger precision doesn't add any value.
+ if (matrixData.length) {
+ params.transformPrecision = Math.min(params.transformPrecision,
+ Math.max.apply(Math, matrixData.map(floatDigits)) || params.transformPrecision);
+
+ significantDigits = Math.max.apply(Math, matrixData.map(function(n) {
+ return String(n).replace(/\D+/g, '').length; // Number of digits in a number. 123.45 → 5
+ }));
+ }
+ // No sense in angle precision more then number of significant digits in matrix.
+ if (!('degPrecision' in params)) {
+ params.degPrecision = Math.max(0, Math.min(params.floatPrecision, significantDigits - 2));
+ }
+
+ floatRound = params.floatPrecision >= 1 && params.floatPrecision < 20 ?
+ smartRound.bind(this, params.floatPrecision) :
+ round;
+ degRound = params.degPrecision >= 1 && params.floatPrecision < 20 ?
+ smartRound.bind(this, params.degPrecision) :
+ round;
+ transformRound = params.transformPrecision >= 1 && params.floatPrecision < 20 ?
+ smartRound.bind(this, params.transformPrecision) :
+ round;
+
+ return params;
+}
+
+/**
+ * Gathers four first matrix parameters.
+ *
+ * @param {Array} a array of data
+ * @param {Object} transform
+ * @return {Array} output array
+ */
+function getMatrixData(a, b) {
+ return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a;
+}
+
+/**
+ * Returns number of digits after the point. 0.125 → 3
+ */
+function floatDigits(n) {
+ return (n = String(n)).slice(n.indexOf('.')).length - 1;
+}
+
+/**
+ * Convert transforms to the shorthand alternatives.
+ *
+ * @param {Array} transforms input array
+ * @param {Object} params plugin params
+ * @return {Array} output array
+ */
+function convertToShorts(transforms, params) {
+
+ for(var i = 0; i < transforms.length; i++) {
+
+ var transform = transforms[i];
+
+ // convert matrix to the short aliases
+ if (
+ params.matrixToTransform &&
+ transform.name === 'matrix'
+ ) {
+ var decomposed = matrixToTransform(transform, params);
+ if (decomposed != transform &&
+ js2transform(decomposed, params).length <= js2transform([transform], params).length) {
+
+ transforms.splice.apply(transforms, [i, 1].concat(decomposed));
+ }
+ transform = transforms[i];
+ }
+
+ // fixed-point numbers
+ // 12.754997 → 12.755
+ roundTransform(transform);
+
+ // convert long translate transform notation to the shorts one
+ // translate(10 0) → translate(10)
+ if (
+ params.shortTranslate &&
+ transform.name === 'translate' &&
+ transform.data.length === 2 &&
+ !transform.data[1]
+ ) {
+ transform.data.pop();
+ }
+
+ // convert long scale transform notation to the shorts one
+ // scale(2 2) → scale(2)
+ if (
+ params.shortScale &&
+ transform.name === 'scale' &&
+ transform.data.length === 2 &&
+ transform.data[0] === transform.data[1]
+ ) {
+ transform.data.pop();
+ }
+
+ // convert long rotate transform notation to the short one
+ // translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy)
+ if (
+ params.shortRotate &&
+ transforms[i - 2] &&
+ transforms[i - 2].name === 'translate' &&
+ transforms[i - 1].name === 'rotate' &&
+ transforms[i].name === 'translate' &&
+ transforms[i - 2].data[0] === -transforms[i].data[0] &&
+ transforms[i - 2].data[1] === -transforms[i].data[1]
+ ) {
+ transforms.splice(i - 2, 3, {
+ name: 'rotate',
+ data: [
+ transforms[i - 1].data[0],
+ transforms[i - 2].data[0],
+ transforms[i - 2].data[1]
+ ]
+ });
+
+ // splice compensation
+ i -= 2;
+
+ transform = transforms[i];
+ }
+
+ }
+
+ return transforms;
+
+}
+
+/**
+ * Remove useless transforms.
+ *
+ * @param {Array} transforms input array
+ * @return {Array} output array
+ */
+function removeUseless(transforms) {
+
+ return transforms.filter(function(transform) {
+
+ // translate(0), rotate(0[, cx, cy]), skewX(0), skewY(0)
+ if (
+ ['translate', 'rotate', 'skewX', 'skewY'].indexOf(transform.name) > -1 &&
+ (transform.data.length == 1 || transform.name == 'rotate') &&
+ !transform.data[0] ||
+
+ // translate(0, 0)
+ transform.name == 'translate' &&
+ !transform.data[0] &&
+ !transform.data[1] ||
+
+ // scale(1)
+ transform.name == 'scale' &&
+ transform.data[0] == 1 &&
+ (transform.data.length < 2 || transform.data[1] == 1) ||
+
+ // matrix(1 0 0 1 0 0)
+ transform.name == 'matrix' &&
+ transform.data[0] == 1 &&
+ transform.data[3] == 1 &&
+ !(transform.data[1] || transform.data[2] || transform.data[4] || transform.data[5])
+ ) {
+ return false;
+ }
+
+ return true;
+
+ });
+
+}
+
+/**
+ * Convert transforms JS representation to string.
+ *
+ * @param {Array} transformJS JS representation array
+ * @param {Object} params plugin params
+ * @return {String} output string
+ */
+function js2transform(transformJS, params) {
+
+ var transformString = '';
+
+ // collect output value string
+ transformJS.forEach(function(transform) {
+ roundTransform(transform);
+ transformString += (transformString && ' ') + transform.name + '(' + cleanupOutData(transform.data, params) + ')';
+ });
+
+ return transformString;
+
+}
+
+function roundTransform(transform) {
+ switch (transform.name) {
+ case 'translate':
+ transform.data = floatRound(transform.data);
+ break;
+ case 'rotate':
+ transform.data = degRound(transform.data.slice(0, 1)).concat(floatRound(transform.data.slice(1)));
+ break;
+ case 'skewX':
+ case 'skewY':
+ transform.data = degRound(transform.data);
+ break;
+ case 'scale':
+ transform.data = transformRound(transform.data);
+ break;
+ case 'matrix':
+ transform.data = transformRound(transform.data.slice(0, 4)).concat(floatRound(transform.data.slice(4)));
+ break;
+ }
+ return transform;
+}
+
+/**
+ * Rounds numbers in array.
+ *
+ * @param {Array} data input data array
+ * @return {Array} output data array
+ */
+function round(data) {
+ return data.map(Math.round);
+}
+
+/**
+ * Decrease accuracy of floating-point numbers
+ * in transforms keeping a specified number of decimals.
+ * Smart rounds values like 2.349 to 2.35.
+ *
+ * @param {Number} fixed number of decimals
+ * @param {Array} data input data array
+ * @return {Array} output data array
+ */
+function smartRound(precision, data) {
+ for (var i = data.length, tolerance = +Math.pow(.1, precision).toFixed(precision); i--;) {
+ if (data[i].toFixed(precision) != data[i]) {
+ var rounded = +data[i].toFixed(precision - 1);
+ data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance ?
+ +data[i].toFixed(precision) :
+ rounded;
+ }
+ }
+ return data;
+}
diff --git a/node_modules/svgo/plugins/inlineStyles.js b/node_modules/svgo/plugins/inlineStyles.js
new file mode 100644
index 0000000..e4f65e0
--- /dev/null
+++ b/node_modules/svgo/plugins/inlineStyles.js
@@ -0,0 +1,245 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = true;
+
+exports.params = {
+ onlyMatchedOnce: true,
+ removeMatchedSelectors: true,
+ useMqs: ['', 'screen'],
+ usePseudos: ['']
+};
+
+exports.description = 'inline styles (additional options)';
+
+
+var csstree = require('css-tree'),
+ cssTools = require('../lib/css-tools');
+
+/**
+ * Moves + merges styles from style elements to element styles
+ *
+ * Options
+ * onlyMatchedOnce (default: true)
+ * inline only selectors that match once
+ *
+ * removeMatchedSelectors (default: true)
+ * clean up matched selectors,
+ * leave selectors that hadn't matched
+ *
+ * useMqs (default: ['', 'screen'])
+ * what media queries to be used
+ * empty string element for styles outside media queries
+ *
+ * usePseudos (default: [''])
+ * what pseudo-classes/-elements to be used
+ * empty string element for all non-pseudo-classes and/or -elements
+ *
+ * @param {Object} document document element
+ * @param {Object} opts plugin params
+ *
+ * @author strarsis <strarsis@gmail.com>
+ */
+exports.fn = function(document, opts) {
+
+ // collect <style/>s
+ var styleEls = document.querySelectorAll('style');
+
+ //no <styles/>s, nothing to do
+ if (styleEls === null) {
+ return document;
+ }
+
+ var styles = [],
+ selectors = [];
+
+ for (var styleEl of styleEls) {
+ if (styleEl.isEmpty() || styleEl.closestElem('foreignObject')) {
+ // skip empty <style/>s or <foreignObject> content.
+ continue;
+ }
+
+ var cssStr = cssTools.getCssStr(styleEl);
+
+ // collect <style/>s and their css ast
+ var cssAst = {};
+ try {
+ cssAst = csstree.parse(cssStr, {
+ parseValue: false,
+ parseCustomProperty: false
+ });
+ } catch (parseError) {
+ // console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError);
+ continue;
+ }
+
+ styles.push({
+ styleEl: styleEl,
+ cssAst: cssAst
+ });
+
+ selectors = selectors.concat(cssTools.flattenToSelectors(cssAst));
+ }
+
+
+ // filter for mediaqueries to be used or without any mediaquery
+ var selectorsMq = cssTools.filterByMqs(selectors, opts.useMqs);
+
+
+ // filter for pseudo elements to be used
+ var selectorsPseudo = cssTools.filterByPseudos(selectorsMq, opts.usePseudos);
+
+ // remove PseudoClass from its SimpleSelector for proper matching
+ cssTools.cleanPseudos(selectorsPseudo);
+
+
+ // stable sort selectors
+ var sortedSelectors = cssTools.sortSelectors(selectorsPseudo).reverse();
+
+
+ var selector,
+ selectedEl;
+
+ // match selectors
+ for (selector of sortedSelectors) {
+ var selectorStr = csstree.generate(selector.item.data),
+ selectedEls = null;
+
+ try {
+ selectedEls = document.querySelectorAll(selectorStr);
+ } catch (selectError) {
+ if (selectError.constructor === SyntaxError) {
+ // console.warn('Warning: Syntax error when trying to select \n\n' + selectorStr + '\n\n, skipped. Error details: ' + selectError);
+ continue;
+ }
+ throw selectError;
+ }
+
+ if (selectedEls === null) {
+ // nothing selected
+ continue;
+ }
+
+ selector.selectedEls = selectedEls;
+ }
+
+
+ // apply <style/> styles to matched elements
+ for (selector of sortedSelectors) {
+ if(!selector.selectedEls) {
+ continue;
+ }
+
+ if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) {
+ // skip selectors that match more than once if option onlyMatchedOnce is enabled
+ continue;
+ }
+
+ // apply <style/> to matched elements
+ for (selectedEl of selector.selectedEls) {
+ if (selector.rule === null) {
+ continue;
+ }
+
+ // merge declarations
+ csstree.walk(selector.rule, {visit: 'Declaration', enter: function(styleCsstreeDeclaration) {
+
+ // existing inline styles have higher priority
+ // no inline styles, external styles, external styles used
+ // inline styles, external styles same priority as inline styles, inline styles used
+ // inline styles, external styles higher priority than inline styles, external styles used
+ var styleDeclaration = cssTools.csstreeToStyleDeclaration(styleCsstreeDeclaration);
+ if (selectedEl.style.getPropertyValue(styleDeclaration.name) !== null &&
+ selectedEl.style.getPropertyPriority(styleDeclaration.name) >= styleDeclaration.priority) {
+ return;
+ }
+ selectedEl.style.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority);
+ }});
+ }
+
+ if (opts.removeMatchedSelectors && selector.selectedEls !== null && selector.selectedEls.length > 0) {
+ // clean up matching simple selectors if option removeMatchedSelectors is enabled
+ selector.rule.prelude.children.remove(selector.item);
+ }
+ }
+
+
+ if (!opts.removeMatchedSelectors) {
+ return document; // no further processing required
+ }
+
+
+ // clean up matched class + ID attribute values
+ for (selector of sortedSelectors) {
+ if(!selector.selectedEls) {
+ continue;
+ }
+
+ if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) {
+ // skip selectors that match more than once if option onlyMatchedOnce is enabled
+ continue;
+ }
+
+ for (selectedEl of selector.selectedEls) {
+ // class
+ var firstSubSelector = selector.item.data.children.first();
+ if(firstSubSelector.type === 'ClassSelector') {
+ selectedEl.class.remove(firstSubSelector.name);
+ }
+ // clean up now empty class attributes
+ if(typeof selectedEl.class.item(0) === 'undefined') {
+ selectedEl.removeAttr('class');
+ }
+
+ // ID
+ if(firstSubSelector.type === 'IdSelector') {
+ selectedEl.removeAttr('id', firstSubSelector.name);
+ }
+ }
+ }
+
+
+ // clean up now empty elements
+ for (var style of styles) {
+ csstree.walk(style.cssAst, {visit: 'Rule', enter: function(node, item, list) {
+ // clean up <style/> atrules without any rulesets left
+ if (node.type === 'Atrule' &&
+ // only Atrules containing rulesets
+ node.block !== null &&
+ node.block.children.isEmpty()) {
+ list.remove(item);
+ return;
+ }
+
+ // clean up <style/> rulesets without any css selectors left
+ if (node.type === 'Rule' &&
+ node.prelude.children.isEmpty()) {
+ list.remove(item);
+ }
+ }});
+
+
+ if (style.cssAst.children.isEmpty()) {
+ // clean up now emtpy <style/>s
+ var styleParentEl = style.styleEl.parentNode;
+ styleParentEl.spliceContent(styleParentEl.content.indexOf(style.styleEl), 1);
+
+ if (styleParentEl.elem === 'defs' &&
+ styleParentEl.content.length === 0) {
+ // also clean up now empty <def/>s
+ var defsParentEl = styleParentEl.parentNode;
+ defsParentEl.spliceContent(defsParentEl.content.indexOf(styleParentEl), 1);
+ }
+
+ continue;
+ }
+
+
+ // update existing, left over <style>s
+ cssTools.setCssStr(style.styleEl, csstree.generate(style.cssAst));
+ }
+
+
+ return document;
+};
diff --git a/node_modules/svgo/plugins/mergePaths.js b/node_modules/svgo/plugins/mergePaths.js
new file mode 100644
index 0000000..6a18996
--- /dev/null
+++ b/node_modules/svgo/plugins/mergePaths.js
@@ -0,0 +1,73 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'merges multiple paths in one if possible';
+
+exports.params = {
+ collapseRepeated: true,
+ force: false,
+ leadingZero: true,
+ negativeExtraSpace: true,
+ noSpaceAfterFlags: true
+};
+
+var path2js = require('./_path.js').path2js,
+ js2path = require('./_path.js').js2path,
+ intersects = require('./_path.js').intersects;
+
+/**
+ * Merge multiple Paths into one.
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich, Lev Solntsev
+ */
+exports.fn = function(item, params) {
+
+ if (!item.isElem() || item.isEmpty()) return;
+
+ var prevContentItem = null,
+ prevContentItemKeys = null;
+
+ item.content = item.content.filter(function(contentItem) {
+
+ if (prevContentItem &&
+ prevContentItem.isElem('path') &&
+ prevContentItem.isEmpty() &&
+ prevContentItem.hasAttr('d') &&
+ contentItem.isElem('path') &&
+ contentItem.isEmpty() &&
+ contentItem.hasAttr('d')
+ ) {
+
+ if (!prevContentItemKeys) {
+ prevContentItemKeys = Object.keys(prevContentItem.attrs);
+ }
+
+ var contentItemAttrs = Object.keys(contentItem.attrs),
+ equalData = prevContentItemKeys.length == contentItemAttrs.length &&
+ contentItemAttrs.every(function(key) {
+ return key == 'd' ||
+ prevContentItem.hasAttr(key) &&
+ prevContentItem.attr(key).value == contentItem.attr(key).value;
+ }),
+ prevPathJS = path2js(prevContentItem),
+ curPathJS = path2js(contentItem);
+
+ if (equalData && (params.force || !intersects(prevPathJS, curPathJS))) {
+ js2path(prevContentItem, prevPathJS.concat(curPathJS), params);
+ return false;
+ }
+ }
+
+ prevContentItem = contentItem;
+ prevContentItemKeys = null;
+ return true;
+
+ });
+
+};
diff --git a/node_modules/svgo/plugins/minifyStyles.js b/node_modules/svgo/plugins/minifyStyles.js
new file mode 100644
index 0000000..d240900
--- /dev/null
+++ b/node_modules/svgo/plugins/minifyStyles.js
@@ -0,0 +1,160 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = true;
+
+exports.description = 'minifies styles and removes unused styles based on usage data';
+
+exports.params = {
+ // ... CSSO options goes here
+
+ // additional
+ usage: {
+ force: false, // force to use usage data even if it unsafe (document contains <script> or on* attributes)
+ ids: true,
+ classes: true,
+ tags: true
+ }
+};
+
+var csso = require('csso');
+
+/**
+ * Minifies styles (<style> element + style attribute) using CSSO
+ *
+ * @author strarsis <strarsis@gmail.com>
+ */
+exports.fn = function(ast, options) {
+ options = options || {};
+
+ var minifyOptionsForStylesheet = cloneObject(options);
+ var minifyOptionsForAttribute = cloneObject(options);
+ var elems = findStyleElems(ast);
+
+ minifyOptionsForStylesheet.usage = collectUsageData(ast, options);
+ minifyOptionsForAttribute.usage = null;
+
+ elems.forEach(function(elem) {
+ if (elem.isElem('style')) {
+ // <style> element
+ var styleCss = elem.content[0].text || elem.content[0].cdata || [];
+ var DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text';
+
+ elem.content[0][DATA] = csso.minify(styleCss, minifyOptionsForStylesheet).css;
+ } else {
+ // style attribute
+ var elemStyle = elem.attr('style').value;
+
+ elem.attr('style').value = csso.minifyBlock(elemStyle, minifyOptionsForAttribute).css;
+ }
+ });
+
+ return ast;
+};
+
+function cloneObject(obj) {
+ var result = {};
+
+ for (var key in obj) {
+ result[key] = obj[key];
+ }
+
+ return result;
+}
+
+function findStyleElems(ast) {
+
+ function walk(items, styles) {
+ for (var i = 0; i < items.content.length; i++) {
+ var item = items.content[i];
+
+ // go deeper
+ if (item.content) {
+ walk(item, styles);
+ }
+
+ if (item.isElem('style') && !item.isEmpty()) {
+ styles.push(item);
+ } else if (item.isElem() && item.hasAttr('style')) {
+ styles.push(item);
+ }
+ }
+
+ return styles;
+ }
+
+ return walk(ast, []);
+}
+
+function shouldFilter(options, name) {
+ if ('usage' in options === false) {
+ return true;
+ }
+
+ if (options.usage && name in options.usage === false) {
+ return true;
+ }
+
+ return Boolean(options.usage && options.usage[name]);
+}
+
+function collectUsageData(ast, options) {
+
+ function walk(items, usageData) {
+ for (var i = 0; i < items.content.length; i++) {
+ var item = items.content[i];
+
+ // go deeper
+ if (item.content) {
+ walk(item, usageData);
+ }
+
+ if (item.isElem('script')) {
+ safe = false;
+ }
+
+ if (item.isElem()) {
+ usageData.tags[item.elem] = true;
+
+ if (item.hasAttr('id')) {
+ usageData.ids[item.attr('id').value] = true;
+ }
+
+ if (item.hasAttr('class')) {
+ item.attr('class').value.replace(/^\s+|\s+$/g, '').split(/\s+/).forEach(function(className) {
+ usageData.classes[className] = true;
+ });
+ }
+
+ if (item.attrs && Object.keys(item.attrs).some(function(name) { return /^on/i.test(name); })) {
+ safe = false;
+ }
+ }
+ }
+
+ return usageData;
+ }
+
+ var safe = true;
+ var usageData = {};
+ var hasData = false;
+ var rawData = walk(ast, {
+ ids: Object.create(null),
+ classes: Object.create(null),
+ tags: Object.create(null)
+ });
+
+ if (!safe && options.usage && options.usage.force) {
+ safe = true;
+ }
+
+ for (var key in rawData) {
+ if (shouldFilter(options, key)) {
+ usageData[key] = Object.keys(rawData[key]);
+ hasData = true;
+ }
+ }
+
+ return safe && hasData ? usageData : null;
+}
diff --git a/node_modules/svgo/plugins/moveElemsAttrsToGroup.js b/node_modules/svgo/plugins/moveElemsAttrsToGroup.js
new file mode 100644
index 0000000..0f3b65c
--- /dev/null
+++ b/node_modules/svgo/plugins/moveElemsAttrsToGroup.js
@@ -0,0 +1,126 @@
+'use strict';
+
+exports.type = 'perItemReverse';
+
+exports.active = true;
+
+exports.description = 'moves elements attributes to the existing group wrapper';
+
+var inheritableAttrs = require('./_collections').inheritableAttrs,
+ pathElems = require('./_collections.js').pathElems;
+
+/**
+ * Collapse content's intersected and inheritable
+ * attributes to the existing group wrapper.
+ *
+ * @example
+ * <g attr1="val1">
+ * <g attr2="val2">
+ * text
+ * </g>
+ * <circle attr2="val2" attr3="val3"/>
+ * </g>
+ * ⬇
+ * <g attr1="val1" attr2="val2">
+ * <g>
+ * text
+ * </g>
+ * <circle attr3="val3"/>
+ * </g>
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('g') && !item.isEmpty() && item.content.length > 1) {
+
+ var intersection = {},
+ hasTransform = false,
+ hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'),
+ intersected = item.content.every(function(inner) {
+ if (inner.isElem() && inner.hasAttr()) {
+ // don't mess with possible styles (hack until CSS parsing is implemented)
+ if (inner.hasAttr('class')) return false;
+ if (!Object.keys(intersection).length) {
+ intersection = inner.attrs;
+ } else {
+ intersection = intersectInheritableAttrs(intersection, inner.attrs);
+
+ if (!intersection) return false;
+ }
+
+ return true;
+ }
+ }),
+ allPath = item.content.every(function(inner) {
+ return inner.isElem(pathElems);
+ });
+
+ if (intersected) {
+
+ item.content.forEach(function(g) {
+
+ for (var name in intersection) {
+
+ if (!allPath && !hasClip || name !== 'transform') {
+
+ g.removeAttr(name);
+
+ if (name === 'transform') {
+ if (!hasTransform) {
+ if (item.hasAttr('transform')) {
+ item.attr('transform').value += ' ' + intersection[name].value;
+ } else {
+ item.addAttr(intersection[name]);
+ }
+
+ hasTransform = true;
+ }
+ } else {
+ item.addAttr(intersection[name]);
+ }
+
+ }
+ }
+
+ });
+
+ }
+
+ }
+
+};
+
+/**
+ * Intersect inheritable attributes.
+ *
+ * @param {Object} a first attrs object
+ * @param {Object} b second attrs object
+ *
+ * @return {Object} intersected attrs object
+ */
+function intersectInheritableAttrs(a, b) {
+
+ var c = {};
+
+ for (var n in a) {
+ if (
+ b.hasOwnProperty(n) &&
+ inheritableAttrs.indexOf(n) > -1 &&
+ a[n].name === b[n].name &&
+ a[n].value === b[n].value &&
+ a[n].prefix === b[n].prefix &&
+ a[n].local === b[n].local
+ ) {
+ c[n] = a[n];
+ }
+ }
+
+ if (!Object.keys(c).length) return false;
+
+ return c;
+
+}
diff --git a/node_modules/svgo/plugins/moveGroupAttrsToElems.js b/node_modules/svgo/plugins/moveGroupAttrsToElems.js
new file mode 100644
index 0000000..a966f88
--- /dev/null
+++ b/node_modules/svgo/plugins/moveGroupAttrsToElems.js
@@ -0,0 +1,63 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'moves some group attributes to the content elements';
+
+var collections = require('./_collections.js'),
+ pathElems = collections.pathElems.concat(['g', 'text']),
+ referencesProps = collections.referencesProps;
+
+/**
+ * Move group attrs to the content elements.
+ *
+ * @example
+ * <g transform="scale(2)">
+ * <path transform="rotate(45)" d="M0,0 L10,20"/>
+ * <path transform="translate(10, 20)" d="M0,10 L20,30"/>
+ * </g>
+ * ⬇
+ * <g>
+ * <path transform="scale(2) rotate(45)" d="M0,0 L10,20"/>
+ * <path transform="scale(2) translate(10, 20)" d="M0,10 L20,30"/>
+ * </g>
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ // move group transform attr to content's pathElems
+ if (
+ item.isElem('g') &&
+ item.hasAttr('transform') &&
+ !item.isEmpty() &&
+ !item.someAttr(function(attr) {
+ return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
+ }) &&
+ item.content.every(function(inner) {
+ return inner.isElem(pathElems) && !inner.hasAttr('id');
+ })
+ ) {
+ item.content.forEach(function(inner) {
+ var attr = item.attr('transform');
+ if (inner.hasAttr('transform')) {
+ inner.attr('transform').value = attr.value + ' ' + inner.attr('transform').value;
+ } else {
+ inner.addAttr({
+ 'name': attr.name,
+ 'local': attr.local,
+ 'prefix': attr.prefix,
+ 'value': attr.value
+ });
+ }
+ });
+
+ item.removeAttr('transform');
+ }
+
+};
diff --git a/node_modules/svgo/plugins/prefixIds.js b/node_modules/svgo/plugins/prefixIds.js
new file mode 100644
index 0000000..2222e7e
--- /dev/null
+++ b/node_modules/svgo/plugins/prefixIds.js
@@ -0,0 +1,243 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.params = {
+ delim: '__',
+ prefixIds: true,
+ prefixClassNames: true,
+};
+
+exports.description = 'prefix IDs';
+
+
+var path = require('path'),
+ csstree = require('css-tree'),
+ unquote = require('unquote'),
+ collections = require('./_collections.js'),
+ referencesProps = collections.referencesProps,
+ rxId = /^#(.*)$/, // regular expression for matching an ID + extracing its name
+ addPrefix = null;
+
+
+// Escapes a string for being used as ID
+var escapeIdentifierName = function(str) {
+ return str.replace(/[\. ]/g, '_');
+};
+
+// Matches an #ID value, captures the ID name
+var matchId = function(urlVal) {
+ var idUrlMatches = urlVal.match(rxId);
+ if (idUrlMatches === null) {
+ return false;
+ }
+ return idUrlMatches[1];
+};
+
+// Matches an url(...) value, captures the URL
+var matchUrl = function(val) {
+ var urlMatches = /url\((.*?)\)/gi.exec(val);
+ if (urlMatches === null) {
+ return false;
+ }
+ return urlMatches[1];
+};
+
+// Checks if attribute is empty
+var attrNotEmpty = function(attr) {
+ return (attr && attr.value && attr.value.length > 0);
+};
+
+// prefixes an #ID
+var prefixId = function(val) {
+ var idName = matchId(val);
+ if (!idName) {
+ return false;
+ }
+ return '#' + addPrefix(idName);
+};
+
+
+// attr.value helper methods
+
+// prefixes a class attribute value
+var addPrefixToClassAttr = function(attr) {
+ if (!attrNotEmpty(attr)) {
+ return;
+ }
+
+ attr.value = attr.value.split(/\s+/).map(addPrefix).join(' ');
+};
+
+// prefixes an ID attribute value
+var addPrefixToIdAttr = function(attr) {
+ if (!attrNotEmpty(attr)) {
+ return;
+ }
+
+ attr.value = addPrefix(attr.value);
+};
+
+// prefixes a href attribute value
+var addPrefixToHrefAttr = function(attr) {
+ if (!attrNotEmpty(attr)) {
+ return;
+ }
+
+ var idPrefixed = prefixId(attr.value);
+ if (!idPrefixed) {
+ return;
+ }
+ attr.value = idPrefixed;
+};
+
+// prefixes an URL attribute value
+var addPrefixToUrlAttr = function(attr) {
+ if (!attrNotEmpty(attr)) {
+ return;
+ }
+
+ // url(...) in value
+ var urlVal = matchUrl(attr.value);
+ if (!urlVal) {
+ return;
+ }
+
+ var idPrefixed = prefixId(urlVal);
+ if (!idPrefixed) {
+ return;
+ }
+
+ attr.value = 'url(' + idPrefixed + ')';
+};
+
+
+/**
+ * Prefixes identifiers
+ *
+ * @param {Object} node node
+ * @param {Object} opts plugin params
+ * @param {Object} extra plugin extra information
+ *
+ * @author strarsis <strarsis@gmail.com>
+ */
+exports.fn = function(node, opts, extra) {
+
+ // skip subsequent passes when multipass is used
+ if(extra.multipassCount && extra.multipassCount > 0) {
+ return node;
+ }
+
+ // prefix, from file name or option
+ var prefix = 'prefix';
+ if (opts.prefix) {
+ if (typeof opts.prefix === 'function') {
+ prefix = opts.prefix(node, extra);
+ } else {
+ prefix = opts.prefix;
+ }
+ } else if (opts.prefix === false) {
+ prefix = false;
+ } else if (extra && extra.path && extra.path.length > 0) {
+ var filename = path.basename(extra.path);
+ prefix = filename;
+ }
+
+
+ // prefixes a normal value
+ addPrefix = function(name) {
+ if(prefix === false){
+ return escapeIdentifierName(name);
+ }
+ return escapeIdentifierName(prefix + opts.delim + name);
+ };
+
+
+ // <style/> property values
+
+ if (node.elem === 'style') {
+ if (node.isEmpty()) {
+ // skip empty <style/>s
+ return node;
+ }
+
+ var cssStr = node.content[0].text || node.content[0].cdata || [];
+
+ var cssAst = {};
+ try {
+ cssAst = csstree.parse(cssStr, {
+ parseValue: true,
+ parseCustomProperty: false
+ });
+ } catch (parseError) {
+ console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError);
+ return node;
+ }
+
+ var idPrefixed = '';
+ csstree.walk(cssAst, function(node) {
+
+ // #ID, .class
+ if (((opts.prefixIds && node.type === 'IdSelector') ||
+ (opts.prefixClassNames && node.type === 'ClassSelector')) &&
+ node.name) {
+ node.name = addPrefix(node.name);
+ return;
+ }
+
+ // url(...) in value
+ if (node.type === 'Url' &&
+ node.value.value && node.value.value.length > 0) {
+ idPrefixed = prefixId(unquote(node.value.value));
+ if (!idPrefixed) {
+ return;
+ }
+ node.value.value = idPrefixed;
+ }
+
+ });
+
+ // update <style>s
+ node.content[0].text = csstree.generate(cssAst);
+ return node;
+ }
+
+
+ // element attributes
+
+ if (!node.attrs) {
+ return node;
+ }
+
+
+ // Nodes
+
+ if(opts.prefixIds) {
+ // ID
+ addPrefixToIdAttr(node.attrs.id);
+ }
+
+ if(opts.prefixClassNames) {
+ // Class
+ addPrefixToClassAttr(node.attrs.class);
+ }
+
+
+ // References
+
+ // href
+ addPrefixToHrefAttr(node.attrs.href);
+
+ // (xlink:)href (deprecated, must be still supported)
+ addPrefixToHrefAttr(node.attrs['xlink:href']);
+
+ // (referenceable) properties
+ for (var referencesProp of referencesProps) {
+ addPrefixToUrlAttr(node.attrs[referencesProp]);
+ }
+
+
+ return node;
+};
diff --git a/node_modules/svgo/plugins/removeAttributesBySelector.js b/node_modules/svgo/plugins/removeAttributesBySelector.js
new file mode 100644
index 0000000..3ae7463
--- /dev/null
+++ b/node_modules/svgo/plugins/removeAttributesBySelector.js
@@ -0,0 +1,70 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes attributes of elements that match a css selector';
+
+
+/**
+ * Removes attributes of elements that match a css selector.
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @example
+ * <caption>A selector removing a single attribute</caption>
+ * plugins:
+ * - removeAttributesBySelector:
+ * selector: "[fill='#00ff00']"
+ * attributes: "fill"
+ *
+ * <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
+ * ↓
+ * <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/>
+ *
+ * <caption>A selector removing multiple attributes</caption>
+ * plugins:
+ * - removeAttributesBySelector:
+ * selector: "[fill='#00ff00']"
+ * attributes:
+ * - fill
+ * - stroke
+ *
+ * <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
+ * ↓
+ * <rect x="0" y="0" width="100" height="100"/>
+ *
+ * <caption>Multiple selectors removing attributes</caption>
+ * plugins:
+ * - removeAttributesBySelector:
+ * selectors:
+ * - selector: "[fill='#00ff00']"
+ * attributes: "fill"
+ *
+ * - selector: "#remove"
+ * attributes:
+ * - stroke
+ * - id
+ *
+ * <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
+ * ↓
+ * <rect x="0" y="0" width="100" height="100"/>
+ *
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|MDN CSS Selectors}
+ *
+ * @author Bradley Mease
+ */
+exports.fn = function(item, params) {
+
+ var selectors = Array.isArray(params.selectors) ? params.selectors : [params];
+
+ selectors.map(function(i) {
+ if (item.matches(i.selector)) {
+ item.removeAttr(i.attributes);
+ }
+ });
+
+};
diff --git a/node_modules/svgo/plugins/removeAttrs.js b/node_modules/svgo/plugins/removeAttrs.js
new file mode 100644
index 0000000..491e0dc
--- /dev/null
+++ b/node_modules/svgo/plugins/removeAttrs.js
@@ -0,0 +1,150 @@
+'use strict';
+
+var DEFAULT_SEPARATOR = ':';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes specified attributes';
+
+exports.params = {
+ elemSeparator: DEFAULT_SEPARATOR,
+ preserveCurrentColor: false,
+ attrs: []
+};
+
+/**
+ * Remove attributes
+ *
+ * @param elemSeparator
+ * format: string
+ *
+ * @param preserveCurrentColor
+ * format: boolean
+ *
+ * @param attrs:
+ *
+ * format: [ element* : attribute* : value* ]
+ *
+ * element : regexp (wrapped into ^...$), single * or omitted > all elements (must be present when value is used)
+ * attribute : regexp (wrapped into ^...$)
+ * value : regexp (wrapped into ^...$), single * or omitted > all values
+ *
+ * examples:
+ *
+ * > basic: remove fill attribute
+ * ---
+ * removeAttrs:
+ * attrs: 'fill'
+ *
+ * > remove fill attribute on path element
+ * ---
+ * attrs: 'path:fill'
+ *
+ * > remove fill attribute on path element where value is none
+ * ---
+ * attrs: 'path:fill:none'
+ *
+ *
+ * > remove all fill and stroke attribute
+ * ---
+ * attrs:
+ * - 'fill'
+ * - 'stroke'
+ *
+ * [is same as]
+ *
+ * attrs: '(fill|stroke)'
+ *
+ * [is same as]
+ *
+ * attrs: '*:(fill|stroke)'
+ *
+ * [is same as]
+ *
+ * attrs: '.*:(fill|stroke)'
+ *
+ * [is same as]
+ *
+ * attrs: '.*:(fill|stroke):.*'
+ *
+ *
+ * > remove all stroke related attributes
+ * ----
+ * attrs: 'stroke.*'
+ *
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Benny Schudel
+ */
+exports.fn = function(item, params) {
+ // wrap into an array if params is not
+ if (!Array.isArray(params.attrs)) {
+ params.attrs = [params.attrs];
+ }
+
+ if (item.isElem()) {
+ var elemSeparator = typeof params.elemSeparator == 'string' ? params.elemSeparator : DEFAULT_SEPARATOR;
+ var preserveCurrentColor = typeof params.preserveCurrentColor == 'boolean' ? params.preserveCurrentColor : false;
+
+ // prepare patterns
+ var patterns = params.attrs.map(function(pattern) {
+
+ // if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value*
+ if (pattern.indexOf(elemSeparator) === -1) {
+ pattern = ['.*', elemSeparator, pattern, elemSeparator, '.*'].join('');
+
+ // if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
+ } else if (pattern.split(elemSeparator).length < 3) {
+ pattern = [pattern, elemSeparator, '.*'].join('');
+ }
+
+ // create regexps for element, attribute name, and attribute value
+ return pattern.split(elemSeparator)
+ .map(function(value) {
+
+ // adjust single * to match anything
+ if (value === '*') { value = '.*'; }
+
+ return new RegExp(['^', value, '$'].join(''), 'i');
+ });
+
+ });
+
+ // loop patterns
+ patterns.forEach(function(pattern) {
+
+ // matches element
+ if (pattern[0].test(item.elem)) {
+
+ // loop attributes
+ item.eachAttr(function(attr) {
+ var name = attr.name;
+ var value = attr.value;
+ var isFillCurrentColor = preserveCurrentColor && name == 'fill' && value == 'currentColor';
+ var isStrokeCurrentColor = preserveCurrentColor && name == 'stroke' && value == 'currentColor';
+
+ if (!(isFillCurrentColor || isStrokeCurrentColor)) {
+ // matches attribute name
+ if (pattern[1].test(name)) {
+
+ // matches attribute value
+ if (pattern[2].test(attr.value)) {
+ item.removeAttr(name);
+ }
+ }
+ }
+
+ });
+
+ }
+
+ });
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeComments.js b/node_modules/svgo/plugins/removeComments.js
new file mode 100644
index 0000000..8bfd21b
--- /dev/null
+++ b/node_modules/svgo/plugins/removeComments.js
@@ -0,0 +1,27 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes comments';
+
+/**
+ * Remove comments.
+ *
+ * @example
+ * <!-- Generator: Adobe Illustrator 15.0.0, SVG Export
+ * Plug-In . SVG Version: 6.00 Build 0) -->
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (item.comment && item.comment.charAt(0) !== '!') {
+ return false;
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeDesc.js b/node_modules/svgo/plugins/removeDesc.js
new file mode 100644
index 0000000..76e6959
--- /dev/null
+++ b/node_modules/svgo/plugins/removeDesc.js
@@ -0,0 +1,32 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.params = {
+ removeAny: true
+};
+
+exports.description = 'removes <desc>';
+
+var standardDescs = /^(Created with|Created using)/;
+
+/**
+ * Removes <desc>.
+ * Removes only standard editors content or empty elements 'cause it can be used for accessibility.
+ * Enable parameter 'removeAny' to remove any description.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Daniel Wabyick
+ */
+exports.fn = function(item, params) {
+
+ return !item.isElem('desc') || !(params.removeAny || item.isEmpty() ||
+ standardDescs.test(item.content[0].text));
+
+};
diff --git a/node_modules/svgo/plugins/removeDimensions.js b/node_modules/svgo/plugins/removeDimensions.js
new file mode 100644
index 0000000..7cbd65c
--- /dev/null
+++ b/node_modules/svgo/plugins/removeDimensions.js
@@ -0,0 +1,49 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes width and height in presence of viewBox (opposite to removeViewBox, disable it first)';
+
+/**
+ * Remove width/height attributes and add the viewBox attribute if it's missing
+ *
+ * @example
+ * <svg width="100" height="50" />
+ * ↓
+ * <svg viewBox="0 0 100 50" />
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if true, with and height will be filtered out
+ *
+ * @author Benny Schudel
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('svg')) {
+ if (item.hasAttr('viewBox')) {
+ item.removeAttr('width');
+ item.removeAttr('height');
+ } else if (
+ item.hasAttr('width') &&
+ item.hasAttr('height') &&
+ !isNaN(Number(item.attr('width').value)) &&
+ !isNaN(Number(item.attr('height').value))
+ ) {
+ item.addAttr({
+ name: 'viewBox',
+ value:
+ '0 0 ' +
+ Number(item.attr('width').value) +
+ ' ' +
+ Number(item.attr('height').value),
+ prefix: '',
+ local: 'viewBox'
+ });
+ item.removeAttr('width');
+ item.removeAttr('height');
+ }
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeDoctype.js b/node_modules/svgo/plugins/removeDoctype.js
new file mode 100644
index 0000000..32ee4f4
--- /dev/null
+++ b/node_modules/svgo/plugins/removeDoctype.js
@@ -0,0 +1,40 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes doctype declaration';
+
+/**
+ * Remove DOCTYPE declaration.
+ *
+ * "Unfortunately the SVG DTDs are a source of so many
+ * issues that the SVG WG has decided not to write one
+ * for the upcoming SVG 1.2 standard. In fact SVG WG
+ * members are even telling people not to use a DOCTYPE
+ * declaration in SVG 1.0 and 1.1 documents"
+ * https://jwatt.org/svg/authoring/#doctype-declaration
+ *
+ * @example
+ * <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ * q"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+ *
+ * @example
+ * <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ * "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [
+ * <!-- an internal subset can be embedded here -->
+ * ]>
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (item.doctype) {
+ return false;
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeEditorsNSData.js b/node_modules/svgo/plugins/removeEditorsNSData.js
new file mode 100644
index 0000000..9e5c8cd
--- /dev/null
+++ b/node_modules/svgo/plugins/removeEditorsNSData.js
@@ -0,0 +1,65 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes editors namespaces, elements and attributes';
+
+var editorNamespaces = require('./_collections').editorNamespaces,
+ prefixes = [];
+
+exports.params = {
+ additionalNamespaces: []
+};
+
+/**
+ * Remove editors namespaces, elements and attributes.
+ *
+ * @example
+ * <svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd">
+ * <sodipodi:namedview/>
+ * <path sodipodi:nodetypes="cccc"/>
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (Array.isArray(params.additionalNamespaces)) {
+ editorNamespaces = editorNamespaces.concat(params.additionalNamespaces);
+ }
+
+ if (item.elem) {
+
+ if (item.isElem('svg')) {
+
+ item.eachAttr(function(attr) {
+ if (attr.prefix === 'xmlns' && editorNamespaces.indexOf(attr.value) > -1) {
+ prefixes.push(attr.local);
+
+ // <svg xmlns:sodipodi="">
+ item.removeAttr(attr.name);
+ }
+ });
+
+ }
+
+ // <* sodipodi:*="">
+ item.eachAttr(function(attr) {
+ if (prefixes.indexOf(attr.prefix) > -1) {
+ item.removeAttr(attr.name);
+ }
+ });
+
+ // <sodipodi:*>
+ if (prefixes.indexOf(item.prefix) > -1) {
+ return false;
+ }
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeElementsByAttr.js b/node_modules/svgo/plugins/removeElementsByAttr.js
new file mode 100644
index 0000000..c726f70
--- /dev/null
+++ b/node_modules/svgo/plugins/removeElementsByAttr.js
@@ -0,0 +1,80 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes arbitrary elements by ID or className (disabled by default)';
+
+exports.params = {
+ id: [],
+ class: []
+};
+
+/**
+ * Remove arbitrary SVG elements by ID or className.
+ *
+ * @param id
+ * examples:
+ *
+ * > single: remove element with ID of `elementID`
+ * ---
+ * removeElementsByAttr:
+ * id: 'elementID'
+ *
+ * > list: remove multiple elements by ID
+ * ---
+ * removeElementsByAttr:
+ * id:
+ * - 'elementID'
+ * - 'anotherID'
+ *
+ * @param class
+ * examples:
+ *
+ * > single: remove all elements with class of `elementClass`
+ * ---
+ * removeElementsByAttr:
+ * class: 'elementClass'
+ *
+ * > list: remove all elements with class of `elementClass` or `anotherClass`
+ * ---
+ * removeElementsByAttr:
+ * class:
+ * - 'elementClass'
+ * - 'anotherClass'
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Eli Dupuis (@elidupuis)
+ */
+exports.fn = function(item, params) {
+ var elemId, elemClass;
+
+ // wrap params in an array if not already
+ ['id', 'class'].forEach(function(key) {
+ if (!Array.isArray(params[key])) {
+ params[key] = [ params[key] ];
+ }
+ });
+
+ // abort if current item is no an element
+ if (!item.isElem()) {
+ return;
+ }
+
+ // remove element if it's `id` matches configured `id` params
+ elemId = item.attr('id');
+ if (elemId) {
+ return params.id.indexOf(elemId.value) === -1;
+ }
+
+ // remove element if it's `class` contains any of the configured `class` params
+ elemClass = item.attr('class');
+ if (elemClass) {
+ var hasClassRegex = new RegExp(params.class.join('|'));
+ return !hasClassRegex.test(elemClass.value);
+ }
+};
diff --git a/node_modules/svgo/plugins/removeEmptyAttrs.js b/node_modules/svgo/plugins/removeEmptyAttrs.js
new file mode 100644
index 0000000..ae73e6c
--- /dev/null
+++ b/node_modules/svgo/plugins/removeEmptyAttrs.js
@@ -0,0 +1,29 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes empty attributes';
+
+/**
+ * Remove attributes with empty values.
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (item.elem) {
+
+ item.eachAttr(function(attr) {
+ if (attr.value === '') {
+ item.removeAttr(attr.name);
+ }
+ });
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeEmptyContainers.js b/node_modules/svgo/plugins/removeEmptyContainers.js
new file mode 100644
index 0000000..356a583
--- /dev/null
+++ b/node_modules/svgo/plugins/removeEmptyContainers.js
@@ -0,0 +1,32 @@
+'use strict';
+
+exports.type = 'perItemReverse';
+
+exports.active = true;
+
+exports.description = 'removes empty container elements';
+
+var container = require('./_collections').elemsGroups.container;
+
+/**
+ * Remove empty containers.
+ *
+ * @see http://www.w3.org/TR/SVG/intro.html#TermContainerElement
+ *
+ * @example
+ * <defs/>
+ *
+ * @example
+ * <g><marker><a/></marker></g>
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ return !(item.isElem(container) && !item.isElem('svg') && item.isEmpty() &&
+ (!item.isElem('pattern') || !item.hasAttrLocal('href')));
+
+};
diff --git a/node_modules/svgo/plugins/removeEmptyText.js b/node_modules/svgo/plugins/removeEmptyText.js
new file mode 100644
index 0000000..049b181
--- /dev/null
+++ b/node_modules/svgo/plugins/removeEmptyText.js
@@ -0,0 +1,59 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes empty <text> elements';
+
+exports.params = {
+ text: true,
+ tspan: true,
+ tref: true
+};
+
+/**
+ * Remove empty Text elements.
+ *
+ * @see http://www.w3.org/TR/SVG/text.html
+ *
+ * @example
+ * Remove empty text element:
+ * <text/>
+ *
+ * Remove empty tspan element:
+ * <tspan/>
+ *
+ * Remove tref with empty xlink:href attribute:
+ * <tref xlink:href=""/>
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ // Remove empty text element
+ if (
+ params.text &&
+ item.isElem('text') &&
+ item.isEmpty()
+ ) return false;
+
+ // Remove empty tspan element
+ if (
+ params.tspan &&
+ item.isElem('tspan') &&
+ item.isEmpty()
+ ) return false;
+
+ // Remove tref with empty xlink:href attribute
+ if (
+ params.tref &&
+ item.isElem('tref') &&
+ !item.hasAttrLocal('href')
+ ) return false;
+
+};
diff --git a/node_modules/svgo/plugins/removeHiddenElems.js b/node_modules/svgo/plugins/removeHiddenElems.js
new file mode 100644
index 0000000..7379125
--- /dev/null
+++ b/node_modules/svgo/plugins/removeHiddenElems.js
@@ -0,0 +1,225 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes hidden elements (zero sized, with absent attributes)';
+
+exports.params = {
+ isHidden: true,
+ displayNone: true,
+ opacity0: true,
+ circleR0: true,
+ ellipseRX0: true,
+ ellipseRY0: true,
+ rectWidth0: true,
+ rectHeight0: true,
+ patternWidth0: true,
+ patternHeight0: true,
+ imageWidth0: true,
+ imageHeight0: true,
+ pathEmptyD: true,
+ polylineEmptyPoints: true,
+ polygonEmptyPoints: true
+};
+
+var regValidPath = /M\s*(?:[-+]?(?:\d*\.\d+|\d+(?:\.|(?!\.)))([eE][-+]?\d+)?(?!\d)\s*,?\s*){2}\D*\d/i;
+
+/**
+ * Remove hidden elements with disabled rendering:
+ * - display="none"
+ * - opacity="0"
+ * - circle with zero radius
+ * - ellipse with zero x-axis or y-axis radius
+ * - rectangle with zero width or height
+ * - pattern with zero width or height
+ * - image with zero width or height
+ * - path with empty data
+ * - polyline with empty points
+ * - polygon with empty points
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function (item, params) {
+
+ if (item.elem) {
+ // Removes hidden elements
+ // https://www.w3schools.com/cssref/pr_class_visibility.asp
+ if (
+ params.isHidden &&
+ item.hasAttr('visibility', 'hidden')
+ ) return false;
+
+ // display="none"
+ //
+ // http://www.w3.org/TR/SVG/painting.html#DisplayProperty
+ // "A value of display: none indicates that the given element
+ // and its children shall not be rendered directly"
+ if (
+ params.displayNone &&
+ item.hasAttr('display', 'none')
+ ) return false;
+
+ // opacity="0"
+ //
+ // http://www.w3.org/TR/SVG/masking.html#ObjectAndGroupOpacityProperties
+ if (
+ params.opacity0 &&
+ item.hasAttr('opacity', '0')
+ ) return false;
+
+ // Circles with zero radius
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#CircleElementRAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <circle r="0">
+ if (
+ params.circleR0 &&
+ item.isElem('circle') &&
+ item.isEmpty() &&
+ item.hasAttr('r', '0')
+ ) return false;
+
+ // Ellipse with zero x-axis radius
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#EllipseElementRXAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <ellipse rx="0">
+ if (
+ params.ellipseRX0 &&
+ item.isElem('ellipse') &&
+ item.isEmpty() &&
+ item.hasAttr('rx', '0')
+ ) return false;
+
+ // Ellipse with zero y-axis radius
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#EllipseElementRYAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <ellipse ry="0">
+ if (
+ params.ellipseRY0 &&
+ item.isElem('ellipse') &&
+ item.isEmpty() &&
+ item.hasAttr('ry', '0')
+ ) return false;
+
+ // Rectangle with zero width
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#RectElementWidthAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <rect width="0">
+ if (
+ params.rectWidth0 &&
+ item.isElem('rect') &&
+ item.isEmpty() &&
+ item.hasAttr('width', '0')
+ ) return false;
+
+ // Rectangle with zero height
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#RectElementHeightAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <rect height="0">
+ if (
+ params.rectHeight0 &&
+ params.rectWidth0 &&
+ item.isElem('rect') &&
+ item.isEmpty() &&
+ item.hasAttr('height', '0')
+ ) return false;
+
+ // Pattern with zero width
+ //
+ // http://www.w3.org/TR/SVG/pservers.html#PatternElementWidthAttribute
+ // "A value of zero disables rendering of the element (i.e., no paint is applied)"
+ //
+ // <pattern width="0">
+ if (
+ params.patternWidth0 &&
+ item.isElem('pattern') &&
+ item.hasAttr('width', '0')
+ ) return false;
+
+ // Pattern with zero height
+ //
+ // http://www.w3.org/TR/SVG/pservers.html#PatternElementHeightAttribute
+ // "A value of zero disables rendering of the element (i.e., no paint is applied)"
+ //
+ // <pattern height="0">
+ if (
+ params.patternHeight0 &&
+ item.isElem('pattern') &&
+ item.hasAttr('height', '0')
+ ) return false;
+
+ // Image with zero width
+ //
+ // http://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <image width="0">
+ if (
+ params.imageWidth0 &&
+ item.isElem('image') &&
+ item.hasAttr('width', '0')
+ ) return false;
+
+ // Image with zero height
+ //
+ // http://www.w3.org/TR/SVG/struct.html#ImageElementHeightAttribute
+ // "A value of zero disables rendering of the element"
+ //
+ // <image height="0">
+ if (
+ params.imageHeight0 &&
+ item.isElem('image') &&
+ item.hasAttr('height', '0')
+ ) return false;
+
+ // Path with empty data
+ //
+ // http://www.w3.org/TR/SVG/paths.html#DAttribute
+ //
+ // <path d=""/>
+ if (
+ params.pathEmptyD &&
+ item.isElem('path') &&
+ (!item.hasAttr('d') || !regValidPath.test(item.attr('d').value))
+ ) return false;
+
+ // Polyline with empty points
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#PolylineElementPointsAttribute
+ //
+ // <polyline points="">
+ if (
+ params.polylineEmptyPoints &&
+ item.isElem('polyline') &&
+ !item.hasAttr('points')
+ ) return false;
+
+ // Polygon with empty points
+ //
+ // http://www.w3.org/TR/SVG/shapes.html#PolygonElementPointsAttribute
+ //
+ // <polygon points="">
+ if (
+ params.polygonEmptyPoints &&
+ item.isElem('polygon') &&
+ !item.hasAttr('points')
+ ) return false;
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeMetadata.js b/node_modules/svgo/plugins/removeMetadata.js
new file mode 100644
index 0000000..fa7a579
--- /dev/null
+++ b/node_modules/svgo/plugins/removeMetadata.js
@@ -0,0 +1,23 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes <metadata>';
+
+/**
+ * Remove <metadata>.
+ *
+ * http://www.w3.org/TR/SVG/metadata.html
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ return !item.isElem('metadata');
+
+};
diff --git a/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js b/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js
new file mode 100644
index 0000000..85e3b97
--- /dev/null
+++ b/node_modules/svgo/plugins/removeNonInheritableGroupAttrs.js
@@ -0,0 +1,37 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes non-inheritable group’s presentational attributes';
+
+var inheritableAttrs = require('./_collections').inheritableAttrs,
+ attrsGroups = require('./_collections').attrsGroups,
+ applyGroups = require('./_collections').presentationNonInheritableGroupAttrs;
+
+/**
+ * Remove non-inheritable group's "presentation" attributes.
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('g')) {
+
+ item.eachAttr(function(attr) {
+ if (
+ ~attrsGroups.presentation.indexOf(attr.name) &&
+ !~inheritableAttrs.indexOf(attr.name) &&
+ !~applyGroups.indexOf(attr.name)
+ ) {
+ item.removeAttr(attr.name);
+ }
+ });
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeOffCanvasPaths.js b/node_modules/svgo/plugins/removeOffCanvasPaths.js
new file mode 100644
index 0000000..5bcb9a1
--- /dev/null
+++ b/node_modules/svgo/plugins/removeOffCanvasPaths.js
@@ -0,0 +1,133 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes elements that are drawn outside of the viewbox (disabled by default)';
+
+var SVGO = require('../lib/svgo.js'),
+ _path = require('./_path.js'),
+ intersects = _path.intersects,
+ path2js = _path.path2js,
+ viewBox,
+ viewBoxJS;
+
+/**
+ * Remove elements that are drawn outside of the viewbox.
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author JoshyPHP
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('path') && item.hasAttr('d') && typeof viewBox !== 'undefined')
+ {
+ // Consider that any item with a transform attribute or a M instruction
+ // within the viewBox is visible
+ if (hasTransform(item) || pathMovesWithinViewBox(item.attr('d').value))
+ {
+ return true;
+ }
+
+ var pathJS = path2js(item);
+ if (pathJS.length === 2)
+ {
+ // Use a closed clone of the path if it's too short for intersects()
+ pathJS = JSON.parse(JSON.stringify(pathJS));
+ pathJS.push({ instruction: 'z' });
+ }
+
+ return intersects(viewBoxJS, pathJS);
+ }
+ if (item.isElem('svg'))
+ {
+ parseViewBox(item);
+ }
+
+ return true;
+};
+
+/**
+ * Test whether given item or any of its ancestors has a transform attribute.
+ *
+ * @param {String} path
+ * @return {Boolean}
+ */
+function hasTransform(item)
+{
+ return item.hasAttr('transform') || (item.parentNode && hasTransform(item.parentNode));
+}
+
+/**
+ * Parse the viewBox coordinates and compute the JS representation of its path.
+ *
+ * @param {Object} svg svg element item
+ */
+function parseViewBox(svg)
+{
+ var viewBoxData = '';
+ if (svg.hasAttr('viewBox'))
+ {
+ // Remove commas and plus signs, normalize and trim whitespace
+ viewBoxData = svg.attr('viewBox').value;
+ }
+ else if (svg.hasAttr('height') && svg.hasAttr('width'))
+ {
+ viewBoxData = '0 0 ' + svg.attr('width').value + ' ' + svg.attr('height').value;
+ }
+
+ // Remove commas and plus signs, normalize and trim whitespace
+ viewBoxData = viewBoxData.replace(/[,+]|px/g, ' ').replace(/\s+/g, ' ').replace(/^\s*|\s*$/g, '');
+
+ // Ensure that the dimensions are 4 values separated by space
+ var m = /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(viewBoxData);
+ if (!m)
+ {
+ return;
+ }
+
+ // Store the viewBox boundaries
+ viewBox = {
+ left: parseFloat(m[1]),
+ top: parseFloat(m[2]),
+ right: parseFloat(m[1]) + parseFloat(m[3]),
+ bottom: parseFloat(m[2]) + parseFloat(m[4])
+ };
+
+ var path = new SVGO().createContentItem({
+ elem: 'path',
+ prefix: '',
+ local: 'path'
+ });
+ path.addAttr({
+ name: 'd',
+ prefix: '',
+ local: 'd',
+ value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z'
+ });
+
+ viewBoxJS = path2js(path);
+}
+
+/**
+ * Test whether given path has a M instruction with coordinates within the viewBox.
+ *
+ * @param {String} path
+ * @return {Boolean}
+ */
+function pathMovesWithinViewBox(path)
+{
+ var regexp = /M\s*(-?\d*\.?\d+)(?!\d)\s*(-?\d*\.?\d+)/g, m;
+ while (null !== (m = regexp.exec(path)))
+ {
+ if (m[1] >= viewBox.left && m[1] <= viewBox.right && m[2] >= viewBox.top && m[2] <= viewBox.bottom)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/node_modules/svgo/plugins/removeRasterImages.js b/node_modules/svgo/plugins/removeRasterImages.js
new file mode 100644
index 0000000..cbddebe
--- /dev/null
+++ b/node_modules/svgo/plugins/removeRasterImages.js
@@ -0,0 +1,28 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes raster images (disabled by default)';
+
+/**
+ * Remove raster images references in <image>.
+ *
+ * @see https://bugs.webkit.org/show_bug.cgi?id=63548
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (
+ item.isElem('image') &&
+ item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/)
+ ) {
+ return false;
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeScriptElement.js b/node_modules/svgo/plugins/removeScriptElement.js
new file mode 100644
index 0000000..f80410b
--- /dev/null
+++ b/node_modules/svgo/plugins/removeScriptElement.js
@@ -0,0 +1,23 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes <script> elements (disabled by default)';
+
+/**
+ * Remove <script>.
+ *
+ * https://www.w3.org/TR/SVG/script.html
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Patrick Klingemann
+ */
+exports.fn = function(item) {
+
+ return !item.isElem('script');
+
+};
diff --git a/node_modules/svgo/plugins/removeStyleElement.js b/node_modules/svgo/plugins/removeStyleElement.js
new file mode 100644
index 0000000..964ce45
--- /dev/null
+++ b/node_modules/svgo/plugins/removeStyleElement.js
@@ -0,0 +1,23 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes <style> element (disabled by default)';
+
+/**
+ * Remove <style>.
+ *
+ * http://www.w3.org/TR/SVG/styling.html#StyleElement
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Betsy Dupuis
+ */
+exports.fn = function(item) {
+
+ return !item.isElem('style');
+
+};
diff --git a/node_modules/svgo/plugins/removeTitle.js b/node_modules/svgo/plugins/removeTitle.js
new file mode 100644
index 0000000..841d178
--- /dev/null
+++ b/node_modules/svgo/plugins/removeTitle.js
@@ -0,0 +1,23 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes <title>';
+
+/**
+ * Remove <title>.
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Igor Kalashnikov
+ */
+exports.fn = function(item) {
+
+ return !item.isElem('title');
+
+};
diff --git a/node_modules/svgo/plugins/removeUnknownsAndDefaults.js b/node_modules/svgo/plugins/removeUnknownsAndDefaults.js
new file mode 100644
index 0000000..31970a4
--- /dev/null
+++ b/node_modules/svgo/plugins/removeUnknownsAndDefaults.js
@@ -0,0 +1,150 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes unknown elements content and attributes, removes attrs with default values';
+
+exports.params = {
+ unknownContent: true,
+ unknownAttrs: true,
+ defaultAttrs: true,
+ uselessOverrides: true,
+ keepDataAttrs: true,
+ keepAriaAttrs: true,
+ keepRoleAttr: false
+};
+
+var collections = require('./_collections'),
+ elems = collections.elems,
+ attrsGroups = collections.attrsGroups,
+ elemsGroups = collections.elemsGroups,
+ attrsGroupsDefaults = collections.attrsGroupsDefaults,
+ attrsInheritable = collections.inheritableAttrs,
+ applyGroups = collections.presentationNonInheritableGroupAttrs;
+
+// collect and extend all references
+for (var elem in elems) {
+ elem = elems[elem];
+
+ if (elem.attrsGroups) {
+ elem.attrs = elem.attrs || [];
+
+ elem.attrsGroups.forEach(function(attrsGroupName) {
+ elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]);
+
+ var groupDefaults = attrsGroupsDefaults[attrsGroupName];
+
+ if (groupDefaults) {
+ elem.defaults = elem.defaults || {};
+
+ for (var attrName in groupDefaults) {
+ elem.defaults[attrName] = groupDefaults[attrName];
+ }
+ }
+ });
+
+ }
+
+ if (elem.contentGroups) {
+ elem.content = elem.content || [];
+
+ elem.contentGroups.forEach(function(contentGroupName) {
+ elem.content = elem.content.concat(elemsGroups[contentGroupName]);
+ });
+ }
+}
+
+/**
+ * Remove unknown elements content and attributes,
+ * remove attributes with default values.
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ // elems w/o namespace prefix
+ if (item.isElem() && !item.prefix) {
+
+ var elem = item.elem;
+
+ // remove unknown element's content
+ if (
+ params.unknownContent &&
+ !item.isEmpty() &&
+ elems[elem] && // make sure we know of this element before checking its children
+ elem !== 'foreignObject' // Don't check foreignObject
+ ) {
+ item.content.forEach(function(content, i) {
+ if (
+ content.isElem() &&
+ !content.prefix &&
+ (
+ (
+ elems[elem].content && // Do we have a record of its permitted content?
+ elems[elem].content.indexOf(content.elem) === -1
+ ) ||
+ (
+ !elems[elem].content && // we dont know about its permitted content
+ !elems[content.elem] // check that we know about the element at all
+ )
+ )
+ ) {
+ item.content.splice(i, 1);
+ }
+ });
+ }
+
+ // remove element's unknown attrs and attrs with default values
+ if (elems[elem] && elems[elem].attrs) {
+
+ item.eachAttr(function(attr) {
+
+ if (
+ attr.name !== 'xmlns' &&
+ (attr.prefix === 'xml' || !attr.prefix) &&
+ (!params.keepDataAttrs || attr.name.indexOf('data-') != 0) &&
+ (!params.keepAriaAttrs || attr.name.indexOf('aria-') != 0) &&
+ (!params.keepRoleAttr || attr.name != 'role')
+ ) {
+ if (
+ // unknown attrs
+ (
+ params.unknownAttrs &&
+ elems[elem].attrs.indexOf(attr.name) === -1
+ ) ||
+ // attrs with default values
+ (
+ params.defaultAttrs &&
+ !item.hasAttr('id') &&
+ elems[elem].defaults &&
+ elems[elem].defaults[attr.name] === attr.value && (
+ attrsInheritable.indexOf(attr.name) < 0 ||
+ !item.parentNode.computedAttr(attr.name)
+ )
+ ) ||
+ // useless overrides
+ (
+ params.uselessOverrides &&
+ !item.hasAttr('id') &&
+ applyGroups.indexOf(attr.name) < 0 &&
+ attrsInheritable.indexOf(attr.name) > -1 &&
+ item.parentNode.computedAttr(attr.name, attr.value)
+ )
+ ) {
+ item.removeAttr(attr.name);
+ }
+ }
+
+ });
+
+ }
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeUnusedNS.js b/node_modules/svgo/plugins/removeUnusedNS.js
new file mode 100644
index 0000000..db0df76
--- /dev/null
+++ b/node_modules/svgo/plugins/removeUnusedNS.js
@@ -0,0 +1,109 @@
+'use strict';
+
+exports.type = 'full';
+
+exports.active = true;
+
+exports.description = 'removes unused namespaces declaration';
+
+/**
+ * Remove unused namespaces declaration.
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(data) {
+
+ var svgElem,
+ xmlnsCollection = [];
+
+ /**
+ * Remove namespace from collection.
+ *
+ * @param {String} ns namescape name
+ */
+ function removeNSfromCollection(ns) {
+
+ var pos = xmlnsCollection.indexOf(ns);
+
+ // if found - remove ns from the namespaces collection
+ if (pos > -1) {
+ xmlnsCollection.splice(pos, 1);
+ }
+
+ }
+
+ /**
+ * Bananas!
+ *
+ * @param {Array} items input items
+ *
+ * @return {Array} output items
+ */
+ function monkeys(items) {
+
+ var i = 0,
+ length = items.content.length;
+
+ while(i < length) {
+
+ var item = items.content[i];
+
+ if (item.isElem('svg')) {
+
+ item.eachAttr(function(attr) {
+ // collect namespaces
+ if (attr.prefix === 'xmlns' && attr.local) {
+ xmlnsCollection.push(attr.local);
+ }
+ });
+
+ // if svg element has ns-attr
+ if (xmlnsCollection.length) {
+ // save svg element
+ svgElem = item;
+ }
+
+ }
+
+ if (xmlnsCollection.length) {
+
+ // check item for the ns-attrs
+ if (item.prefix) {
+ removeNSfromCollection(item.prefix);
+ }
+
+ // check each attr for the ns-attrs
+ item.eachAttr(function(attr) {
+ removeNSfromCollection(attr.prefix);
+ });
+
+ }
+
+ // if nothing is found - go deeper
+ if (xmlnsCollection.length && item.content) {
+ monkeys(item);
+ }
+
+ i++;
+
+ }
+
+ return items;
+
+ }
+
+ data = monkeys(data);
+
+ // remove svg element ns-attributes if they are not used even once
+ if (xmlnsCollection.length) {
+ xmlnsCollection.forEach(function(name) {
+ svgElem.removeAttr('xmlns:' + name);
+ });
+ }
+
+ return data;
+
+};
diff --git a/node_modules/svgo/plugins/removeUselessDefs.js b/node_modules/svgo/plugins/removeUselessDefs.js
new file mode 100644
index 0000000..87badd9
--- /dev/null
+++ b/node_modules/svgo/plugins/removeUselessDefs.js
@@ -0,0 +1,53 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes elements in <defs> without id';
+
+var nonRendering = require('./_collections').elemsGroups.nonRendering;
+
+/**
+ * Removes content of defs and properties that aren't rendered directly without ids.
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Lev Solntsev
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('defs')) {
+
+ if (item.content) {
+ item.content = getUsefulItems(item, []);
+ }
+
+ if (item.isEmpty()) return false;
+
+ } else if (item.isElem(nonRendering) && !item.hasAttr('id')) {
+
+ return false;
+
+ }
+
+};
+
+function getUsefulItems(item, usefulItems) {
+
+ item.content.forEach(function(child) {
+ if (child.hasAttr('id') || child.isElem('style')) {
+
+ usefulItems.push(child);
+ child.parentNode = item;
+
+ } else if (!child.isEmpty()) {
+
+ child.content = getUsefulItems(child, usefulItems);
+
+ }
+ });
+
+ return usefulItems;
+}
diff --git a/node_modules/svgo/plugins/removeUselessStrokeAndFill.js b/node_modules/svgo/plugins/removeUselessStrokeAndFill.js
new file mode 100644
index 0000000..e6b8eea
--- /dev/null
+++ b/node_modules/svgo/plugins/removeUselessStrokeAndFill.js
@@ -0,0 +1,100 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes useless stroke and fill attributes';
+
+exports.params = {
+ stroke: true,
+ fill: true,
+ removeNone: false,
+ hasStyleOrScript: false
+};
+
+var shape = require('./_collections').elemsGroups.shape,
+ regStrokeProps = /^stroke/,
+ regFillProps = /^fill-/,
+ styleOrScript = ['style', 'script'];
+
+/**
+ * Remove useless stroke and fill attrs.
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item, params) {
+
+ if (item.isElem(styleOrScript)) {
+ params.hasStyleOrScript = true;
+ }
+
+ if (!params.hasStyleOrScript && item.isElem(shape) && !item.computedAttr('id')) {
+
+ var stroke = params.stroke && item.computedAttr('stroke'),
+ fill = params.fill && !item.computedAttr('fill', 'none');
+
+ // remove stroke*
+ if (
+ params.stroke &&
+ (!stroke ||
+ stroke == 'none' ||
+ item.computedAttr('stroke-opacity', '0') ||
+ item.computedAttr('stroke-width', '0')
+ )
+ ) {
+ var parentStroke = item.parentNode.computedAttr('stroke'),
+ declineStroke = parentStroke && parentStroke != 'none';
+
+ item.eachAttr(function(attr) {
+ if (regStrokeProps.test(attr.name)) {
+ item.removeAttr(attr.name);
+ }
+ });
+
+ if (declineStroke) item.addAttr({
+ name: 'stroke',
+ value: 'none',
+ prefix: '',
+ local: 'stroke'
+ });
+ }
+
+ // remove fill*
+ if (
+ params.fill &&
+ (!fill || item.computedAttr('fill-opacity', '0'))
+ ) {
+ item.eachAttr(function(attr) {
+ if (regFillProps.test(attr.name)) {
+ item.removeAttr(attr.name);
+ }
+ });
+
+ if (fill) {
+ if (item.hasAttr('fill'))
+ item.attr('fill').value = 'none';
+ else
+ item.addAttr({
+ name: 'fill',
+ value: 'none',
+ prefix: '',
+ local: 'fill'
+ });
+ }
+ }
+
+ if (params.removeNone &&
+ (!stroke || item.hasAttr('stroke') && item.attr('stroke').value=='none') &&
+ (!fill || item.hasAttr('fill') && item.attr('fill').value=='none')) {
+
+ return false;
+ }
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeViewBox.js b/node_modules/svgo/plugins/removeViewBox.js
new file mode 100644
index 0000000..2fbcba4
--- /dev/null
+++ b/node_modules/svgo/plugins/removeViewBox.js
@@ -0,0 +1,48 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes viewBox attribute when possible';
+
+var viewBoxElems = ['svg', 'pattern', 'symbol'];
+
+/**
+ * Remove viewBox attr which coincides with a width/height box.
+ *
+ * @see http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
+ *
+ * @example
+ * <svg width="100" height="50" viewBox="0 0 100 50">
+ * ⬇
+ * <svg width="100" height="50">
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ if (
+ item.isElem(viewBoxElems) &&
+ item.hasAttr('viewBox') &&
+ item.hasAttr('width') &&
+ item.hasAttr('height')
+ ) {
+
+ var nums = item.attr('viewBox').value.split(/[ ,]+/g);
+
+ if (
+ nums[0] === '0' &&
+ nums[1] === '0' &&
+ item.attr('width').value.replace(/px$/, '') === nums[2] && // could use parseFloat too
+ item.attr('height').value.replace(/px$/, '') === nums[3]
+ ) {
+ item.removeAttr('viewBox');
+ }
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/removeXMLNS.js b/node_modules/svgo/plugins/removeXMLNS.js
new file mode 100644
index 0000000..afda99d
--- /dev/null
+++ b/node_modules/svgo/plugins/removeXMLNS.js
@@ -0,0 +1,28 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'removes xmlns attribute (for inline svg, disabled by default)';
+
+/**
+ * Remove the xmlns attribute when present.
+ *
+ * @example
+ * <svg viewBox="0 0 100 50" xmlns="http://www.w3.org/2000/svg">
+ * ↓
+ * <svg viewBox="0 0 100 50">
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if true, xmlns will be filtered out
+ *
+ * @author Ricardo Tomasi
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('svg') && item.hasAttr('xmlns')) {
+ item.removeAttr('xmlns');
+ }
+
+};
\ No newline at end of file
diff --git a/node_modules/svgo/plugins/removeXMLProcInst.js b/node_modules/svgo/plugins/removeXMLProcInst.js
new file mode 100644
index 0000000..afd425d
--- /dev/null
+++ b/node_modules/svgo/plugins/removeXMLProcInst.js
@@ -0,0 +1,24 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'removes XML processing instructions';
+
+/**
+ * Remove XML Processing Instruction.
+ *
+ * @example
+ * <?xml version="1.0" encoding="utf-8"?>
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author Kir Belevich
+ */
+exports.fn = function(item) {
+
+ return !(item.processinginstruction && item.processinginstruction.name === 'xml');
+
+};
diff --git a/node_modules/svgo/plugins/reusePaths.js b/node_modules/svgo/plugins/reusePaths.js
new file mode 100644
index 0000000..ba097da
--- /dev/null
+++ b/node_modules/svgo/plugins/reusePaths.js
@@ -0,0 +1,168 @@
+/**
+ * @license
+ * The MIT License
+ *
+ * Copyright © 2012–2016 Kir Belevich
+ *
+ * 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.
+ *
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ *
+ * Лицензия MIT
+ *
+ * Copyright © 2012–2016 Кир Белевич
+ *
+ * Данная лицензия разрешает лицам, получившим копию
+ * данного
+ * программного обеспечения и сопутствующей
+ * документации
+ * (в дальнейшем именуемыми «Программное Обеспечение»),
+ * безвозмездно
+ * использовать Программное Обеспечение без
+ * ограничений, включая
+ * неограниченное право на использование, копирование,
+ * изменение,
+ * добавление, публикацию, распространение,
+ * сублицензирование
+ * и/или продажу копий Программного Обеспечения, также
+ * как и лицам,
+ * которым предоставляется данное Программное
+ * Обеспечение,
+ * при соблюдении следующих условий:
+ *
+ * Указанное выше уведомление об авторском праве и
+ * данные условия
+ * должны быть включены во все копии или значимые части
+ * данного
+ * Программного Обеспечения.
+ *
+ * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК
+ * ЕСТЬ»,
+ * БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ
+ * ПОДРАЗУМЕВАЕМЫХ,
+ * ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ
+ * ПРИГОДНОСТИ,
+ * СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И
+ * ОТСУТСТВИЯ НАРУШЕНИЙ
+ * ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ
+ * НЕСУТ
+ * ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ
+ * ИЛИ ДРУГИХ
+ * ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ
+ * ИНОМУ,
+ * ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С
+ * ПРОГРАММНЫМ
+ * ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО
+ * ОБЕСПЕЧЕНИЯ
+ * ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
+ */
+
+'use strict';
+
+var JSAPI = require('../lib/svgo/jsAPI');
+
+exports.type = 'full';
+
+exports.active = false;
+
+exports.description = 'Finds <path> elements with the same d, fill, and ' +
+ 'stroke, and converts them to <use> elements ' +
+ 'referencing a single <path> def.';
+
+/**
+ * Finds <path> elements with the same d, fill, and stroke, and converts them to
+ * <use> elements referencing a single <path> def.
+ *
+ * @author Jacob Howcroft
+ */
+exports.fn = function(data) {
+ const seen = new Map();
+ let count = 0;
+ const defs = [];
+ traverse(data, item => {
+ if (!item.isElem('path') || !item.hasAttr('d')) {
+ return;
+ }
+ const d = item.attr('d').value;
+ const fill = (item.hasAttr('fill') && item.attr('fill').value) || '';
+ const stroke = (item.hasAttr('stroke') && item.attr('stroke').value) || '';
+ const key = d + ';s:' + stroke + ';f:' + fill;
+ const hasSeen = seen.get(key);
+ if (!hasSeen) {
+ seen.set(key, {elem: item, reused: false});
+ return;
+ }
+ if (!hasSeen.reused) {
+ hasSeen.reused = true;
+ if (!hasSeen.elem.hasAttr('id')) {
+ hasSeen.elem.addAttr({name: 'id', local: 'id',
+ prefix: '', value: 'reuse-' + (count++)});
+ }
+ defs.push(hasSeen.elem);
+ }
+ item = convertToUse(item, hasSeen.elem.attr('id').value);
+ });
+ const defsTag = new JSAPI({
+ elem: 'defs', prefix: '', local: 'defs', content: [], attrs: []}, data);
+ data.content[0].spliceContent(0, 0, defsTag);
+ for (let def of defs) {
+ // Remove class and style before copying to avoid circular refs in
+ // JSON.stringify. This is fine because we don't actually want class or
+ // style information to be copied.
+ const style = def.style;
+ const defClass = def.class;
+ delete def.style;
+ delete def.class;
+ const defClone = def.clone();
+ def.style = style;
+ def.class = defClass;
+ defClone.removeAttr('transform');
+ defsTag.spliceContent(0, 0, defClone);
+ // Convert the original def to a use so the first usage isn't duplicated.
+ def = convertToUse(def, defClone.attr('id').value);
+ def.removeAttr('id');
+ }
+ return data;
+};
+
+/** */
+function convertToUse(item, href) {
+ item.renameElem('use');
+ item.removeAttr('d');
+ item.removeAttr('stroke');
+ item.removeAttr('fill');
+ item.addAttr({name: 'xlink:href', local: 'xlink:href',
+ prefix: 'none', value: '#' + href});
+ delete item.pathJS;
+ return item;
+}
+
+/** */
+function traverse(parent, callback) {
+ if (parent.isEmpty()) {
+ return;
+ }
+ for (let child of parent.content) {
+ callback(child);
+ traverse(child, callback);
+ }
+}
diff --git a/node_modules/svgo/plugins/sortAttrs.js b/node_modules/svgo/plugins/sortAttrs.js
new file mode 100644
index 0000000..cba5c1d
--- /dev/null
+++ b/node_modules/svgo/plugins/sortAttrs.js
@@ -0,0 +1,84 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = false;
+
+exports.description = 'sorts element attributes (disabled by default)';
+
+exports.params = {
+ order: [
+ 'id',
+ 'width', 'height',
+ 'x', 'x1', 'x2',
+ 'y', 'y1', 'y2',
+ 'cx', 'cy', 'r',
+ 'fill', 'stroke', 'marker',
+ 'd', 'points'
+ ]
+};
+
+/**
+ * Sort element attributes for epic readability.
+ *
+ * @param {Object} item current iteration item
+ * @param {Object} params plugin params
+ *
+ * @author Nikolay Frantsev
+ */
+exports.fn = function(item, params) {
+
+ var attrs = [],
+ sorted = {},
+ orderlen = params.order.length + 1,
+ xmlnsOrder = params.xmlnsOrder || 'front';
+
+ if (item.elem) {
+
+ item.eachAttr(function(attr) {
+ attrs.push(attr);
+ });
+
+ attrs.sort(function(a, b) {
+ if (a.prefix != b.prefix) {
+ // xmlns attributes implicitly have the prefix xmlns
+ if (xmlnsOrder == 'front') {
+ if (a.prefix == 'xmlns')
+ return -1;
+ if (b.prefix == 'xmlns')
+ return 1;
+ }
+ return a.prefix < b.prefix ? -1 : 1;
+ }
+
+ var aindex = orderlen;
+ var bindex = orderlen;
+
+ for (var i = 0; i < params.order.length; i++) {
+ if (a.name == params.order[i]) {
+ aindex = i;
+ } else if (a.name.indexOf(params.order[i] + '-') === 0) {
+ aindex = i + .5;
+ }
+ if (b.name == params.order[i]) {
+ bindex = i;
+ } else if (b.name.indexOf(params.order[i] + '-') === 0) {
+ bindex = i + .5;
+ }
+ }
+
+ if (aindex != bindex) {
+ return aindex - bindex;
+ }
+ return a.name < b.name ? -1 : 1;
+ });
+
+ attrs.forEach(function (attr) {
+ sorted[attr.name] = attr;
+ });
+
+ item.attrs = sorted;
+
+ }
+
+};
diff --git a/node_modules/svgo/plugins/sortDefsChildren.js b/node_modules/svgo/plugins/sortDefsChildren.js
new file mode 100644
index 0000000..bf1d1c4
--- /dev/null
+++ b/node_modules/svgo/plugins/sortDefsChildren.js
@@ -0,0 +1,47 @@
+'use strict';
+
+exports.type = 'perItem';
+
+exports.active = true;
+
+exports.description = 'Sorts children of <defs> to improve compression';
+
+/**
+ * Sorts children of defs in order to improve compression.
+ * Sorted first by frequency then by element name length then by element name (to ensure grouping).
+ *
+ * @param {Object} item current iteration item
+ * @return {Boolean} if false, item will be filtered out
+ *
+ * @author David Leston
+ */
+exports.fn = function(item) {
+
+ if (item.isElem('defs')) {
+
+ if (item.content) {
+ var frequency = item.content.reduce(function (frequency, child) {
+ if (child.elem in frequency) {
+ frequency[child.elem]++;
+ } else {
+ frequency[child.elem] = 1;
+ }
+ return frequency;
+ }, {});
+ item.content.sort(function (a, b) {
+ var frequencyComparison = frequency[b.elem] - frequency[a.elem];
+ if (frequencyComparison !== 0 ) {
+ return frequencyComparison;
+ }
+ var lengthComparison = b.elem.length - a.elem.length;
+ if (lengthComparison !== 0) {
+ return lengthComparison;
+ }
+ return a.elem != b.elem ? a.elem > b.elem ? -1 : 1 : 0;
+ });
+ }
+
+ return true;
+ }
+
+};