Repository: svg/svgo
Pull request #1064 (2018-12-07 05:54:29)

- update namespace list


Patch:
diff --git a/.gitignore b/.gitignore
index 7ab3c06..b7daeed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ bin/svgo-profiling
 *.log
 .DS_Store
 .idea
+.vscode
diff --git a/.svgo.yml b/.svgo.yml
index 313bf7c..eb02b2d 100644
--- a/.svgo.yml
+++ b/.svgo.yml
@@ -55,11 +55,14 @@ plugins:
   - removeDesc
   - removeDimensions
   - removeAttrs
+  - removeAttributesBySelector
   - removeElementsByAttr
   - addClassesToSVGElement
   - removeStyleElement
   - removeScriptElement
   - addAttributesToSVGElement
+  - removeOffCanvasPaths
+  - reusePaths
 
 # configure the indent (default 4 spaces) used by `--pretty` here:
 #
diff --git a/README.md b/README.md
index 66a254a..ea2ef54 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ Today we have:
 | [removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) | remove non-inheritable group's "presentation" attributes |
 | [removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) | remove useless `stroke` and `fill` attrs |
 | [removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) | remove unused namespaces declaration |
+| [prefixIds](https://github.com/svg/svgo/blob/master/plugins/prefixIds.js) | prefix IDs and classes with the SVG filename or an arbitrary string |
 | [cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) | remove unused and minify used IDs |
 | [cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) | round numeric values to the fixed precision, remove default `px` units |
 | [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`) |
@@ -58,11 +59,13 @@ Today we have:
 | [sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) | sort element attributes for epic readability (disabled by default) |
 | [removeDimensions](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) | remove `width`/`height` attributes if `viewBox` is present (opposite to removeViewBox, disable it first) (disabled by default) |
 | [removeAttrs](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) | remove attributes by pattern (disabled by default) |
+| [removeAttributesBySelector](https://github.com/svg/svgo/blob/master/plugins/removeAttributesBySelector.js) | removes attributes of elements that match a css selector (disabled by default) |
 | [removeElementsByAttr](https://github.com/svg/svgo/blob/master/plugins/removeElementsByAttr.js) | remove arbitrary elements by ID or className (disabled by default) |
 | [addClassesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addClassesToSVGElement.js) | add classnames to an outer `<svg>` element (disabled by default) |
 | [addAttributesToSVGElement](https://github.com/svg/svgo/blob/master/plugins/addAttributesToSVGElement.js) | adds attributes to an outer `<svg>` element (disabled by default) |
 | [removeStyleElement](https://github.com/svg/svgo/blob/master/plugins/removeStyleElement.js) | remove `<style>` elements (disabled by default) |
 | [removeScriptElement](https://github.com/svg/svgo/blob/master/plugins/removeScriptElement.js) | remove `<script>` elements (disabled by default) |
+| [reusePaths](https://github.com/svg/svgo/blob/master/plugins/reusePaths.js) | Find duplicated <path> elements and replace them with <use> links. (disabled by default) |
 
 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))
 
@@ -90,8 +93,8 @@ Options:
   -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 (*nix)
-  --enable=PLUGIN : Enable plugin by name, "--enable={PLUGIN3,PLUGIN4}" for multiple plugins (*nix)
+  --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 : Enable multipass
   --pretty : Make SVG pretty printed
diff --git a/README.ru.md b/README.ru.md
index 0c53b14..5557d01 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -46,6 +46,7 @@ SVGO имеет расширяемую архитектуру, в которой
 | [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`
diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js
index 012b51e..a3eedde 100644
--- a/lib/svgo/coa.js
+++ b/lib/svgo/coa.js
@@ -1,10 +1,10 @@
 /* jshint quotmark: false */
 'use strict';
 
-require('colors');
-
 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),
@@ -14,6 +14,7 @@ var FS = require('fs'),
     PKG = require('../../package.json'),
     encodeSVGDatauri = require('./tools.js').encodeSVGDatauri,
     decodeSVGDatauri = require('./tools.js').decodeSVGDatauri,
+    checkIsDir = require('./tools.js').checkIsDir,
     regSVGFile = /\.svg$/,
     noop = () => {},
     svgo;
@@ -120,6 +121,11 @@ module.exports = require('coa').Cmd()
             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')
@@ -198,6 +204,11 @@ module.exports = require('coa').Cmd()
             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);
@@ -296,6 +307,8 @@ module.exports = require('coa').Cmd()
  * @return {Object} changed config
  */
 function changePluginsState(names, state, config) {
+    names.forEach(flattenPluginsCbk);
+
     // extend config
     if (config.plugins) {
         for (var name of names) {
@@ -335,6 +348,25 @@ function changePluginsState(names, state, config) {
     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
@@ -358,13 +390,46 @@ function optimizeFolder(config, dir, output) {
  * @return {Promise}
  */
 function processDirectory(config, dir, files, output) {
-    // take only *.svg files
-    var svgFiles = files.filter(name => regSVGFile.test(name));
-    return svgFiles.length ?
-        Promise.all(svgFiles.map(name => optimizeFile(config, PATH.resolve(dir, name), PATH.resolve(output, name)))) :
+    // 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
@@ -423,9 +488,13 @@ function writeOutput(input, output, data) {
         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.
@@ -445,7 +514,7 @@ function printProfitInfo(inBytes, outBytes) {
     console.log(
         (Math.round((inBytes / 1024) * 1000) / 1000) + ' KiB' +
         (profitPercents < 0 ? ' + ' : ' - ') +
-        String(Math.abs((Math.round(profitPercents * 10) / 10)) + '%').green + ' = ' +
+        chalk.green(Math.abs((Math.round(profitPercents * 10) / 10)) + '%') + ' = ' +
         (Math.round((outBytes / 1024) * 1000) / 1000) + ' KiB'
     );
 }
@@ -483,18 +552,6 @@ function checkWriteFileError(input, output, data, error) {
     }
 }
 
-/**
- * Synchronously check if path is a directory. Tolerant to errors like ENOENT.
- * @param {string} path
- */
-function checkIsDir(path) {
-    try {
-        return FS.lstatSync(path).isDirectory();
-    } catch(e) {
-        return false;
-    }
-}
-
 /**
  * Show list of available plugins with short description.
  */
@@ -504,7 +561,7 @@ function showAvailablePlugins() {
     // 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 => ` [ ${plugin.name.green} ] ${plugin.description}`)
+        .map(plugin => ` [ ${chalk.green(plugin.name)} ] ${plugin.description}`)
         .join('\n');
     console.log(list);
 }
@@ -515,7 +572,7 @@ function showAvailablePlugins() {
  * @return {Promise} a promise for running tests
  */
 function printErrorAndExit(error) {
-    console.error(error);
+    console.error(chalk.red(error));
     process.exit(1);
     return Promise.reject(error); // for tests
-}
\ No newline at end of file
+}
diff --git a/lib/svgo/tools.js b/lib/svgo/tools.js
index fb52c9d..c6b3c80 100644
--- a/lib/svgo/tools.js
+++ b/lib/svgo/tools.js
@@ -1,5 +1,7 @@
 'use strict';
 
+var FS = require('fs');
+
 /**
  * Encode plain SVG data string into Data URI string.
  *
@@ -148,3 +150,16 @@ var removeLeadingZero = exports.removeLeadingZero = function(num) {
     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/package.json b/package.json
index adfa84e..4b3548b 100644
--- a/package.json
+++ b/package.json
@@ -49,8 +49,8 @@
     "jshint": "npm run lint"
   },
   "dependencies": {
+    "chalk": "^2.4.1",
     "coa": "~2.0.1",
-    "colors": "~1.1.2",
     "css-select": "^2.0.0",
     "css-select-base-adapter": "~0.1.0",
     "css-tree": "1.0.0-alpha.28",
diff --git a/plugins/_collections.js b/plugins/_collections.js
index 165fe35..8179f30 100644
--- a/plugins/_collections.js
+++ b/plugins/_collections.js
@@ -2280,7 +2280,14 @@ exports.editorNamespaces = [
     '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://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
diff --git a/plugins/cleanupIDs.js b/plugins/cleanupIDs.js
index 2b61b93..f1fdc9f 100644
--- a/plugins/cleanupIDs.js
+++ b/plugins/cleanupIDs.js
@@ -11,6 +11,7 @@ exports.params = {
     minify: true,
     prefix: '',
     preserve: [],
+    preservePrefixes: [],
     force: false
 };
 
@@ -41,6 +42,7 @@ exports.fn = function(data, params) {
         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 = '.';
 
@@ -54,7 +56,7 @@ exports.fn = function(data, params) {
         for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
             var item = items.content[i];
 
-            // quit if <style> of <script> presents ('force' param prevents quitting)
+            // quit if <style> or <script> present ('force' param prevents quitting)
             if (!params.force) {
                 if (item.isElem(styleOrScript)) {
                     hasStyleOrScript = true;
@@ -124,7 +126,7 @@ exports.fn = function(data, params) {
 
         if (IDs.has(key)) {
             // replace referenced IDs with the minified ones
-            if (params.minify && !preserveIDs.has(key)) {
+            if (params.minify && !preserveIDs.has(key) && !idMatchesPrefix(preserveIDPrefixes, key)) {
                 currentIDstring = getIDstring(currentID = generateID(currentID), params);
                 IDs.get(key).attr('id').value = currentIDstring;
 
@@ -141,7 +143,7 @@ exports.fn = function(data, params) {
     // remove non-referenced IDs attributes from elements
     if (params.remove) {
         for(var keyElem of IDs) {
-            if (!preserveIDs.has(keyElem[0])) {
+            if (!preserveIDs.has(keyElem[0]) && !idMatchesPrefix(preserveIDPrefixes, keyElem[0])) {
                 keyElem[1].removeAttr('id');
             }
         }
@@ -149,6 +151,20 @@ exports.fn = function(data, params) {
     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.
  *
diff --git a/plugins/removeAttributesBySelector.js b/plugins/removeAttributesBySelector.js
new file mode 100644
index 0000000..3ae7463
--- /dev/null
+++ b/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/plugins/removeAttrs.js b/plugins/removeAttrs.js
index c8968c2..0ee35f2 100644
--- a/plugins/removeAttrs.js
+++ b/plugins/removeAttrs.js
@@ -10,6 +10,7 @@ exports.description = 'removes specified attributes';
 
 exports.params = {
     elemSeparator: DEFAULT_SEPARATOR,
+    preserveCurrentColor: false,
     attrs: []
 };
 
@@ -19,6 +20,9 @@ exports.params = {
  * @param elemSeparator
  *   format: string
  *
+ * @param preserveCurrentColor
+ *   format: boolean
+ *
  * @param attrs:
  *
  *   format: [ element* : attribute* ]
@@ -69,7 +73,6 @@ exports.params = {
  * @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];
@@ -77,6 +80,7 @@ exports.fn = function(item, params) {
 
     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) {
@@ -107,10 +111,15 @@ exports.fn = function(item, params) {
                     // 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)) {
-                        item.removeAttr(name);
+                        if (pattern[1].test(name)) {
+                            item.removeAttr(name);
+                        }
                     }
 
                 });
diff --git a/plugins/removeOffCanvasPaths.js b/plugins/removeOffCanvasPaths.js
new file mode 100644
index 0000000..5bcb9a1
--- /dev/null
+++ b/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/plugins/reusePaths.js b/plugins/reusePaths.js
new file mode 100644
index 0000000..ba097da
--- /dev/null
+++ b/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);
+  }
+}


Test patch:
diff --git a/test/coa/_index.js b/test/coa/_index.js
index 14820f9..ada38de 100644
--- a/test/coa/_index.js
+++ b/test/coa/_index.js
@@ -7,9 +7,11 @@ const fs = require('fs'),
     path = require('path'),
     svgPath = path.resolve(__dirname, 'test.svg'),
     svgFolderPath = path.resolve(__dirname, 'testSvg'),
+    svgFolderPathRecursively = path.resolve(__dirname, 'testSvgRecursively'),
     svgFiles = [path.resolve(__dirname, 'testSvg/test.svg'), path.resolve(__dirname, 'testSvg/test.1.svg')],
     tempFolder = 'temp',
     fse = require('fs-extra'),
+    checkIsDir = require('../../lib/svgo/tools.js').checkIsDir,
     noop = () => {};
 
 describe('coa', function() {
@@ -49,8 +51,10 @@ describe('coa', function() {
     }
 
     function calcFolderSvgWeight(folderPath) {
-        return fs.readdirSync(folderPath).reduce((initWeight, fileName) => (
-            initWeight + (/.svg/.test(fileName) ? fs.statSync(path.join(folderPath, fileName)).size : 0)
+        return fs.readdirSync(folderPath).reduce((initWeight, name) => (
+            initWeight +
+                (/.svg/.test(name) ? fs.statSync(path.join(folderPath, name)).size : 0) +
+                (checkIsDir(path.join(folderPath, name)) ? calcFolderSvgWeight(path.join(folderPath, name)) : 0)
         ), 0);
     }
 
@@ -82,6 +86,16 @@ describe('coa', function() {
         }, error => done(error));
     });
 
+    it('should optimize folder recursively', function(done) {
+        const initWeight = calcFolderSvgWeight(svgFolderPathRecursively);
+
+        svgo({ folder: svgFolderPathRecursively, output: tempFolder, quiet: true, recursive: true }).then(function() {
+            const optimizedWeight = calcFolderSvgWeight(svgFolderPathRecursively);
+
+            done(optimizedWeight > 0 && initWeight <= optimizedWeight ? null : 'Folder was not optimized');
+        }, error => done(error));
+    });
+
     it('should optimize file', function(done) {
         const initialFileLength = fs.readFileSync(path.resolve(__dirname, 'test.svg')).length;
 
diff --git a/test/coa/testSvgRecursively/depth-1/depth-2/test.1.svg b/test/coa/testSvgRecursively/depth-1/depth-2/test.1.svg
new file mode 100644
index 0000000..de7975d
--- /dev/null
+++ b/test/coa/testSvgRecursively/depth-1/depth-2/test.1.svg
@@ -0,0 +1,1 @@
+<!--! https://github.com/svg/svgo--><!--! SVGO project logo by Yegor Bolshakov (http://xizzzy.ru/)--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><defs><path id="a" d="M512 274.094v-36.191l-31.59-5.743a224.595 224.595 0 0 0-7.93-40.031l26.958-17.377-13.852-33.438-31.354 6.776a226.088 226.088 0 0 0-22.705-33.898l18.286-26.415-25.594-25.591-26.409 18.285a226.197 226.197 0 0 0-33.898-22.706l6.773-31.354-33.437-13.851-17.376 26.958a224.75 224.75 0 0 0-40.032-7.931L274.098 0h-36.193l-5.744 31.59a224.512 224.512 0 0 0-40.033 7.931l-17.376-26.959-33.438 13.851 6.776 31.354a226.053 226.053 0 0 0-33.899 22.706L87.776 62.185l-25.591 25.59 18.287 26.415a226.089 226.089 0 0 0-22.705 33.898l-31.355-6.776-13.85 33.438 26.959 17.377a224.567 224.567 0 0 0-7.93 40.03L0 237.902v36.191l31.59 5.744a224.484 224.484 0 0 0 7.931 40.032l-26.959 17.378 13.85 33.435 31.355-6.773a226.012 226.012 0 0 0 22.705 33.898l-18.287 26.414 25.591 25.593 26.415-18.287a225.977 225.977 0 0 0 33.899 22.706l-6.776 31.354 33.438 13.852 17.377-26.958a224.932 224.932 0 0 0 40.031 7.93l5.744 31.59h36.192l5.744-31.59a224.62 224.62 0 0 0 40.03-7.93l17.378 26.957 33.436-13.852-6.772-31.354a226.06 226.06 0 0 0 33.897-22.706l26.414 18.286 25.593-25.593-18.286-26.412a226.486 226.486 0 0 0 22.706-33.899l31.354 6.772 13.853-33.435-26.958-17.377a224.943 224.943 0 0 0 7.93-40.032L512 274.094z"/></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"/></clipPath><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="480.818" y1="380.617" x2="31.183" y2="131.38"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><circle clip-path="url(#b)" fill="url(#c)" cx="256" cy="255.998" r="257"/><radialGradient id="d" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".73" stop-color="#004ED4" stop-opacity=".4"/><stop offset=".784" stop-color="#437CDE" stop-opacity=".319"/><stop offset=".842" stop-color="#83A8E7" stop-opacity=".234"/><stop offset=".894" stop-color="#B5CAEE" stop-opacity=".157"/><stop offset=".94" stop-color="#DAE3F4" stop-opacity=".089"/><stop offset=".977" stop-color="#F0F2F7" stop-opacity=".035"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><circle clip-path="url(#b)" fill="url(#d)" cx="256" cy="255.998" r="257"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="352.299" y1="494.346" x2="159.701" y2="17.65"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#e)" cx="256" cy="255.998" r="257"/><radialGradient id="f" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".8" stop-color="#6B6B6B" stop-opacity="0"/><stop offset=".826" stop-color="#848484" stop-opacity=".02"/><stop offset=".883" stop-color="#B5B5B5" stop-opacity=".066"/><stop offset=".933" stop-color="#DADADA" stop-opacity=".107"/><stop offset=".974" stop-color="#F0F0F0" stop-opacity=".139"/><stop offset="1" stop-color="#F8F8F8" stop-opacity=".16"/></radialGradient><circle clip-path="url(#b)" fill="url(#f)" cx="256" cy="255.998" r="257"/><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="74.274" y1="437.724" x2="437.726" y2="74.272"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#g)" cx="256" cy="255.998" r="257"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="45.46" y1="403.419" x2="466.539" y2="108.576"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#h)" cx="256" cy="255.998" r="257"/><defs><path id="i" d="M256.001 50.999C142.777 50.999 51 142.774 51 255.998s91.777 204.999 205.001 204.999C369.226 460.997 461 369.222 461 255.998S369.226 50.999 256.001 50.999z"/></defs><clipPath id="j"><use xlink:href="#i" overflow="visible"/></clipPath><linearGradient id="k" gradientUnits="userSpaceOnUse" x1="441.158" y1="358.64" x2="70.835" y2="153.366" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#j)" fill="url(#k)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><radialGradient id="l" cx="255.997" cy="256.006" r="217.969" gradientTransform="matrix(0 -.971 .971 0 7.396 504.601)" gradientUnits="userSpaceOnUse"><stop offset=".86" stop-color="#0058D4" stop-opacity=".6"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#j)" fill="url(#l)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="335.313" y1="452.313" x2="176.686" y2="59.7" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#m)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="n" gradientUnits="userSpaceOnUse" x1="106.329" y1="405.673" x2="405.669" y2="106.333" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#n)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="o" gradientUnits="userSpaceOnUse" x1="82.599" y1="377.421" x2="429.401" y2="134.588" gradientTransform="rotate(-90 256 256)"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#o)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><defs><path id="p" d="M446 255.999c0-104.932-85.066-190-190-190s-190 85.068-190 190c0 104.934 85.066 189.998 190 189.998s190-85.064 190-189.998z"/></defs><clipPath id="q"><use xlink:href="#p" overflow="visible"/></clipPath><linearGradient id="r" gradientUnits="userSpaceOnUse" x1="427.61" y1="351.133" x2="84.388" y2="160.881"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#q)" fill="url(#r)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><radialGradient id="s" cx="260.891" cy="260.9" r="191.461" gradientTransform="matrix(.971 0 0 .971 7.397 7.398)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0037D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#s)" d="M446.679 260.746c0 102.678-83.253 185.939-185.931 185.939-102.677 0-185.928-83.262-185.928-185.939 0-102.676 83.25-185.915 185.928-185.915s185.931 83.239 185.931 185.915z"/><radialGradient id="t" cx="256" cy="256" r="197.367" gradientTransform="matrix(.973 0 0 .973 6.961 6.96)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0066D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#t)" d="M448 255.987C448 362.019 362.032 448 255.999 448 149.967 448 64 362.019 64 255.987 64 149.957 149.967 64 255.999 64 362.032 64 448 149.957 448 255.987z"/><linearGradient id="u" gradientUnits="userSpaceOnUse" x1="329.512" y1="437.945" x2="182.495" y2="74.067"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#u)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="v" gradientUnits="userSpaceOnUse" x1="117.285" y1="394.722" x2="394.718" y2="117.289"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#v)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="w" gradientUnits="userSpaceOnUse" x1="95.291" y1="368.536" x2="416.713" y2="143.474"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#w)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><defs><path id="x" d="M256.001 80.999C159.355 80.999 81 159.354 81 255.998c0 96.644 78.355 174.999 175.001 174.999 96.645 0 174.999-78.355 174.999-174.999 0-96.644-78.354-174.999-174.999-174.999z"/></defs><clipPath id="y"><use xlink:href="#x" overflow="visible"/></clipPath><linearGradient id="z" gradientUnits="userSpaceOnUse" x1="131.906" y1="131.904" x2="380.096" y2="380.094"><stop offset="0" stop-color="#14B9FF"/><stop offset="1" stop-color="#48007F"/></linearGradient><path clip-path="url(#y)" fill="url(#z)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="A" cx="256" cy="255.998" r="175.5" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".33" stop-color="#006CC2" stop-opacity="0"/><stop offset=".628" stop-color="#016EC3" stop-opacity=".232"/><stop offset=".736" stop-color="#0575C7" stop-opacity=".315"/><stop offset=".813" stop-color="#0D80CE" stop-opacity=".374"/><stop offset=".874" stop-color="#1791D8" stop-opacity=".422"/><stop offset=".927" stop-color="#25A7E4" stop-opacity=".464"/><stop offset=".974" stop-color="#36C2F4" stop-opacity=".499"/><stop offset="1" stop-color="#42D5FF" stop-opacity=".52"/></radialGradient><path clip-path="url(#y)" fill="url(#A)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="B" cx="202" cy="192.998" r="127" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#E1FFFF" stop-opacity=".5"/><stop offset=".093" stop-color="#D9F9FD" stop-opacity=".453"/><stop offset=".239" stop-color="#C3E7F6" stop-opacity=".38"/><stop offset=".42" stop-color="#9ECAEC" stop-opacity=".29"/><stop offset=".628" stop-color="#6CA2DE" stop-opacity=".186"/><stop offset=".855" stop-color="#2C6FCC" stop-opacity=".072"/><stop offset="1" stop-color="#004CBF" stop-opacity="0"/></radialGradient><path clip-path="url(#y)" fill="url(#B)" d="M202.001 65.999c-70.134 0-127.001 56.867-127.001 127 0 70.128 56.867 126.999 127.001 126.999C272.13 319.998 329 263.127 329 192.999c0-70.133-56.87-127-126.999-127z"/><path opacity=".31" clip-path="url(#y)" fill="#191919" d="M256.001 67C151.62 67 67 151.619 67 256s84.62 189 189.001 189S445 360.381 445 256 360.382 67 256.001 67zm0 361.481c-95.259 0-172.485-77.224-172.485-172.481 0-95.257 77.226-172.484 172.485-172.484 95.259 0 172.48 77.226 172.48 172.484 0 95.258-77.221 172.481-172.48 172.481z"/><path stroke="#E4EAF4" stroke-width="3" stroke-miterlimit="10" fill="none" d="M231.267 242.166l65.335-54.5m0 0L245.867 136.5m50.735 51.166l19.5-49.228m-84.835 103.728l-85.232-23.999m85.232 23.999l-50.7 70.334m50.7-70.334l56.6 63.4m0 0l72.334 24.301m-72.334-24.301l-34.564 63.967"/><defs><circle id="C" cx="231.267" cy="242.166" r="34.333"/></defs><clipPath id="D"><use xlink:href="#C" overflow="visible"/></clipPath><radialGradient id="E" cx="219.436" cy="230.335" r="51.497" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#D)" fill="url(#E)" cx="219.436" cy="230.335" r="51.498"/><radialGradient id="F" cx="228.484" cy="237.666" r="34.647" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EBF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDBF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C7EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#D)" fill="url(#F)" cx="229.934" cy="240.833" r="36.833"/><defs><circle id="G" cx="180.568" cy="312.5" r="24.033"/></defs><clipPath id="H"><use xlink:href="#G" overflow="visible"/></clipPath><radialGradient id="I" cx="172.285" cy="304.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#H)" fill="url(#I)" cx="172.285" cy="304.219" r="36.048"/><radialGradient id="J" cx="181.17" cy="304.201" r="24.252" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EAF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED9F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C4EF" stop-opacity=".712"/><stop offset="1" stop-color="#95AEE9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#H)" fill="url(#J)" cx="179.634" cy="311.566" r="25.783"/><defs><circle id="K" cx="288.801" cy="306.5" r="24.033"/></defs><clipPath id="L"><use xlink:href="#K" overflow="visible"/></clipPath><radialGradient id="M" cx="280.519" cy="298.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#L)" fill="url(#M)" cx="280.519" cy="298.219" r="36.048"/><radialGradient id="N" cx="282.978" cy="298.557" r="24.253" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F5FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E7F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED4F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2BBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95A2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#L)" fill="url(#N)" cx="287.867" cy="305.566" r="25.783"/><defs><circle id="O" cx="146.035" cy="218.167" r="17.167"/></defs><clipPath id="P"><use xlink:href="#O" overflow="visible"/></clipPath><radialGradient id="Q" cx="140.119" cy="212.251" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#P)" fill="url(#Q)" cx="140.119" cy="212.252" r="25.749"/><radialGradient id="R" cx="148.938" cy="215.719" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#P)" fill="url(#R)" cx="145.368" cy="217.5" r="18.416"/><defs><circle id="S" cx="296.603" cy="187.667" r="17.167"/></defs><clipPath id="T"><use xlink:href="#S" overflow="visible"/></clipPath><radialGradient id="U" cx="290.687" cy="181.751" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#T)" fill="url(#U)" cx="290.687" cy="181.751" r="25.749"/><radialGradient id="V" cx="290.568" cy="187.029" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2CBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95B7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#T)" fill="url(#V)" cx="295.936" cy="187" r="18.416"/><defs><circle id="W" cx="253.304" cy="369.533" r="17.167"/></defs><clipPath id="X"><use xlink:href="#W" overflow="visible"/></clipPath><radialGradient id="Y" cx="247.388" cy="363.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#X)" fill="url(#Y)" cx="247.388" cy="363.619" r="25.749"/><radialGradient id="Z" cx="249.839" cy="358.1" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CECFF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2B4EF" stop-opacity=".712"/><stop offset="1" stop-color="#9598E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#X)" fill="url(#Z)" cx="252.637" cy="368.867" r="18.416"/><defs><circle id="aa" cx="360.868" cy="330.533" r="17.167"/></defs><clipPath id="ab"><use xlink:href="#aa" overflow="visible"/></clipPath><radialGradient id="ac" cx="354.952" cy="324.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ac)" cx="354.952" cy="324.619" r="25.749"/><radialGradient id="ad" cx="351.019" cy="321.415" r="17.322" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FDFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F5F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E9E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#D7CEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#C0B2EF" stop-opacity=".712"/><stop offset="1" stop-color="#A995E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ad)" cx="360.201" cy="329.867" r="18.416"/><defs><circle id="ae" cx="245.867" cy="136.5" r="13.733"/></defs><clipPath id="af"><use xlink:href="#ae" overflow="visible"/></clipPath><radialGradient id="ag" cx="241.135" cy="131.768" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#af)" fill="url(#ag)" cx="241.135" cy="131.768" r="20.599"/><radialGradient id="ah" cx="242.97" cy="139.026" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#af)" fill="url(#ah)" cx="245.334" cy="135.967" r="14.733"/><defs><circle id="ai" cx="316.102" cy="138.438" r="13.733"/></defs><clipPath id="aj"><use xlink:href="#ai" overflow="visible"/></clipPath><radialGradient id="ak" cx="311.369" cy="133.706" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#aj)" fill="url(#ak)" cx="311.369" cy="133.707" r="20.599"/><radialGradient id="al" cx="309.035" cy="140.85" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDDF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C9EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B5E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#aj)" fill="url(#al)" cx="315.568" cy="137.905" r="14.733"/></svg>
\ No newline at end of file
diff --git a/test/coa/testSvgRecursively/depth-1/depth-2/test.svg b/test/coa/testSvgRecursively/depth-1/depth-2/test.svg
new file mode 100644
index 0000000..de7975d
--- /dev/null
+++ b/test/coa/testSvgRecursively/depth-1/depth-2/test.svg
@@ -0,0 +1,1 @@
+<!--! https://github.com/svg/svgo--><!--! SVGO project logo by Yegor Bolshakov (http://xizzzy.ru/)--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><defs><path id="a" d="M512 274.094v-36.191l-31.59-5.743a224.595 224.595 0 0 0-7.93-40.031l26.958-17.377-13.852-33.438-31.354 6.776a226.088 226.088 0 0 0-22.705-33.898l18.286-26.415-25.594-25.591-26.409 18.285a226.197 226.197 0 0 0-33.898-22.706l6.773-31.354-33.437-13.851-17.376 26.958a224.75 224.75 0 0 0-40.032-7.931L274.098 0h-36.193l-5.744 31.59a224.512 224.512 0 0 0-40.033 7.931l-17.376-26.959-33.438 13.851 6.776 31.354a226.053 226.053 0 0 0-33.899 22.706L87.776 62.185l-25.591 25.59 18.287 26.415a226.089 226.089 0 0 0-22.705 33.898l-31.355-6.776-13.85 33.438 26.959 17.377a224.567 224.567 0 0 0-7.93 40.03L0 237.902v36.191l31.59 5.744a224.484 224.484 0 0 0 7.931 40.032l-26.959 17.378 13.85 33.435 31.355-6.773a226.012 226.012 0 0 0 22.705 33.898l-18.287 26.414 25.591 25.593 26.415-18.287a225.977 225.977 0 0 0 33.899 22.706l-6.776 31.354 33.438 13.852 17.377-26.958a224.932 224.932 0 0 0 40.031 7.93l5.744 31.59h36.192l5.744-31.59a224.62 224.62 0 0 0 40.03-7.93l17.378 26.957 33.436-13.852-6.772-31.354a226.06 226.06 0 0 0 33.897-22.706l26.414 18.286 25.593-25.593-18.286-26.412a226.486 226.486 0 0 0 22.706-33.899l31.354 6.772 13.853-33.435-26.958-17.377a224.943 224.943 0 0 0 7.93-40.032L512 274.094z"/></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"/></clipPath><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="480.818" y1="380.617" x2="31.183" y2="131.38"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><circle clip-path="url(#b)" fill="url(#c)" cx="256" cy="255.998" r="257"/><radialGradient id="d" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".73" stop-color="#004ED4" stop-opacity=".4"/><stop offset=".784" stop-color="#437CDE" stop-opacity=".319"/><stop offset=".842" stop-color="#83A8E7" stop-opacity=".234"/><stop offset=".894" stop-color="#B5CAEE" stop-opacity=".157"/><stop offset=".94" stop-color="#DAE3F4" stop-opacity=".089"/><stop offset=".977" stop-color="#F0F2F7" stop-opacity=".035"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><circle clip-path="url(#b)" fill="url(#d)" cx="256" cy="255.998" r="257"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="352.299" y1="494.346" x2="159.701" y2="17.65"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#e)" cx="256" cy="255.998" r="257"/><radialGradient id="f" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".8" stop-color="#6B6B6B" stop-opacity="0"/><stop offset=".826" stop-color="#848484" stop-opacity=".02"/><stop offset=".883" stop-color="#B5B5B5" stop-opacity=".066"/><stop offset=".933" stop-color="#DADADA" stop-opacity=".107"/><stop offset=".974" stop-color="#F0F0F0" stop-opacity=".139"/><stop offset="1" stop-color="#F8F8F8" stop-opacity=".16"/></radialGradient><circle clip-path="url(#b)" fill="url(#f)" cx="256" cy="255.998" r="257"/><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="74.274" y1="437.724" x2="437.726" y2="74.272"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#g)" cx="256" cy="255.998" r="257"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="45.46" y1="403.419" x2="466.539" y2="108.576"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#h)" cx="256" cy="255.998" r="257"/><defs><path id="i" d="M256.001 50.999C142.777 50.999 51 142.774 51 255.998s91.777 204.999 205.001 204.999C369.226 460.997 461 369.222 461 255.998S369.226 50.999 256.001 50.999z"/></defs><clipPath id="j"><use xlink:href="#i" overflow="visible"/></clipPath><linearGradient id="k" gradientUnits="userSpaceOnUse" x1="441.158" y1="358.64" x2="70.835" y2="153.366" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#j)" fill="url(#k)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><radialGradient id="l" cx="255.997" cy="256.006" r="217.969" gradientTransform="matrix(0 -.971 .971 0 7.396 504.601)" gradientUnits="userSpaceOnUse"><stop offset=".86" stop-color="#0058D4" stop-opacity=".6"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#j)" fill="url(#l)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="335.313" y1="452.313" x2="176.686" y2="59.7" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#m)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="n" gradientUnits="userSpaceOnUse" x1="106.329" y1="405.673" x2="405.669" y2="106.333" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#n)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="o" gradientUnits="userSpaceOnUse" x1="82.599" y1="377.421" x2="429.401" y2="134.588" gradientTransform="rotate(-90 256 256)"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#o)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><defs><path id="p" d="M446 255.999c0-104.932-85.066-190-190-190s-190 85.068-190 190c0 104.934 85.066 189.998 190 189.998s190-85.064 190-189.998z"/></defs><clipPath id="q"><use xlink:href="#p" overflow="visible"/></clipPath><linearGradient id="r" gradientUnits="userSpaceOnUse" x1="427.61" y1="351.133" x2="84.388" y2="160.881"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#q)" fill="url(#r)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><radialGradient id="s" cx="260.891" cy="260.9" r="191.461" gradientTransform="matrix(.971 0 0 .971 7.397 7.398)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0037D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#s)" d="M446.679 260.746c0 102.678-83.253 185.939-185.931 185.939-102.677 0-185.928-83.262-185.928-185.939 0-102.676 83.25-185.915 185.928-185.915s185.931 83.239 185.931 185.915z"/><radialGradient id="t" cx="256" cy="256" r="197.367" gradientTransform="matrix(.973 0 0 .973 6.961 6.96)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0066D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#t)" d="M448 255.987C448 362.019 362.032 448 255.999 448 149.967 448 64 362.019 64 255.987 64 149.957 149.967 64 255.999 64 362.032 64 448 149.957 448 255.987z"/><linearGradient id="u" gradientUnits="userSpaceOnUse" x1="329.512" y1="437.945" x2="182.495" y2="74.067"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#u)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="v" gradientUnits="userSpaceOnUse" x1="117.285" y1="394.722" x2="394.718" y2="117.289"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#v)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="w" gradientUnits="userSpaceOnUse" x1="95.291" y1="368.536" x2="416.713" y2="143.474"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#w)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><defs><path id="x" d="M256.001 80.999C159.355 80.999 81 159.354 81 255.998c0 96.644 78.355 174.999 175.001 174.999 96.645 0 174.999-78.355 174.999-174.999 0-96.644-78.354-174.999-174.999-174.999z"/></defs><clipPath id="y"><use xlink:href="#x" overflow="visible"/></clipPath><linearGradient id="z" gradientUnits="userSpaceOnUse" x1="131.906" y1="131.904" x2="380.096" y2="380.094"><stop offset="0" stop-color="#14B9FF"/><stop offset="1" stop-color="#48007F"/></linearGradient><path clip-path="url(#y)" fill="url(#z)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="A" cx="256" cy="255.998" r="175.5" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".33" stop-color="#006CC2" stop-opacity="0"/><stop offset=".628" stop-color="#016EC3" stop-opacity=".232"/><stop offset=".736" stop-color="#0575C7" stop-opacity=".315"/><stop offset=".813" stop-color="#0D80CE" stop-opacity=".374"/><stop offset=".874" stop-color="#1791D8" stop-opacity=".422"/><stop offset=".927" stop-color="#25A7E4" stop-opacity=".464"/><stop offset=".974" stop-color="#36C2F4" stop-opacity=".499"/><stop offset="1" stop-color="#42D5FF" stop-opacity=".52"/></radialGradient><path clip-path="url(#y)" fill="url(#A)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="B" cx="202" cy="192.998" r="127" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#E1FFFF" stop-opacity=".5"/><stop offset=".093" stop-color="#D9F9FD" stop-opacity=".453"/><stop offset=".239" stop-color="#C3E7F6" stop-opacity=".38"/><stop offset=".42" stop-color="#9ECAEC" stop-opacity=".29"/><stop offset=".628" stop-color="#6CA2DE" stop-opacity=".186"/><stop offset=".855" stop-color="#2C6FCC" stop-opacity=".072"/><stop offset="1" stop-color="#004CBF" stop-opacity="0"/></radialGradient><path clip-path="url(#y)" fill="url(#B)" d="M202.001 65.999c-70.134 0-127.001 56.867-127.001 127 0 70.128 56.867 126.999 127.001 126.999C272.13 319.998 329 263.127 329 192.999c0-70.133-56.87-127-126.999-127z"/><path opacity=".31" clip-path="url(#y)" fill="#191919" d="M256.001 67C151.62 67 67 151.619 67 256s84.62 189 189.001 189S445 360.381 445 256 360.382 67 256.001 67zm0 361.481c-95.259 0-172.485-77.224-172.485-172.481 0-95.257 77.226-172.484 172.485-172.484 95.259 0 172.48 77.226 172.48 172.484 0 95.258-77.221 172.481-172.48 172.481z"/><path stroke="#E4EAF4" stroke-width="3" stroke-miterlimit="10" fill="none" d="M231.267 242.166l65.335-54.5m0 0L245.867 136.5m50.735 51.166l19.5-49.228m-84.835 103.728l-85.232-23.999m85.232 23.999l-50.7 70.334m50.7-70.334l56.6 63.4m0 0l72.334 24.301m-72.334-24.301l-34.564 63.967"/><defs><circle id="C" cx="231.267" cy="242.166" r="34.333"/></defs><clipPath id="D"><use xlink:href="#C" overflow="visible"/></clipPath><radialGradient id="E" cx="219.436" cy="230.335" r="51.497" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#D)" fill="url(#E)" cx="219.436" cy="230.335" r="51.498"/><radialGradient id="F" cx="228.484" cy="237.666" r="34.647" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EBF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDBF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C7EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#D)" fill="url(#F)" cx="229.934" cy="240.833" r="36.833"/><defs><circle id="G" cx="180.568" cy="312.5" r="24.033"/></defs><clipPath id="H"><use xlink:href="#G" overflow="visible"/></clipPath><radialGradient id="I" cx="172.285" cy="304.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#H)" fill="url(#I)" cx="172.285" cy="304.219" r="36.048"/><radialGradient id="J" cx="181.17" cy="304.201" r="24.252" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EAF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED9F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C4EF" stop-opacity=".712"/><stop offset="1" stop-color="#95AEE9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#H)" fill="url(#J)" cx="179.634" cy="311.566" r="25.783"/><defs><circle id="K" cx="288.801" cy="306.5" r="24.033"/></defs><clipPath id="L"><use xlink:href="#K" overflow="visible"/></clipPath><radialGradient id="M" cx="280.519" cy="298.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#L)" fill="url(#M)" cx="280.519" cy="298.219" r="36.048"/><radialGradient id="N" cx="282.978" cy="298.557" r="24.253" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F5FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E7F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED4F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2BBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95A2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#L)" fill="url(#N)" cx="287.867" cy="305.566" r="25.783"/><defs><circle id="O" cx="146.035" cy="218.167" r="17.167"/></defs><clipPath id="P"><use xlink:href="#O" overflow="visible"/></clipPath><radialGradient id="Q" cx="140.119" cy="212.251" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#P)" fill="url(#Q)" cx="140.119" cy="212.252" r="25.749"/><radialGradient id="R" cx="148.938" cy="215.719" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#P)" fill="url(#R)" cx="145.368" cy="217.5" r="18.416"/><defs><circle id="S" cx="296.603" cy="187.667" r="17.167"/></defs><clipPath id="T"><use xlink:href="#S" overflow="visible"/></clipPath><radialGradient id="U" cx="290.687" cy="181.751" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#T)" fill="url(#U)" cx="290.687" cy="181.751" r="25.749"/><radialGradient id="V" cx="290.568" cy="187.029" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2CBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95B7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#T)" fill="url(#V)" cx="295.936" cy="187" r="18.416"/><defs><circle id="W" cx="253.304" cy="369.533" r="17.167"/></defs><clipPath id="X"><use xlink:href="#W" overflow="visible"/></clipPath><radialGradient id="Y" cx="247.388" cy="363.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#X)" fill="url(#Y)" cx="247.388" cy="363.619" r="25.749"/><radialGradient id="Z" cx="249.839" cy="358.1" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CECFF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2B4EF" stop-opacity=".712"/><stop offset="1" stop-color="#9598E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#X)" fill="url(#Z)" cx="252.637" cy="368.867" r="18.416"/><defs><circle id="aa" cx="360.868" cy="330.533" r="17.167"/></defs><clipPath id="ab"><use xlink:href="#aa" overflow="visible"/></clipPath><radialGradient id="ac" cx="354.952" cy="324.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ac)" cx="354.952" cy="324.619" r="25.749"/><radialGradient id="ad" cx="351.019" cy="321.415" r="17.322" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FDFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F5F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E9E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#D7CEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#C0B2EF" stop-opacity=".712"/><stop offset="1" stop-color="#A995E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ad)" cx="360.201" cy="329.867" r="18.416"/><defs><circle id="ae" cx="245.867" cy="136.5" r="13.733"/></defs><clipPath id="af"><use xlink:href="#ae" overflow="visible"/></clipPath><radialGradient id="ag" cx="241.135" cy="131.768" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#af)" fill="url(#ag)" cx="241.135" cy="131.768" r="20.599"/><radialGradient id="ah" cx="242.97" cy="139.026" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#af)" fill="url(#ah)" cx="245.334" cy="135.967" r="14.733"/><defs><circle id="ai" cx="316.102" cy="138.438" r="13.733"/></defs><clipPath id="aj"><use xlink:href="#ai" overflow="visible"/></clipPath><radialGradient id="ak" cx="311.369" cy="133.706" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#aj)" fill="url(#ak)" cx="311.369" cy="133.707" r="20.599"/><radialGradient id="al" cx="309.035" cy="140.85" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDDF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C9EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B5E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#aj)" fill="url(#al)" cx="315.568" cy="137.905" r="14.733"/></svg>
\ No newline at end of file
diff --git a/test/coa/testSvgRecursively/test.1.svg b/test/coa/testSvgRecursively/test.1.svg
new file mode 100644
index 0000000..de7975d
--- /dev/null
+++ b/test/coa/testSvgRecursively/test.1.svg
@@ -0,0 +1,1 @@
+<!--! https://github.com/svg/svgo--><!--! SVGO project logo by Yegor Bolshakov (http://xizzzy.ru/)--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><defs><path id="a" d="M512 274.094v-36.191l-31.59-5.743a224.595 224.595 0 0 0-7.93-40.031l26.958-17.377-13.852-33.438-31.354 6.776a226.088 226.088 0 0 0-22.705-33.898l18.286-26.415-25.594-25.591-26.409 18.285a226.197 226.197 0 0 0-33.898-22.706l6.773-31.354-33.437-13.851-17.376 26.958a224.75 224.75 0 0 0-40.032-7.931L274.098 0h-36.193l-5.744 31.59a224.512 224.512 0 0 0-40.033 7.931l-17.376-26.959-33.438 13.851 6.776 31.354a226.053 226.053 0 0 0-33.899 22.706L87.776 62.185l-25.591 25.59 18.287 26.415a226.089 226.089 0 0 0-22.705 33.898l-31.355-6.776-13.85 33.438 26.959 17.377a224.567 224.567 0 0 0-7.93 40.03L0 237.902v36.191l31.59 5.744a224.484 224.484 0 0 0 7.931 40.032l-26.959 17.378 13.85 33.435 31.355-6.773a226.012 226.012 0 0 0 22.705 33.898l-18.287 26.414 25.591 25.593 26.415-18.287a225.977 225.977 0 0 0 33.899 22.706l-6.776 31.354 33.438 13.852 17.377-26.958a224.932 224.932 0 0 0 40.031 7.93l5.744 31.59h36.192l5.744-31.59a224.62 224.62 0 0 0 40.03-7.93l17.378 26.957 33.436-13.852-6.772-31.354a226.06 226.06 0 0 0 33.897-22.706l26.414 18.286 25.593-25.593-18.286-26.412a226.486 226.486 0 0 0 22.706-33.899l31.354 6.772 13.853-33.435-26.958-17.377a224.943 224.943 0 0 0 7.93-40.032L512 274.094z"/></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"/></clipPath><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="480.818" y1="380.617" x2="31.183" y2="131.38"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><circle clip-path="url(#b)" fill="url(#c)" cx="256" cy="255.998" r="257"/><radialGradient id="d" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".73" stop-color="#004ED4" stop-opacity=".4"/><stop offset=".784" stop-color="#437CDE" stop-opacity=".319"/><stop offset=".842" stop-color="#83A8E7" stop-opacity=".234"/><stop offset=".894" stop-color="#B5CAEE" stop-opacity=".157"/><stop offset=".94" stop-color="#DAE3F4" stop-opacity=".089"/><stop offset=".977" stop-color="#F0F2F7" stop-opacity=".035"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><circle clip-path="url(#b)" fill="url(#d)" cx="256" cy="255.998" r="257"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="352.299" y1="494.346" x2="159.701" y2="17.65"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#e)" cx="256" cy="255.998" r="257"/><radialGradient id="f" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".8" stop-color="#6B6B6B" stop-opacity="0"/><stop offset=".826" stop-color="#848484" stop-opacity=".02"/><stop offset=".883" stop-color="#B5B5B5" stop-opacity=".066"/><stop offset=".933" stop-color="#DADADA" stop-opacity=".107"/><stop offset=".974" stop-color="#F0F0F0" stop-opacity=".139"/><stop offset="1" stop-color="#F8F8F8" stop-opacity=".16"/></radialGradient><circle clip-path="url(#b)" fill="url(#f)" cx="256" cy="255.998" r="257"/><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="74.274" y1="437.724" x2="437.726" y2="74.272"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#g)" cx="256" cy="255.998" r="257"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="45.46" y1="403.419" x2="466.539" y2="108.576"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#h)" cx="256" cy="255.998" r="257"/><defs><path id="i" d="M256.001 50.999C142.777 50.999 51 142.774 51 255.998s91.777 204.999 205.001 204.999C369.226 460.997 461 369.222 461 255.998S369.226 50.999 256.001 50.999z"/></defs><clipPath id="j"><use xlink:href="#i" overflow="visible"/></clipPath><linearGradient id="k" gradientUnits="userSpaceOnUse" x1="441.158" y1="358.64" x2="70.835" y2="153.366" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#j)" fill="url(#k)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><radialGradient id="l" cx="255.997" cy="256.006" r="217.969" gradientTransform="matrix(0 -.971 .971 0 7.396 504.601)" gradientUnits="userSpaceOnUse"><stop offset=".86" stop-color="#0058D4" stop-opacity=".6"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#j)" fill="url(#l)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="335.313" y1="452.313" x2="176.686" y2="59.7" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#m)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="n" gradientUnits="userSpaceOnUse" x1="106.329" y1="405.673" x2="405.669" y2="106.333" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#n)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="o" gradientUnits="userSpaceOnUse" x1="82.599" y1="377.421" x2="429.401" y2="134.588" gradientTransform="rotate(-90 256 256)"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#o)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><defs><path id="p" d="M446 255.999c0-104.932-85.066-190-190-190s-190 85.068-190 190c0 104.934 85.066 189.998 190 189.998s190-85.064 190-189.998z"/></defs><clipPath id="q"><use xlink:href="#p" overflow="visible"/></clipPath><linearGradient id="r" gradientUnits="userSpaceOnUse" x1="427.61" y1="351.133" x2="84.388" y2="160.881"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#q)" fill="url(#r)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><radialGradient id="s" cx="260.891" cy="260.9" r="191.461" gradientTransform="matrix(.971 0 0 .971 7.397 7.398)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0037D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#s)" d="M446.679 260.746c0 102.678-83.253 185.939-185.931 185.939-102.677 0-185.928-83.262-185.928-185.939 0-102.676 83.25-185.915 185.928-185.915s185.931 83.239 185.931 185.915z"/><radialGradient id="t" cx="256" cy="256" r="197.367" gradientTransform="matrix(.973 0 0 .973 6.961 6.96)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0066D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#t)" d="M448 255.987C448 362.019 362.032 448 255.999 448 149.967 448 64 362.019 64 255.987 64 149.957 149.967 64 255.999 64 362.032 64 448 149.957 448 255.987z"/><linearGradient id="u" gradientUnits="userSpaceOnUse" x1="329.512" y1="437.945" x2="182.495" y2="74.067"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#u)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="v" gradientUnits="userSpaceOnUse" x1="117.285" y1="394.722" x2="394.718" y2="117.289"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#v)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="w" gradientUnits="userSpaceOnUse" x1="95.291" y1="368.536" x2="416.713" y2="143.474"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#w)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><defs><path id="x" d="M256.001 80.999C159.355 80.999 81 159.354 81 255.998c0 96.644 78.355 174.999 175.001 174.999 96.645 0 174.999-78.355 174.999-174.999 0-96.644-78.354-174.999-174.999-174.999z"/></defs><clipPath id="y"><use xlink:href="#x" overflow="visible"/></clipPath><linearGradient id="z" gradientUnits="userSpaceOnUse" x1="131.906" y1="131.904" x2="380.096" y2="380.094"><stop offset="0" stop-color="#14B9FF"/><stop offset="1" stop-color="#48007F"/></linearGradient><path clip-path="url(#y)" fill="url(#z)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="A" cx="256" cy="255.998" r="175.5" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".33" stop-color="#006CC2" stop-opacity="0"/><stop offset=".628" stop-color="#016EC3" stop-opacity=".232"/><stop offset=".736" stop-color="#0575C7" stop-opacity=".315"/><stop offset=".813" stop-color="#0D80CE" stop-opacity=".374"/><stop offset=".874" stop-color="#1791D8" stop-opacity=".422"/><stop offset=".927" stop-color="#25A7E4" stop-opacity=".464"/><stop offset=".974" stop-color="#36C2F4" stop-opacity=".499"/><stop offset="1" stop-color="#42D5FF" stop-opacity=".52"/></radialGradient><path clip-path="url(#y)" fill="url(#A)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="B" cx="202" cy="192.998" r="127" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#E1FFFF" stop-opacity=".5"/><stop offset=".093" stop-color="#D9F9FD" stop-opacity=".453"/><stop offset=".239" stop-color="#C3E7F6" stop-opacity=".38"/><stop offset=".42" stop-color="#9ECAEC" stop-opacity=".29"/><stop offset=".628" stop-color="#6CA2DE" stop-opacity=".186"/><stop offset=".855" stop-color="#2C6FCC" stop-opacity=".072"/><stop offset="1" stop-color="#004CBF" stop-opacity="0"/></radialGradient><path clip-path="url(#y)" fill="url(#B)" d="M202.001 65.999c-70.134 0-127.001 56.867-127.001 127 0 70.128 56.867 126.999 127.001 126.999C272.13 319.998 329 263.127 329 192.999c0-70.133-56.87-127-126.999-127z"/><path opacity=".31" clip-path="url(#y)" fill="#191919" d="M256.001 67C151.62 67 67 151.619 67 256s84.62 189 189.001 189S445 360.381 445 256 360.382 67 256.001 67zm0 361.481c-95.259 0-172.485-77.224-172.485-172.481 0-95.257 77.226-172.484 172.485-172.484 95.259 0 172.48 77.226 172.48 172.484 0 95.258-77.221 172.481-172.48 172.481z"/><path stroke="#E4EAF4" stroke-width="3" stroke-miterlimit="10" fill="none" d="M231.267 242.166l65.335-54.5m0 0L245.867 136.5m50.735 51.166l19.5-49.228m-84.835 103.728l-85.232-23.999m85.232 23.999l-50.7 70.334m50.7-70.334l56.6 63.4m0 0l72.334 24.301m-72.334-24.301l-34.564 63.967"/><defs><circle id="C" cx="231.267" cy="242.166" r="34.333"/></defs><clipPath id="D"><use xlink:href="#C" overflow="visible"/></clipPath><radialGradient id="E" cx="219.436" cy="230.335" r="51.497" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#D)" fill="url(#E)" cx="219.436" cy="230.335" r="51.498"/><radialGradient id="F" cx="228.484" cy="237.666" r="34.647" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EBF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDBF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C7EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#D)" fill="url(#F)" cx="229.934" cy="240.833" r="36.833"/><defs><circle id="G" cx="180.568" cy="312.5" r="24.033"/></defs><clipPath id="H"><use xlink:href="#G" overflow="visible"/></clipPath><radialGradient id="I" cx="172.285" cy="304.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#H)" fill="url(#I)" cx="172.285" cy="304.219" r="36.048"/><radialGradient id="J" cx="181.17" cy="304.201" r="24.252" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EAF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED9F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C4EF" stop-opacity=".712"/><stop offset="1" stop-color="#95AEE9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#H)" fill="url(#J)" cx="179.634" cy="311.566" r="25.783"/><defs><circle id="K" cx="288.801" cy="306.5" r="24.033"/></defs><clipPath id="L"><use xlink:href="#K" overflow="visible"/></clipPath><radialGradient id="M" cx="280.519" cy="298.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#L)" fill="url(#M)" cx="280.519" cy="298.219" r="36.048"/><radialGradient id="N" cx="282.978" cy="298.557" r="24.253" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F5FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E7F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED4F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2BBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95A2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#L)" fill="url(#N)" cx="287.867" cy="305.566" r="25.783"/><defs><circle id="O" cx="146.035" cy="218.167" r="17.167"/></defs><clipPath id="P"><use xlink:href="#O" overflow="visible"/></clipPath><radialGradient id="Q" cx="140.119" cy="212.251" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#P)" fill="url(#Q)" cx="140.119" cy="212.252" r="25.749"/><radialGradient id="R" cx="148.938" cy="215.719" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#P)" fill="url(#R)" cx="145.368" cy="217.5" r="18.416"/><defs><circle id="S" cx="296.603" cy="187.667" r="17.167"/></defs><clipPath id="T"><use xlink:href="#S" overflow="visible"/></clipPath><radialGradient id="U" cx="290.687" cy="181.751" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#T)" fill="url(#U)" cx="290.687" cy="181.751" r="25.749"/><radialGradient id="V" cx="290.568" cy="187.029" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2CBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95B7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#T)" fill="url(#V)" cx="295.936" cy="187" r="18.416"/><defs><circle id="W" cx="253.304" cy="369.533" r="17.167"/></defs><clipPath id="X"><use xlink:href="#W" overflow="visible"/></clipPath><radialGradient id="Y" cx="247.388" cy="363.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#X)" fill="url(#Y)" cx="247.388" cy="363.619" r="25.749"/><radialGradient id="Z" cx="249.839" cy="358.1" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CECFF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2B4EF" stop-opacity=".712"/><stop offset="1" stop-color="#9598E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#X)" fill="url(#Z)" cx="252.637" cy="368.867" r="18.416"/><defs><circle id="aa" cx="360.868" cy="330.533" r="17.167"/></defs><clipPath id="ab"><use xlink:href="#aa" overflow="visible"/></clipPath><radialGradient id="ac" cx="354.952" cy="324.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ac)" cx="354.952" cy="324.619" r="25.749"/><radialGradient id="ad" cx="351.019" cy="321.415" r="17.322" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FDFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F5F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E9E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#D7CEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#C0B2EF" stop-opacity=".712"/><stop offset="1" stop-color="#A995E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ad)" cx="360.201" cy="329.867" r="18.416"/><defs><circle id="ae" cx="245.867" cy="136.5" r="13.733"/></defs><clipPath id="af"><use xlink:href="#ae" overflow="visible"/></clipPath><radialGradient id="ag" cx="241.135" cy="131.768" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#af)" fill="url(#ag)" cx="241.135" cy="131.768" r="20.599"/><radialGradient id="ah" cx="242.97" cy="139.026" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#af)" fill="url(#ah)" cx="245.334" cy="135.967" r="14.733"/><defs><circle id="ai" cx="316.102" cy="138.438" r="13.733"/></defs><clipPath id="aj"><use xlink:href="#ai" overflow="visible"/></clipPath><radialGradient id="ak" cx="311.369" cy="133.706" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#aj)" fill="url(#ak)" cx="311.369" cy="133.707" r="20.599"/><radialGradient id="al" cx="309.035" cy="140.85" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDDF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C9EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B5E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#aj)" fill="url(#al)" cx="315.568" cy="137.905" r="14.733"/></svg>
\ No newline at end of file
diff --git a/test/coa/testSvgRecursively/test.svg b/test/coa/testSvgRecursively/test.svg
new file mode 100644
index 0000000..de7975d
--- /dev/null
+++ b/test/coa/testSvgRecursively/test.svg
@@ -0,0 +1,1 @@
+<!--! https://github.com/svg/svgo--><!--! SVGO project logo by Yegor Bolshakov (http://xizzzy.ru/)--><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><defs><path id="a" d="M512 274.094v-36.191l-31.59-5.743a224.595 224.595 0 0 0-7.93-40.031l26.958-17.377-13.852-33.438-31.354 6.776a226.088 226.088 0 0 0-22.705-33.898l18.286-26.415-25.594-25.591-26.409 18.285a226.197 226.197 0 0 0-33.898-22.706l6.773-31.354-33.437-13.851-17.376 26.958a224.75 224.75 0 0 0-40.032-7.931L274.098 0h-36.193l-5.744 31.59a224.512 224.512 0 0 0-40.033 7.931l-17.376-26.959-33.438 13.851 6.776 31.354a226.053 226.053 0 0 0-33.899 22.706L87.776 62.185l-25.591 25.59 18.287 26.415a226.089 226.089 0 0 0-22.705 33.898l-31.355-6.776-13.85 33.438 26.959 17.377a224.567 224.567 0 0 0-7.93 40.03L0 237.902v36.191l31.59 5.744a224.484 224.484 0 0 0 7.931 40.032l-26.959 17.378 13.85 33.435 31.355-6.773a226.012 226.012 0 0 0 22.705 33.898l-18.287 26.414 25.591 25.593 26.415-18.287a225.977 225.977 0 0 0 33.899 22.706l-6.776 31.354 33.438 13.852 17.377-26.958a224.932 224.932 0 0 0 40.031 7.93l5.744 31.59h36.192l5.744-31.59a224.62 224.62 0 0 0 40.03-7.93l17.378 26.957 33.436-13.852-6.772-31.354a226.06 226.06 0 0 0 33.897-22.706l26.414 18.286 25.593-25.593-18.286-26.412a226.486 226.486 0 0 0 22.706-33.899l31.354 6.772 13.853-33.435-26.958-17.377a224.943 224.943 0 0 0 7.93-40.032L512 274.094z"/></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"/></clipPath><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="480.818" y1="380.617" x2="31.183" y2="131.38"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><circle clip-path="url(#b)" fill="url(#c)" cx="256" cy="255.998" r="257"/><radialGradient id="d" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".73" stop-color="#004ED4" stop-opacity=".4"/><stop offset=".784" stop-color="#437CDE" stop-opacity=".319"/><stop offset=".842" stop-color="#83A8E7" stop-opacity=".234"/><stop offset=".894" stop-color="#B5CAEE" stop-opacity=".157"/><stop offset=".94" stop-color="#DAE3F4" stop-opacity=".089"/><stop offset=".977" stop-color="#F0F2F7" stop-opacity=".035"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><circle clip-path="url(#b)" fill="url(#d)" cx="256" cy="255.998" r="257"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="352.299" y1="494.346" x2="159.701" y2="17.65"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#e)" cx="256" cy="255.998" r="257"/><radialGradient id="f" cx="256" cy="255.998" r="257" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".8" stop-color="#6B6B6B" stop-opacity="0"/><stop offset=".826" stop-color="#848484" stop-opacity=".02"/><stop offset=".883" stop-color="#B5B5B5" stop-opacity=".066"/><stop offset=".933" stop-color="#DADADA" stop-opacity=".107"/><stop offset=".974" stop-color="#F0F0F0" stop-opacity=".139"/><stop offset="1" stop-color="#F8F8F8" stop-opacity=".16"/></radialGradient><circle clip-path="url(#b)" fill="url(#f)" cx="256" cy="255.998" r="257"/><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="74.274" y1="437.724" x2="437.726" y2="74.272"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#g)" cx="256" cy="255.998" r="257"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="45.46" y1="403.419" x2="466.539" y2="108.576"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><circle clip-path="url(#b)" fill="url(#h)" cx="256" cy="255.998" r="257"/><defs><path id="i" d="M256.001 50.999C142.777 50.999 51 142.774 51 255.998s91.777 204.999 205.001 204.999C369.226 460.997 461 369.222 461 255.998S369.226 50.999 256.001 50.999z"/></defs><clipPath id="j"><use xlink:href="#i" overflow="visible"/></clipPath><linearGradient id="k" gradientUnits="userSpaceOnUse" x1="441.158" y1="358.64" x2="70.835" y2="153.366" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#j)" fill="url(#k)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><radialGradient id="l" cx="255.997" cy="256.006" r="217.969" gradientTransform="matrix(0 -.971 .971 0 7.396 504.601)" gradientUnits="userSpaceOnUse"><stop offset=".86" stop-color="#0058D4" stop-opacity=".6"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#j)" fill="url(#l)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="335.313" y1="452.313" x2="176.686" y2="59.7" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#m)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="n" gradientUnits="userSpaceOnUse" x1="106.329" y1="405.673" x2="405.669" y2="106.333" gradientTransform="rotate(-90 256 256)"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#n)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><linearGradient id="o" gradientUnits="userSpaceOnUse" x1="82.599" y1="377.421" x2="429.401" y2="134.588" gradientTransform="rotate(-90 256 256)"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#j)" fill="url(#o)" d="M256 44.334c116.894 0 211.676 94.771 211.676 211.664S372.894 467.673 256 467.673c-116.893 0-211.665-94.782-211.665-211.675S139.107 44.334 256 44.334z"/><defs><path id="p" d="M446 255.999c0-104.932-85.066-190-190-190s-190 85.068-190 190c0 104.934 85.066 189.998 190 189.998s190-85.064 190-189.998z"/></defs><clipPath id="q"><use xlink:href="#p" overflow="visible"/></clipPath><linearGradient id="r" gradientUnits="userSpaceOnUse" x1="427.61" y1="351.133" x2="84.388" y2="160.881"><stop offset="0" stop-color="#BDC6C9"/><stop offset=".092" stop-color="#ABB4B7"/><stop offset=".277" stop-color="#7D8588"/><stop offset=".483" stop-color="#444A4D"/><stop offset=".584" stop-color="#5E6669"/><stop offset=".772" stop-color="#899396"/><stop offset=".916" stop-color="#A3AFB2"/><stop offset="1" stop-color="#ADBABD"/></linearGradient><path clip-path="url(#q)" fill="url(#r)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><radialGradient id="s" cx="260.891" cy="260.9" r="191.461" gradientTransform="matrix(.971 0 0 .971 7.397 7.398)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0037D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#s)" d="M446.679 260.746c0 102.678-83.253 185.939-185.931 185.939-102.677 0-185.928-83.262-185.928-185.939 0-102.676 83.25-185.915 185.928-185.915s185.931 83.239 185.931 185.915z"/><radialGradient id="t" cx="256" cy="256" r="197.367" gradientTransform="matrix(.973 0 0 .973 6.961 6.96)" gradientUnits="userSpaceOnUse"><stop offset=".88" stop-color="#0066D4"/><stop offset="1" stop-color="#F8F8F8" stop-opacity="0"/></radialGradient><path clip-path="url(#q)" fill="url(#t)" d="M448 255.987C448 362.019 362.032 448 255.999 448 149.967 448 64 362.019 64 255.987 64 149.957 149.967 64 255.999 64 362.032 64 448 149.957 448 255.987z"/><linearGradient id="u" gradientUnits="userSpaceOnUse" x1="329.512" y1="437.945" x2="182.495" y2="74.067"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#4D5057" stop-opacity=".75"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#u)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="v" gradientUnits="userSpaceOnUse" x1="117.285" y1="394.722" x2="394.718" y2="117.289"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#828282" stop-opacity=".6"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#v)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><linearGradient id="w" gradientUnits="userSpaceOnUse" x1="95.291" y1="368.536" x2="416.713" y2="143.474"><stop offset=".2" stop-color="#fff" stop-opacity="0"/><stop offset=".5" stop-color="#fff" stop-opacity=".36"/><stop offset=".8" stop-color="#fff" stop-opacity="0"/></linearGradient><path clip-path="url(#q)" fill="url(#w)" d="M452.182 255.998c0 108.338-87.844 196.19-196.182 196.19-108.339 0-196.179-87.853-196.179-196.19S147.661 59.832 256 59.832c108.338 0 196.182 87.829 196.182 196.166z"/><defs><path id="x" d="M256.001 80.999C159.355 80.999 81 159.354 81 255.998c0 96.644 78.355 174.999 175.001 174.999 96.645 0 174.999-78.355 174.999-174.999 0-96.644-78.354-174.999-174.999-174.999z"/></defs><clipPath id="y"><use xlink:href="#x" overflow="visible"/></clipPath><linearGradient id="z" gradientUnits="userSpaceOnUse" x1="131.906" y1="131.904" x2="380.096" y2="380.094"><stop offset="0" stop-color="#14B9FF"/><stop offset="1" stop-color="#48007F"/></linearGradient><path clip-path="url(#y)" fill="url(#z)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="A" cx="256" cy="255.998" r="175.5" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset=".33" stop-color="#006CC2" stop-opacity="0"/><stop offset=".628" stop-color="#016EC3" stop-opacity=".232"/><stop offset=".736" stop-color="#0575C7" stop-opacity=".315"/><stop offset=".813" stop-color="#0D80CE" stop-opacity=".374"/><stop offset=".874" stop-color="#1791D8" stop-opacity=".422"/><stop offset=".927" stop-color="#25A7E4" stop-opacity=".464"/><stop offset=".974" stop-color="#36C2F4" stop-opacity=".499"/><stop offset="1" stop-color="#42D5FF" stop-opacity=".52"/></radialGradient><path clip-path="url(#y)" fill="url(#A)" d="M256.001 80.499c-96.922 0-175.501 78.578-175.501 175.499 0 96.92 78.579 175.499 175.501 175.499 96.921 0 175.499-78.579 175.499-175.499 0-96.921-78.578-175.499-175.499-175.499z"/><radialGradient id="B" cx="202" cy="192.998" r="127" gradientTransform="translate(0 .001)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#E1FFFF" stop-opacity=".5"/><stop offset=".093" stop-color="#D9F9FD" stop-opacity=".453"/><stop offset=".239" stop-color="#C3E7F6" stop-opacity=".38"/><stop offset=".42" stop-color="#9ECAEC" stop-opacity=".29"/><stop offset=".628" stop-color="#6CA2DE" stop-opacity=".186"/><stop offset=".855" stop-color="#2C6FCC" stop-opacity=".072"/><stop offset="1" stop-color="#004CBF" stop-opacity="0"/></radialGradient><path clip-path="url(#y)" fill="url(#B)" d="M202.001 65.999c-70.134 0-127.001 56.867-127.001 127 0 70.128 56.867 126.999 127.001 126.999C272.13 319.998 329 263.127 329 192.999c0-70.133-56.87-127-126.999-127z"/><path opacity=".31" clip-path="url(#y)" fill="#191919" d="M256.001 67C151.62 67 67 151.619 67 256s84.62 189 189.001 189S445 360.381 445 256 360.382 67 256.001 67zm0 361.481c-95.259 0-172.485-77.224-172.485-172.481 0-95.257 77.226-172.484 172.485-172.484 95.259 0 172.48 77.226 172.48 172.484 0 95.258-77.221 172.481-172.48 172.481z"/><path stroke="#E4EAF4" stroke-width="3" stroke-miterlimit="10" fill="none" d="M231.267 242.166l65.335-54.5m0 0L245.867 136.5m50.735 51.166l19.5-49.228m-84.835 103.728l-85.232-23.999m85.232 23.999l-50.7 70.334m50.7-70.334l56.6 63.4m0 0l72.334 24.301m-72.334-24.301l-34.564 63.967"/><defs><circle id="C" cx="231.267" cy="242.166" r="34.333"/></defs><clipPath id="D"><use xlink:href="#C" overflow="visible"/></clipPath><radialGradient id="E" cx="219.436" cy="230.335" r="51.497" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#D)" fill="url(#E)" cx="219.436" cy="230.335" r="51.498"/><radialGradient id="F" cx="228.484" cy="237.666" r="34.647" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EBF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDBF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C7EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#D)" fill="url(#F)" cx="229.934" cy="240.833" r="36.833"/><defs><circle id="G" cx="180.568" cy="312.5" r="24.033"/></defs><clipPath id="H"><use xlink:href="#G" overflow="visible"/></clipPath><radialGradient id="I" cx="172.285" cy="304.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#H)" fill="url(#I)" cx="172.285" cy="304.219" r="36.048"/><radialGradient id="J" cx="181.17" cy="304.201" r="24.252" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F6FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4EAF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED9F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C4EF" stop-opacity=".712"/><stop offset="1" stop-color="#95AEE9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#H)" fill="url(#J)" cx="179.634" cy="311.566" r="25.783"/><defs><circle id="K" cx="288.801" cy="306.5" r="24.033"/></defs><clipPath id="L"><use xlink:href="#K" overflow="visible"/></clipPath><radialGradient id="M" cx="280.519" cy="298.218" r="36.048" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#L)" fill="url(#M)" cx="280.519" cy="298.219" r="36.048"/><radialGradient id="N" cx="282.978" cy="298.557" r="24.253" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F5FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E7F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CED4F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2BBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95A2E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#L)" fill="url(#N)" cx="287.867" cy="305.566" r="25.783"/><defs><circle id="O" cx="146.035" cy="218.167" r="17.167"/></defs><clipPath id="P"><use xlink:href="#O" overflow="visible"/></clipPath><radialGradient id="Q" cx="140.119" cy="212.251" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#P)" fill="url(#Q)" cx="140.119" cy="212.252" r="25.749"/><radialGradient id="R" cx="148.938" cy="215.719" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#P)" fill="url(#R)" cx="145.368" cy="217.5" r="18.416"/><defs><circle id="S" cx="296.603" cy="187.667" r="17.167"/></defs><clipPath id="T"><use xlink:href="#S" overflow="visible"/></clipPath><radialGradient id="U" cx="290.687" cy="181.751" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#T)" fill="url(#U)" cx="290.687" cy="181.751" r="25.749"/><radialGradient id="V" cx="290.568" cy="187.029" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2CBEF" stop-opacity=".712"/><stop offset="1" stop-color="#95B7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#T)" fill="url(#V)" cx="295.936" cy="187" r="18.416"/><defs><circle id="W" cx="253.304" cy="369.533" r="17.167"/></defs><clipPath id="X"><use xlink:href="#W" overflow="visible"/></clipPath><radialGradient id="Y" cx="247.388" cy="363.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#X)" fill="url(#Y)" cx="247.388" cy="363.619" r="25.749"/><radialGradient id="Z" cx="249.839" cy="358.1" r="17.323" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CECFF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2B4EF" stop-opacity=".712"/><stop offset="1" stop-color="#9598E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#X)" fill="url(#Z)" cx="252.637" cy="368.867" r="18.416"/><defs><circle id="aa" cx="360.868" cy="330.533" r="17.167"/></defs><clipPath id="ab"><use xlink:href="#aa" overflow="visible"/></clipPath><radialGradient id="ac" cx="354.952" cy="324.618" r="25.749" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ac)" cx="354.952" cy="324.619" r="25.749"/><radialGradient id="ad" cx="351.019" cy="321.415" r="17.322" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FDFCFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F5F3FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E9E4F9" stop-opacity=".487"/><stop offset=".755" stop-color="#D7CEF5" stop-opacity=".604"/><stop offset=".89" stop-color="#C0B2EF" stop-opacity=".712"/><stop offset="1" stop-color="#A995E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#ab)" fill="url(#ad)" cx="360.201" cy="329.867" r="18.416"/><defs><circle id="ae" cx="245.867" cy="136.5" r="13.733"/></defs><clipPath id="af"><use xlink:href="#ae" overflow="visible"/></clipPath><radialGradient id="ag" cx="241.135" cy="131.768" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#af)" fill="url(#ag)" cx="241.135" cy="131.768" r="20.599"/><radialGradient id="ah" cx="242.97" cy="139.026" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFEFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F9FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4F1F9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEE5F5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2D6EF" stop-opacity=".712"/><stop offset="1" stop-color="#95C7E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#af)" fill="url(#ah)" cx="245.334" cy="135.967" r="14.733"/><defs><circle id="ai" cx="316.102" cy="138.438" r="13.733"/></defs><clipPath id="aj"><use xlink:href="#ai" overflow="visible"/></clipPath><radialGradient id="ak" cx="311.369" cy="133.706" r="20.599" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#B8C4D1"/></radialGradient><circle clip-path="url(#aj)" fill="url(#ak)" cx="311.369" cy="133.707" r="20.599"/><radialGradient id="al" cx="309.035" cy="140.85" r="13.859" gradientTransform="translate(-12.968 -11.834) scale(1.063)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset=".265" stop-color="#FCFDFE" stop-opacity=".212"/><stop offset=".449" stop-color="#F3F7FD" stop-opacity=".359"/><stop offset=".609" stop-color="#E4ECF9" stop-opacity=".487"/><stop offset=".755" stop-color="#CEDDF5" stop-opacity=".604"/><stop offset=".89" stop-color="#B2C9EF" stop-opacity=".712"/><stop offset="1" stop-color="#95B5E9" stop-opacity=".8"/></radialGradient><circle clip-path="url(#aj)" fill="url(#al)" cx="315.568" cy="137.905" r="14.733"/></svg>
\ No newline at end of file
diff --git a/test/plugins/cleanupIDs.12.svg b/test/plugins/cleanupIDs.12.svg
new file mode 100644
index 0000000..1cb08f3
--- /dev/null
+++ b/test/plugins/cleanupIDs.12.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 230 120">
+    <circle id="garbage1" fill="red" cx="60" cy="60" r="50"/>
+    <rect id="garbage2" fill="blue" x="120" y="10" width="100" height="100"/>
+    <view id="xyzgarbage1" viewBox="0 0 120 120"/>
+    <view id="xyzgarbage2" viewBox="110 0 120 120"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 230 120">
+    <circle fill="red" cx="60" cy="60" r="50"/>
+    <rect fill="blue" x="120" y="10" width="100" height="100"/>
+    <view id="xyzgarbage1" viewBox="0 0 120 120"/>
+    <view id="xyzgarbage2" viewBox="110 0 120 120"/>
+</svg>
+
+@@@
+
+{"preservePrefixes": ["xyz"]}
diff --git a/test/plugins/cleanupIDs.13.svg b/test/plugins/cleanupIDs.13.svg
new file mode 100644
index 0000000..4349677
--- /dev/null
+++ b/test/plugins/cleanupIDs.13.svg
@@ -0,0 +1,22 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 120">
+    <style>
+        svg .hidden { display: none; }
+        svg .hidden:target { display: inline; }
+    </style>
+    <circle id="pre1_circle" class="hidden" fill="red" cx="60" cy="60" r="50"/>
+    <rect id="pre2_rect" class="hidden" fill="blue" x="10" y="10" width="100" height="100"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 120">
+    <style>
+        svg .hidden { display: none; } svg .hidden:target { display: inline; }
+    </style>
+    <circle id="pre1_circle" class="hidden" fill="red" cx="60" cy="60" r="50"/>
+    <rect id="pre2_rect" class="hidden" fill="blue" x="10" y="10" width="100" height="100"/>
+</svg>
+
+@@@
+
+{"force": true, "preservePrefixes": ["pre1_", "pre2_"]}
diff --git a/test/plugins/cleanupIDs.14.svg b/test/plugins/cleanupIDs.14.svg
new file mode 100644
index 0000000..ae8d80c
--- /dev/null
+++ b/test/plugins/cleanupIDs.14.svg
@@ -0,0 +1,34 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 120">
+    <style>
+        svg .hidden { display: none; }
+        svg .hidden:target { display: inline; }
+    </style>
+    <defs>
+        <circle id="circle" fill="red" cx="60" cy="60" r="50"/>
+        <rect id="rect" fill="blue" x="10" y="10" width="100" height="100"/>
+    </defs>
+    <g id="pre1_figure" class="hidden">
+        <use xlink:href="#circle"/>
+        <use href="#rect"/>
+    </g>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 120">
+    <style>
+        svg .hidden { display: none; } svg .hidden:target { display: inline; }
+    </style>
+    <defs>
+        <circle id="a" fill="red" cx="60" cy="60" r="50"/>
+        <rect id="b" fill="blue" x="10" y="10" width="100" height="100"/>
+    </defs>
+    <g id="pre1_figure" class="hidden">
+        <use xlink:href="#a"/>
+        <use href="#b"/>
+    </g>
+</svg>
+
+@@@
+
+{"force": true, "preservePrefixes": "pre1_"}
diff --git a/test/plugins/cleanupIDs.15.svg b/test/plugins/cleanupIDs.15.svg
new file mode 100644
index 0000000..ec0534f
--- /dev/null
+++ b/test/plugins/cleanupIDs.15.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 230 120">
+    <circle id="circle" fill="red" cx="60" cy="60" r="50"/>
+    <rect id="rect" fill="blue" x="120" y="10" width="100" height="100"/>
+    <view id="circle-suffix" viewBox="0 0 120 120"/>
+    <view id="rect-suffix" viewBox="110 0 120 120"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 230 120">
+    <circle id="circle" fill="red" cx="60" cy="60" r="50"/>
+    <rect id="rect" fill="blue" x="120" y="10" width="100" height="100"/>
+    <view viewBox="0 0 120 120"/>
+    <view id="rect-suffix" viewBox="110 0 120 120"/>
+</svg>
+
+@@@
+
+{"preserve": ["circle"], "preservePrefixes": ["suffix", "rect"]}
diff --git a/test/plugins/removeAttributesBySelector.01.svg b/test/plugins/removeAttributesBySelector.01.svg
new file mode 100644
index 0000000..cf47799
--- /dev/null
+++ b/test/plugins/removeAttributesBySelector.01.svg
@@ -0,0 +1,13 @@
+<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
+</svg>
+
+@@@
+
+<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/>
+</svg>
+
+@@@
+
+{ "selector": "[fill='#00ff00']", "attributes": "fill" }
diff --git a/test/plugins/removeAttributesBySelector.02.svg b/test/plugins/removeAttributesBySelector.02.svg
new file mode 100644
index 0000000..a584eb7
--- /dev/null
+++ b/test/plugins/removeAttributesBySelector.02.svg
@@ -0,0 +1,13 @@
+<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
+</svg>
+
+@@@
+
+<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <rect x="0" y="0" width="100" height="100"/>
+</svg>
+
+@@@
+
+{ "selector": "[fill='#00ff00']", "attributes": ["fill", "stroke"] }
diff --git a/test/plugins/removeAttributesBySelector.03.svg b/test/plugins/removeAttributesBySelector.03.svg
new file mode 100644
index 0000000..d54f731
--- /dev/null
+++ b/test/plugins/removeAttributesBySelector.03.svg
@@ -0,0 +1,13 @@
+<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <rect id="remove" x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
+</svg>
+
+@@@
+
+<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <rect x="0" y="0" width="100" height="100"/>
+</svg>
+
+@@@
+
+{ "selectors": [{ "selector": "[fill='#00ff00']", "attributes": "fill" }, { "selector": "#remove", "attributes": ["stroke", "id"] }] }
diff --git a/test/plugins/removeAttrs.03.svg b/test/plugins/removeAttrs.03.svg
new file mode 100644
index 0000000..f4cf672
--- /dev/null
+++ b/test/plugins/removeAttrs.03.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+    <circle fill="currentColor" stroke-width="6" stroke-dashoffset="5" cx="60" cy="60" r="50"/>
+    <circle fill="red" stroke="#000" stroke-width="6" stroke-dashoffset="5" stroke-opacity="0" cx="60" cy="60" r="50"/>
+    <circle stroke="currentColor" stroke-width="6" stroke-dashoffset="5" stroke-opacity="0" cx="60" cy="60" r="50"/>
+    <path fill="red" stroke="red" d="M100,200 300,400 H100 V300 C100,100 250,100 250,200 S400,300 400,200 Q400,50 600,300 T1000,300 z"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg">
+    <circle fill="currentColor" stroke-width="6" stroke-dashoffset="5" cx="60" cy="60" r="50"/>
+    <circle stroke-width="6" stroke-dashoffset="5" stroke-opacity="0" cx="60" cy="60" r="50"/>
+    <circle stroke="currentColor" stroke-width="6" stroke-dashoffset="5" stroke-opacity="0" cx="60" cy="60" r="50"/>
+    <path d="M100,200 300,400 H100 V300 C100,100 250,100 250,200 S400,300 400,200 Q400,50 600,300 T1000,300 z"/>
+</svg>
+
+@@@
+
+{"attrs":"(fill|stroke)", "preserveCurrentColor": true}
diff --git a/test/plugins/removeOffCanvasPaths.01.svg b/test/plugins/removeOffCanvasPaths.01.svg
new file mode 100644
index 0000000..6bf8f43
--- /dev/null
+++ b/test/plugins/removeOffCanvasPaths.01.svg
@@ -0,0 +1,13 @@
+<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+    <path d="M10 10 h 80 v 80 h -80 z"/>
+    <path d="M10 -90 h 80 v 80 h -80 z"/>
+    <path d="M110 10 h 80 v 80 h -80 z"/>
+    <path d="M10 110 h 80 v 80 h -80 z"/>
+    <path d="M-90 10 h 80 v 80 h -80 z"/>
+</svg>
+
+@@@
+
+<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+    <path d="M10 10 h 80 v 80 h -80 z"/>
+</svg>
diff --git a/test/plugins/removeOffCanvasPaths.02.svg b/test/plugins/removeOffCanvasPaths.02.svg
new file mode 100644
index 0000000..3597831
--- /dev/null
+++ b/test/plugins/removeOffCanvasPaths.02.svg
@@ -0,0 +1,15 @@
+<svg height="1000" width="1000" xmlns="http://www.w3.org/2000/svg">
+    <path d="M10 10 h 80 v 80 h -80 z"/>
+    <path d="M10 -90 h 80 v 80 h -80 z"/>
+    <path d="M110 10 h 80 v 80 h -80 z"/>
+    <path d="M10 110 h 80 v 80 h -80 z"/>
+    <path d="M-90 10 h 80 v 80 h -80 z"/>
+</svg>
+
+@@@
+
+<svg height="1000" width="1000" xmlns="http://www.w3.org/2000/svg">
+    <path d="M10 10 h 80 v 80 h -80 z"/>
+    <path d="M110 10 h 80 v 80 h -80 z"/>
+    <path d="M10 110 h 80 v 80 h -80 z"/>
+</svg>
diff --git a/test/plugins/removeOffCanvasPaths.03.svg b/test/plugins/removeOffCanvasPaths.03.svg
new file mode 100644
index 0000000..c9a25d6
--- /dev/null
+++ b/test/plugins/removeOffCanvasPaths.03.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
+    <path d="M0 0h128v128H0z" fill="none" stroke="red"/>
+    <path d="M10.14 51.5c4.07 1.56 7.52 4.47 7.37 11.16" fill="none" stroke="#00f"/>
+    <path d="M100 200c4.07 1.56 7.52 4.47 7.37 11.16" fill="none" stroke="#00f"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
+    <path d="M0 0h128v128H0z" fill="none" stroke="red"/>
+    <path d="M10.14 51.5c4.07 1.56 7.52 4.47 7.37 11.16" fill="none" stroke="#00f"/>
+</svg>
diff --git a/test/plugins/removeOffCanvasPaths.04.svg b/test/plugins/removeOffCanvasPaths.04.svg
new file mode 100644
index 0000000..7ddb7f2
--- /dev/null
+++ b/test/plugins/removeOffCanvasPaths.04.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
+    <path d="M20.16 107.3l13.18-12.18m-1.6-5.41l-16.32 6.51M13 84.5h18m77 22.8L94.83 95.12m1.6-5.41l16.32 6.51M115 84.5H98" fill="none" stroke="#444" stroke-width="3"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
+    <path d="M20.16 107.3l13.18-12.18m-1.6-5.41l-16.32 6.51M13 84.5h18m77 22.8L94.83 95.12m1.6-5.41l16.32 6.51M115 84.5H98" fill="none" stroke="#444" stroke-width="3"/>
+</svg>
diff --git a/test/plugins/removeOffCanvasPaths.05.svg b/test/plugins/removeOffCanvasPaths.05.svg
new file mode 100644
index 0000000..1c76296
--- /dev/null
+++ b/test/plugins/removeOffCanvasPaths.05.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <path d="M-100-100h50v50h-50z" fill="red" transform="translate(100 100)"/>
+    <g transform="translate(150 150)">
+        <path d="M-100-100h50v50h-50z" fill="blue"/>
+    </g>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
+    <path d="M-100-100h50v50h-50z" fill="red" transform="translate(100 100)"/>
+    <g transform="translate(150 150)">
+        <path d="M-100-100h50v50h-50z" fill="blue"/>
+    </g>
+</svg>
diff --git a/test/plugins/reusePaths.01.svg b/test/plugins/reusePaths.01.svg
new file mode 100644
index 0000000..3630385
--- /dev/null
+++ b/test/plugins/reusePaths.01.svg
@@ -0,0 +1,35 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+    <path id="test0" d="M 10,50 l 20,30 L 20,30"/>
+    <path transform="translate(10, 10)"
+          d="M 10,50 c 20,30 40,50 60,70 C 20,30 40,50 60,70"/>
+    <path transform="translate(20, 20)"
+          d="M 10,50 c 20,30 40,50 60,70 C 20,30 40,50 60,70"/>
+    <path d="M 10,50 c 20,30 40,50 60,70 C 20,30 40,50 60,70"/>
+    <path id="test1" d="M 10,50 l 20,30 L 20,30"/>
+    <path d="M 10,50 a 20,60 45 0,1 40,70 A 20,60 45 0,1 40,70"/>
+    <path d="M 20,30 a 20,60 45 0,1 40,70 A 20,60 45 0,1 40,70"/>
+    <g>
+      <path id="test2" d="M 10,50 l 20,30 L 20,30"/>
+    </g>
+    <path d="M 10,50 c 20,30 40,50 60,70 C 20,30 40,50 60,70"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg">
+    <defs>
+        <path id="test0" d="M 10,50 l 20,30 L 20,30"/>
+        <path d="M 10,50 c 20,30 40,50 60,70 C 20,30 40,50 60,70" id="reuse-0"/>
+    </defs>
+    <use xlink:href="#test0"/>
+    <use transform="translate(10, 10)" xlink:href="#reuse-0"/>
+    <use transform="translate(20, 20)" xlink:href="#reuse-0"/>
+    <use xlink:href="#reuse-0"/>
+    <use id="test1" xlink:href="#test0"/>
+    <path d="M 10,50 a 20,60 45 0,1 40,70 A 20,60 45 0,1 40,70"/>
+    <path d="M 20,30 a 20,60 45 0,1 40,70 A 20,60 45 0,1 40,70"/>
+    <g>
+        <use id="test2" xlink:href="#test0"/>
+    </g>
+    <use xlink:href="#reuse-0"/>
+</svg>
diff --git a/test/plugins/reusePaths.02.svg b/test/plugins/reusePaths.02.svg
new file mode 100644
index 0000000..45bfefd
--- /dev/null
+++ b/test/plugins/reusePaths.02.svg
@@ -0,0 +1,23 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+    <path id="test0" d="M 10,50 l 20,30 L 20,30"/>
+    <path id="test1" stroke="red" d="M 10,50 l 20,30 L 20,30"/>
+    <path id="test2" stroke="blue" d="M 10,50 l 20,30 L 20,30"/>
+    <path id="test3" d="M 10,50 l 20,30 L 20,30"/>
+    <path id="test4" stroke="blue" d="M 10,50 l 20,30 L 20,30"/>
+    <path id="test1" stroke="red" fill="green" d="M 10,50 l 20,30 L 20,30"/>
+</svg>
+
+@@@
+
+<svg xmlns="http://www.w3.org/2000/svg">
+    <defs>
+        <path id="test2" stroke="blue" d="M 10,50 l 20,30 L 20,30"/>
+        <path id="test0" d="M 10,50 l 20,30 L 20,30"/>
+    </defs>
+    <use xlink:href="#test0"/>
+    <path id="test1" stroke="red" d="M 10,50 l 20,30 L 20,30"/>
+    <use xlink:href="#test2"/>
+    <use id="test3" xlink:href="#test0"/>
+    <use id="test4" xlink:href="#test2"/>
+    <path id="test1" stroke="red" fill="green" d="M 10,50 l 20,30 L 20,30"/>
+</svg>