From 39fb9eee021e328261075481a2addbdca2c6cf19 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Sun, 6 Dec 2015 17:23:15 +0100 Subject: [PATCH] Prepare history merge --- CONTRIBUTORS | 27 - NOTICE | 2 - README.txt => README.md | 0 crunch.sh | 7 - fulltests/Degri_Energy_Saving_Lightbulb.svg | 185 - fulltests/GusEinstein_Angel.svg | 140 - fulltests/News_Paper.svg | 127 - fulltests/OperaMarketShareEEhover.svg | 685 - fulltests/Simon_Printer_on_fire.svg | 119 - fulltests/Tree_of_Life_SVG.svg | 25653 ---------------- fulltests/Wave.svg | 611 - fulltests/Web20Map.svg | 1100 - fulltests/acid.svg | 58 - fulltests/apartment.svg | 132 - fulltests/boom.svg | 360 - fulltests/cgmail.svg | 536 - fulltests/deja-dup.svg | 207 - fulltests/dragonfly.svg | 22 - fulltests/gimp.svg | 199 - fulltests/git-cola-icons.svg | 300 - fulltests/go-bottom.svg | 249 - fulltests/grapes.svg | 171 - fulltests/inkscape.svg | 3835 --- fulltests/lightning.svg | 82 - fulltests/manchester.svg | 194 - fulltests/notebook.svg | 233 - fulltests/notification-audio-next.svg | 581 - fulltests/ocal.svg | 158 - fulltests/oggconvert.svg | 483 - fulltests/pear.svg | 123 - fulltests/poster3.svg | 555 - fulltests/present.svg | 212 - fulltests/scantailor.svg | 151 - fulltests/strawberry.svg | 580 - fulltests/tree-of-life.svg | 285 - fulltests/view-refresh.svg | 397 - fulltests/web-process.svg | 594 - fulltests/wifi.svg | 65 - fulltests/woman_in_red.svg | 347 - lite/index.html | 124 - lite/muther.js | 49 - lite/pdom.js | 883 - lite/pdom_support.html | 203 - lite/pdom_test.html | 279 - lite/scour.js | 121 - logos/logo-14x14.png | Bin 3117 -> 0 bytes logos/logo-192x192.png | Bin 31940 -> 0 bytes logos/logo-64x64.png | Bin 7280 -> 0 bytes logos/logo.png | Bin 52143 -> 0 bytes logos/logo.svg | 129 - package.sh | 6 - push.sh | 6 - python-modules-pre24/fixedpoint.py | 619 - python-modules-pre24/optparse.py | 1569 - python-modules-pre24/textwrap.py | 374 - release-notes.html | 343 - scour.inkscape.py | 78 - scour.inx | 68 - scour.py => scour/scour.py | 0 svg_regex.py => scour/svg_regex.py | 0 svg_transform.py => scour/svg_transform.py | 0 yocto_css.py => scour/yocto_css.py | 0 scra.py | 115 - statistics.html | 388 - statistics.xls | Bin 70144 -> 0 bytes testcss.py | 47 - testscour.py | 1370 - unittests/adobe.svg | 45 - .../cascading-default-attribute-removal.svg | 23 - unittests/cdata.svg | 6 - .../collapse-gradients-gradientUnits.svg | 11 - unittests/collapse-gradients.svg | 11 - unittests/collapse-same-path-points.svg | 4 - unittests/color-formats.svg | 12 - unittests/comment-beside-xml-decl.svg | 10 - unittests/comments.svg | 6 - unittests/commonized-referenced-elements.svg | 9 - unittests/consecutive-hlines.svg | 6 - unittests/css-reference.svg | 27 - unittests/doctype.svg | 7 - unittests/dont-collapse-gradients.svg | 13 - unittests/dont-convert-short-color-names.svg | 4 - unittests/duplicate-gradient-stops-pct.svg | 12 - unittests/duplicate-gradient-stops.svg | 19 - .../duplicate-gradients-update-style.svg | 15 - unittests/empty-g.svg | 7 - unittests/empty-metadata.svg | 3 - unittests/empty-style.svg | 4 - unittests/fill-none.svg | 5 - unittests/font-styles.svg | 4 - unittests/full-metadata.svg | 22 - unittests/gradient-default-attrs.svg | 10 - unittests/group-creation.svg | 6 - unittests/group-no-creation.svg | 6 - unittests/groups-in-switch-with-id.svg | 18 - unittests/groups-in-switch.svg | 18 - unittests/groups-with-title-desc.svg | 13 - unittests/ids-to-strip.svg | 11 - unittests/important-groups-in-defs.svg | 12 - unittests/inkscape.svg | 7 - unittests/metadata-with-text.svg | 4 - .../move-common-attributes-to-grandparent.svg | 10 - .../move-common-attributes-to-parent.svg | 13 - unittests/nested-defs.svg | 14 - unittests/nested-useless-groups.svg | 9 - unittests/no-collapse-lines.svg | 8 - unittests/overflow-marker.svg | 12 - unittests/overflow-svg.svg | 9 - unittests/path-abs-to-rel.svg | 4 - unittests/path-bez-optimize.svg | 4 - unittests/path-elliptical-arc-parsing.svg | 4 - unittests/path-empty-move.svg | 5 - unittests/path-implicit-line.svg | 4 - unittests/path-line-optimize.svg | 4 - unittests/path-precision.svg | 4 - unittests/path-quad-optimize.svg | 4 - unittests/path-simple-triangle.svg | 8 - unittests/path-sn.svg | 4 - unittests/path-truncate-zeros-calc.svg | 4 - unittests/path-truncate-zeros.svg | 4 - unittests/path-use-scientific-notation.svg | 4 - unittests/path-with-caps.svg | 4 - unittests/path-with-closepath.svg | 4 - unittests/polygon-coord-neg-first.svg | 4 - unittests/polygon-coord-neg.svg | 4 - unittests/polygon-coord.svg | 4 - unittests/polygon.svg | 5 - unittests/polyline-coord-neg-first.svg | 4 - unittests/polyline-coord-neg.svg | 4 - unittests/polyline-coord.svg | 4 - unittests/protection.svg | 11 - unittests/quot-in-url.svg | 10 - unittests/redundant-svg-namespace.svg | 8 - unittests/referenced-elements-1.svg | 11 - unittests/referenced-font.svg | 17 - unittests/refs-in-defs.svg | 8 - unittests/remove-duplicate-gradients.svg | 23 - .../remove-unused-attributes-on-parent.svg | 8 - unittests/scour-lengths.svg | 5 - unittests/shorten-ids.svg | 10 - unittests/sodipodi.svg | 7 - unittests/straight-curve.svg | 4 - unittests/stroke-none.svg | 4 - unittests/stroke-nowidth.svg | 4 - unittests/stroke-transparent.svg | 4 - unittests/style-cdata.svg | 16 - unittests/style-to-attr.svg | 9 - unittests/transform-matrix-is-identity.svg | 3 - unittests/transform-matrix-is-rotate-135.svg | 4 - unittests/transform-matrix-is-rotate-225.svg | 4 - unittests/transform-matrix-is-rotate-45.svg | 4 - unittests/transform-matrix-is-rotate-90.svg | 4 - .../transform-matrix-is-rotate-neg-45.svg | 4 - .../transform-matrix-is-rotate-neg-90.svg | 4 - unittests/transform-matrix-is-scale-2-3.svg | 3 - unittests/transform-matrix-is-scale-neg-1.svg | 4 - unittests/transform-matrix-is-translate.svg | 3 - unittests/transform-rotate-fold-3args.svg | 5 - unittests/transform-rotate-is-identity.svg | 3 - .../transform-rotate-trim-range-719.5.svg | 5 - .../transform-rotate-trim-range-neg-540.0.svg | 5 - unittests/transform-skewX-is-identity.svg | 4 - unittests/transform-skewY-is-identity.svg | 4 - unittests/transform-translate-is-identity.svg | 5 - unittests/unreferenced-font.svg | 17 - unittests/unreferenced-linearGradient.svg | 6 - unittests/unreferenced-pattern.svg | 6 - unittests/unreferenced-radialGradient.svg | 6 - unittests/useless-defs.svg | 21 - unittests/utf8.svg | 5 - unittests/whitespace-defs.svg | 6 - unittests/whitespace-important.svg | 4 - unittests/whitespace-nested.svg | 4 - unittests/xml-namespace-attrs.svg | 24 - unittests/xml-ns-decl.svg | 30 - unittests/xml-well-formed.svg | 9 - webscour.py | 61 - 177 files changed, 47521 deletions(-) delete mode 100644 CONTRIBUTORS delete mode 100644 NOTICE rename README.txt => README.md (100%) delete mode 100755 crunch.sh delete mode 100644 fulltests/Degri_Energy_Saving_Lightbulb.svg delete mode 100644 fulltests/GusEinstein_Angel.svg delete mode 100644 fulltests/News_Paper.svg delete mode 100644 fulltests/OperaMarketShareEEhover.svg delete mode 100644 fulltests/Simon_Printer_on_fire.svg delete mode 100644 fulltests/Tree_of_Life_SVG.svg delete mode 100644 fulltests/Wave.svg delete mode 100644 fulltests/Web20Map.svg delete mode 100644 fulltests/acid.svg delete mode 100644 fulltests/apartment.svg delete mode 100644 fulltests/boom.svg delete mode 100644 fulltests/cgmail.svg delete mode 100644 fulltests/deja-dup.svg delete mode 100644 fulltests/dragonfly.svg delete mode 100644 fulltests/gimp.svg delete mode 100644 fulltests/git-cola-icons.svg delete mode 100644 fulltests/go-bottom.svg delete mode 100644 fulltests/grapes.svg delete mode 100644 fulltests/inkscape.svg delete mode 100644 fulltests/lightning.svg delete mode 100644 fulltests/manchester.svg delete mode 100644 fulltests/notebook.svg delete mode 100644 fulltests/notification-audio-next.svg delete mode 100644 fulltests/ocal.svg delete mode 100644 fulltests/oggconvert.svg delete mode 100644 fulltests/pear.svg delete mode 100644 fulltests/poster3.svg delete mode 100644 fulltests/present.svg delete mode 100644 fulltests/scantailor.svg delete mode 100644 fulltests/strawberry.svg delete mode 100644 fulltests/tree-of-life.svg delete mode 100644 fulltests/view-refresh.svg delete mode 100644 fulltests/web-process.svg delete mode 100644 fulltests/wifi.svg delete mode 100644 fulltests/woman_in_red.svg delete mode 100644 lite/index.html delete mode 100644 lite/muther.js delete mode 100644 lite/pdom.js delete mode 100644 lite/pdom_support.html delete mode 100644 lite/pdom_test.html delete mode 100644 lite/scour.js delete mode 100644 logos/logo-14x14.png delete mode 100644 logos/logo-192x192.png delete mode 100644 logos/logo-64x64.png delete mode 100644 logos/logo.png delete mode 100644 logos/logo.svg delete mode 100755 package.sh delete mode 100755 push.sh delete mode 100644 python-modules-pre24/fixedpoint.py delete mode 100644 python-modules-pre24/optparse.py delete mode 100644 python-modules-pre24/textwrap.py delete mode 100644 release-notes.html delete mode 100755 scour.inkscape.py delete mode 100644 scour.inx rename scour.py => scour/scour.py (100%) rename svg_regex.py => scour/svg_regex.py (100%) rename svg_transform.py => scour/svg_transform.py (100%) rename yocto_css.py => scour/yocto_css.py (100%) delete mode 100644 scra.py delete mode 100644 statistics.html delete mode 100644 statistics.xls delete mode 100755 testcss.py delete mode 100755 testscour.py delete mode 100644 unittests/adobe.svg delete mode 100644 unittests/cascading-default-attribute-removal.svg delete mode 100644 unittests/cdata.svg delete mode 100644 unittests/collapse-gradients-gradientUnits.svg delete mode 100644 unittests/collapse-gradients.svg delete mode 100644 unittests/collapse-same-path-points.svg delete mode 100644 unittests/color-formats.svg delete mode 100644 unittests/comment-beside-xml-decl.svg delete mode 100644 unittests/comments.svg delete mode 100644 unittests/commonized-referenced-elements.svg delete mode 100644 unittests/consecutive-hlines.svg delete mode 100644 unittests/css-reference.svg delete mode 100644 unittests/doctype.svg delete mode 100644 unittests/dont-collapse-gradients.svg delete mode 100644 unittests/dont-convert-short-color-names.svg delete mode 100644 unittests/duplicate-gradient-stops-pct.svg delete mode 100644 unittests/duplicate-gradient-stops.svg delete mode 100644 unittests/duplicate-gradients-update-style.svg delete mode 100644 unittests/empty-g.svg delete mode 100644 unittests/empty-metadata.svg delete mode 100644 unittests/empty-style.svg delete mode 100644 unittests/fill-none.svg delete mode 100644 unittests/font-styles.svg delete mode 100644 unittests/full-metadata.svg delete mode 100644 unittests/gradient-default-attrs.svg delete mode 100644 unittests/group-creation.svg delete mode 100644 unittests/group-no-creation.svg delete mode 100644 unittests/groups-in-switch-with-id.svg delete mode 100644 unittests/groups-in-switch.svg delete mode 100644 unittests/groups-with-title-desc.svg delete mode 100644 unittests/ids-to-strip.svg delete mode 100644 unittests/important-groups-in-defs.svg delete mode 100644 unittests/inkscape.svg delete mode 100644 unittests/metadata-with-text.svg delete mode 100644 unittests/move-common-attributes-to-grandparent.svg delete mode 100644 unittests/move-common-attributes-to-parent.svg delete mode 100644 unittests/nested-defs.svg delete mode 100644 unittests/nested-useless-groups.svg delete mode 100644 unittests/no-collapse-lines.svg delete mode 100644 unittests/overflow-marker.svg delete mode 100644 unittests/overflow-svg.svg delete mode 100644 unittests/path-abs-to-rel.svg delete mode 100644 unittests/path-bez-optimize.svg delete mode 100644 unittests/path-elliptical-arc-parsing.svg delete mode 100644 unittests/path-empty-move.svg delete mode 100644 unittests/path-implicit-line.svg delete mode 100644 unittests/path-line-optimize.svg delete mode 100644 unittests/path-precision.svg delete mode 100644 unittests/path-quad-optimize.svg delete mode 100644 unittests/path-simple-triangle.svg delete mode 100644 unittests/path-sn.svg delete mode 100644 unittests/path-truncate-zeros-calc.svg delete mode 100644 unittests/path-truncate-zeros.svg delete mode 100644 unittests/path-use-scientific-notation.svg delete mode 100644 unittests/path-with-caps.svg delete mode 100644 unittests/path-with-closepath.svg delete mode 100644 unittests/polygon-coord-neg-first.svg delete mode 100644 unittests/polygon-coord-neg.svg delete mode 100644 unittests/polygon-coord.svg delete mode 100644 unittests/polygon.svg delete mode 100644 unittests/polyline-coord-neg-first.svg delete mode 100644 unittests/polyline-coord-neg.svg delete mode 100644 unittests/polyline-coord.svg delete mode 100644 unittests/protection.svg delete mode 100644 unittests/quot-in-url.svg delete mode 100644 unittests/redundant-svg-namespace.svg delete mode 100644 unittests/referenced-elements-1.svg delete mode 100644 unittests/referenced-font.svg delete mode 100644 unittests/refs-in-defs.svg delete mode 100644 unittests/remove-duplicate-gradients.svg delete mode 100644 unittests/remove-unused-attributes-on-parent.svg delete mode 100644 unittests/scour-lengths.svg delete mode 100644 unittests/shorten-ids.svg delete mode 100644 unittests/sodipodi.svg delete mode 100644 unittests/straight-curve.svg delete mode 100644 unittests/stroke-none.svg delete mode 100644 unittests/stroke-nowidth.svg delete mode 100644 unittests/stroke-transparent.svg delete mode 100644 unittests/style-cdata.svg delete mode 100644 unittests/style-to-attr.svg delete mode 100644 unittests/transform-matrix-is-identity.svg delete mode 100644 unittests/transform-matrix-is-rotate-135.svg delete mode 100644 unittests/transform-matrix-is-rotate-225.svg delete mode 100644 unittests/transform-matrix-is-rotate-45.svg delete mode 100644 unittests/transform-matrix-is-rotate-90.svg delete mode 100644 unittests/transform-matrix-is-rotate-neg-45.svg delete mode 100644 unittests/transform-matrix-is-rotate-neg-90.svg delete mode 100644 unittests/transform-matrix-is-scale-2-3.svg delete mode 100644 unittests/transform-matrix-is-scale-neg-1.svg delete mode 100644 unittests/transform-matrix-is-translate.svg delete mode 100644 unittests/transform-rotate-fold-3args.svg delete mode 100644 unittests/transform-rotate-is-identity.svg delete mode 100644 unittests/transform-rotate-trim-range-719.5.svg delete mode 100644 unittests/transform-rotate-trim-range-neg-540.0.svg delete mode 100644 unittests/transform-skewX-is-identity.svg delete mode 100644 unittests/transform-skewY-is-identity.svg delete mode 100644 unittests/transform-translate-is-identity.svg delete mode 100644 unittests/unreferenced-font.svg delete mode 100644 unittests/unreferenced-linearGradient.svg delete mode 100644 unittests/unreferenced-pattern.svg delete mode 100644 unittests/unreferenced-radialGradient.svg delete mode 100644 unittests/useless-defs.svg delete mode 100644 unittests/utf8.svg delete mode 100644 unittests/whitespace-defs.svg delete mode 100644 unittests/whitespace-important.svg delete mode 100644 unittests/whitespace-nested.svg delete mode 100644 unittests/xml-namespace-attrs.svg delete mode 100644 unittests/xml-ns-decl.svg delete mode 100644 unittests/xml-well-formed.svg delete mode 100644 webscour.py diff --git a/CONTRIBUTORS b/CONTRIBUTORS deleted file mode 100644 index f05918f..0000000 --- a/CONTRIBUTORS +++ /dev/null @@ -1,27 +0,0 @@ -Thanks to the following contributors to scour: - -* Johan Sundström - -* Jan Thor - -* Louis Simard - Bugs Fixed: - - https://bugs.launchpad.net/scour/+bug/583758 - - https://bugs.launchpad.net/scour/+bug/583458 - - https://bugs.launchpad.net/scour/+bug/594930 - - https://bugs.launchpad.net/scour/+bug/576958 - New features: - - https://bugs.launchpad.net/scour/+bug/428069 Remove metadata option. - - https://bugs.launchpad.net/scour/+bug/582619 Feature implementations: --quiet, --enable-comment-stripping. - - Add options --shorten-ids, --renderer-workaround. - -* Martin: - - better methods of handling string-to-float conversions in Python - - document functions in the traditional Python way - - rewrite option parsing code - -* Doug Schepers (W3C SVG WG) - - function to embed rasters as base64 data: URLs - - report file size reduction - - prettied up the report - diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 1e6364c..0000000 --- a/NOTICE +++ /dev/null @@ -1,2 +0,0 @@ -scour -Copyright 2009 Jeff Schiller \ No newline at end of file diff --git a/README.txt b/README.md similarity index 100% rename from README.txt rename to README.md diff --git a/crunch.sh b/crunch.sh deleted file mode 100755 index 480b188..0000000 --- a/crunch.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -mkdir $1 -for FILE in `ls fulltests` -do - echo Doing $FILE: - python ./scour.py -i fulltests/$FILE -o $1/$FILE 2>> $1/report.txt -done diff --git a/fulltests/Degri_Energy_Saving_Lightbulb.svg b/fulltests/Degri_Energy_Saving_Lightbulb.svg deleted file mode 100644 index 42f5d8e..0000000 --- a/fulltests/Degri_Energy_Saving_Lightbulb.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/GusEinstein_Angel.svg b/fulltests/GusEinstein_Angel.svg deleted file mode 100644 index f567c5f..0000000 --- a/fulltests/GusEinstein_Angel.svg +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/News_Paper.svg b/fulltests/News_Paper.svg deleted file mode 100644 index 43c6a9f..0000000 --- a/fulltests/News_Paper.svg +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/OperaMarketShareEEhover.svg b/fulltests/OperaMarketShareEEhover.svg deleted file mode 100644 index 73b75d7..0000000 --- a/fulltests/OperaMarketShareEEhover.svg +++ /dev/null @@ -1,685 +0,0 @@ - - - Opera market share in Eastern and Central Europe - Every country has an id which is its ISO-3116-1-ALPHA2 code in lower case. - Members of the EU have a class="eu", countries in europe (which I found turkey to be but russia not) have a class="europe". Image based on a map (http://commons.wikimedia.org/wiki/Image:Europe_countries.svg) by Julio "Tintazul" Reis. made by Marian "maix" Sigler. Released under CreativeCommons Attribution ShareAlike (http://creativecommons.org/licenses/by-sa/2.5/). Updated by David Storey to include Opera market share taken from April 2009 figures from StatCounter, and related infographics and text labels. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BELARUS - - - - - - - POLAND - - - - - - - - - - - - - KAZAKHSTAN - - - - - - - - - - - - - - - - UKRAINE - - - - - - - - - - - - - AZERBAIJAN - - - - - - - - - - GEORGIA - - - - - - - - - - - - ARMENIA - - - - - - - - - - - - - - - - - - CZECH REP. - - - - - - - - SLOVAKIA - - - - - - - - HUNGARY - - - - - - - LITHUANIA - - - - - - - LATVIA - - - - - - - - MOLDOVA - - - - - - - ROMANIA - - - - - - - BULGARIA - - - - - - - ALBANIA - - - - - - - ESTONIA - - - - - - - - - - - - - - - - - - - - - - - BOSNIA - - - - - - - SLOVENIA - - - - - - - MACEDONIA - - - - - - - - CROATIA - - - - - - - - - - RUSSIAN FEDERATION - - - - - - - - - - - - - - - - - MONT. - - - - - - - SERBIA - - - - - - - - - - - - - - - 0% - 50% - 100% - - Opera Market Share - - - - BY - - - - - 51% - - - - - GE - - - - - 47% - - - - - UA - - - - - 44% - - - - - KZ - - - - - 39% - - - - RU - - - - 38% - - - - AM - - - - 28% - - - - AZ - - - - 28% - - - - MD - - - - 23% - - - - SK - - - - 15% - - - - LT - - - - 12% - - - - PL - - - - 10% - - - - CZ - - - - 10% - - - - RS - - - - 10% - - - - LV - - - - 9% - - - - ME - - - - 8% - - - - EE - - - - 7% - - - - RO - - - - 6% - - - - BG - - - - 6% - - - - BA - - - - 5% - - - - HR - - - - 4% - - - - - HU - - - - 4% - - - - MK - - - - 4% - - - - AL - - - - 3% - - - - SI - - - - 2% - - - - APRIL 2009 - - - - - \ No newline at end of file diff --git a/fulltests/Simon_Printer_on_fire.svg b/fulltests/Simon_Printer_on_fire.svg deleted file mode 100644 index 1e8c486..0000000 --- a/fulltests/Simon_Printer_on_fire.svg +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/Tree_of_Life_SVG.svg b/fulltests/Tree_of_Life_SVG.svg deleted file mode 100644 index 27829f5..0000000 --- a/fulltests/Tree_of_Life_SVG.svg +++ /dev/null @@ -1,25653 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/Wave.svg b/fulltests/Wave.svg deleted file mode 100644 index e0d5bc4..0000000 --- a/fulltests/Wave.svg +++ /dev/null @@ -1,611 +0,0 @@ - - - - - - - - - - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eJztvQtvJUeOJnr/gP7DuVj4wsYdy/HMjHQvFtBz1ndPdxfsntleDAaGrFLZ2tajIKnc7fn1N8iP -ZESec5TSeFvdmoHg7lIVlSdPBD8Gg0EyyM/+73fffXnw/vaHiy/jvlvtffbZ0d3F2cPt3dcrpq6+ -ubr6dP9wR6TPv/1i5d2+qw8dfFO+lwf/+eLu/vL25mv91Sl99vNv62fvHlb/4+7sf1/8+f5Pl1+s -Pv+i/vIPlw9XF/XX//Ps54v9s8sv9PvqC47PHupvvP/K56/cUN/2tRtX735bnzi8/XTz/vLmx8Pb -v9QHJlf/71fJj6vB0Rf+98tvL+43n9kPU57owf1hSPT0sO/84Fd5mvZ9Sb5+7vj2/NP1xc3Du7vb -84v7+6Pbq9u7+69XR7+c3ax+e/Zj/c3Z6n9dXF3d/nl1eHV2/qe9Ouv8/enl1UWd4vXZw2qg+R58 -E7/nj/7Tff1M/Tj9ncjj999cV8p3Fw8PdVz1xTTWb//xsP+6SuT/Pv+Xby9+vGQ2V0786xfM4QHv -/e7i4xno9VV1bvW/z+svV8cXH84+XT3gC1ftqfrXhy8IyP939fuPRLjnDw31a7z8H/95/FeMoP99 -6el/7bHtv9HfwyquEn/Nu3fH9BUBvx/cKuX62yDP+0fe/zkNkrj3h4vrj1cVfIYuVujjNOhPeaLy -nH9Ln87jsBpjwG8ahhc/X178+evV725vLgDUwd3Dd5f/VhEZfFiNUwD1209XF3f/dHP5ULnCpAlc -/u3t+4urOgv77OnV2Y/MuTYH/hMP/OHs7seLhyp3t1efHlj6i5Nf/e7T9frslwsSJY8v+P3Hi5s/ -3P4zj+/LGIZVSYU4H4aymiowAdgMqxQ6YOR19GH6qL5zrCx/V+Xq93eXP17efM0jYla8O/t4cfft -xfnD119WTMcxVVlPldFFfv/bOuT6gfq7LxNhUIdQIKf/eHf5vonpGFYFf/B890v3/0n/j4lVHj08 -XNxAtE9u3h/dXhMY97RmqzzfVFG/uv0Rv7O/82/q1336iAnyv7+vuL27u7yhMez97uOeXx3edL/+ -x7uz95f1zVVz/NPNzdn1xfvVj0Ja+S/2dhHr2MPq8P3ev+z9173T09OT0+PTo9PD04PT6bScjqfD -aT5Np/E0nPpTd3J6cnJyfHJ0cnhycDKdlJPxZDjJJ+kknoQTf+KOT49Pjo+Pj44Pjw+Op+Oydzwe -D8f5OB3H43Dsj93R6dHJ0fHR0dHh0cHRdFSOxqPhKB+lo3gUjvyROzw9PDk8Pjw6PDw8OJwOy+F4 -OBzmw3QYD8OhP3R7B6cHJwfHB0cHhwcHB9NBORgPhoN8kA7iQTjwB246nU6m4+loOpwOpmkq0zgN -VcGlKU5hququnJaTclyOymE5KFMpe2UsQ8lV0GIJxRc3no4n4/F4NB6OB+M0lnEchzGPaYxjGP3o -htPhZDgejobD4WCYhjKMwzDkIQ1xCIMf3F4+zSf5OB/lw3yQp1zymIecc8oxh+yzS6fpJB2no3SY -DtKUShrTkHJKKaaQfHLxNJ7E43gUD+NBnGLZi2McYo4pxhiijy6chpNwHI7CYTgIUyhhDEPIIYUY -QvDB+VN/4o/9kT/0B1WvFz9WfZ598tEH773bcxVIV7Fwh64yzNU5u8HVgbn6bufr8vxve2712feH -d1UmWJHUleaY8t3eZ993lMP7PY9/2W/t3/V3h8eQzCrUKpdG6OX4yy8XBPzXfGDCb0ixPfxydXG/ -99X/uLn98w3/Y/X13uf/IlvCv36x+up3dT2s/mHvq+8uq3K90Efc6vd7c/X/x7NK+HZvruD/eLDX -/eOX+o//r/7lf1fSn1dp9dvVv/yrW72v1D9+u8fveL/31buzOtTVb/ZWX9VB1J883Dq/NtgnZ/zu -7KoqoQsey7sfNoa0uUPyr/74b3tb9Hfne+8O7cv0nf8evq7r63pmbs2FH/g1AHqHX333y/UPt1f0 -mv9LyPVFG8R/98vL9++uPrGuvP308ZubD7d7n8OCe0dK+u7m95XBDz+tDu8+3f+0+sPt7VU1yWYP -yK/wFvpltd+6pxe/oz77+Pvbi37Vu7875/HtevP8V/b2HZ9Y/Iajs6ury7p3fPzp8nzX1+z4vX3X -Y59d/MK6cd5dtHfwP+3nMjNYSi7vrxsPOkr7+1MSUYG6urh5f2+vwT/bmNaXPytx+WV1nVRzuIOW -qSc3P19c3X7sJmmUs5v3q/95dvfxsdfS6D5c3ryvAH736fLhosFwe/2RzPzVdz9VW6eSt55cWDiy -yNVgrKeNs6rXv9J/V+VI/7o8JzVydvcL/v3H365/Vw1D/sfn/+W9PFvV63cP9eU/rj7/y/XVTX3g -S/qDTJAvqs797Pvdv//57OqTPDCtvvqmfufs1w+/fJTffnVwd3e2awTXFw9n7+vA/88H4H/dAH4+ -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 -YnX/0+2fiVI/oo9/9tnJ70/3/n8YRKVb - - - \ No newline at end of file diff --git a/fulltests/Web20Map.svg b/fulltests/Web20Map.svg deleted file mode 100644 index 1067cca..0000000 --- a/fulltests/Web20Map.svg +++ /dev/null @@ -1,1100 +0,0 @@ - - - - - - - image/svg+xml - - - - Web 2.0 Map - 25/12/2006 - - - Luca Cremonini - - - - - - - - - English - - - - Web 2.0 - Web 2.0 Map - Web 2.0 Cloudview - Web 2.0 Tags - - - - - - Markus Angermeier, http://kosmar.de/wp-content/web20map.png - - - - - - - - - - - - - - - - - - Usability - - - Economy - - - - Design - - - Standardization - - - - Remixability - - - Convergence - - - Participation - - - - - - Widgets - - - Collaboration - - - - Sharing - - - Pagerank - - - - User Centered - - - Perpetual Beta - - - Trust - - - - FOAF - - - Six Degrees - - - - XFN - - - Aggregators - - - VC - - - - Pay Per Click - - - Modularity - - - - Ruby on Rails - - - Syndication - - - SOAP - - - - REST - - - SEO - - - - IM - - - XHTML - - - Accessibility - - - - Semantic - - - XML - - - - UMTS - - - Videocasting - - - Podcasting - - - - SVG - - - Atom - - - - Browser - - - OpenID - - - - - - Wikis - - - Simplicity - - - Joy of Use - - - - AJAX - - - The Long Tail - - - - Affiliation - - - CSS - - - Web Standards - - - - Microformats - - - DataDriven - - - - OpenAPIs - - - RSS - - - Mobility - - - - Video - - - Audio - - - - Blogs - - - Social Software - - - Recommendation - - - - Folksonomy - - - - - Web 2.0 - - - - diff --git a/fulltests/acid.svg b/fulltests/acid.svg deleted file mode 100644 index 5b12c90..0000000 --- a/fulltests/acid.svg +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - image/svg+xml - - Sign corrosive - 11/09/2006 - - - h0us3s - - - es - - - Inkscape - Sign Hazard - Warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/apartment.svg b/fulltests/apartment.svg deleted file mode 100644 index 988fbd0..0000000 --- a/fulltests/apartment.svg +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - Hotel Icon Collection In Room Blank - - - - icon - symbol - hotel - - - - - Open Clip Art Library - - - - - Gerald G. - - - - - Gerald G. - - - - image/svg+xml - - - en - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Apartment \ No newline at end of file diff --git a/fulltests/boom.svg b/fulltests/boom.svg deleted file mode 100644 index d418952..0000000 --- a/fulltests/boom.svg +++ /dev/null @@ -1,360 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/cgmail.svg b/fulltests/cgmail.svg deleted file mode 100644 index fc9f5ab..0000000 --- a/fulltests/cgmail.svg +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Mail - - - Jakub Steiner - - - - - Andreas Nilsson - - - - - - mail - e-mail - MUA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/deja-dup.svg b/fulltests/deja-dup.svg deleted file mode 100644 index ca3506c..0000000 --- a/fulltests/deja-dup.svg +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Déjà Dup - - - reload - refresh - view - - - - - Michael Terry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/dragonfly.svg b/fulltests/dragonfly.svg deleted file mode 100644 index 1212268..0000000 --- a/fulltests/dragonfly.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - \ No newline at end of file diff --git a/fulltests/gimp.svg b/fulltests/gimp.svg deleted file mode 100644 index 435665f..0000000 --- a/fulltests/gimp.svg +++ /dev/null @@ -1,199 +0,0 @@ - - - - version="1.0" - x="0.0000000" - y="0.0000000" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - Wilber, the GIMP - 10/23/05 - - - worthawholebean - - - - - Inkscape - - - This is an SVG version of the original Wilber. - - - worthawholebean - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/git-cola-icons.svg b/fulltests/git-cola-icons.svg deleted file mode 100644 index b36f125..0000000 --- a/fulltests/git-cola-icons.svg +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/go-bottom.svg b/fulltests/go-bottom.svg deleted file mode 100644 index 263df90..0000000 --- a/fulltests/go-bottom.svg +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/grapes.svg b/fulltests/grapes.svg deleted file mode 100644 index 6f32572..0000000 --- a/fulltests/grapes.svg +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/inkscape.svg b/fulltests/inkscape.svg deleted file mode 100644 index 271af62..0000000 --- a/fulltests/inkscape.svg +++ /dev/null @@ -1,3835 +0,0 @@ - - - - - Inkscape 0.47 contest entry - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Inkscape 0.47 contest entry - 2009-05-14 - - - Johan Forsberg - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - jf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/lightning.svg b/fulltests/lightning.svg deleted file mode 100644 index 4db6001..0000000 --- a/fulltests/lightning.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - Lightning Icon - - - - icon - weather - lightning - - - - - Benji Park - - - - - Benji Park - - - - - Benji Park - - - - image/svg+xml - - - en - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/manchester.svg b/fulltests/manchester.svg deleted file mode 100644 index 49b712c..0000000 --- a/fulltests/manchester.svg +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/notebook.svg b/fulltests/notebook.svg deleted file mode 100644 index 5c5ded4..0000000 --- a/fulltests/notebook.svg +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/notification-audio-next.svg b/fulltests/notification-audio-next.svg deleted file mode 100644 index 7251a9b..0000000 --- a/fulltests/notification-audio-next.svg +++ /dev/null @@ -1,581 +0,0 @@ - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/ocal.svg b/fulltests/ocal.svg deleted file mode 100644 index 6e098e2..0000000 --- a/fulltests/ocal.svg +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - image/svg+xml - - Open Clip Art Logo - - 10-01-2004 - - - Andreas Nilsson - - - - - - - Jon Phillips, Tobias Jakobs - - - This is one version of the official Open Clip Art Library logo. - logo, open clip art library logo, logotype - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/oggconvert.svg b/fulltests/oggconvert.svg deleted file mode 100644 index 1adda62..0000000 --- a/fulltests/oggconvert.svg +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - OggConvert - - - A. Bram Neijt - - - - - convert - ogg - oggconvert - - - - - - - - - Based on "Save" by Jakub Steiner from http://jimmac.musichall.cz, downloaded from http://tango.freedesktop.org/ - - - - - - - - - - - - - - - - - Ogg - - - - - diff --git a/fulltests/pear.svg b/fulltests/pear.svg deleted file mode 100644 index 12e1988..0000000 --- a/fulltests/pear.svg +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/poster3.svg b/fulltests/poster3.svg deleted file mode 100644 index e65e0bd..0000000 --- a/fulltests/poster3.svg +++ /dev/null @@ -1,555 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SVG Open 2009 - - - - - - - - - - - - - - October 2-4, 2009 Mountainview, CA - Registration - Venue - The SVG Open 2009 conference will be held October 2-4, 2009, in Mountain View, California, hosted by Google at their Crittenden Lane campus. - Registration and more information at http://svgopen.org - Register online at http://svgopen.org - - - - - SVG coming of age - - - - - - Hosted by - Sponsored by - - At the SVG Open Conference you will learn to use SVG to create effective and compelling web content and learn techniques for using SVG in software. You can meet creators of SVG applications in person as well as the authors of the SVG specifications.The conference will be of interest to: • Software developers • Web and UI designers • Web application developers • Graphic artists • Creators of mobile computing solutions • GIS, CAD, and modeling specialists • Data visualization creators and users - - \ No newline at end of file diff --git a/fulltests/present.svg b/fulltests/present.svg deleted file mode 100644 index 0625d1b..0000000 --- a/fulltests/present.svg +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/scantailor.svg b/fulltests/scantailor.svg deleted file mode 100644 index 37d2e84..0000000 --- a/fulltests/scantailor.svg +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/strawberry.svg b/fulltests/strawberry.svg deleted file mode 100644 index 8e48eb2..0000000 --- a/fulltests/strawberry.svg +++ /dev/null @@ -1,580 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/tree-of-life.svg b/fulltests/tree-of-life.svg deleted file mode 100644 index 0cd9dfc..0000000 --- a/fulltests/tree-of-life.svg +++ /dev/null @@ -1,285 +0,0 @@ - - -Spirochaetes -Chlamydias -Hyperthermophilic bacteria -Cyanobacteria -Low-GC Gram-positives -High-GC Gram-positives -Deinococcus/Thermus -Proteobacteria -Crenarchaeota -Euryarchaeota -Haptophytes -Brown algae -Diatoms -Oomycetes -Dinoflagellates -Apicomplexans -Ciliates -Eudicots -Monocots -Magnoliids -Star anise -Water lilies -Amborella -Conifers -Gnetophytes -Ginkgo -Cycads -Ferns -Horsetails -Whisk ferns -Club mosses and relatives -Hornworts -Mosses -Liverworts -Charales -Coleochaetales -Chlorophytes -Red Algae -Glaucophytes -Kinetoplastids -Euglenids -Heteroloboseans -Parabasalids -Diplomonads -Foraminiferans -Cercozoans -Radiolarians -Amoebozoans -Club Fungi -Sac Fungi -Arbuscular Mycorrhizal Fungi -"Zygospore Fungi" -"Chytrids" -Microsporidia -Choanoflagellates -Glass sponges -Demosponges -Calcareous sponges -Placozoans -Ctenophores -Cnidarians -Bryozoans -Flatworms -Rotifers -Ribbon worms -Brachiopods -Phoronids -Annelids -Mollusks -Arrow worms -Priapulids -Kinorhynchs -Loriciferans -Horsehair worms -Nematodes -Tardigrades -Onychophorans -Chelicerates -Myriapods -Crustaceans -Hexapods -Echinoderms -Hemichordates -Cephalochordates -Urochordates -Hagfishes -Lampreys -Chondrichthyans -Ray-finned fishes -Lobe-finned fishes -Lungfishes -Amphibians -Mammals -Turtles -Lepidosaurs -Crocodilians -Birds - diff --git a/fulltests/view-refresh.svg b/fulltests/view-refresh.svg deleted file mode 100644 index fb51a42..0000000 --- a/fulltests/view-refresh.svg +++ /dev/null @@ -1,397 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - View Refresh - - - reload - refresh - view - - - - - Ricardo 'Rick' González - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fulltests/web-process.svg b/fulltests/web-process.svg deleted file mode 100644 index 54a3850..0000000 --- a/fulltests/web-process.svg +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Twisted Web - - - http://example.com/foo/bar/baz - - HTTP - - ObjectPublisher - getChild("foo") getChild("bar") getChild("baz") - - - - - - - Finish - - - Render - - - - TemplatingSystem - - Request - Response - Browser - - - diff --git a/fulltests/wifi.svg b/fulltests/wifi.svg deleted file mode 100644 index 1adc9b7..0000000 --- a/fulltests/wifi.svg +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fulltests/woman_in_red.svg b/fulltests/woman_in_red.svg deleted file mode 100644 index f5c5cc8..0000000 --- a/fulltests/woman_in_red.svg +++ /dev/null @@ -1,347 +0,0 @@ - - - - girl - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - girl - - - hrum - - - woman, red, tie, color, glases, sexy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lite/index.html b/lite/index.html deleted file mode 100644 index e230dd9..0000000 --- a/lite/index.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - Scour Lite - - - -

Scour Lite

- - - - - - - - diff --git a/lite/muther.js b/lite/muther.js deleted file mode 100644 index 672615e..0000000 --- a/lite/muther.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Mini Unit Test Harness - * Copyright(c) 2011, Google Inc. - * - * A really tiny unit test harness. - */ - -var muther = muther || {}; - -muther.assert = function(cond, err) { - if (!cond) { - throw err; - } -}; - -muther.addTest_ = function(testDiv, innerHTML, pass) { - var theTest = document.createElement('div'); - // Convert all angle brackets into displayable text. - innerHTML = innerHTML.replace(/&/g, '&'). - replace(//g, '>'); - theTest.innerHTML = innerHTML; - theTest.setAttribute('style', pass ? 'color:#090' : 'color:#900'); - testDiv.appendChild(theTest); -}; - -// Run through all tests and record the results. -muther.test = function(testsToRun) { - var progress = document.createElement('progress'); - var testDiv = document.createElement('div'); - document.body.insertBefore(testDiv, document.body.firstChild); - document.body.insertBefore(progress, document.body.firstChild); - - var max = testsToRun.length; - progress.max = max; - progress.value = 0; - testDiv.innerHTML = max + ' Tests'; - for (var t = 0; t < max; ++t) { - var test = testsToRun[t]; - try { - test(); - muther.addTest_(testDiv, test.name + ': Pass', true); - } catch(e) { - muther.addTest_(testDiv, test.name + ': Fail. ' + e, false); - } - progress.value += 1; - } -}; - diff --git a/lite/pdom.js b/lite/pdom.js deleted file mode 100644 index 5d6a947..0000000 --- a/lite/pdom.js +++ /dev/null @@ -1,883 +0,0 @@ -/** - * Pico DOM - * Copyright(c) 2011, Google Inc. - * - * A really tiny implementation of the DOM for use in Web Workers. - */ - -// TODO: Look into defineProperty instead of getters. - -var pdom = pdom || {}; - -// =========================================================================== -// Stolen from Closure because it's the best way to do Java-like inheritance. -pdom.base = function(me, opt_methodName, var_args) { - var caller = arguments.callee.caller; - if (caller.superClass_) { - // This is a constructor. Call the superclass constructor. - return caller.superClass_.constructor.apply( - me, Array.prototype.slice.call(arguments, 1)); - } - - var args = Array.prototype.slice.call(arguments, 2); - var foundCaller = false; - for (var ctor = me.constructor; - ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) { - if (ctor.prototype[opt_methodName] === caller) { - foundCaller = true; - } else if (foundCaller) { - return ctor.prototype[opt_methodName].apply(me, args); - } - } - - // If we did not find the caller in the prototype chain, - // then one of two things happened: - // 1) The caller is an instance method. - // 2) This method was not called by the right caller. - if (me[opt_methodName] === caller) { - return me.constructor.prototype[opt_methodName].apply(me, args); - } else { - throw Error( - 'goog.base called from a method of one name ' + - 'to a method of a different name'); - } -}; -pdom.inherits = function(childCtor, parentCtor) { - /** @constructor */ - function tempCtor() {}; - tempCtor.prototype = parentCtor.prototype; - childCtor.superClass_ = parentCtor.prototype; - childCtor.prototype = new tempCtor(); - childCtor.prototype.constructor = childCtor; -}; -// =========================================================================== - - -/** - * A DOMException - * - * @param {number} code The DOM exception code. - * @constructor - */ -pdom.DOMException = function(code) { - this.__defineGetter__('code', function() { return code }); -}; -pdom.DOMException.INDEX_SIZE_ERR = 1; -pdom.DOMException.DOMSTRING_SIZE_ERR = 2; -pdom.DOMException.HIERARCHY_REQUEST_ERR = 3; -pdom.DOMException.WRONG_DOCUMENT_ERR = 4; -pdom.DOMException.INVALID_CHARACTER_ERR = 5; -pdom.DOMException.NO_DATA_ALLOWED_ERR = 6; -pdom.DOMException.NO_MODIFICATION_ALLOWED_ERR = 7; -pdom.DOMException.NOT_FOUND_ERR = 8; -pdom.DOMException.NOT_SUPPORTED_ERR = 9; -pdom.DOMException.INUSE_ATTRIBUTE_ERR = 10; -pdom.DOMException.INVALID_STATE_ERR = 11; -pdom.DOMException.SYNTAX_ERR = 12; -pdom.DOMException.INVALID_MODIFICATION_ERR = 13; -pdom.DOMException.NAMESPACE_ERR = 14; -pdom.DOMException.INVALID_ACCESS_ERR = 15; -pdom.DOMException.VALIDATION_ERR = 16; -pdom.DOMException.TYPE_MISMATCH_ERR = 17; - - -/** - * A NodeList. - * - * @param {Array.} nodeArray The array of nodes. - * @constructor - */ -pdom.NodeList = function(nodeArray) { - this.nodes_ = nodeArray; - - this.__defineGetter__('length', function() { return this.nodes_.length; }); -}; - - -/** - * @param {number} index The index of the node to return. - * @return {pdom.Node} The node. - */ -pdom.NodeList.prototype.item = function(index) { - if (index >= 0 && index < this.length) { - return this.nodes_[index]; - } - return null; -}; - - -/** - * @param {Object.} nodeMap An object containing the - * attribute name-Node pairs. - * @param {pdom.Node} opt_refNode An optional reference node. - * @constructor - */ -pdom.NamedNodeMap = function(nodeMap, opt_refNode) { - this.setNodeMapInternal(nodeMap, opt_refNode); - this.__defineGetter__('length', function() { return this.attrs_.length }); -}; - - -/** - * An array of the nodes. - * @type {Array.} - * @private - */ -pdom.NamedNodeMap.prototype.attrs_ = []; - - -/** - * The node map. - * @type {Object.} - * @private - */ -pdom.NamedNodeMap.prototype.nodeMap_ = {}; - - -/** - * Sets the internal node map (and updates the array). - * @param {Object.} The node map. - * @param {pdom.Node} opt_refNode The optional reference node for namespace prefix checking. - */ -pdom.NamedNodeMap.prototype.setNodeMapInternal = function(nodeMap, opt_refNode) { - var nsPrefixMap = {}; - if (opt_refNode) { - var node = opt_refNode; - while (node) { - for (var prefix in node.nsPrefixMapInternal) { - nsPrefixMap[prefix] = node.nsPrefixMapInternal[prefix]; - } - node = node.parentNode; - } - } - this.nodeMap_ = {}; - this.attrs_ = []; - for (var name in nodeMap) { - // If the attribute name includes a colon, resolve the namespace prefix. - var colonIndex = name.indexOf(':'); - var namespaceURI = null; - if (colonIndex != -1) { - var prefix = name.substring(0, colonIndex); - var uri = nsPrefixMap[prefix]; - if (uri) { - namespaceURI = uri; - } - } - var attr = new pdom.Attr(name, nodeMap[name], namespaceURI); - this.attrs_.push(attr); - this.nodeMap_[name] = attr; - } -}; - - -/** - * @param {string} name The name of the node to return. - * @return {pdom.Node} The named node. - */ -pdom.NamedNodeMap.prototype.getNamedItem = function(name) { - return this.nodeMap_[name] || null; -}; - - -/** - * @param {number} index The index of the node to return. - */ -pdom.NamedNodeMap.prototype.item = function(index) { - if (index >= 0 && index < this.attrs_.length) { - return this.attrs_[index]; - } - return null; -}; - - -/** - * A Node. - * - * @param {pdom.Node} opt_parentNode The parent node, which can be null. - * @constructor - */ -pdom.Node = function(opt_parentNode) { - this.parentNode_ = opt_parentNode; - - this.__defineGetter__('nodeType', function() { throw 'Unknown type of Node' }); - this.__defineGetter__('parentNode', function() { return this.parentNode_ }); - - /** - * An array of child nodes. - * @type {Array.} - * @private - */ - this.childNodes_ = []; - - // Read-only properties. - this.__defineGetter__('childNodes', function() { - return new pdom.NodeList(this.childNodes_); - }); - this.__defineGetter__('firstChild', function() { - return this.childNodes_[0] || null; - }); - this.__defineGetter__('lastChild', function() { - return this.childNodes_.length <= 0 ? null : - this.childNodes_[this.childNodes_.length - 1]; - }); - this.__defineGetter__('previousSibling', function() { - var parent = this.parentNode; - if (parent) { - var familySize = parent.childNodes_.length; - for (var i = 0; i < familySize; ++i) { - var child = parent.childNodes_[i]; - if (child === this && i > 0) { - return parent.childNodes_[i - 1]; - } - } - } - return null; - }); - this.__defineGetter__('nextSibling', function() { - var parent = this.parentNode; - if (parent) { - var familySize = parent.childNodes_.length; - for (var i = 0; i < familySize; ++i) { - var child = parent.childNodes_[i]; - if (child === this && i < familySize - 1) { - return parent.childNodes_[i + 1]; - } - } - } - return null; - }); - this.__defineGetter__('attributes', function() { return null }); - - this.__defineGetter__('namespaceURI', function() { - if (this.parentNode_) { - return this.parentNode_.namespaceURI; - } - return null; - }); -}; - - -pdom.Node.ELEMENT_NODE = 1; -pdom.Node.ATTRIBUTE_NODE = 2; -pdom.Node.TEXT_NODE = 3; -pdom.Node.CDATA_SECTION_NODE = 4; -pdom.Node.ENTITY_REFERENCE_NODE = 5; -pdom.Node.ENTITY_NODE = 6; -pdom.Node.PROCESSING_INSTRUCTION_NODE = 7; -pdom.Node.COMMENT_NODE = 8; -pdom.Node.DOCUMENT_NODE = 9; -pdom.Node.DOCUMENT_TYPE_NODE = 10; -pdom.Node.DOCUMENT_FRAGMENT_NODE = 11; -pdom.Node.NOTATION_NODE = 12; - - -/** - * @return {boolean} Whether the node has any children. - */ -pdom.Node.prototype.hasChildNodes = function() { - return this.childNodes_.length > 0; -}; - - -/** - * @param {pdom.Node} child The node to remove. - * @return {pdom.Node} The removed node. - */ -pdom.Node.prototype.removeChild = function(child) { - var max = this.childNodes.length; - for (var i = 0; i < max; ++i) { - if (this.childNodes_[i] == child) { - this.childNodes_.splice(i, 1); - child.parentNode_ = null; - return child; - } - } - throw new pdom.DOMException(pdom.DOMException.NOT_FOUND_ERR); -}; - - -/** - * @param {pdom.Node} child The node to append. - * @return {pdom.Node} The appended node. - */ -pdom.Node.prototype.appendChild = function(child) { - if (child.parentNode) { - child.parentNode.removeChild(child); - } - this.childNodes_.push(child); - return child; -}; - - -/** - * A XML Document. - * - * @param {string} opt_text The optional text of the document. - * @param {pdom.Node} opt_parentNode The parent node, which can be null. - * @constructor - * @extends {pdom.Node} - */ -pdom.XMLDocument = function(opt_text) { - pdom.base(this, null); - - this.__defineGetter__('nodeType', function() { - return pdom.Node.DOCUMENT_NODE; - }); - this.__defineGetter__('documentElement', function() { - for (var i = 0; i < this.childNodes_.length; ++i) { - if (this.childNodes_[i].nodeType == 1) { - return this.childNodes_[i]; - } - } - return null; - }); -}; -pdom.inherits(pdom.XMLDocument, pdom.Node); - - -/** - * A DocumentType node. - * - * @constructor - * @extends {pdom.Node} - */ -pdom.DocumentType = function() { - pdom.base(this, null); - - this.__defineGetter__('nodeType', function() { - return pdom.Node.DOCUMENT_TYPE_NODE - }); -}; -pdom.inherits(pdom.DocumentType, pdom.Node); - - -/** - * An Attr node. - * - * @param {string} name The name of the attribute. - * @param {string} value The value of the attribute. - * @param {stirng} opt_namespaceURI Optional namespace URI. - * @constructor - * @extends {pdom.Attr} - */ -pdom.Attr = function(name, value, opt_namespaceURI) { - pdom.base(this, null); - - this.__defineGetter__('nodeType', function() { - return pdom.Node.ATTRIBUTE_NODE; - }); - this.__defineGetter__('name', function() { return name }); - this.__defineGetter__('namespaceURI', function() { return opt_namespaceURI }); - - /** - * @type {string} - */ - this.value = value; -}; -pdom.inherits(pdom.Attr, pdom.Node); - - -/** - * An Element node. - * - * @param {string} tagName The tag name of this element. - * @param {pdom.Node} opt_parentNode The parent node, which can be null. - * @param {Object.} opt_attrs The attribute map. - * @constructor - * @extends {pdom.Node} - */ -pdom.Element = function(tagName, opt_parentNode, opt_attrs) { - pdom.base(this, opt_parentNode); - - /** - * Internal map of attributes for this element. - * - * @type {Object.} - * @private - */ - this.attributes_ = opt_attrs || {}; - - this.__defineGetter__('attributes', function() { - if (!this.attributeMap_) { - this.attributeMap_ = new pdom.NamedNodeMap(this.attributes_, this); - } - return this.attributeMap_; - }); - - this.__defineGetter__('nodeType', function() { - return pdom.Node.ELEMENT_NODE; - }); - this.__defineGetter__('tagName', function() { return tagName }); - this.__defineGetter__('nodeName', function() { return tagName }); - - /** - * @type {string} - * @private - */ - this.namespaceURI_ = this.parentNode_ ? this.parentNode_.namespaceURI : null; - - /** - * Map of namespace prefix to URI. - * - * @type {Object.} - */ - this.nsPrefixMapInternal = {}; - - // Generate map of prefixes to namespace URIs. Also, discover if there is - // a default namespace on this element. - for (var attrName in this.attributes_) { - if (attrName.indexOf('xmlns:') == 0 && attrName.length > 6) { - var prefix = attrName.substring(6); - this.nsPrefixMapInternal[prefix] = this.attributes_[attrName]; - } else if (attrName === 'xmlns') { - this.namespaceURI_ = this.attributes_[attrName]; - } - } - - // If the tagname includes a colon, resolve the namespace prefix. - var colonIndex = tagName.indexOf(':'); - if (colonIndex != -1) { - var prefix = tagName.substring(0, colonIndex); - var node = this; - while (node) { - var uri = node.nsPrefixMapInternal[prefix]; - if (uri) { - this.namespaceURI_ = uri; - break; - } - node = node.parentNode; - } - } - - this.__defineGetter__('namespaceURI', function() { return this.namespaceURI_ }); -}; -pdom.inherits(pdom.Element, pdom.Node); - - -/** - * @type {pdom.NamedNodeMap} - * @private - */ -pdom.Element.prototype.attributeMap_ = null; - - -/** - * @param {string} attrName The attribute name to get. - */ -pdom.Element.prototype.getAttribute = function(attrName) { - var attrVal = this.attributes_[attrName] || ''; - return attrVal; -}; - - -/** - * @param {string} name The attribute name to set. - * @param {string} value The attribute value to set. - */ -pdom.Element.prototype.setAttribute = function(name, value) { - this.attributes_[name] = value; - if (this.attributeMap_) { - this.attributeMap_.setNodeMapInternal(this.attributes_, this); - } -}; - - -/** - * @param {string} name The attribute to remove. - */ -pdom.Element.prototype.removeAttribute = function(name) { - delete this.attributes_[name]; - if (this.attributeMap_) { - this.attributeMap_.setNodeMapInternal(this.attributes_, this); - } -}; - - -/** - * @return {boolean} Whether the element had an attribute. - */ -pdom.Element.prototype.hasAttribute = function(name) { - return !!this.attributes_[name]; -}; - - -/** - * CharacterData node. - * - * @param {string} opt_text The optional text of the document. - * @param {pdom.Node} opt_parentNode The parent node, which can be null. - * @constructor - * @extends {pdom.Node} - */ -pdom.CharacterData = function(opt_text, opt_parentNode) { - pdom.base(this, opt_parentNode); - - this.__defineGetter__('data', function() { return opt_text }); -}; -pdom.inherits(pdom.CharacterData, pdom.Node); - - -/** - * A Comment node. - * - * @param {string} opt_text The optional text of the comment. - * @param {pdom.Node} opt_parentNode The parent node, which can be null. - * @constructor - * @extends {pdom.CharacterData} - */ -pdom.Comment = function(opt_text, opt_parentNode) { - pdom.base(this, opt_text); - - this.__defineGetter__('nodeType', function() { - return pdom.Node.COMMENT_NODE; - }); -}; -pdom.inherits(pdom.Comment, pdom.CharacterData); - - -/** - * A Text node. - * - * @param {string} opt_text The optional text of the comment. - * @param {pdom.Node} opt_parentNode The parent node, which can be null. - * @constructor - * @extends {pdom.CharacterData} - */ -pdom.Text = function(opt_text, opt_parentNode) { - pdom.base(this, opt_text, opt_parentNode); - - this.__defineGetter__('nodeType', function() { - return pdom.Node.TEXT_NODE; - }); -}; -pdom.inherits(pdom.Text, pdom.CharacterData); - - - -pdom.parse = {}; - -/** - * Swallows all whitespace on the left. - * - * @private - * @return {boolean} True if some whitespace characters were swallowed. - */ -pdom.parse.swallowWS_ = function(parsingContext) { - var wsMatches = parsingContext.xmlText.match(/^\s+/); - if (wsMatches && wsMatches.length > 0) { - parsingContext.offset += wsMatches[0].length; - return true; - } - return false; -}; - - -/** - * @private - * @returns {boolean} True if some cruft was swallowed. - */ -pdom.parse.swallowXmlCruft_ = function(parsingContext, head, tail) { - pdom.parse.swallowWS_(parsingContext); - var text = parsingContext.xmlText; - var start = parsingContext.offset; - // If we find the start, strip it all off. - if (text.indexOf(head, start) == 0) { - var end = text.indexOf(tail, start + head.length); - if (end == -1) { - throw 'Could not find the end of the thing (' + tail + ')'; - } - parsingContext.offset = end + tail.length; - return true; - } - return false; -} - - -/** - * Parses the XML prolog, if present. - * - * @private - * @return {boolean} True if an XML prolog was found. - */ -pdom.parse.parseProlog_ = function(parsingContext) { - return pdom.parse.swallowXmlCruft_(parsingContext, ''); -}; - - -/** - * Parses the DOCTYPE, if present. - * - * @return {boolean} True if a DOCTYPE was found. - */ -pdom.parse.parseDocType_ = function(parsingContext) { - swallowWS(parsingContext); - var text = parsingContext.xmlText; - var start = parsingContext.offset; - var head = '', start + head.length); - if (endDocType == -1) { - throw 'Could not find the end of the DOCTYPE (>)'; - } - parsingContext.offset = endDocType + 2; - return true; - } - return false; -}; - - -/** - * Parses one node from the XML stream. - * - * @private - * @param {Object} parsingContext The parsing context. - * @return {pdom.Node} Returns the Node or null if none are found. - */ -pdom.parse.parseOneNode_ = function(parsingContext) { - var i = parsingContext.offset; - var xmlText = parsingContext.xmlText; - - // Detect if it's a comment () - var COMMENT_START = ''; - if (xmlText.indexOf(COMMENT_START, i) == i) { - var endComment = xmlText.indexOf(COMMENT_END, i + COMMENT_START.length + 1); - if (endComment == -1) { - throw "End tag for comment not found"; - } - var newComment = new pdom.Comment( - xmlText.substring(i + COMMENT_START.length, endComment), - parsingContext.currentNode); - parsingContext.currentNode.childNodes_.push(newComment); - parsingContext.offset = endComment + COMMENT_END.length; - return newComment; - } - - // Determine if it's a DOCTYPE () - var DOCTYPE_START = ''; - if (xmlText.indexOf(DOCTYPE_START, i) == i) { - // Deal with [] in the DOCTYPE. - var startBracket = xmlText.indexOf('[', i + DOCTYPE_START.length + 1); - if (startBracket != -1) { - var endBracket = xmlText.indexOf(']', startBracket + 1); - if (endBracket == -1) { - throw 'Could not find end ] in DOCTYPE'; - } - i = endBracket + 1; - } - - // TODO: Is this right? Shouldn't it be after the [] if they were present? - var endDocType = xmlText.indexOf('>', i + DOCTYPE_START.length + 1); - if (endDocType == -1) { - throw 'Could not find the end of the DOCTYPE (>)'; - } - var newDocType = new pdom.DocumentType(); - parsingContext.currentNode.childNodes_.push(newDocType); - parsingContext.offset = endDocType + 1; - return newDocType; - } - - // If we are inside an element, see if we have the end tag. - if (parsingContext.currentNode.nodeType == 1 && - xmlText.indexOf('', i + 2); - if (endEndTagIndex == -1) { - throw 'Could not find end of end tag'; - } - - // Check if the tagname matches the end tag. If not, that's an error. - var tagName = xmlText.substring(i + 2, endEndTagIndex); - if (tagName != parsingContext.currentNode.tagName) { - throw 'Found instead of '; - } - - // Otherwise, parsing of the current element is done. Return it and - // update the parsing context. - var elementToReturn = parsingContext.currentNode; - parsingContext.offset = endEndTagIndex + 1; - parsingContext.currentNode = elementToReturn.parentNode; - return elementToReturn; - } - - // TODO: Detect if the element has a proper name. - if (xmlText[i] == '<') { - var isSelfClosing = false; - var selfClosingElementIndex = xmlText.indexOf('/>', i + 1); - var endStartTagIndex = xmlText.indexOf('>', i + 1) - if (selfClosingElementIndex == -1 && endStartTagIndex == -1) { - throw 'Could not find end of start tag in Element'; - } - - // Self-closing element. - if (selfClosingElementIndex != -1 && - selfClosingElementIndex < endStartTagIndex) { - endStartTagIndex = selfClosingElementIndex; - isSelfClosing = true; - } - - var attrs = {}; - - // Find if whitespace occurs before the end of the start tag. - var wsMatches = xmlText.substring(i + 1).match(/\s+/); - var tagNameIndex = wsMatches && wsMatches.length > 0 ? - wsMatches.index + i + 1 : - endStartTagIndex; - if (tagNameIndex > endStartTagIndex) { - tagNameIndex = endStartTagIndex; - } else { - // Find all attributes and record them. - var attrGlobs = xmlText.substring(tagNameIndex + 1, endStartTagIndex).trim(); - var j = 0; - while (j < attrGlobs.length) { - var equalsIndex = attrGlobs.indexOf('=', j); - if (equalsIndex == -1) { - break; - } - - // Found an attribute name-value pair. - var attrName = attrGlobs.substring(j, equalsIndex).trim(); - - j = equalsIndex + 1; - var theRest = attrGlobs.substring(j); - var singleQuoteIndex = theRest.indexOf('\'', 0); - var doubleQuoteIndex = theRest.indexOf('"', 0); - if (singleQuoteIndex == -1 && doubleQuoteIndex == -1) { - throw 'Attribute "' + attrName + '" found with no quoted value'; - } - - var quoteChar = '"'; - var quoteIndex = doubleQuoteIndex; - if (singleQuoteIndex != -1 && - ((doubleQuoteIndex != -1 && singleQuoteIndex < doubleQuoteIndex) || - doubleQuoteIndex == -1)) { - // Singly-quoted. - quoteChar = '\''; - quoteIndex = singleQuoteIndex; - } - - var endQuoteIndex = theRest.indexOf(quoteChar, quoteIndex + 1); - if (endQuoteIndex == -1) { - throw 'Did not find end quote for value of attribute "' + attrName + '"'; - } - - var attrVal = theRest.substring(quoteIndex + 1, endQuoteIndex); - attrs[attrName] = attrVal; - - j += endQuoteIndex + 1; - } - } - - var newElementNode = new pdom.Element( - xmlText.substring(i + 1, tagNameIndex), - parsingContext.currentNode, - attrs); - - parsingContext.offset = endStartTagIndex + 1; - parsingContext.currentNode.childNodes_.push(newElementNode); - - if (isSelfClosing) { - // Nudge it past the closing bracket. - parsingContext.offset += 1; - return newElementNode; - } - - // Else, recurse into this element. - parsingContext.currentNode = newElementNode; - return pdom.parse.parseOneNode_(parsingContext); - } - - // Everything else is a text node. - if (i != xmlText.length) { - var endTextIndex = xmlText.indexOf('<', i + 1); - if (endTextIndex == -1) { - endTextIndex = xmlText.length; - } - var theText = xmlText.substring(i, endTextIndex); - var newTextNode = new pdom.Text(theText, parsingContext.currentNode); - parsingContext.currentNode.childNodes_.push(newTextNode); - parsingContext.offset = endTextIndex; - return newTextNode; - } - - return null; -}; - - -/** - * A DOM Parser. - */ -pdom.DOMParser = function(xmlText) { -}; - - -/** - * - * @param {string} xmlText The XML Text. - * @return {pdom.XMLDocument} - */ -pdom.DOMParser.prototype.parseFromString = function(xmlText) { - var theDoc = new pdom.XMLDocument(xmlText); - var parsingContext = {xmlText: xmlText, offset: 0, currentNode: theDoc}; - pdom.parse.parseProlog_(parsingContext); - while (!!(node = pdom.parse.parseOneNode_(parsingContext))) { - // do nothing. - }; - return theDoc; -}; - - -/** - * A XML Serializer. - */ -pdom.XMLSerializer = function() { -}; - - -/** - * @param {pdom.Node} node A node. - * @return {string} The node serialized to text. - */ -pdom.XMLSerializer.prototype.serializeToString = function(node) { - if (!(node instanceof pdom.Node)) { - throw 'Argument XMLSerializer.serializeToString() was not a pdom.Node'; - } - var str = ''; - switch (node.nodeType) { - case pdom.Node.DOCUMENT_NODE: - return this.serializeToString(node.documentElement); - case pdom.Node.ELEMENT_NODE: - str = '<' + node.tagName; - if (node.attributes && node.attributes.length > 0) { - for (var i = 0; i < node.attributes.length; ++i) { - var attr = node.attributes.item(i); - str += ' ' + attr.name + '="' + attr.value + '"'; - } - } - if (node.childNodes.length > 0) { - str += '>'; - for (var i = 0; i < node.childNodes.length; ++i) { - var child = node.childNodes.item(i); - str += this.serializeToString(child); - } - str += ''; - } else { - str += '/>' - } - return str; - case pdom.Node.TEXT_NODE: - return node.data; - } -}; diff --git a/lite/pdom_support.html b/lite/pdom_support.html deleted file mode 100644 index 9a8e9b6..0000000 --- a/lite/pdom_support.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - DOM Core Support in pdom - - - -

DOM Core Support in pdom

-

This table shows the current level of DOM Core support in pdom. At present, this table only shows DOM Core Level 1 and a couple properties/methods from DOM Level 2.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InterfaceProperty/MethodSupport?
NodeDOMString nodeName
DOMString nodeValue
unsigned short nodeType
Node parentNode
NodeList childNodes
Node firstChild
Node lastChild
Node previousSibling
Node nextSibling
NamedNodeMap attributes
Document ownerDocument
Node insertBefore(in Node newChild, in Node refChild)
Node replaceChild(in Node newChild, in Node oldChild)
Node removeChild(in Node oldChild)
Node appendChild(in Node newChild)
boolean hasChildNodes()
Node cloneNode(in boolean deep)
DOMString namespaceURI
Element : NodeDOMString tagName
DOMString getAttribute(in DOMString name)
void setAttribute(in DOMString name, in DOMString value)
void removeAttribute(in DOMString name)
Attr getAttributeNode(in DOMString name)
Attr setAttributeNode(in Attr newAttr)
Attr removeAttributeNode(in Attr oldAttr)
NodeList getElementsByTagName(in DOMString name)
boolean hasAttribute(in DOMString name)
Document : NodeDocumentType doctype
DOMImplementation implementation
Element documentElement
Element createElement(in DOMString tagName)
DocumentFragment createDocumentFragment()
createTextNode(in DOMString data)
createComment(in DOMString data)
createCDATASection(in DOMString data)
createProcessingInstruction(in DOMString target, in DOMString data)
Attr createAttribute(in DOMString name)
EntityReference createEntityByReference(in DOMString name)
NodeList getElementsByTagName(in DOMString tagName)
Element getElementById(in DOMString elementId)
NodeListNode item(in unsigned long index)
unsigned long length
NamedNodeMapNode getNamedItem(in DOMString name)
Node setNamedItem(in Node arg)
Node removeNamedItem(in DOMString name)
Node item(in unsigned long index)
unsigned long length
CharacterData : NodeDOMString data
unsigned long length
DOMString substringData(in unsigned long offset, in unsigned long count)
void appendData(in DOMString arg)
void insertData(in unsigned long offset, in DOMString arg)
void deleteData(in unsigned long offset, in unsigned long count)
void replaceData(in unsigned long offset, in unsigned long count, in DOMString arg)
Text : CharacterDataText splitText(in unsigned long offset)
Attr : NodeDOMString name
boolean specified
DOMString value
Element ownerElement
Comment : CharacterData(empty)
CDATASection : Text(empty)
DOMExceptionunsigned short code
DOMImplementationboolean hasFeature(in DOMString feature, in DOMString version)
DocumentFragment(empty)
DocumentType : NodeDOMString name
NamedNodeMap entities
NamedNodeMap notations
Notation : NodeDOMString publicId
DOMString systemId
Entity : NodeDOMString publicId
DOMString systemId
DOMString notationName
EntityReference : Node(empty)
ProcessingInstruction : NodeDOMString target
DOMString data
- - \ No newline at end of file diff --git a/lite/pdom_test.html b/lite/pdom_test.html deleted file mode 100644 index 8104955..0000000 --- a/lite/pdom_test.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - pdom unit tests - - - - - - - diff --git a/lite/scour.js b/lite/scour.js deleted file mode 100644 index f540270..0000000 --- a/lite/scour.js +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Scour Lite (the JS version) - * - * Copyright(c) 2011 Google Inc. - */ - -importScripts('pdom.js'); - -onmessage = function(evt) { - // Now evt.data contains the text of the SVG file. - postMessage({ - progress: {loaded: 100, total: 100}, - scouredSvg: scourString(evt.data) - }); -}; - -var NS = { - 'SVG': 'http://www.w3.org/2000/svg', - 'XLINK': 'http://www.w3.org/1999/xlink', - 'SODIPODI': 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd', - 'INKSCAPE': 'http://www.inkscape.org/namespaces/inkscape', - 'ADOBE_ILLUSTRATOR': 'http://ns.adobe.com/AdobeIllustrator/10.0/', - 'ADOBE_GRAPHS': 'http://ns.adobe.com/Graphs/1.0/', - 'ADOBE_SVG_VIEWER': 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/', - 'ADOBE_VARIABLES': 'http://ns.adobe.com/Variables/1.0/', - 'ADOBE_SFW': 'http://ns.adobe.com/SaveForWeb/1.0/', - 'ADOBE_EXTENSIBILITY': 'http://ns.adobe.com/Extensibility/1.0/', - 'ADOBE_FLOWS': 'http://ns.adobe.com/Flows/1.0/', - 'ADOBE_IMAGE_REPLACEMENT': 'http://ns.adobe.com/ImageReplacement/1.0/', - 'ADOBE_CUSTOM': 'http://ns.adobe.com/GenericCustomNamespace/1.0/', - 'ADOBE_XPATH': 'http://ns.adobe.com/XPath/1.0/' -}; - -var unwanted_ns = [ NS['SODIPODI'], NS['INKSCAPE'], NS['ADOBE_ILLUSTRATOR'], - NS['ADOBE_GRAPHS'], NS['ADOBE_SVG_VIEWER'], NS['ADOBE_VARIABLES'], - NS['ADOBE_SFW'], NS['ADOBE_EXTENSIBILITY'], NS['ADOBE_FLOWS'], - NS['ADOBE_IMAGE_REPLACEMENT'], NS['ADOBE_CUSTOM'], NS['ADOBE_XPATH'] ]; - -/** - * @param {pdom.Node|Node} node The parent node. - * @param {Array.} namespaces An array of namespace URIs. - */ -var removeNamespacedElements = function(node, namespaces) { - if (node.nodeType == 1) { - // Remove all namespace'd child nodes from this element. - var childrenToRemove = []; - for (var i = 0; i < node.childNodes.length; ++i) { - var child = node.childNodes.item(i); - if (namespaces.indexOf(child.namespaceURI) != -1) { - childrenToRemove.push(child); - postMessage({update: '.'}); - } - } - - for (var i = 0; i < childrenToRemove.length; ++i) { - node.removeChild(childrenToRemove[i]); - } - - // Now recurse for children. - for (var i = 0; i < node.childNodes.length; ++i) { - removeNamespacedElements(node.childNodes.item(i), namespaces); - } - } -}; - - -/** - * @param {pdom.Node|Node} node The parent node. - * @param {Array.} namespaces An array of namespace URIs. - */ -var removeNamespacedAttributes = function(node, namespaces) { - if (node.nodeType == 1) { - // Remove all namespace'd attributes from this element. - var attrsToRemove = []; - for (var i = 0; i < node.attributes.length; ++i) { - var attr = node.attributes.item(i); - if (namespaces.indexOf(attr.namespaceURI) != -1 || - (namespaces.indexOf(attr.value) != -1 && attr.name.indexOf('xmlns:') == 0)) { - attrsToRemove.push(attr); - postMessage({update: '.'}); - } - } - - for (var i = 0; i < attrsToRemove.length; ++i) { - node.removeAttribute(attrsToRemove[i].name); - } - - // Now recurse for children. - for (var i = 0; i < node.childNodes.length; ++i) { - removeNamespacedAttributes(node.childNodes.item(i), namespaces); - } - } -}; - - -/** - * @param {string} in_string The SVG document as a string. - * @param {object} opt_options An optional set of options. - */ -var scourString = function(in_string, opt_options) { - postMessage({progress: {loaded: 0, total: 100}}); - - var parser = new pdom.DOMParser(); - var options = opt_options || {}; - var doc = parser.parseFromString(in_string, 'text/xml'); - - // Remove editor stuff. - if (!options.keep_editor_data) { - postMessage({message: 'Removing namespaced elements '}); - removeNamespacedElements(doc.documentElement, unwanted_ns); - postMessage({update: ' done!'}); - postMessage({progress: {loaded: 45, total: 100}}); - - postMessage({message: 'Removing namespaced attributes '}); - removeNamespacedAttributes(doc.documentElement, unwanted_ns); - postMessage({update: ' done!'}); - postMessage({progress: {loaded: 90, total: 100}}); - } - - return new pdom.XMLSerializer().serializeToString(doc); -}; diff --git a/logos/logo-14x14.png b/logos/logo-14x14.png deleted file mode 100644 index 54007048bff570bb2d34deee13f181c0a973d4ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3117 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 Hu0mjfc?iPX diff --git a/logos/logo-192x192.png b/logos/logo-192x192.png deleted file mode 100644 index 4f5991c08c452a5f72f5e29675d64d344afa3727..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31940 zcmd>l`#;nF|NclUkr6o-W7vcYITLf-7&hl)v>ZlGu_P*Ka%dEW9Lr&3Oim-mh*qcx znH+Pd77~#cCHn0B>-S&y{_x!Mc6;7#`(gL{<9Xe$`*mGQbF{Y>S-sctisL$4~z6;sO*FO8@};4tR5ON5|lZn26}$h)6l4xw%~A z)rdg+l>h+X`gDm?kh9auDdXMwUkKaOM6zuJRtzYIMchvm%~DbU9|NIM!DUlom_A`k zOCISrPg0L$W+sxvFscIS{2%!~gUd7TR-~p6?JvexgtEGJzrH)9Pnxjnwo95v_?qcV7=M7C)<--rD0E;oVMh{ibHA^KL@+O8ImMi|?3HCkygs^)*ut~_24tTOM z?Y15HzuH)qJ#3$v`ttenN7Mkq%YVr2=3&swi@k0KSAO3z`n$Wc(6a=&qv>67aI5tC2n0SzH0T=7|IPknGl{oe_N>pui)E!FLx&V*hPiIIw=A z2uKV>W=8=4z7`O5=b`2cuYmx7#gjWK4QA56`Xp3)d1d;J&h{Pu>!(9RKn7kSKnVWJ zi85FHV0B3d=)HFhr&avUeK0+(-HQpnmlJtH{iVzE6ULE3fBb=^ebBBu$9T-%08jdZ zr&GBurMoL+0>ulG_rQHNJRQ^EPm7y0e^%&FL-UtK9l2-c}u1hHn6x zNq_HkS;NV9nlQ#61nB1NPj#h;R^`XvUygwnJ~;KH=>63eDPxjO8T);0u+a1a6Z6*^ zz27AGv<9wds5ANzje4rba&W_q@^u2W45(Ou5 z?_geudD3`sxr-rp94Fa)T@@TESbL9f=lpTE<>6>ezwA`Ap z+vLCte9Mob_KIWdkFlZE`P;YB=S4SQOEBpwZM$}OfOjZ0FF(({)}|IyYrWR3Q@>ta zQq^tQ>9K$3gxPD9vbVBz&;#bt61LNn(_A%w^(nNm!A`w8HIyP<)@c#@BE0&?qtYJV z#8SJ6>iM{C_8*y>=MJ0?!v0k6SPQuGHVZ&_X9SoMMz79CMHrnv_j=|h#@wgh)STj< z>z}_!%xWJss+h3Kuo5ES8Q#l~X#G>1)U{!{8hIX&ty?s~y zj#Y5J$QVAU$u43SO%{D>^Ygs!soMIq^?3lY>9c2*$B)*o@MKSY4~n~sr%$sLt%Rn? z>ZEm63s<+>=h)YlvV!^>ezp#_*0f1BeEG;bQ{NiadecAXl6X+ttNQ*QIo&xoJ8oti z81o6HOr5Ab?RolEbjwvy16PCjLT2%g3pZc=%3C=X8n+G- z4{DFTyPbMJ%{FORJ>NvVNSZPCru#E0W+%#L@y6IrNl|mr%k`%-&wl9q!2d{@ef(DY zF|5=>EBbx^8}kLsm(dHyALnX>eyY3WVD4}yh|X3xhdY<$Mw@JCqr_5o{Wru-{xiAy zc-dsxNOxXy-s9q1-QKo0ZNm=z5v3QCKbhZF_;>l=jenzn>O@7Zpd)E_%aUd4o}9%3}D+o9cY zfuSDg@pi(!#2tCXRz_c4rCuleO3$ai>)RPbP>tw8ACV$+^(=UVM&yDJgrhYW{Rykw8Wut<=k^McZ>wFyK zl@>+yOFL1y=3$qepxs=NLFuW&YjR~%2n}=o|>K1Q2 z{;gD%y)(toGYDwIsb9i`7t&}_n+JgAN?U6-}RsN_lX&=uH6HZ!JZix zE*JDf;6%Vaa=&@^LVX%_WiM|(%!g(l7PbER$k>qsK7|vllkFcSPLCNoV;`{2u34XW zE!%TgvJtB$s3Yi-QOsCUh_s0Nys~@j)9x8TgXwFe__{^DaoKC9gHE3dK@@HkS`|4J z?t5MG>Tq~#GRj(=zwy_4Mpmd;+sGphwe38JpI%8C&k5QZA(iBo+`Og!d)9BJyfvPU zV}1$|irDA?#Vn3l{=3gM>@s9}Z#|FMYMS|S((Soh;WLAaVXHB#Mu$1$4zD|lI}7XE zy+hl7+~}sq2kx#&m+CU-es#zFJoS$?QL1k|*S&osV)xbV&Zkpzx2`H5Fo!#*VwHc; zx*WPL{xV%Rn=+qEnYiF}IQwy9_I5~b?33-$S?gWiSvwDe%#S`OcrbiV@ZMUf zo{7Hx(uJ!BD}SraM=p;jm5Lvh9}d@xpE`GIZ(?ndIr?a{EPpFM=S5foNVzY*h;RhrRz42` zfshkNye0-la!Kn><%M~4pE+I96Ymkw`s~vMmVuY`tE_iZ~>eqh$d-kL=#ZSDGzu~^mcNNZ)##%t<$5-{--!J`t`p_lO=ldl$u4|3=eU5&7 zrG8C}Q=O0h&%;AE-YH|A&OKSbnB~D!=>G;Uf8uQr>ZJj~d3(8Lk1PlQ5>6z}alZ8T zfhPG^oEMKAhd92t^4Nj+XAD;|c#|eRmCe5Wl+2w)ekvVMN0;T=i~#%{teJP9 zOU|%rxTf&zXU*fq0Go3&O@k&c>>|g-g=4r9eOgBc4=n@IvFY0Aht&m4uYwSEJGvPH z!B|kp#hNNGuqJw(I=L>;tnDF{fg=3(H@RT{%=PQH!fsXw_By!Uy)Cd{+sVKA;>73t zsq(?Y?49p+s;iU(%KBAXshi2WA{XC@FOk6M3ImwWOL|vHa0gTFL_m^hA^_1VIgTBY zN8{#(t`<>_0V%>@q9&vFC|^)Z^&PDIY6nucZGU~8 zc37vwP=8jZQ$14JcF^~bR!wCuOq?P`2F;sChB|H6Dz-u z+qPrVU;HFI^X*(s$6;uNPwSc5M6?{6HA z{kzn*oYw2pQPQ1iyO~gyaJc?0uIHy>{(@z49{e6OJGIh6)KVw2GHvM%L-Q&Ia#M6r zjtE4grfab@7!rx5Aen%!%VZLiLI5=K0Kq)`JjWi25-W@0;+9RB%Qni$as`-x;)g_@ z>#{_;`h;gJ9j-+Ll?F{cofulX)=4pp3*R<69tFWM+AGOJprl{(d>c0-=lMeGoKU~Z z>%1|!Oo`AI%^UcDiCh0|Uo19!9`X2h&&JISR7H!A*C!htown(_eNQK$V%Aulbywe5 zgRq(PmK1!UYnJHrexlX+pTW*b73JTqgze1qW3m8TCD-CNhQqsSWG%A{WBqIBO|9w_ zvL}C;`KH?hdfR$F<@SjMWq|g-i(XvnYVY!!xHywxGyqZX;!U3Mh(mYGZB37_=feIr z9einfygfq!J;e11U_^i0@Lv$Ncqv&y##q6QD)JCP0~n$SEmloLUi!puZo zziE2=*@HSm%L}Jp9S;fU$z{K3R)yg0aFTEsQI5O`lH&p~Z2F;2WUQ@ZGij_>k1vRf z9eNIWiv+7M9&!7XL^}>OQ0wt7lXa@YPwQ4&>Zp0=^Ik=@2)`b6m3gHAw&>U2=8|Jh z+rUa(2yzbU z8WdNVUUB_wdN~FXpa^jzH70_d66{05u#^~Imz|i3LLIJ}%Mi}l6lj9Lmh@b)s1bby zz;lASj%VAdRe;MJ1XV+X2X3iKfA%o28?Pi|gPHB-zz?2hSF4cLmQyuUgK>r<5tI!X z^~gKX1d$xFVG%)VCCVAtCe_*)4H*J&zyGBEWCd9tHRuS0Us(6$b^ESKGp zM+LJ#?0EiUKO9bz?tQ#mdo@#a_)G+R(oR*|nApG2qv zLEM$QCe5sCB)FCdkqAhS))7IF^u!f|>@ZdW6jgvJ@J`BtLIoP@O7PZ2e=oi(1SWz+ zxlw?0&?N~H#OaKBxfhVS&k^dvJY^SDU3n{Npfc|-2BnC zL0kv`_8nK}MQq(6W57hmY%O!iBY>|rAF>|V;pb?pH&FPJs|=SsMX$KL6JrqCG6ajY z8G$N-dHhM})vCeTjvr8(qT+yZ)a+$EbzGH>7fFF+3M<1iD*cj<_eoSd-hY{2m{V=< zKKZCZ4;kbQFvDu zLhGDt3|~LygeljaR}Oh)^7Ii$z(0ZB870@>`X66JJn(o_WLc;rKhmUeLATR*V(nLF zNoH8=bTGR;Lw*tPvc=WIrPc=ah0YoqinSOap{j&Fh3k*wHx!Qw-Z^Sknt?uIw#hXRFD_Ho$CD_>lLXqk zd|u3iD7lev94t!8$|5(Vm)qFFWZ1J#sIx>rdSmWb$2;gEMs!p!-2f@mwyeh=B{B+0 zM~YfHqs%BEKT;ebl^+Npf|3(I#7C6S?WLEcDTq1k%g*Gk8kgp-jvImTowuV1VLq}( z4GzVIx54An0{aL4xVkT3;>Q$_ByJj*T5iJ&%?#z257N30WfHpq zhbD=eJ9PljUOqs=GR5#~U|{RU^Mk6zp6>YB#k>2H|830F(g=f$uU|i0yKNd&RrRs& z$bJ%b`W&tP`F(M>mwtLJKz|z`Udh!n@gY$p`#3XO4>@-2>;?pRsW|#(Xc##8y=Hc* zJQARN@y3Eb;q&{xdEM@x1ZDdYeXoSW;}=!FvIEf-+MlN9GdX}>QEn$L{#89;cxJv> zDaweJQIkPuK*KWV1MapNjkBH#b@VZP*{Mit?QhjF8GD zf_f#?5Q)4C$qSIo@?V9u_9Wkbg>GM&?G|`ikySwzrU#R5z(y28!l{$F9(fI4zD#_1 zmHhh^BqL|R+`rBx1KSFvI+6pR!|9>{$lS3^j4Rd(#a*5NWO=e%SQdE2LM!WxkZh}( zJd9H8JcYSWObQnLOD*OSZ96_0jJf^poY5;(FJGs&-uBo9X|Ri;*I6EPBD z^6Z-*hO{g&Jj_Sk4J}vxeP4bY9u^jMe>`Y}{`mUp3Z5odQpbJ!fI?oNct81cWHWR4 z@8;;)AI}NPg=Zb!J~kr!dAsaTGCTcocD|N8eY>CT_V}Q5_okP=gjjTu*9?tHRlwQd zXkiH8(ZoVWY9)v|7rrvJ0yDgz+b=FIUM2K>t~nom>ap={|DCr}+m)k*cv=np1XG_z zR;jA4q88P^2yCT>ev&02=03z|tL#06R#0m)LRv(VUVCJd0A#M5bV(wb!nZ3Lb$lt;HAGk3;L} zivcc!{+Q21kU}!lx&ra)Oxkl=Rl_du38 z-&NF#5s>$IbaTb;-yY|6wU&X3Eh=kI>(=V(*GM1{Wh6-(>0L_s7GuyeF|-QFRKt-R z5qcEuCT7;cO+OMGh3D{gwofE04uOA|#FzMxTF2n_(S_EglhTti(zEje&}$u+&=ubX z5)!p|HSG^FY=Gy1qW~lBGIc#kZawh(KECzhSf-&hNEQ6yF6qE8%x>%h+I50ZMb7pN zt)&YxB!XVs0!?9~sERt3PuhY6aH@7@K=we*!t6;z2$&ew=C#Sx4M6Zw4k~Ug#7qM$41>C{QiO^(kkYH3 zp_ga@EQ6K14nVLs{~|*Y9MQeY^pplTb4WrGFSrz-4dCX2Qy|r3t75pL)m`$KCW9Yk zg9eTQxw!mHh(J@TMDIwjnOw$s3~;k}6wUZpwSCJum%b)+Z)#}Ob9eFe<3~Hpwr8DR zhk{PA*}T>Ek8?R!_g77iLutURuc5Rf&iVf;$g95Yo;}p@@SSD7CZtI0pS%9?dQwxl z6Fc{5M(4Iv&&QSiS@F$pol)aVZ!6NM1uV?u@8|;|*_+>MLi}$jO|?Zt@PRk0Fu7Py zd_@MFrO!qH&jZXQj|SQC!^YkDVG2kX2d3OYaOCq$ zA}GPsj|?({y(1CYck5s2KaixH;4nIXEFzMH!3k)wL;!`La@Z478*><~lB|y8Fl+^q zqdhDQ2yPVO>f2vP*kpPM*7qfaTXfaUm9pbC_}W0cfBA z7y?3QgCog}y%NJvGXc^;d{FnK89X%1TDT1i#-ko<} zd-t(Tf~$T6PQ!QI?bADUD)9G6pL%VexSjb6JZy%Ovk!zEC%%aB;6MH98^v-QH8 zRB7XoGjQh8g1I63WNCopGN~DoCMsUcBJ}6y<@YZ;6c4N#eEa^Z#ly#I*P)aH8l6Fn z9c#>)AO%UrVf6N%#`DxwhJH}mZs|z`jv03reR6c|+K2DIoV5(KDB0S0J@GuJRRAKf zw=TMoW#Ba3QbMm00$*iX@-&d5)g&g1o6GpD(Bs;c7}likO?ktF&0eE`5679DDd!Oy zHm7|>PipYc?~#j3jy77Mc*o4Dd_;dOC2`ENmagNAPwv2A&z4BwqK8sNi)|6m0(WCH z3E&u*%Rc>DXjx&Ro~%(6 zD;kF`r!(oSFj<5ZEH_G~MiqSzpM4@5QeSSPQyk5gsJEsEP0QBHLyErAOdqr1S5ZJN zK`%v#3Zv4Vkoi#sPl%j@z}r8%bs%Jt6fLgaT1>d+Jz#DJ%k?Nc<f559QI>&&80EhM}*% zy58RFyuGK4beZfbVc!T3x0)lc*QMJ&UB!(KX_?66{{F+Tsv>`-x%w(b)dfIOis7;V ze^OeJRRDVYGlyxg?gdxW&@(x77Yxy0gdlACk4nGNl(N9)A^5Ff88rG7=d8Ew_fKKq z*`7saE|VG2XPU>IeszC3RKvH;g`dT#Y}{Pw=5)8CzUT?LDg!$!aRes-XJjXu5%s*AyGSTQOa2Ri~&v~9&Stp4z04?2(ea}d(!Zg(vwNTew z=d{CU=n&c$M5;VGhXzUK)yx(P@^(Un0q^LspTk{MXj>il4pdEPEcjHm8wR4QAS{^t zSqxVv=|upAs_L=^P%CwKXKU%X^9-e8t=xdYz|t>wRnhmg)1)OW?`fjUfiI<`bu&WT z2y>Re;;669+Aby6yxP3l-))H^WumP-c;vR{#}l7)?M~|lWi;Bu1aSgc*am2(r3_Lf zSq=dNf{k#b*IAztsQ?6&i^miKkV@K}H(V-KMpwkROrpo3KCZc^#VjRG95;~3xQ@w7 z8_g6>nofBi$+W_z-XYjOusZ6>VtvsHVxra5XfbXq)--BmxV!i^|HA7Y&!Zg8?E>NV z>F)6A-+lkq;~y6nmDD^o_#Jco`(U*`+sKY!n53C!+gDLgQ=>UN7B=)0i`u8H-|Fg~ z+t5Z4Ko7sHcXe!~|Pv? z{V`!uBQ&$z235+h?zw*Ltg8Ckf~gh!XgK{5>kq;rTdj^lO5mb zWu!N0drl2W7+-r{d>32j=AyP*Wj3c>i5JD7;5ao!qIMR!LN7f;{kcEU;DKpzv|Xrz zG-a%VnnSH`ZlX>zI(ki`&ZMV<#~PL!gh;c^zWh*WFxcDXekhDsM&jju z`SQyN`dpD$2Xg(0Uj<<7;?e+ zJO@{YnUF65ZFBY0CD+D>wA7O2=JzW(ikZ$m&$U$ey%1w&*KZIu34rsNgHDhG0<8M8 zW~2lf=yWyC^fi(Z;|LQ!zrX#!8tqTf`ET84)@Izo0|%GMcysMGbid!fGM7_jE1J<` zW|KBY3p>pnqQyL1*~vg}1>HVe=|1RtvTt-Rglj?UWbC)ID!muEHaFB?EcfdEqKoTbp!hK3%bXJ@7(@&a-{pmT%~ z<;M57B^Ajb6|_;-pM}tkgk^I_GU%ONa~4@Wv*O{vG0!;0G6b~*4QZQMZ+NaT^BFH? zDEnq?Y-@FEwFBd6&fiA_HKWIWNm1lwx&4V8O_C2OB2;0+B1M@4E?hez6XAT)%_S$# zWr9kj&Ol2X83~X9jqIz?N@%61U=XLR-n|1Za3w6`at1bR;%O#bU7kmWM}iRyBT4|( zQH)^oV?X5}fI9}V@}1A>mDjC`%-Stk^9ke zScAzPATb%>F-dnurD>E|K3IW>k^yIMFX#Q-{qS*=+KdAI=eIv``pw5TAOEGxZ9e`q zqG9=R;6g>yXD_dtQ?ddTjnz+Tu<3t5ZvtYZOn!P3;s0I5Eqxx7VI-Sql@u5IJ2;^r27Vf*6KkG8{V7FMff@Hs zUkee*k4V+B|A1Dgg+GSW7FAKC#3Vx%xiG}+LM>N*n03;2A;zHfJ#ZkUx0sL>tv>3> z4*7oabzi&{kVag%3EoT9@`W>gK^~p}`+c`^FLDox4)vLlm^s2-LCzyJs$^dUSvGOF z8UkpnE_FvP(J)jYAgn5P)tSEP8Hz>0%5Cx*NxaBx(I}Z*EWhIO2C|3{k2^b=BT|uv zimFzi6bj3Vbo;Cn<6|P+b@S(jGZDk49k=wz#$d)4pZeWhbQG|*)RxIy>Wj3=9n&E$ zNZ_0^ogz0)cs9HvnJ3vYjVw=D24bazuZ)O{!h=LQASy?VyOlWXi#V&Z)`TD3Yl z8;im?4rzlMSe;MkWiBphw{AZoyUeBIrfkQxds8|>RuN~NBtq+i?tnmplA*S+_@r$f zQ8-Q@dz-NjQmXO%Vg3*Zj${twtWVJF(S&;!cFz4~}jP>^#o?1cZ%fZF2r~!{;&EBen7~k6)C?GkVh%WBcWMTDgFED!)iA{6#2Zy{ko|JgV9 zC#Qinn|Hj}@)hXtx-dhwfe8=tm=q$o531I_a8$Zk{oMc}CrTJf<^wfp zK`xQymO$T0f~zk2b8$4GVyFslg<2Uh2t@$zh@gldZFBgjbope4{VQl%kMMSa}7KGFuweU~$<&`VQHTED^57+g!L7p46Xx{hq^g zc;l#21bG!t^I{%NLYITCwoP*Fy zO?6=|lL2!dn4YrClFovcVW)${RY(6lY1{O)k;&mQS|nZmE(xk>S;f}ed}6@sf(rvf}E73E6|2@#OC zsRVccP)JC7>Ei_%tkU3_M$@FAh6PrLoex(9l`T^~k^p8obk3av!B z=Bta+L7QiszXPJ`vz4-6qSGBbL@kXnFM)Bw$)Kkp(}uM6tc?V8ap$ z1<_@;&;n($W;Gf!LGW?QRUeu@6(C0KV4-Tp+@-sAX$$5f`jZ4^pMiMS?&VAGjsZp_ zLcazEt@>6kXUghd4hpLB$O{;K`zz+4$t&W!tZ_o5D++eF@Zdti&&Pl7KQ_KXYCqk} zcX8?RcgKyL(pw_tsPrcfb5{KgP_eLip@(x-RM` zwLY0%PZY{%Ww;WS@0ZKi_pCiKuqMxyxs*IOndlb^Qy887`qQ^;AmUNF(6Ac(NC8H6*734e+ zMZSz@F}GsUqm_zxdZ5Gp81ey?8cL(LGUHLlau8Ngs^i*d!){;0h%agkDD1A#5m|)f z!rFrWYhI!TLe9*F0bP$|RBgF3n;hFeZ&d%%EgC`!k5#P zJf&B=mitmt9ar^nia?bOZyFs=AA=6_ySOw~;VZE!6O2~kf-{f{0j#6fQ;YmPTn;#5 z5o_9j%?)5k<{+~NJPIr0^5{)QYbcmJ4LzYvtt;vXk($s(Nl$3|;yFuGGb;^*c&o?G z0;y&yNFrArE#zTVxrhr#8ks-gLc?&FWl2>Hv-vIEEACs1SI=B{mTPH_s;#@IrClV) z7P@Q~auiy|!^6p7J=%W_RFp~lOv11azTss5{TlL#oj+6GzM9_MU+(Vf;ql2R>hDLv z;${o{QEqN__n&)hFO)sKKJDcLZl&HnT0U$0-*JwYQnr2b!d~n^+l%e>+Gn?S&hiOe z_@l>S>9Px}z{D}L(rN|Rz~<5x|NesY;oqSuOn&ea0C_#7mY4WuA3qA|{=s-RSAebKag#S!kGCK}up znsypm>y+w`E*vmb5{I83y8djuW@f!BV<>a`H*@jUnb*NCxMe%-ldU|=P zt1HWWLK}Sj!X{YYu2AxJc)tgm6dTFlXZs|Xddhvf%IqYK6?B9TVK4$iO)A6G@YO0E zRMA463z)|eNRtd|U#PQ%-4{l@XH;fj$2~)ryC?hjP6Ca%O#%GeCqO59MGzL*7A@l| z4{O5n9UKT1=5v`>+Pt(!w9X7emx`;&+0H0@ww^0K`(85XiW|hZ?c4Cen|p9?q`5!=WvU)(Cw1;{Ks!TTTwNXQfZn-66U9rNKWRPschG4h za$_#?d-~V^YH}RJ16qfWR?So%zI zPBBZ;dQ4l<$?3Go#QIQ8O*m)qeNM(6-JmrxrE!n2Dj`z2fIIx)60#;FN;F$L$|HLZ zk|t~^ES40_eDs9Okb}H@q*KSJ8}TzuJ(~JhMoucJn(NLDA$7&rEOMp@ibSu+OT`ZU zQ?0$HLolzc;y7eP7Bz+m3oR*l-%x{9(qutc&%Hy%q(gC`K3Lrh^nGu}4^WVEg3??qeLU;mA=?wjOm%HEcSrewsE*-!l3fXEmlRoJG3S z=fOCdA6J_HzXMD#>=?&)UaL*+%H^1n$snV0a^T5OX{aKHxd9c4Sk$*|qVVObm57g1 z$qP|wAtFkGLWg4)Wm6yjQcuzNeF%QIV2nuIn%CtRJ{gTDn3pSo0~wZ>_lr*#IKX(n z$!@hHt$R0@USCCi%Gqq|BCh;-x4s^Xi#C+aNRN4WIk>9&M#Yz0dSL6yo<)LQ;=A%ZxKUJ8g ztM@(-%-1>s3FE0&H8#@y-Mi>bPQoUHl7T@@b>I;$6J=0aY~BR%y?a^{wY;Og!m4IZ z#5nY={LlF~* z-+w=5I-mc{)9ty1!w0;g)zOl*kwdPfYeu$lGOyJ@*)U2HHl1`=`y3A&zFh2uv-8mn zkJorVb8tsm!0MJe$;M~mgTd=#a!?!`(ZG!R(lyR92%-tH3@(*Wm~o5U`QSaETn)&m z5;+S&Qk%6$<4OxSxxLZ=li}uvib$JrqD59^)wLb`U3$CfWnf~mQyd|Rkl62X!e*5 zMjuR`2A_VRvzG`zI?K1=-N58y%M?d9u!J{G7jJ*y+xYA5UIcfmx>|u*NvQyz7O+at zQ~4a}3<+=vVCpZIJX6llt*3@u%u`Hns;nr#Z0TVc;PGmH|J$qCDREf#;fUOu#jOo9 z7#*K|9d=Zi=(u5A7ahs^9il2^IKuHyqIUlCiueEoae^>6uf+v~eNxo@SNq%lwqWmz zLxUGBM|;P$Yw8W6u2jsd_-U(5{rMW``yd}Z`ShL!gX4HSD<~>xEwPs-X?`tUtHft( zSfR5ky}HA_b~{QmCf3SlRyI|KFBe+C#pQ9N!NCNXb9&Jv_=x^439ezKY_g^o4?r-M zZIxKs#LZc`??(#&n(ev?J3%2!{hm0|7=wjguBE?%?FX;zrd-mHVN{gAZDDBw)b|!%hu^syt?s^NBjE&ibGyuT^OI;X+z{WX zjk_eXLw@g97vME>kVju$IkEqrdcExIi)U}PuXJ3H*o%J=dAlnps&D?rIKgYASl`WL z>toI~psL&^eE!xjdScO>&oeIXdQg9rPRGaDY1iEgzk;1bUnSA=CI|}2pw@Bx1oJmD zQZJp%8vRV{S*gV&iuNjV&2H@+?$!9ZbuX($c)r-Fk{*L*RxR0tpzyuKZ|Zux$ihde z$b@W$%@WZPtAW51LEj(`3*CnsA4?&w3w!N&*V?@q(7f2h-~oWSz#lS$>l~ zr$1f@rGdew8y1JlGVp}W0ex{F&p)}?r&RuVzU6M^`S_)~oDYM+GuKHq&xiD%(de$y z%PnK|;ZheT1gTUdOOK|eI(HA(rne%#fQ4CrhT}GQmkP zTKeclGJOgaKO9K$MW_9{SD#o-Mns+gDw>79<65e|G52twQOMMvR7Ie1P>h3Kr@jWZ zWu7)}F}|RCmdnBuUz70@O)EZrf{1NxZ>O9|*lU#NEtYN@I*(1Qni#s-Ik81kjrJ(L zXJqRk^O~FMSQ$}^0Zj}SMRM@0wPP+Etf%|pkJrE73rB=5NM)Weh^(3me}w?{K}!hp zvJ~0j9|==x)hw3I zdH}x$cf;Qa`+NJ{gP&=}7uTjjz7!lD2qi#I3s_g!pkzUHvGeily9Ac>a#tg-XVDY- zJ)L_{icJMW;6)Xt4kPH6aVi6gl|HGz22IqHvjF0P0*m25V4uT(i(8(&?N_?M?N>x* zZ$EBN$Nku%3`Y9$`|IKIG*^#-OR*xRHcyDWjHm44P8-x?NYtA#(YVr4Rip^mVr*#p zo$FaII_tc6Uj9^$L&>Vi&M&PLis;VSi?{awl-=DIU!@{-TU)Kz=TrqZZhsrCn;VMS z^*Og)+<4_?bf>3}mn>ImXGtq3>w5Ba)8DdR#OWJ6X~uc;Uaa_;3xD?=7Y-z$5Cf}V0;9oDk9L)0_nivm`zK`3A{gfSiNLB8TlUd-;~q(<9rO{6VbKAZ86l8J&n_aoUd z3+$J!Yo%Y7HFcWg=M1rg+E0(qWbk`?`)1XKu8k)}H$B(5pqCK&V)fc|B~==msdcU^ zywH!PHNW2rrF%!}h7K9`qD^%0v^9GJ(L$*?c&OG0%((O`WlgBY{3A4jOUM4PzV5*nES>}h_L%`knFe7bWPg5p%*h~C z3rywi_kvFbS2v#&6ch~Q=-Hq6@u@Rz?>(26ma$kg^ZMM=KmuXTIQr|Awc{6WG#q|= zeZiQpw{VzoGhW;$ud0rN&C2z92CIbWP)^KK*w=NZ3sek=`o64JUL4JUevtzKgy%co z?3*5Y@;W9kL?XZym8pte>&g}91iHzNwHalcXj)TUb`^#bmy8(meSQkr{tkM!F4kVU zzpx5fOZ^cNR>h4FLD*D+?n2Xb6kyiHjSK^J9UVe6HAV=?a(qB9yfLjsiP@eM9j>>W z4k8zC3sXKgBDe!cT2_kOS3xbu%3u|oKP7m6^`N%sgvSwbBd%P@>cD?UJDW+Hk6fQ{ z3h?+6x+Z-&j!?40cf`phw}JJ0@Sz%%hIZ2JsS6>y3|d=CiUkxnyX3fso3gydU%Hj8up_U#!XL|o|+V&RIrlPK2>mpneuC}y0mBS^Ptn){r5#hCF&d) zYBSc={lDVAGAgR?`+MjVkVZ;G1q2CcNkKqCLApa4Y3Upq$@wa&v_kQCzBEkg%Wl*iI`B(P{8<&t zteNx#J>A8e$_$Wkp%2%632Iq^8=rf~A=7RMkE!%o(AVu)V^C6P@6tX48Ud}J?~+l4 z#F6BN>9Kj!D5-PhIXq~mp#jBlf5OZUjy}dyRh-3^{7jx(1`2Fp&*O70OMHd~lhn1%v`%0GKjVzb0v9N7>n(C!JR_GOWi zrB+Bt?)e$}{b$to-dN-b<(`y=#Tyl_i3xabU)a|OH|dACNp2>>ZxNthn;`W4-+l72 zKf8gG`{c9A_Hslg30qE}!!TYkypbocA+eO0s{L02%@ht{;@E#(K(9Q0O_?ARub#tF>6pv`Jl~ybNP9m>BXPU$(b9ia^0tc z!-}61@!P&FH}xLAahKTT8k!C{QFS*c{quE`Yvx0Z|Cg?b)6>(#tiT=3QI5Tf`IUCF zR6)2_-8jpxemcidb+v0_Mh{{*CEktJXW!6<&xpy<$zfErpfulaq4Z%~+AH|uD0U89 z4%y|Qi)ryJTZ>uvHxah5F4v~7U86cYxomVz55n~JnJeM1EgWY#CxF3*NOugTh>=aF zX!`U({}tO4uJDy~M)+?V#N)4@z8nzJAdRd`|M(MTC;ATQf3p1X{S_H5Qh~6Y-d^5V z)L)C*70N#dW~)Vt-ZEF6t<2!VOkSa)%_g0?gQO%K%i4{+wnZ-429i*VdwI zW#}V7iFlwWS-Egfd}$00+El-(t8c9QbjkfLJN{FJp%&NFrwJ2@b%lNnk9=eBh$u)6 zLhmn3%uljh4T*30o3M!9a~5xO9?qO7$P#ZxH9}E61fGiVD(cq-rsw*;R~zrOlh^ux za*E=2s%IyTh{ZG5q?5E0%D&Q`aJTX(^|)Cb1C9M$Sgx_7aP%@~Zgf!n!>EAdJl-e^ zRv6mXUM?Hry)UUg3$S3ksBlg(t&BWaLpgw{CzR(kzB&_)25NomFP@;21}v??PFs7S zIL$g*V=FK5?ZdpN2bvF7_E# zEjTHFHXuhU2BgJ}CiCkVu-#((VWr)-X`$D0-?|>Yrb>nr!B#nyA24Xb&%5sJS@yw& zDc@~3sT&9*Sb}E%)_l}nIB#&0oA~>4J3{r+`KyS5!S)X~-owS1eD&I*wEQA&W9mE> zn!Kk2V{}$=4TZ1AZS!lAsVHY3wFhv~ZE8HZXr-2sVn{>_llL@-VUD+D9h4w#g_Wa<$^wiBDNxz&LG7A2&IFcQu^ z+UxwAblxqPzze(=ynX67HP(?BiFZ7Uq|2Dp5{T)MZI?4PN{Nblh3k>a5LCZZ(%l6U zLEZ7e;;^RXj>&`vDWp7bZ6Kuu!xxC`NA5Su3{@p^xbDcx)`(P!S$&&yw|<|3X7WitnIUZ4cNFiQucwpXK9DE; zd^7~9cMo`y&{a7+_R!KN0u+ICGOKkmqa=r4Cg-VV=2s?$P$~;s{QU@*VukUNY7lp+ zQ-9}t;7ZLF{axVT>6b)UfS31v=-8~`W^05M7D$|eVBioWRe8uRK=0ac8G%rjU zhPE&tM}nOLdfF3mcFc_Sg8KnQJueChld3!xra`>s-jjsUaPcy#wZ^=@yw_$3@kiNf z2jRt*5BvT|>N$;sE~f1w!cSiDqM ze~CHJg;pP3>Mm*X@(hZG-G2}^2zE#(;)=DhnjDAP`s4(r@lf2)PA|HnyCtRG)`=m%9zqqPfb2KZp#Hx&3-dhMN zr(JJNG*5p#W{3D$v)5W^&Me8VLW^uTpQlq>-M<-;*vN%takSpt__gGpQG~SrcI_O5 z;)&YcMST5fnuOg%*Jdi_ZdPluM6alU0?m6XoqjN8W6tvCk4qP@z|~QCjc3=!`#uw6 zm}@tv|3pmlCOb@O#_wMxhhNIg{>k&uWNmxDEv=~C@?*>etR?8X|LJoVAn6EIxaahY8U4Gbl)fO+mOe6Gv_CI7iC(+iSvsq3a!H_(~g+O%@xhP`i8-MVOhxUHBw z$Uq22CwJ4$-^5`_c=!|4*OE+Gcje6!Z5itkC4<`>;$sR0RC7tl1Y@f4X&zCA;BqYmp``W$w7r+=7EXk-il>^llJDb^m)9e@ zF7|!)i&fw5VR%gbDJu=D3A;it#BKAYH+xf=7gqrVhl0q-i#(+NVP=np#e&wiS2w#$ zmmjZJWT3WtUp`(9Z+)`13%mF|wy^-G30WqV!R+|Ph4{V7MZ8^QnK%ebqbhz_H zQZO00q>HtD3cs-F`vrCoK$b94<)I#kq%gN=o*0+o-m4+;)U@4Y?Q-v&&=*|ot8(Pk zg1gA82u{lE#B8T~uligMH`n&+T6R6>b}jD&NkE!*xVhSvQqNU5xgSASbfup|FAz%? zd%9$`wF4-5=n3Q6*Q4#3nIp!PtgBG3^2Lvcl^PS#r+ZDi=NF-98xf3+Mv!yB+^+YD z@zl;MkMgt?iA9eo5?p48$w_qae@FpdC}*@-3&PMe*rew(47xSW=RGRga)aNr8c$V! zGmCQ`he6@gUnjf5&(BxznC4}09C=!H)AqfG?90R&2)Qy(B;s3Oits<9Cn=PNW!R{biR))2bB*Dy3z+2CUUk z3Jbi{tnDCy=-ogfWkRQx0}8PMsuf3Ac$Oe8E5Fn@{Ik59M3&bSGe?EjFm;JX>egEQ z8t9PQj^}oLZ)cC39{l6!GWSP`Lz5N7^rCg!O7}Jt{5QOy?mgKH;Fc}z!iMM3oSbYQ ze2auH2a#D{oS{cgQ#7)d&>F-pg7AbY2t)>>0%)yx(Ad4DyC5Q{Mz; zsr816;C{f?-;a7Gn>MXy_A-*^g<0O^21`seH-;o9j3xoh`2{Wh{TI_KcyCS)nFo}J zTsmtA4l?!wA2nosc{>Gcsx1eD?uiAnMT_`@rxpj?x z%fLdc2n(V__GbmvF7DtE@6zMg1CpYHqp9b%0Fz8Zkg7!YO*1$%5(k|xuweg!Fuo_V z;nVH+RMX)%q`wXmiMs(8fQk(d&3`_zsx~FP#lt15R&`9!_Jc;Sps1}v=bWUY_tC+1 z%Q;HJ@AY)18>ho5NSpVn3;djF<0NA!dMHWUn2iE<*>;vB;=*TmtqbOQtLb-jqIFmh z(<>Lu-HvMl-{5U}ky0eamQ+}S)%4nV6bk-hIZ7^TG{d!DcJ$L{UDL}O%*o@KGUe+M z%D;@A59J2w#w;ZtUrhoZ zjlKL{CcJp&=(Tcc2(!?N6%<0BzClFilGNA#3ZLm-jDL~3xArQ5(5;&Jjar;;5ZDv= zUmiH?M9*NcW9(4Gsqum{-|xb$1e&Ronqil_pvopLpQ-fU7laDAWN2~Oe9S{yzE4ko zxmvU%nCMb!DX{Oe2U7$!`{ifG(UA@2@CaL58;E`MW(m^-OSyie^RHIC69-lv?jqj& z$MMm=qR;o=KFTjJ7@1{@#yynGxUO3VB5nArMpk2+xlLWz!}cxXOZoNqOch&vpxXQokx=m?s>FOAn`2&zW zLFi4P(wX$t^o0`>NfVmcYx(PVF<(`f&3PX5IsjnNJ@naIi@>tD?K1HoXaCMPzK#cR z2kWBqpI#BqUq=_O7(yH{>E(V4zmXxTl2Y=!N=)dpAtTSlpzd%MLaY)Gy}&K( zz~%C$yHm!(H*Y<1vk(S5OQLb@Kjo4Y^-{O7;onE`K``ZvE3f#=QoB-Xho(7;g$YH; zGQ7y_zJ<;)d}aN4j~*g`C@i*vL zuko6ti%`F_ri&9%r?ZByI4n8y%+w`vDp^9ehxS;4zyFczZ?W zwV%v^p>BF>{nt0i+*pu(Uo>-t^zzO{9G!;pk}E-3;}!%UL2O#NM40;MG7XlqtF-W^(&q?--$n z<9)oIQ1XoS0P=LWmS|`q6Bzf^Zv#4;-Qm2o=tqQv4H?w!zSIh#;TL;iJxlbz42hz@ zx7UDMOVZs5*1!k3IsAgG$UxpM)X+&XcDrnm90IZi91t+PF+!VRXIZY8@QcNvgX*ET zI&F4;Yv7J`Or7MIHqjiOi6OUsjrT$yT#oK2!JQ7=87F=9wnsNDH$0vhxvjOR98>Kq z2`1<5?qW|igqw&qRDnLf{9l;x8FqSO#mx0@)AQco*7KIB z^z@9)pD7OnU-$iw%m8T43N%rGA-WEvypeMz5jEf(mq~*9n}$$8l@QaPeFle`DtJ#0 z=gJ^RY6C;C4Dmbf0UVT9j`(iNFSXDy_{JW2AD{JI@}08g53EJt%%+I1o3xzlh&=BG zJY}vgdiTFzSEu9+^XjimoM8DbkcLr!8;_gW6w%Q^k4(NF&SY7{3_$HU>a7#+N8|Pv zy{JnHQ7cIv!}p;DlQX+O>PJ@q920Z&q1$EJvn(gPgg(w(0tm-$@)BXDXmKAWp(r zhAfWiM0OUGW5SM7H*BxpYz<1qQMY= zmrL)P$PbT9pC@6$ouPS|E}@HLW_uU<*{oSEKe9seM|S{N)`&|bMgIA-q7sk#-|S6H zNVlA~2@d~;2G)kAmCJ;sIf;dlsHFY0kK=~zw_n7h=^1Ub*!J(&c$vmkBSl@VYY6VX zj!!7iarw8*BS$zrfA6gkHW8e2%$=!8L1VeMUED}-wu?rI4izuDgwG|es1SN_K{lo( zryML9Q^9}c@E`A^9)LwE19Kam&t86RYmw5lt)t>8b&w~HP=oHh2C(Ct%2Owe%ju{t zimy+*%QL5}|K{x)MM$va-BVuGmA(YJ(GT4c(SlDHd4{}3I76jkq<+|iwg1FMk}jx5 zBn+2imkF1NAC$;0eeAqT8bNc)dzzj2;@hiVRrFX`=>o@*G^$KXZeOw8`JXU$jfyF* z#I7clw~(nn7~Qq3M;@uY2SagDHNH$!WFm5KO0m5c z$5<{!xG$CO`}ARDn~N5E{3B`fMZ)=5=-;q`?*h5H$=H=FCRrHgo5clAEZ-VZP+Haz%1JF zlsn{3{gLJBo`pl~8Rc)P3}Hi%5mxlS-1UBhU&o5PTX)zh<`l^tgpW$W;*m0?Hw~E5 zW^Ba-4-Xq6`&5!LIPyq0a4@-MpNSrmLqrw=Pp@ zQ7Ns+n(0=r9XGYJkCytR%0%BK169=(iQ^xBrYGfgZ{(US#Z`h0b{a$mw#pG&w3D$d zH!it}a^|6=&4h|_eko8#y`GH9R>ub_U0L7%QjN6@fRt$yhGFp7AT`6O(+5_K6yX=0 zd$B;zBvBPqq(dL~fv|n#L$}LNj@_~9w?wyyV%44Qbg8 zZb9t_Gu^rbc+U6!Nz5RW2$gXrEgDi*R>x>FrJJKAoTXY4tPBkH5R;7LIEWaWAVHC# zN-9}K5;?;3BQdY{RG+UkA76!j0F<;vrN>oh(ez7!;m8uocHeO>eJ zazWraj&7#E^~s~7Z{>a`9%8M(!uk9+|B@7WLJ{c2FxH#xC0se8mg8l+d6z%I%w$p2 z{v7*g2U(HZ^^)%I%P_7f-fzGj7W8#fgqO!T$4RK{c_p3Kye|`5?DcNZq*?5H&-}PQ zf9}@Ssu;PMvxbm=Vh>j3P+)@TlD>+UIvRe8EiS=QJhdHL{WOw%u>Co?1#@Dp_kLY7 zwl0%#Td|3cuv7CUN;T z;95mvVu9{hbiDD^g6ZlHD_;_}U9Q_A>p>m`aMkUicgqV`ekvx%F{a&ftQ4E-439BP z-LjTY$mzbQRNGHiDyFe0N-;I>{66=mVu9~q1A%l!mm*?SDOE~J9QS{u4OG2&rf)?E zZ>jend$#JmS{UPfvh5_Btbo{|VH<(R$8~op^Oc{D?*0(-cety&^pV=5w6aBDR=_h1 z5*jsT?^szQEH`c|)Gup~1EDA5exp`{>P66v*x7ut2p0P+7U0B8F8z@VSanYZhig~t zXxEn-L9WC@T=2NHQ8(IKCDRr($N8OztLX8>J;FtHm&*HoE?UP022UQrSu;q91pPb{RQb-sa~DQo=o0R?0mm{S1O#Q0r*|}(b&&Z&Z?Vw5JY0R$%+7-meWq$*l}FBY zaqbWCMy*tX4ATeH5hcVM!y4G)HTPEOOQDH$mv`?>@qtxpv`o~&{gQIxa-TI}F{mpQ zOv)9D&poRQe(X;-T#HnQkO&>E;9_f| z?_5La;7G$i6h~e{j(DIU+Bpf}NHnyPjFC~kX+3Gm%-WTBJ5ByaRBHMwEI7RxGZ}08 z99Qz6p;$o@k|X9IikAYwpIdy`S;5MNTT*rh6%6yYGcpdGA^LTQtMO4Q=^iU8D$7Wl zxKsyQk*I{R)du=*W%W?xrr)cXRy*&%JPTb1{*qg5#Nu-$S@jUxiu$7KEqaGe)x0Pz zG|0@gg#?KM>;-z#C$@x+ya@w7OENv{l=S$4lq!= z?cOp>6F)!1`BLIKpA~0(pZ@B$4QS1S_(x%8_3K3eKzR>dcz`;tCP1Y3Eit>L<{TB! z^Gdhu#5cQhg2FhEtm}@~1;0ucFZ0v*9=R>vtWmeA8s%`benGhnxeUZ9p&0iugE7)K z@F^2=F@n29^B5FE7{3WkrsVH1>s4ufMX#!dh=jVJlL=|XT>K23knM8mptLd>(jiXx z+ZDu>s|yQ=cJtv?5blbAui~KK7Al~%1*B5oSdQ8svtr8ds zW_WV~44Gf9$GxeGBX*Avt7+8UJ5eNvp#wFUh<$VpCTQGd3Vx7~sAn*%*ev~W!uFlA z*I4oZ_Z&ZbrNN#od#N0#=&RZN`OpuIFM&Qz-(M-BLRWaX62ImF7G|~#r|V4zKEM;j z+H6JTe1IqHP#48|)Nc<_)t?q!gTb-@L06LLRM{M}u^B~CFHD#=TW#LOEBFW2XymYbJPZmmaBepT6yV#{V zA+|-KCLE#EOaM-@nvkwWekXy)zT$xIc`dkN5BV9ny5E&^amX<2G!q-z`rE&pIV=?g z2rh+xdXFVsg|XS%IAo5*E<-65^4?M3Df&?I&d?C?mkT0!-Yc%Rjbdy?GbAQ;Or8>k zzKHtnP*ExVvLGWngTwo(FppWZs!Uil!$jfBtAN7bO&iQYWEZ2U*R^7@A`3zwOSF}m z4e1)&^Szb4%`j_8U7ip`IjQtzl#CMOA+B;zxz?qC#9!jdTdP_i~QlImr^n+4XotGR#cO*Oq0<=r?)m zSukIA5%reAd$A(VZyzS>6o00<_MZhu4zK32LaA9Vs|gOysp#Ms=%IQT#Q(5bZIv!? zZTRyKN^%)rPvi*%zGp?dkE)Y7EmW!owa&HAp>Eb=Odbf`xzb|+$db%v>^CiPKYChW z{Lag6{j~DmWPr)hl1q7#r5UpO->4M047^pMNQ4763MfY&&#&75LM&Y6=;wewVh17c zSBs1y1Ux~QS$5*GM|lHndD9Vb>g#OF($H}-u)L1kjMJYtN9Znj2wR`M!J7TfLt~x) z5rQ@OoUk3$Yk>?VD!-w;(`E>x2>P>2X}^tgKUO!UVe(x+sGm7`8BuG@w!OJRtyFYu zx@`ly_DNIi2s~%%PetvoI6f)wd+_=wm# z^qv$JvADc7M_kr-T6cUCh66AEK3UaU9_<-M0NzI?NA!y4^JB`hc{Fa>?+-F97f3`2;Ci=4l%R%2T`7x*$c}5b=|$SCYgv_ z6g`Lf;FE+)C%ayV##V&3m|q~yTqrS+Xb2j*wp^HT+m(@x(Tk-gvVGH59z%$$?zc@C z^8IjX($<3*8Hgj3K`Ff-ZT<*rtmYrU%YSQ2&tWPA0F-qdOvgF=ofh^54}Td-+=?1t z?Yt!zw}W4f87lakC%^*zKm;x%vG2Nd{NzF3T3%woq{!uO4C?M}DL~Eidqcp}U0*2S zGSV|-sj&<$INapjXwaCnJTzC{hQ=%(iFtanWP!HXk=fOT;f48czFWP9dh>}D zod31SYQq7(UuHN<)kFCDB%u=7FwW#kCu;zq`4=_@Qf`pP)^`DEuXKIg%)|IbZO!6v z#+@-6H`S6J)a!y=e@>**y6knVlhK@Ma0Ob~QQcyNXv-0Yy3V~s^}liO)9m>iQGSt@ z4i#+&UGEEJf5+K9WMO5lyBAQP=jBECC@j+9ZpohWi*J-gNigLLT)AQCCJS{ zHQa&(cl^_~dod3`pYJYVn2HSETh+iI%bPYj2U&qfnw%;ik@2vrvGbIk0<6Oap!y$E zwIH+q`Vj{Rom=}IHNz(v?kR!AW}&N293SL5_)ZibdU>E!Q8}sfMS)XMSo*Y2sRD`- zTGf+dj3i)rPQoQFBBCTw8m-w(dM5Lc_WFHz%?ViT_e|?C3`X^0Izc^Zym5jGpI_>W z{M>R?XqkKKc>$=NBMbt~#NI66fF~2ji}&u2xJEZ1rCu%^P^lE#7SXeYSVK z`Z~5&I;)A*F84+0PJji>?G=OmyR*=3u~JSV4X>g9E`{#GubsO>ff3JJ1KN%HxCpW%ah< zJDPF=69ez2?qSyHWMZM{7-%#Bt8|QsXd0n zdbRUK=Gj8PkqmlM=JL*)$4Zi{&X|0|gGx{u0LATBAN~Igv%aKM865UNO()Q~AZj9S zdGLL)&e?T}v&A!^vPNH-bsGubH_;B7GUBNmIj>>!`@AJQJ?l7JFpUBdSdLPMtWA=IR~-x+M2&7)c|>`T~i zhTF&mA$YLWSaz?PaUylyj6>XE!uIO#a3BP8)w6_Cdgno3P&(`xgdmtRWh!$6dO#cQF{7D!)X2L^s1_CNvyoFJuq6E z&!nWvd|6Z5Pd%gZlBB`91O+h3>p^0m;Xzs7&zhk?6{fptdX*$Ykb|2$n%a8`#=^zb z?zX6&1$Vw4BR6*{3q5Purs>37DP_R|FQ#Pf(kMusk0`NjQJC%A!}dNO71-QYleyvl z@>22-{leK?E9Uq4EfmjR+#zgt**f0p8GCti1N8UObFL?^A-95f>8b_87)uGL<;K#@ z+d609kIhuymiFtgy&-MG#(J|i32SSmX?2%t`>H?t9E|i5#bnsjiQ8EO;S1aCU3BCZR*iO#V9`LjT)+7LTwp%4FJu;ER<-0ZwoYy;E44O+Dn2V zIi;?$#@GzA$Y2W&1Sf{;byao&HcBr?2s#DsN}{-14_<@X99Ft?W3=-*+|XUMlA3o@aKEH(x->qIXG(CJL! zpMTB5P)Gv`bN~z7nM29ToN|MnL)CcwWbQeMtZE>+ST8q1&l6;tSraL#Qv|ql!T&Tp z7tS%nvC3n)y1<-&Ub>E$GCji#zNv#j!Qx!JnAW7jOu*qA`>OO`QeIsaLs-P!oUXkZ z7LG;b+h{PGqB1AGkW9*S^m^TVne@$OkF=kwojpTaD-L+sk1$mTgJwT9WD+>ERhO)R z7b!Y7vu6R&@B{Y)O^D*6&(((7)nud`p%Om}8#o{}jpCi~>=04AG=Jq#E~sk!xT;E# zY!qTY9)mw_3CvEMe)!qbvvy&_U@qm&8nl!cm_E`cUpe^Se_p)4>TzzoAOwSczMLif z3A4T5$_Pbc&QEN_cU{9kuVKtG&f*n3t->ZJa-s%n@qBih4fnReX;#l0SqY5B8=3Pf z%S|V?_(v_?7`u7Qh#e?dy2={HBHQr@hu$S3rXPG0`bjdh5+F;dlHOVor512XM7>$r3KlqeCfz z3Ta{oYkL2EN&LXjrgREP!=~^MV;&&xf2UluW=ZQMG$k%&wRh7sruu zUkcNI=kGbt%QkB0sD)L;+;P6Sf?l8E$X3fZ1?X1l66an16J(V3fJ}O~JMnXxWY&#t zz5KwRh3V$9Q4tHfDvEC*myy%|%2*?eWvO#WPakbAklcZQNkQ_!*@$$e;-L+*#8=0g zN;!!WSI>m0I-3F(-^$AiM<_aF7mdLjRI39oIvS4mE=*g(yEO1)Duvt^e(7L^$zqm; zerUNgW~4UURr1glSIumQ4e;CVFz1Q$^NKuh>LH+K`PzNz$hOfy#P!ICm*cUG)1E!G zMAr|kS9wQ2iIa0%$|&V6-17SF{g4~3iPFfktr&}}j8fRKn+q9e&h_4$7)qbo#)hc5 zdtO+y96zjmeC@vj5qli=>CK<6qTx(d+t~?E8w;=D^E z)PCzAST{t5P^Ar3Kmk+ds$nFsp(26uQ|;)K=A; zVYIX0_m1#jzR=6JHB}jjshP$_DUz_cF24*Gm7-R^yNQ_+jfTdDHe zTa6<9V9#Ar&_MCYC@aEl3N8QS7pn|8k)0!@ICIccxcvgV*vI3iI~cewzmU1qJM$=^ zX9q%LQhuZsR3!BGGQ#a%In3Sb0I^EYdM0f7%tz82${qGhK#D4I38~-`+Nw48tF}ab zs`N71(NNy@C;3*=3)7cVaUJ0*osC$ZdQa?*PvhCfWbg{cgLhX(B3quRUBaAAdT;&} zmc#7ud`9{IR4Wb%g;Tth&hoR#G4t=^|7Q((OH2svGNtCs*n|LO1JN(8S5KdcM*%d55E*LF?ATYejdxDCxZ0P7V>yXZ8k*x4!0zm zRQKg4rBXJa>ot5tX`azXtIYhq3zE1MM%o#Ry^*L92hObAjk_~}Wh|;|Zy#c_zHXuK zH)7>fOSR>q@8!|XvcupPpdadCXJF^aSGqmx{;2eEVvXCgyu@`EJ&CS{_sRI8qYV~G zIAJ$g2O@XPA)n|W5AcINVcq}#{^S4SMlOxeJrFIQtKcD3Ct(Qqdaa=PvP{k_)rQ)Ch0Dx9kM+157RsUyT^6Rz6 z*?Z~QQF`f^`vL$py86S1PM&_AzD}NAyt?Y@yk0(@j?Qil01))O z$QWf}yv=g|cp+h(t))9JA5K8=9J=oWrGwB&n(B zWM(4~nk1@k6zh;zsWIh=Nng%ZL(5%fyN@@=E?e-*#Ja^DrW$_h z#!Af4z~Jh-m}(RizZbv&Zhi*wz2E}@ClN51@arB8Wi+Oa3x&P@4)k| zKAyETxQUdD6A17%7W)c9Cquzi5@J$qu&^2|`0p7F$y*LKyCICzWNEju? z2?C^{fbB3JUl0(R4=`!{HiaDsH!u)|u9?bjf_3mKXhvCrMZGCZO~r0Oak{L+O!w^m zv%{#0^#$j%OGU}huN;m7Kxqc^^=l6=f^c*VINZI|RyrHeoe$(!x1T;GTyBildR+%@ z)h}Z5QbfF&1Fb}kcE5aeXP?yR33aLe@e9W$des)7bo;yMq1XSo(JV{vn48;JU;l;} zfLq#qF%7>&_1W~AUbvk`z|N2VuDoC4kCL*E(k4Aw=^Oo{kL4PFNg4ZeVKYtpyp8(m zoO}BAfbP={Ga)8|(M|7E4NUT(6!!LW_)Ec0cc!kMtu2e3kti?A0&iTDL7^FZ?P%sJFDQ0y%@am_^g?8y30PU#z(i;GtXz+`fd}&r00t0|X zX_U|#HO@aD*+hEDxjvFDe55|Ny%!7TALxTKz^R_0xqNH|>!RV%_^~(KLbl>xRk>w) zjhx~$z39aH9<|fm_oDx22QK~y?T(@(RT~B~+Cjc2f}SRs@uh-U^W#n+A9YA?zToHm zoXBK!TQ5UaM-rK2!uv>v`}cjH{}d9ev^q1Ch5@PQ^Z0IU$*ia*qx)ZJTGTsU%W=eN zy`r9Y<|m0sV<|0|@Oj5^Klxr6aiZ3V{(G9T`jABL78`~1fSZKaU_bn=ya;8c{m9$f zbu_hu9B&@ik#s%(Yd`)rko0DhW-sME(m*(`-7Pg8Gkr6|Z#u7ex%g#ne5aJ7B#AZZ z6S$rETJPQ6&Ksu#Y)_>m6U=l(_-1dWF^V&UCaMp}@!x!|E+x>B{-5sK3X`duQ(99V zNWN{6>H--Z4!+FK-=DcQQ7B}I@CpydtrxBLuS>6Uu0wuXQWZT_^{zNEUV|dPxFFa! z7&c@!$Q|;e)E<>%kc+R&Om4`gS-|VdT9J)L39lJt{4ok+F)X@z*!ox5(;QB$PRGuT zTYjB47PD^|=1!PSjcjXgs?`CrfiJMf{RMsrjP(M0+G-8rg{lqxDLFnxcoh#+=5eYNgi+HK^B~CMp#X<`>V&&HMHHAE;LtmAti@|-xzYStFu2{~pE{(ts9##8!#qXb>i}gLLmV$eT|G2`%FHA1n|5g3f zrZFRLrr{@_r@^toKFNA}!nnnU<`0b2t@~Bgv3A*ZxvQ}m9h0!~8Lbp8`ef%pD*`{k zeb9Zd{4V)j$Xz{y9fN%g(x9VKuu@51Nq=Z;bnMmGY`$#4eM!6&v4B{BFIaA~wFt5h zX?@+=?x5SWZc%Bz-`edFXQ5z@HG5=X-KNfT_8{f$18(Q64!|hN{Sy64D8v6G$dosg2!&5HqQ_v>N(baNWa7XyQ^I=kathj{1 z74EBqfBKWNEsio9XBht`O=x8t5gc$XGA@|bMzNwgd}9t1Up&`~9udn`7AxQ!TpaFM zNBI5qwq6aH`dd`cT+p}odcJZ0-oEpG!a~WYOo?EzxwP*@|FHUs(Z-|-bxF2_>vCPh z1N8?{s1_ohxV?CWX+8c;8#b`!*zPB*@{zJn2|<|vlUtHnGPfC(>unou8+p+0S!@%x ztRBgC_3SF-Y7(eI-vOaWo=2%gS^jr+5)uaakgB3M?{L&Kx2Kj|+M&j*mKI$fz45Ug z;xzmty&iH*%)@2ioay2oMr_SaP}ptSz37ji5r|8OGmTeC^-473n3T+w4V+w1_g&Wb zr;($vRDhCvpwK9akQGv{5p#ikm+O@2R2dX=G#{NYD>Bn{)8kSQ6Kc5U;r4#{eD5$} zt!Ry!5Xzb-K5Xq3T!!oW6IaDjEp}5xF-KKD(NI3?ml}i6YnJ3YzZnDXq*4X_pQN!O8y&F%)#=^(wEBw$ip4CL0A6>g`-(l1 zF)uUHz2P+wgUnXc4r&25P2xf^2O8ujGkm*|fzAlF^$M^qbe;kyg?J?jT%;^xaO zcK_mwIF*^7Cp9q5v*t2KeuFLqZEz-de)*8UkoB&*cA(?gxZ{-L_U4jku_awjP3~qc zod@mQ_jk0*kKgV6J<^;P&mDu#cg3`-ca(pCwRbyIea4L`shCul{4x1wa&LcXvBeI5 z;xW0;8QOg$^J8Y-vitZ#`SbhvN1#UrGmbM3XS!$2$0`laYqn2v&fKl*4c)!>hDfGJ zE-3iuTJarUXSk>Cn;_F>g?F{-hIrmz7X1tqrM*Y{D5Y?4jn7LXczyera{2fct>X89 z>lC_F;!bisE1Rck2G9=Gg5@AWc|8DwdZE-+nGcy7UH?9!@T3ACt$$ zj9+H_O`}&QOUq9iiKmUGbVi zDYck?=Hyg9|MD~_YEP2YW(jm^9_my#joBfE>#ga*PgKK8MZ z9&!>{{q9vZ!=n+BG8l^_*hqugMAIE2`cOmg-8Pd{db_vVP$~g}#~=Oudp}VAP#HBI z+Sn4LgDiabBt1RdXLe-v-xJ*N#k+U7w%H{O!ML`=(x8GgNH2peSb~)8KN?UxppO23 zw)5`kS5?8102i80wQJ|IO=MH;8XZwY04wA>h`=;3`x|hABxr3D=6UK6f>+?)$a5Qz zRndxNW>`6x8z2;V<62;MDride+5P2-Ea)aCpJYi38CrEzA#)b8oK$1lUsRZds;@~u zg#iv$m9Z9xFWZIdh=Tv4M00)nko&*3=Z=q~%hZg_El+n@JP22lb)1g};7%SYihLII@pKYCqNUK5r77c7U>D9L>8Jyev zZ{O5KV}LUHjTR+j!>1a@{$la6l;e}PcZg57kr2!DlMgnBVavrFCEuvZC8|B$Qa#+| zoU2V1eso;aE%PwJmfPq)c)7K{?`ZjN#Ry1PrcwpLEXA0QmxAX-_cAQ9#YJ(4{04s` zB6&qeDzbg5ABwOv6}pG!xKAQF*6Z+c(T=q#i+V~@ixZ!0R~#;)w8@Kk6`fR_e4&tnF( zH@If}OnCBgAQ-)M5k(x-EoAzA>MiK-l_%&n4c`|ib78Xy*zTX2YFv7?gL$;1#Y2R1 z)|8_%ku=BQQAHLx_MI;JD}A3}|3sV}nyHx+Z;Tpcvz!XUYN)=B*sj=_oCKym0H`T#s@cSJPxzbY5u_ipiUnF^%6;72N5ZK z>$>_G?QY(!IHUEyXEDEV+|=ZdiW^!+45Vcrp<~%2*e_FSR^mxdRgzy#UZ+c-$S7I< z@R}jMMQO3P+|@!)Xm0+y$EH%zex8H5(cARp%B)T`HbW{wEqR9&{lox<*i(rlNBw@U zs;axKwAT1$ky`H*X?1)!?lN~ZU9ZdaEVx==;`kflrC$F;$I79rYydjj>9qAG5 z(7L#NxiACRko^KfG{S%IrTwE{2nM4& zzkn|)E@l%c`QYS*+vzCmcOPl+3+;KAK3OWt>kF=?#6cMc87UlVnEV_`UL({cpuTM=pCuLhj?g z`Ww7c>LHkth=779RrgbRb?Pxo;ajOk9}7H9VxlPE8Ae}z%(Mv4`iC|g7^vqOaqV&t zn@ogmrnq9V`kp0g#-{U+Naax4QA5mLR=~k(Qjm5Ac%^d^zd`j&q0}}0{iBeO@jXjq zV(%Wk2HwBEm)@Ld=%DxT25DJ-CFMCUslAA#0SO0@2|Xnv$^icbP13J6VT#Y7L!0Gn zC)ic&b{6Bt^ihn2a<`uMW#q+GBGYT8JDjWyOQfbi*o|J#4>z1zzhfB84TY-vpwDzM zR2h_?*!i?=6wPns+dAhA+Oatpan(Kd#rs)WWEY%M3zK z2rDu&nl@WAx7|GAjQ7VP5lZ1lR?itYlG9Q>)_sm%+t1H#29(dawd{q59y{s2bQ-^< zETsiz?`~l{Cjm+#?E4flGZ_gnEyDhK1XyLVi*8|)PY2U!6g}WF-ca<+c?eeP=|+}| zpCxd=@Rdr@^sKyQ8vun=P=jP1o=R4jjvKp6F82E?!T;!qI6-{#}p@_IL<%|gsS8#&v1IHa#0$UPLm zZqEX#aLae>V>33-ad6H#kVv9IfI;a&#f|Gqn(Um)15g`kV~E4X=2fBY_I>M-fFpD0cALsW7OB}9!& zz#XnCV^9kvdx5;^Vx=dWvYXr-hN*yqAfSw_n@UNHGMIWOSRGSYJ?C=#@^M!=G_Ik- zghV`Djm;><*g#0L$posZ1~LIt3X%cC_=5JUJ@d_RAnbQlk?mXCNDs%F-=WCr{ZSLy zkj+!ya=SbUT*s9BgH6XO0>1$S%a8nmr&o*>6m%%$momIbhShml!2yZocTN%+VFK3V z16blAnaB*eh&LAg6E0@}dNKp1Qc%=I_I z@$4?yuucykMfwi~B!^{aV*6jviZ#W=E=ACqwg3qGP>`5DZfR!e3DF~yNr4zjt#cVm z8HP4+T2b2;fZ9u>|Cufpr}cz7_7&PsSu5RzYgK>u=+weEbkFRwEf%}}S$MyCM6s|( zpO-GV-68fj2CbWMa1H0Nkhz8qXq@`3=TDll*cC>eo|0n49<95BdO_=}fqhc43%*V~ zm_22`6hfH|EO9)1)AW~I_S^iy*)c@zIOk8u7wagxLl_3fW_$36~4hvRX# zN2CfryooEce`*)OMBlv&6o=Ze7g$>uA$}EM5t#U z>xXlaus`a@E2)-&Bvepl?gj5%kMmcMEoS1FP?Q#|kDWHddbBW}e7Rx`L_AJffcik_F)kEKQ%=GuuFUDKz zF%C;T7mwW2urnujI z!7*xRD)|e})oD+U(4;{3otWM5mFC;(0C5dz)MK=jJwLvsh5h>ld6thxQe`qa=qG1; zZTpZMHkU(lxvbt#k)oLF%Qf{=v&*)*x&jSvmo#6?;Z5hPMjMfE9m4)rzi&CIglmQZ zI?3C3cvFqTeq98vojoXy&ALe<9?NhOAxP8BpfE&g&-Ce4ipMz0C~H`We&12RuwHri z$ue_^F+vic29n~snqf0J-)PS=cy~!cqx-+Ysr7ULxycS!UPo_*G zlK(kUG!}M5a~_YYgP(6u7eI4;B>YmJevG&0%)>zYW&FX_UWc?V+TV1hh@Wp9+lbdC z`4Z(O_JY5C-?yusR98l=R-+!oc*o1*-Yj}e`i8?!M}@u4AZ+FG-aAr?);xPSpl!K{ z`Z^a6|Z(|q|G%Paj58eN8;~D_Kw4jELjNFu|FbO(1Au|yUwlep$cdSWj z9;wYMu3HOLfkk;n9x1_dG4@-!YG4&gGDZF^P9L{QFb4+u5+g z6~4$(@%noK4)B0V0pZ*Sg%&Mc_pdanc16REeA9?LXFvFQB2Sm}TqCa@B#ggPiaGYy zs!yrMdBcbA0h?!&!*^6_6j~t)Ri+gt#Dxg2gL=Ts+Vv9XO%OGX41D>Fo=h!ztp1jd z0%I|2-yVg0*g6a*-Z$#UY;(2QT$;6}^nh!KzC1<$Xm{-`lpr6Io(w}REIZ^NbvGOcmo|i4da$DD`6$T{aTIjx*V zXmTbpOr()BzkPm>$M=sN{@C_-z3x5l`@XL0zV6qL4IgrG@N)nF04_b<`v?Hwln(Q~ zKky9m*@-rn&U`uhT-VYE062H)e~(jubRrl45C-VoziaAGTx$vF7efc~{%h8k-FRX~ zJ7_$ZX|3D%$+uwnb9$j7&EXN}T}cFw?qgA19ua(muC6Yjs~7fE`@DS)p!b95fA{aQ z!memv5hW{mIX<1|IwS9&ta0Po;8acBhDO2abkXYc--nsyp0llXJHNB|-u_-b&O>Bs zV)r#X&04mDvVZN|W^Zru=iT^;40Z}XWe*590r;N+v|a|ZGU~(51DpZ70f1d&!0zm+ zIg>Wk&S2%C@@>FOH}flPWkUe%u&F5he@*(emwv=NXE!24wax-g*Z_wH0A0JZ`LI3z z6rS1crrr2>4gf3QE4wPT=eV-;Rs5gEg(qRy=nDWq_UUjTKzQ4kw)0;%k%(aCb(jmW z0@U0Ww+%CbyAJ-o9Ms*dfmB4ZKv+vKA+vrXLw-wJFKA_1S-T_CayBjA>4t_;l`_)% z6>TRM8ngGu!?s=q*rp#GA4r^ke0BA*Y(az~7-7FWhFhj+8i$0+qHL!27qi zkj99d#{3u%3;5D~N#-SX03mQ_1frK8W(Z9pa1asz?+L_H@SevU+HwtDAV?RGQF%ox zNKNoTuy1Wa-A0y5d5f1x%fD3t^M|F;h~AdXvlMIrfp4F}0tnu(YCFs#3_FblvxRGM z0knXCK65%hOS69L#?P@cK-Id9c8jsjr*_j~C+q7$cA?nllcY|zcX|-_f;;IRq@{AkSAJc(PbCT|lxsw+yr zMOo4svRyVo*8}mJKd+Ng4ShTP8z;v{Ml#z10~>7`D&q>8kk@=qPjKB?$$O8l$j1mg zF_uywZ#PD5Qh#gsoovb<4(~HVeaT$&m~parr1;?PdAmJ5z^*M|H%;ED*^XmItlMu> z(&oQ0C<F<66tkGaIppU9K~DMFr}u_J##wfLM1)o{ffBiece+<1LYB6oIQI^X(<7=&DkTBWl%CJX3`$2hDpyaq8AlDGvk$1 zrx9Uz#crN46i1 zG7P2n%BAh`?=cf;71VQ-W>9c4Oa>PF9>)of{m5g4_$tcE4%NAc7lEjGWbmgTgi{c3 z%75N+B%ZJ8DW*zYpg5|yQR0IU$Duv7VK3sc198=L__vyCe*8tURYh5j7*15I`-f+R zdXqp@K%GEx&c@H4p@LRAynrX3 zyaM^w{r$ha#pUhN<*l}DUW_YEL9H&)N0Oy}G6j!T8*Lj68x5gaFWlCnL$5Z`$cD-m9?V!-rvO z8)0-2j}3Xi=Qb8V_AZBETHQPnarm7*O4k2GE$xfnb-BbH;GKq&XeEcMWsG>g;lAZW&RZYQ->UP#|36OhG zD2+e`)0`~L(a28}ol=8qHBp@ou!X#y>$@Qk`4@W$`W-s^djfXMwBtuWBA9{6~#Fq^#s5*0k&YN z@gyP=?|NRbgwCJrWEp|gw4zs1#Wya9+|t5-4KjKP|5PSzm7HWj`#5)dJxY@^B-{6% z-M(Q2f<+$!T_|~qF&Q(P9*za#Uw;Nd{YPOIp9_fjpbwUvZkZXp7>wH5h0V3Y$Lqw* z`ANU^;U>Sq2@Su&y=g|vgwXj{J2&J>0ElRI*4nzJ&(XwjZ_jJ}hWB=R9eo9M!N0!K z001DQqO6#NNhi6clZtee$Y(Kl4hZ50>)gqCz@gZ#S?}XE{aDYR$NdXVldmkl_BnE= z^gvsi*%yj|c*Sai1u)u$l1ht^C2pFXt>EZ+#dBK%}l&SWv7Jk*0^wp_Ku!HFA<^GAj%8dqE}KFm1UHM_oW6_8NsRI;4f!? z?}$tbkyoFmu6m_U7^CxR=4S?pAYvXNpPolIySbBT6@{!jkIddTBsna{61el`EW8cD zsA|`Y#=@e;qM~F_KTup&SQHfK{aXKJr8ZRc*P2g1gTI6OsZEO0Sw{1Ht-&5}Mtn`T zMRc{If??FN+#cmsH?DV&BhHc4L~t(=Hbq6fh~9dE{c8Hb)DFiju?n7u=M+iwWWL90 zZIPr%sxIzRa6v^10tVG7AYfwK2hpjt0NWDmU4e`Tr3{BK?SoF-;05-^*|*>Kj)$@~ zE<6oWlce1)m*Q7*u?5a2EyjVKp1TUXNJ^+MSJH>X{`Ub$WubA_7~Gqv?ZzTUiat0Z z$LeL!=_z9BH+kvqs^pGig`d{UKYDDozGt=`YdzE8h0=BohvZ?F5U@F8+9`S)~N8GldG3*rr;RhdgcpN&m)AxyhmvbcZ|=k(girIB!@Zyd>XB;Yilq=7HY-JK z&}Xa4h&<43WnNODYkhjeF-A4YFfpH8ZzW(N;9`vu)Q1}5y?){ckOhZBexb`vSn&QQ zdZRKYa((~&E$BPb1P-z!3Nt+_z(jVe5M7q{`eGWS&w+Pqp(J$@GsG540k%iY_i66K zRNh>JZxio3^EQ=Tl?)sC3o58&W%bLFfR6-D%w!kpk>@zqWW={^sU7%B9+tE1XKAt+ z>jxQ)Zbe0IP>3v9R~RppDkQdKlTS#nP5!Nj&X5n=&sU!{sz1dvpLY~Mo)i&H8Za+It!77 z)aw8h0bLjOy>*-Vp}ZMBm5}>wWe#aHC$FkF%6?vr-h!jOpu`K!H;(D~L2^rKeEBsF z6X2C2834yqe3~J2#Bccgy^ZKHJKrWvBIms+E+$a8*C2d4pxQmX))fkg;FbcN!M0`n zW@+Ft_x4gRQ2%v18kGDgirH1>Qq%+L#A)uel**cwHTq6IGIhG z%8C&#MRaE*Tc+us$@We+G4zQIutfnKxEw60b17m$w8ZUJHCpVqGp^`&s^^lst?-ykpW8wTYt=Pt6MjmPB!q<1J9x4oM_2b1JPo5yXQs5- z7$G6~NggCsLHqMX;WwcDSma2qj|WtC3AqWZoYCLj$tw^#vvp zOHcP2{yh)g^`jIMxC`lS$uPBsixC@UH~m_y4h&20%@!bMf0ZSYOgPR$DiVkaR4QhK zYNiulX8cCM8OR~WwnP{ayl3?^w(rUshl6eMa?2oP?;&?eMXeH9mAX$27$h>>EqQ(0 zF27Wa@Qu4;1;wQ#$Y+}R_z{XFp@=bTA>DB$j}^k29N|C)VyiZb1t2af3y62olqaLIU^mTYs zfcDm)$^1>&^WwZuA>~Vkz6^yI=&?fo;hoKk$ta&kkDuc|v9hlHOW`uh6kJ$1A>%Zy)*C<1qX}5PK)BkV>v4*Vhs_0pVb@xfp39&#KWdGRHiJ zZrbeGdYV_zu73x$)KK>9`)#)zIT9=2J`5<|G;Y*aSw;h zVS=@YcKJ!pkOcPKBfuXGz}&>?$;*Ix4uSTgqInC=#XOz|(3M-HrJO{D!WO!~R4~e; zZwXr@2_4c|`{;!Eu8Ku|E6O1#;1$1sH=`S5?4;n(Qyi%S-(Sn&s!Nz%x{tqk=i9C9 zk{TzaS}u@M<*bWPyl7F4J)`2^|fnZ;%GHPKiKOQ7)!XSG}IjG zv`pX(86<7bX@-iv5?s0;Un_WSvTKu-}!jI@XVX8r-MlNG0mO#HOr8sh>(9`vHcO z{k7&kYJghfk_9@h2HOQTv0NxRK>E;bXQV`$6Uq=A)7W9@!l^RzzUTd{JNNwLFHJ#T zNAjfBmAF}2*I>UR;MTAhZE)Wgt{b<{ht6jQ|CBi1&EEI1qc@|Cj10dxJf>L9E+%}l zJK8uY<^{mj1oKlg84ZJPv-kU5HhEijt%5>BXBx-N0RZgx`w;&hTt`f-eH}-rbyY&A zBW_{~Gx%4Fq#jtmU{EqwDVa^%1J-_vnN>Hity*hK0S*`VCQeu~@;Cbue&0R|J-!Io zEpH>rqcHSxWQ+H|(VF4~lQF~Tq{PJMfq~r7Ir1U15NsQESk(Y&CQBlq@S*_3#nY054K(e$8G|HXkv?q z)z^jE)W1OE)yp6>1P6rG7zPptUU~!~@mz{f6vrVR)zvBF07W9th`d`x*`5zC>_6GVUSoRju9xu=9Z$UR_li{CU901 zu_(6eGAXBw{@Bdy+3GD-gOaZipgr|8z_vk!8sx$$gz(<>g}cp z;-*Tew3RUo4b$ZUguh9?-w!RzKwn!5I6HITm}x|wc#3Dk$PQ0DEv-xapvo+nqvS@i z#iSZ-&x!iG;*rNY*pFPD_5D`ss50yQ)^p5Lj4Vft`Mt+!!}a>v3Ysy+wV3qSCwN4! zLOaVTgq`8nJRXZvy;i*~vWp3)9VNp7A~*$Dj4)0C@ECwogyji;{s@o*0w09y-vvX2 zCmF^|cDp2_qt1kLV00Dr%+zgK4t=;TZ1N`Z9&kRu))}*Q>y626E&Q*wL&40<-z(Eq zj8)2X)9>+dTjK8v(|Oy^`z6D~HWvVYnA~n&|LC+4EH(@bIG*&|2a$oc!SfCBp$B!L z3<072WKWycCA94`rqr}%F=BfUd}laa=5aFdFQn_Ei; zX-RjH$%`>;M1`-p*;a4LQ-h_1(wg;i*}GdVgRP8vvww{N;fUD5hJF%3B}Ms5D$GzF zf>RU+Li~NauX9eKwRr#+@t{+zms#!ul2$9#rWWFh>viFPWdJ+K~e!=z!?F^to5S^3`- zsezOqGOQUSo;dEOX7EVE9!b(8WPx|V{db56Zb3zI%p9JXvp2EUo>xScQvcJxGRCcc z#_oN;I!%n!oX_OKs2FGz=qYhbrMxda*@?p7j?JdsKH!seV2g#Cs<6SKrnvV-Md1hz z9Oyoj4SqKNayyS_xuSR~2!FOcX1J&fT6mVkMNW0V@pXKjvC80V(Eg_GB!H^!YwVvH zjAJm0;`K)I81o7pd-K{QUjDYsJUvy~_bAy(j8XX%fALeY4tYXStq)((Wnt|G)Z%&#d||5w={fZe#1tM!4uwkUpKYa-bvrER}7Qpyh|cD4vl zl)FGwEEl6v9F0lE%LWcRX}wuqJJkMnaPKm#YxYn3jyffPui)%-Gq$M_dti95Upo2s z@bEnqTZ)_W7~Ao<`69G#vb3NHLL_G8Ajo^ht8(M;wPO<5j84r=k5{?vJ(97tZ3R^25eOO7N$;8Bi zu0gI+U;$2vRrfmnTHuin^gLVjJ8_SAgpK#^WLsF}OpnKpDOW5&(Kc=^*07O&iax++wo24w zJpl{q<+GG?p4RWNk&@)c@RuMFL2}_#Gd5anV{>mWCv;&+b~BPGTCWC&sRalh{$)}< zRe=AI-j{vRyj}KFb7B4^TCqb7_G|GD%lK7O5Ru0GaQtkm&(1vnz)WW$`@m%OB(ZHz zqxE;^1uGOOTp#*Ik@b#zv0rFbe9bqDj1n&=W&RScuLpbwPIna_n8HuRDk@_#N&oFl zd>{EcFuS{bU>%J=vGJlwIB)oWKJCC<7zm2{ z@38$saOUx=Sw>J;-vV(%5u%jD5(%1uux|a{Z*pR?1o96@Jal5h`-f-ROsCqnPKT)& z_hENpb$$PSh~Q)RCA7d7J|DzuOK-&;=|e#&XhUSWi(`1Qq*$ zQOT_(Zy~_7pjI0F>dk@IqmjHmhhclX7}etEQW}LZT;hQ7>3sp-XY91n*iNiN8POTD zo6|x;Cm!I&!Qgd<)?W5WO4#P&&PnU64=uNCuTv=KLt=gEIo|y?(Npb7CFkX~8B zq=vFj{2nbcd7-NH6LafV+m0V=lEDjZC=8~>vjkh}QzZ`Ft+?(y5R$xvg;N`dSZt2zD*Benb74#0F5wr=sAPBQr!k+DGW~GIA&$wXRzmdbUWYY6rKST96K2kAg9G*~~NTpir zs7hznl!h&(6?n8gUuZZAvJIxR?*8=I9H$#47Mqt>XA(k2Mhn0TiGJW;cf@q?J@WL% z!vUfF`IWW^6;E#71_wj z^rIbk`L*fX1NImo2MtVQF@4UINi%OneX-;mI(1|uaeH+|FL1xGc&`v`-jg(PiMr!v zZuY(EZE-`BHgwLLBA2rG^ie3XSPXERk88m*V>%D;K6@Gb69d4|g>ts(sg zAx}q$;PlPDJvPU>uS%Jz#ACnb9=lTkrTdgj2evfM1EAQD|}M< zvC8(HaoDtJ{q)n2yfQim$K#C{T;(rgX)c{?V`1 zib}Gi4&@W>Q*@FMiy}*R?*m<7F&=cQV#6QB1qFSK!D&e${}WHQw)s~=^?z$NLN?jp zdcld!wW20Kx{|#9ZSnNVS~+W<{{O6A)p%K;4a6~0xdtk(BVZS6G!k7(3(X3EuTFoS92$)t`Q}zt?`B|I<=1-o=w~5EJ5VLPm-(r(vhaUlZu*f9C!sm3=r2No{%j9vV{~FC1WbSJYMJOq)PWfgdZS*4O|zX|MIAF*I zv)RKpA|yZoTFeeE2iVPt7VNV-$l?u4e^L#`^bAW>&F6C|iW_az?!shn` z{*kN37Lue3o-1vca@@71QVq<$6RzoWfycn}93VHq`;Z^3P&OO6@f0HRk?U&+rnZw` zsRR5bCnkuN>_Z^|+|}a|h+9+~$pX=@PBI0O>dU03OfMG}#e!gxVx9(XgmKb%W3~*j z$0FgYzn`>s8pBV~oLyR~7L)^Xlq6%PY{xB*YI}sMgwk z!1969n4i~jQ?H2h{6GeB0-Y@*(EzWU-gZyxT3!1sVI_% z_2^7F6}@1EmaU>HYRO-x;Yo9i8%?fbJO3QV4iXa+x3?VYveu(+uSHb~+#1Ek>dLuM zCiBbCw#HJR2h*L{mnrpct)Wl-heDLe9eG?z)Va=&uV=2{;R4go7OZl)d}e&K*ePjAM2*75DLr**F>0Afg^AR^ z%vg9&WtnvFDrvB`ZL2V)?5LO5Hb5@*(8THgyZ|(O*x<&#%gOB9P+Hvvg|fqtE^n!5 z-bx#!W$!&a*=>?*;0$92gx++I7n`}rBra{IYlVmnJYbanMv(1c(*Hoy%UhR7}X^FTK&DB6s}Z#?r@9X==5=a(%^N;+8rBvEnpxUsanCs|wl`WxS@X@D z=4uMKx#bC|X*K_79;@3fP4OR5R>>v6BPw9v!Uf?FsqtSy>!{SXo8_O9)*9SP2ND(E z*R(IF%?GV7e54y2#VeMnP?czhD8B~vUK}3Oah5_`s6jRv;>zf-g3-wYO`GT5Ib!#p ziG1?z|CB<6kW88Un%a<8+V{Y-H~eO?9odce;*LRngJfnkrN_x~)>)Bimc)m8!r>9g z<0Jp8gus;ZaE66HguWCIWZ=C9V|`YYdbl@8-=ZQ2s}Ei=I>;k5&7{{P#><pw2RwyFkiA1Sefr`UxYg{afmHP&qA4je`l zTSc;PJZ+}|q5EewPyWf@1Nz>(89ERrKXsVSn=NElzqz)5=rfp1H$oQsN}T4!XFi4* z30<~7?%=fz-7Y_h7urAkJ?VG%xvj1Ly5)XH++bB}V*HNJmdANY)8ZkKh#gn6J9JhF z_qnzg@PN@Q+$Q5_dxf7G8Kpu+;|&Z8dq~wJo(NDZ7-eUc(!Vk6dl3PH8l;K-vc{O@W0<)ie2exyERv)z^l( zIf+^6JwG1MF_Cu~l@5)|`klt=%8G}S2c}d9`uVK+&{x{`dco&1eE$=J`Y#e)ApYu4 z1j6mDp~7hEehdAgq7UI9DRs|~55wJ>cYzQ?YQEQ~Q@S#K;r_n`U9wlv`32LrBVFPc zD^!UxIaUSd_vr7a*=0h4m7eRq;a)2}dAiKnFbc931-UA1@OZ2+_n>dJ7Bdn1M7AUR z=4CxOXnugYszJSkw^nioX6*28$g-)Og*`Q3zM1#!@J$wgJ)WU+PO&{L1<^`!#U&{D zW=?gTJiJ;+U{RdmrdEG{cXf53Yue-aDM@HPQz2blQuo)A@OhMXb=o$s;HJ)aZq};n zC7KUvYLXn%UlIhVzZB85{-dCR*&U%+QHwNt7h?s@~YR%x1o>LGb zqkN~L@(W`LN{Un-{LRxU1u@Ag!YEEn{G}G39sG1-h&hwP(j14au4bRxiEi7mJ8E#r z3W&WEw7`e`aBHs@U7mdu9rkn3o_5GCRFB~Uglf1aWIoh-xUu!};7_Q3ml5|DPOv3=xx;*Pod%v~y>M>uLgmN6dd77CtAa-+s|WkeARGdD$7? zGoo|bIemHQ!L?EalvODPU3!@^=vmdF@L*`v`V||s_8iLHp#&Le|FVv$PG6^C5@4c~ z$^JULwL=LTS^ZD#UEZ|O#`hrqBcL*4dG&qnw$I3u_97!RghF<Tp{#j|y#DtO|zd16W zrn)2or+W9Cyp8?M!FCOycs0Olra^a#nsoFzI%H}jo<-x~O+A6Te z1;jzkgNDJd)rZG3Zxge33$q(G_XX;*T4f%2H&b#?mYwc-oAILl zcxz<2u%PV8y>eDsi3H9zK;mKm^wScNau1lhQ}vxpSx}DBoBVmm`2fAuGkBz| zJNr*exi^IAk2^JUw{urC&;RPRcQeQ98~e-h$Kyh~s96g*6k0I0bFjI@YZo#Q`ZF<` zthE!Dy{vgOO!KhG8_3AFJtz|>x4kp1b+9$^Z;zI>4Z-b~A8xm8<{U_I z0lnyh^*yka3ET}YM7`*Iucw=q@CC~?F;JyKmZ8z2pVR+MSI!FkIVZ1~qV;#)Gf2Ny zHRY#wZ?sCu#KAZ}Dy37oo52Wa4GPuv+sOJ>#bChE=6q;rGzOFD$#gr`+FDNH3|I%Q zdro$#>k}(PyQsgTe4beJh5JOQp)WG4>qPRXLCBha)x}OPnY|A^%S!Tn%`(Lma{LQ_ z^9pWzB#UUeTW+r^7!Ej${(ezD_CArrd`3iJb24_J6-GyEwOudMJW4 z{&#Za!UqWieD_DH2uC|7twXw}1>v?rupuCF%&+?*vjfE{3ETu8VO&>4U7l-t5r%2! zqNhI|M!@*UF}bo=0`T)m7H}_h-fYA_#cnb8)mp4&%JLC+=FYgKd2Pu7UZI;*==L## z-wmGQ=4Lv=@f{l}1y?MUwz(Kv-1vc5gF%`-HPQR;*o#}^i&bvn;+hZTA^-rnuh=2m zp?e!_E>B`*m1L3n2oRPGKLt_`HIHCHM^(b0^pJ@Gr+7#n;YK%(J3(4BL$3yg!QTAD0kJ~<(>rpSgDEE=(S0VLnvmbh(LZK@o z@*#f@j(=PTUf4VSQ(OBN2-!{cJlr=rt_|DI^~-8GR(=d`x3acv3t*pZ3~6c%VE8s^ z;cc+q>eIiIr3)mOHp?!ipfQI1XwLoG;LEOkH{c6!aUmv0|7DG~ml#c*bo&dKrV@o6 zzyGTJmf!r96g`1zEx|v=&L-1$w5p>!@2*|QO&6aohuH87J_NS=F>!F{`ru*D$u8XN z8|}@Ltk=*9gs=l%f#p8v0ne$THwF)-aiGXjr_p<_)^}JN)zdybs4HvV8!x9e+LsuN zIR14IoPX}lhXsFeYs*gWNfpP1qaLZH+)rk-CO^kA3(i?Bd@pD1)bih^Yyz$=s`%8$aNO2!z=cCZqcrKnZ8Ov zRPHy6lp5+U1y|*3;=y1EZ`xW(gU=3e_Krqk-Nsalx7UeKMA#WX=$Zq2wrQVorwG5= zTGY%T<78^%uz^t(!eDBX7av$#!l8K|NSF*^@C7r28!%uAcDvNN&WNe!_%M~M_J#)U zz{)n??cNthE5+;kBV)-0*@05X25*k0*4#`)&0I4k9gctp;k_=r6^;OP@U~;$i#{*oBZ1_-)yt8R!*Hn9Z zd#lEOyBA7aKQruCbcI-z@5(xz{sxZYFl_k2^Rs=RYI|l-F~47}*f(TH2C}%KZ{&<# zD@4WmB41_FoGPfLjO2PL#qP=|pdyYNg#%qLfoT7*%|$3Zr^GG_s-bjkl-=);&kKo` z`nieuhUpg*6YTC0$FSqK#&^~E=?Ok^Xw+SLu5_UapM(k0!hxLn!1~MEv%>Fuu46_5 zDQPJ%HE6>|o=qO%F0`WiGvQGt!V-QSp(~2hzEJUbqV$E2$fvqxR+Dsjpr2*(+>$!e z_gA%Ui`<`|@gzPAgdo-5q*$Vvrre9LJTskK9vf*f%l}=Qgo8rVG?@p@jz%>FUKjfF` zeK-A>f0>yQ&a#PEB=%v;T#DomImKT}OR4>p9;MwSSbCnp)LWFMmPWLOOHkm>T1jJ& z@661dNygFq`|}HG|$^Xi8pFhu}L6u!y-OK1w;#J(Gpx7-#gw?>^q}% zIzynv*7uK|Cs_dSeD76I*LUdxzvFnVtplw+rWhj(>GD3HWFB^#+ltX>D6Dtoxtm!n zSy`d0Qmui32=ffO<@f3$gyG(Y;!ldISy#y~cGmf(8bjEb_EN(TIt5d!r4?h0UZ;_I zpov8vyughs-Mm?|VayqY@=-05cIVMYZ`$C+NLx`pjOk9bi6aM2riY?5pYc_mapfn4 zO`$uIo5KwGa;~HrbKsoFMkxd}Gp$i7SlMSfJb-K0AiTYbICHs191dji2zn37rT|kR z?XIB5LN9eZtFshv(qSuQt8E-5`bagDFdd^Nuc1sjOuk&YTK5FpTw_CbsBbgweqirl ziLyx!IB#vFnG(+!7nFvJ-+AYy>IndR9F=V=ptIwsPU4XjnLNOOWJVfYHFU)9eqPG!2hMZ*f;cLa0M zIzaioXBR-bdu*tsO@Jr)(e*WNv?STv!MyEhPvBOhyp25Kf#E>sP;?pn=MdI)*~}QO z`Pl34ZU{)I{+I;VO^A~gI{=UHqi(C_AUi8%zRBx{Ryp8K=gOwz?@m}em6Op&Wdztt zc02|=hp_TSJimy*<(N+zv2os;_#M@(!Dl}Poxm0?5vyul9d%qU0HeN$%>`w_A31Xs zXVaW!VlO-*if5i*V5LQ$zNMixbQEfro&9!TZ~ik`ug{Cvcz|jl-q@Kb57_+9JYP4E z>US&;TJ;S~cw^5Bvy$ACelTY+aNsBwnK$=rnLRjgxK5&JI;rS`xi>|XS;S*`yM$1& zu1M71(4K=%%_E^O`UdfMaWM3dF0{aNf&}cIOS$TgKpct!g6ACAjf{M0Cu6g_**7|3 ztZ23^K{WT^Uo~T$ymp~nZTtK5ZM5eU53@v?xzM6#z?0^exe6qj7|7X-R=RWHeGu^> z#lmeueC#q*rSx15s{%P3G!gop(?J;6e#Fa-vVr0M7|i~8xk|n<=4m52-O2yt=AhR$ zLv@cRPYwFxafW_Xh7obp{N4%qt+B+P>r?^ZIef*orvHfXv8TL03_g)=W=y_DQ#0;NDWH#vF}L5;BA>vI*Pg5BQf>@O@}!L&rK~ZSv0* z7|`_%vk6(uAoiX+yi7ywEa@5f6CaUk%EVFVQUmlF_2DO;&sejE?R&xBCO2)HP5=JT zONvaeZZ`DpV!Ib{F8FP8QBjff#DB51*3&Y9@9#`Z%6t;Tee!R+-`3x5nJr(Lm||(4 zTU$!aAJ3B(czNezOVhJWaolq_hx{+`D>K!;Qs-OX$gy9BJs)t|FkPl>CyOpFRc)AQ z6oGV{CI74(?#`87gHtq_V1g&*AYG>`VEm{5%$|EobYIYQtH5$g9JZ9v`daY`A)&ru zy#ouEJrYN9Fvl%ri52EZ<4jhF8UkkDT61Ue%9~Pnqyr4xuG@U+tfz;&D%2^%#8=;f zhUMy`N`E88RStFL%|B25Gp{h*>0f?IK|@g7BmOd3eH+KJqVE-0sc|r~vDcElJ9INl zq_l|RG@$n}JQi9`PtVMVW5@|C*b{5BW7RZf&1nZAKHx9DZP{IFh6w9PWP<5yAS4d- z7iVvD7O4-FB$?6>s|dIm+!YSxvRR+bI{i5aU?2SFb7I0zqf?*#G}q>mMiQIM%px=D zJnY&m#3pLf+ExTKcN;bi|9MV_{R!E4#iS%Oq=eCGQR}|2y1N%ii459qmZKg7WL2LX z$y;y`?3-rXnGh29_Vs;|x$$KwILtng8k~;*L@5Hv@m>_cg?ps^Cf(^Zdoyj$R8XYq zf$+_bdH9gA?oxpYRc)|5A{SrN2v7Ww8 zrK(D)Dy6DqpY{FZnVl>hSh$7D(5JJqx-gh7%S*xcpZ>eY3OOhH)xuuJQAVVX`{fms zY;9zo{X1EfNQDl2)%Y{c=?=+R>sjk7zqcpXTWF?ca!F=MaVH;rW}7^JhqgRBvn>C! zH701*a+PR8GjIEK5F+#xFD9CyKdbILVC4sVDF`8CAF>RL!nkIcEKKn1{W+O1QO>bS z>7Dp;P3B9;=m6Uv_|WnaL&8-fpg%fK;4V*owex}+)Akt;TDu6}=UIU0k3dAmyCks$ z<3XP*tTbZ+C!sl92a-@E!<}xz`4o_N4zdeFh^vcIZ!i@3*5-PaIFh;H%4=x zYloW!kl*u?X6Ju4bhSIh4f_4`ToKp9AFT3;!lMg3lgb9{u&?*^mMpR~D1Y}-S=sTw zhSV>RUGXDoFCAXkgV`0hLeT1%HDR{j2OYqy$4Z zQBoJ<-z!Qr^}d@<&AJbUQy@xFOZ|JBvHpMKu$UZ~E>Tv$8(y}%9~O-j&fq`_1?oT7 z#7&c=?*hC5PaDs+k`L@dQtRTQT#5N!%|FdQ9B6Ls7kw-yaOjb^OR?8U9lfcKpauk0 zMyvNMV_`;)xwGVY>-hsNl+Qm44#gOlVBF~@SPVM9jk#BG)}F~4Ez|QIlP4Z>UjOQ8 zaHw@L=9Rz{PgIYAxjSbd`Y4KBpk^hPzyU8EI!u$4A$1{KKj3?+l}x3Qc3QeS)mQ;@ z;h;(=S=C@u7nmkFU}NZW0T2U;l9nN>gHC}K6nPaRK-Z^;Hv!>*f^Rtvf|U-bl|AbG z5rg+)cx*_Y*c3*n;<%w0VIntP0-p%gAAuG)mK0COt$JI@Bs&BZbD9~ya)W4#!7T`a z2)IM6NvbF?KufH1?$eVq`WRix-;yi%yntkNTBbnAr`qf{RCLgbQO<|O+b^oEzI<;y zMX%L?Lrbtmf#?-w!^jIcF^b7^_ib)Ll-;>;hljm4P0PUZOYB#(XK(N}uFq`0c_`Pm z@GZJj^8Vp`*s;it=1w8+Mng|@6ANJKG~ltsiGRV}&4;G|VTb28P6JYJkeddHnkS!6 z@01FK{?YW=nD&c2Izl#oM9cZxlGI88tfFUzJj;kj!M}*SyN0Yd>0cHFJhx}Ee>XM+ zn_8KOsa!39cI*8F4}Q@>uKarHkP;VYGg@OUhi>~=Y!(3I4R#PKxI{^-iZFNt>MSFXoKM8jgF zZ#P-GtLon@^IPot)RJn zxndgi2n(yZLIwun{+o7GKixB|*!Pt{bL@4!W|75i{3n$J1t_v?oQ@HWm=ghhdj%4S zfrQVAa4L}JPFMSePi*OVa?Y?SDmAXO^0IK`@FpKMs^X*UzJ)$ipU7TnX;0Bo-lX ziD%z{1h3U`N|G#-^DSe&LVYquC)Hk3&7PP|Dlq!Ja}cDlFtctrHEz{WRHOt^b5b8L!Rr%5FGu{>4K@Sb zHKeR~5!VzrJGbv!7b+7FNTF&3rhko*!&yOHB5%C_M`v7Hi28b)y__D?uLH4ZcNsrK z9g)*&JBISN;JT`(7jV~1o-lWw`(b4nPGMT-7nr{_w;#}Ub2%P}OW>|W*cnH^L*)Am zWma9naDFE%pxLj$>T|l(_=0KMN~$~&Z=H1kqG`;^P?5tBaxl z0PoXJGtm(Ln}%|ni5ZtY-b_#J&zwPF*5Xf%vCE(yU8kKxP6%W`F)=Ga-X$d=S1oNt zaLTZc**D5x2#a2Yl5P^7=~#Y7#E7;7S$VZ%G|4~|FjS=UG75jq4RdeO_q_>+ROvfv z$Wu)AgoEga+BbE9b5AdI*<#RNU_fldAg-`ojG&R`0u0lHMF$N3HD>yJ1LqP{8%-KLty~*xuTl*(N++G&`1u;k;xGl; z1&$wT+F#XxUBJIY-?}E}px&%T6}@O~4)O9@xPY&eTpyrelzJjb#V(4wfBWh z1GAgbspi8OJrg)G`QGKc_~Sqkkpiw^xWt5w&t@-vrJQ)KQ*DtFAczta#+`vUUW8p) z=*m~ijM(W>FbMdgd13R+MM6RQZ3%T~jqk%RS@7wk|nO1}BV@0l};lAE+CS^ga{OC|oOY&41OI>%TWwG`KeJ*8QZa!LX1Z=UH2Z zbw__zAJJ(yXpfY=8GrBrWP-fhDjEAYsoUVbPWeiZaSTXb_~}JJB{V3>Zw4=*m6T@w zy=fez`*PuEW+2pixEd)%>a`-pq_c}QDBhW6wevsnGJyq>y*mSDe8?C`moRHvzPpTC z+|!vrK*TS}Huwv}5gCIjWijA&PDl($8+N0mHp`|rRSbA1p6r*=wIx(ctt6~6^6FFt$Pj@q&>hW1 z2y5%!(LC^)dYFpwAce?5a#ycqPwAZXLv!*cF(gnVF-G@giwX zofof&yBgQ|e_nuIopkXrbP&trg_dEs^z;s*u+?n1$k4!G(f~8oSZgwG(QUJRCIYCP zJRcvr_^7z&>`R$~{~mJ`BX-B%pnT?k-5z&unR9oRaZ=NJmLR(J#9IEw!y!88gQogz z4fUgJ^@gfjdr_zU6Rh)eJ}sAtaqKJ`n(*+}OdZhaw`qtmR$5Z_!BaLi1_HC4pu;kK zpH!WPC)6-_b2uB+z^0VCXk{~yolt@1eKvXvAl$C;FES`e!0xRO0B}gs zXgCe|e>8n{R8;Tx^+-qx10p3gbPU}sNJw`K-QC?NDXlPc2?)qg(jRF=N=igP7`jGs z=#KY(-?e^g%>e%lYwo?z^PGLo*?XV)|KYGn*_&VY@o7?LR{x8HQPZKJehptZ<%j98 zKH)>m{w&bY3ARoEcZnXaG`kJgx!toVGaZkbr`OmL2PZJ&6mC1 z#B3!4@_awDSADQ_l;7*JHzR}9QIHt1|1@1a%3|5OPD3c!Y;h#1r_&ZF=llhl3zIdF zeg4zT)&BV+=Gnq~S$?Wp=4`pMN@uet8;!>bvooHJJd#@B1DQ1q?6JHK^y|a(ZtpWu z;-xWGs*UpkRJJszgNJX`WKVMLgfus1EVB4#UCZ9JyNo1ks*`HMb#oVUUgvgC!Ucj? zF8>f=h8B_@SwSK>?E_>*tpk3gqPg|p3kg40QG zR2p*5jR5>}eBGbynQ;M>)_JS1*q=bzAS_r%1+U~!-f+kz>k73!3nEi|lE&K&t=!>v zrm4(f{wGpP<7F>amDW`dKki?PK7jhSLL}6xEZxsPxEmUH`j;GmFYJ^XQNBtX{gnM+#(!{+{F!!1GtrP1lidFP z8LzJrJ~%kaYe!Dcj5LzU(|`OcdbVL41Ku6SKJb61YxDa3KZ&U=`ln6rML??)(d#RK zi2Y~9w zXB7mW1iugDNZ2_3M|2X8m8vg4e43CghoPB+3aGyf?NFn-##QH`PfOnFQx6-KD*fa# znyb@;Rg!&FMGfX4Ir|nN&?xN^X8s+s#%J&kAGfZVv3#SBjk6fD4Dj|!-yqu65sky- z{+axJDj1G>9K`a?3z{kWZpdc6X+NVMj$0LN)$qOwbOUXi8xJ>I>&{0!FJILkDf5gF zOcuX&asL8AUVJ)LelGnv`-EMS)zX^Z2(r(lQTRIBihVh&-`-3UV)A8w43~8&FXtb; z&{g5eq|Owu<=SGF+$#TFGA;0B0#q*ir%SGkRvXZ1Gzo31D`?_?{do4c7Una!DtR|T395oH3zAK40z6Ss!=u$@;U|iq6^Tl}y;Vj?eVa>*}3s()bO`wGq zR;UEg13VGzW%>Lqs7B@OVaM&(W!M9{`{;$`gN5JZeA6Y1N+Z2(ayAcr*uR(ETf9=8 z4O-F|f{!5<)}8&R>wM7L$8AmGLm=#hTw6X&(_=U%qT81aY~JsUd<&pd0y;GPeC^(O z--R^#h+fmg^DkI~`uPSUC|9j;a7nO+LK}usZVGe zKV-7hj8@y*8^AxCz~S34k)CXZi$Nk_NlZ7}&J8;+wbnUz{PL%D%EU0qQ=m?9mqn^+ zW{h@SLM;wD%+m6+;K4;&1^kw{DCEFG5` z{#j%0%m&px3l8aKRSngus*K+%RZ(t^nLg#ueho5Lv<)xNA+6QB0y&t1?V_+JsKCjJ zeZgN4HV8+0l(vxpyXq5sKwJ;ChOQh@sI)e`2p@lTuVGM95a>YNMWrNpanI*uTc9t| zyi`N|r{%VKjuF88A5yaF*4A>@H(LAkA*(slGH)x+LY}J_4G;b^E_7`|lB|oRakg1@0 znJ`Znv(K0A>;sMY5D&%&9gfwlr`RybSa0_+i5kFiYPU*PmX=xpB&^}6c@RGx+7aaH zn4cZx$%ZH6+wo%9QRaHFKCHj^zLj_3?j{tFz=C=UaR$(UrA=Es3Y(ka{KoR}H1gydn}&s>;W1_yKgnB=EyRCJyd#fpC@97AlxF;!?e z;KLm-Cv#;d1`(wo1DJ*TVYU?4s6@5uMJ$XD3NIjZX!a1aN=9jAUn|aN`-x>RG zPZO#%MctO!Vaj|;*XOSBeg$!38bx9#r)2)hCY>CLC?q1s9!MD|5eUB|gr6_fgVNY? z{eU;$Y2TiA&c0a6?AiTie_55<*T|oL18B|ak+9*?okoA;hdRArq<_sGoG+Z$W18(5 zSRNZ9q>_Gi%AAu7ci5Pr+mZT=*dxtS%>84K3pdC$C}&72Wst|^!SBOz!~nfbZW&zY zbF#15Z<$d|GubOSXx38|uk!mRL3I|VTG8^P0-e#_Ho`{~L|NgM$J$8sbc&J*Nf>kZ zezXlw0g$JY$x}j%EnjSDldUIS2I$~hCNkoCXLe^cK})FQhIGeA_7!8ns$d0>JcuL; z^aRKv!2>DS3xn22#;+LPfh)imgbd7V@nVptOEpMG#`m9AOUK?^fIz;IYnb$RM>rPZ zfpm+$X!BLy2vmosu>Vtjj8kmOiy6QEw)=>$RZ(am_6Xt}ytH}(+>$Hlm21n#b))cs z?1(1?iiEF{OHO5)H^i!zFAVpVMch%d?k`gfUH>zwotknfq@%4Jc3Il4_Gij#x&u(`KWb?s)9_`Lcb^Yy`asi|Pst|5}n;MO@dyR^nJd1hni&c>mN23r?n9^Xu zZw^Pl=?tidTx-nGvxi1RVE8^omC=eV_PE5lR{ z%Ug%V$*5>YG!-2lcrBv+m(P72LZ#4M&_xuH`W!lmMbOksve^v0- z5jZ@R|H~9}!z}kYPA}hK9&Wz_lmcwv!Gov9?{hh{vuIu@zEjm%1+p<%VhtF3OT3(2 zg(QkZ0@Zm~n+fzqcN#K6B#6vZM?S$5evZliT*&#c0HKN_A@2VGoS>|zH@NTOz$cVU zm~B%OLA8Ht1QCtw`Y`ekoy^wdzk+}Kw|3hJ4Ir-!GPS*m_>{agos|Ug$~h)bfWJpw z*{kru-q6V7q@EMk0C3D&@qJm(Z8foM&|`yd#cpUQk$lc3yr`?|+QiTD#K2NAuiMdT zHt`+<^dOiyIk)luqfg{re&jt32JYP{{q@w@Yx;*_^LXVwca&M_WpTi|Vn zq(h*iBNYFz>+%Q{xpN;%A9=D9Ul;l&yW(mqg<-!pSO%`RljXma?fNro+3RhnoebP~`X7auMy%zMJ#kbLH;*CC+lm$bZTH%A* z@k(#fhlRmMfBUVP4M5h9WvhuxUQaI%-6hSoS5ckd;H6Tr!C(SeLHW$($ zD}49rPM4H^8E_`RcQU%s4J{(HO3ICd*6CZ`bhCEaxFU2&KOpBXwX*Oc`6+MqafLM5 zeSvWE>C!7KN69fse?Us;@|0d)e?nYPGovM-=m%GAA)M1scd#|{tN4yTlO%Jw=I2?# z$67Qbrq`ZQ%Q>rE2q-Kju*JkkRleI2@)-mnhrhY2ZhVGfZ6}w@zfVR54`P*xmk5n} zQJWtvP*#5yNcr8Gaq!o_N!A-V@+-jngYJ_m;Xez^r(cKGtqU4QG=7L{iIy|r7>SB3 z`?)m=n!kue?CQ=K*k>h${563NZZ-OtCMkYF0O!`b#B{c(<786RH(8BXY&49JAdarj0a^Vw{pm^;a9rCU zLi?%}$g~8mO+Mt-KW>J0AD!+Zp!6|EgU`o9BfVQZEP~fXWe^d&m5~8^b24Wy(^k~Y zNNw-dCoV3^w@RtSZRs|!qA2_R(Rh_b-&?I&#s3&{K~`Oo#QlTdf)v3zS>;USc4NK) zv81}=8s{1rJ-tBsX|H47vZ_xO<=y9t3;9#grpvk1Y~JHB`+9oJ9^JkdCi&dFM3*`x zLfuK#HVZI0z>WdKQCL1o5Y+eVSg&%h4jChPfgD6^_*81dH>!R`QBzy~3D(`r0%1L^ z5$$hH3Gf6XZQ0AAsq^Ubt_A=;{i?tTmwn|L>XaNic%kCSO}!8I(iE*vfb?P66xa+> z7R5UY*(TcyjXF;Vr0c1wDETH&rNA@2DdC4LhwwxAF0zic-D5U=e_^5)$>XQ0IIr>r z{_ZEG8%ka3W#vZ+)QPRU(0{G9M_D$nZ*}cqe*Ol#TcskVqansn3c!(T(Wl{k5+cSP z#-QUh=BvaG*)%31lrvsVxSaH)py_bX%+L#<46zMCs)*OkX^5HC_H9LD`t6)p2Ry8^ z1OUH-y@HzU)gxo6zKc&2FGZrck_Ns@-7cO=^7i;VjQMLF&x78w9iEMzT|NP=T(EX_ zzkCbEG9BHLGdJRt8#Z-q&{y3OGD41S>61xmt3HVVT~W#%(fv2_1T9SniDK4ZR1xfj z5mkrK$?F^BX4&V?7-VL~TE(u4KmWE07mQ)>nh37a?{G1l5z(zT+_PR1>YoacrmfBU zC1Oq!hi3;{Z-Ohx3%+uG3YZ7zCW_fR33g$}u4?m%pucYmm2d9KM`C1bXe5i4#p8kg zllPp0U>$Uc@((V@iz%RS(EXdGfy<%vVP_eEQ<6BH1YRd};-V}bJ_!VR)KYH>FJl~- z?W58e9pT3X+cAy#8Z@5qU`A~v*V^QCRcek*cM0L)x|jJCzO}ny)5CvNXfxBbT?)^9 z(Li8$2XLjej&Q~Q6TaW(9#DT=M?hl{KM|Ht&W@TrYnairk1Gke0aZ1uT95>LNXRiJ z9jfL1Q^bOoB?yylr00c~F73a(rNa@8Xj&y##{}_O$AL1~Qn#Xebg3MeKyq=*)ooB zo^ffJjaPOJ4QkFKGU95psI|p~Y>Hn>u|dZ1tYYM|P}*OmtfR^l4Zb5dbs#~i>?}e| zLZc26U{$N*?Obc~r4s*%^P%OQi2?o)(OBFHa2GL24A|^U286|rHB|-zDS_{>=}cfd%Ja$T%3F9g{wql8+R6N55~!Qsnqi2T5J@RmX!WhGcm^os9Xs$*pZu;~ZhHsj^rENH4oE=+T{c}=E;t8VhFB}Q& zXk1Qsp7lxL)%zd$!N)gagWCnkQ)WOZqjH3(Unn^v--y}0(|S~4M}aeQcs#FIpS5sK z`q@tHxW)=fRIvL-<1P9rC=6W~kKIjNsfLHkqj5!aFr-;0srW}^3feQRD` zK|*viw6Xrv7_y451ZZF!@+?76F=cy$Ui+@MrlZueNz@bt_66SQBv9P~d|c~rNAk}M z3gDaI#|2aR?_>YyD`Btvzjlk3q21}>c`xiY_ivNpoKKcvBy!;^Ppb~fF8CiBal2`=R4-ss>Q&^r3nHLFTp4i_i{oF*hX4%@2^0GMMo7yT#v zcVr&sywYIgXZV?Tc@}{KtcbXvp$dG;BZOK^3O0!(xP1ppW*iV3{p~mX7(>YDrzW?! zqWTw}ws31zxAuK`@Kg1{rV_>Kj6v%1(<@7$r*nAznc|VGGjXWzCAK^`>{Rrj>N0YP z{yw^fbF@PQzgJWltBb%xn9$Z$eMPMt2O!o+Qkind&8htLCv7SGq586>MWscgYUg(B zOr(tYr5faBTBU{tcO@b+zds zhaXcgY2y=ao*ir(5bmR|x+WTHCOI15+gS}^R>3j?O3FpPL%}kh(6PG6cfRD}qfDc| zADU6=sdh%2Dd1a2LutV_IPo0+w;*PbnZl3YZ z6B3^ye_H|Gs)|Y+vDldgr=}cn$GDSIE5S9;gRUOG!|wnICH(MuZQikXXtL{wH1hiH+U2XrR`RpZ4oR0t z&$boha#3qrc1fM;uy}m1rVb!(%Cd=>CadHaq$)Bn;?oq1`T7(b({uUyaWetHP?4wD zAkfiF51K1t$MdeG=c;Hg%{edZmy#MsxtVAoto~((N4|BJN2UMtwE;3NU`bxQ9=XrQXne)dhbqiQ=?N!pjF$}S*=NdVYl2%NtrG@!8S^+d}o;RkNzw#@( zyvqo`uhlDk-<)ZPUd}UqZEHK6A6`ws(h?7m6b|jYi1^gYo?{?jF!2Q+u&wD$n z-P&hbGWTv*6puGU^b(P4zpFOlM|^MKVEOsw^pu;pzh5scGuOSKA`mPid!2s>s2hyD zzridF_M)3})Hq8~%J8Rn)<`Lp$~0L9mjDcRyKNyb{AJrZ4Sy)$lp~{Umf}@!P>D zPJF26nSv57#)NU3@t*^q25sc%f(LhYzl}~uZEdXOpBKjZEM)Rl6R@o3@{Q0kO50S@ zACR{Lo$U{Y2DCcSU6x;DZUehJI#K)c?aK(YsEp>e*DEbQ zn^osE176Ps^xsAvBs^rVJi0m#dWRi345i!e_`<>N@gGw*f~XfevmfFF6hRL3{~SS} zdeesW6byOXlL8>+U>*^O2NUvRP>SsSz*Bg)?PtQX7vUK=w~zKn>ySiRJG$a!n)|5J)+_Or8w)+9N)@b3*yGTsX zl`Zg4@92)6&ORKH;mRFtp+nKnSC0HG%g{ZSMbh%a^Z6v*D}%KpOnlxV??p3w0}3kE z{`Q#cEW1iyj<$P<o#NTg zYl8pXruDl4wIrbbb+8u`vBF-_2$eaW7@~7tzMmL6wk4J}E|Ly)_}0{7{HtJ7)L>^y ziOM#lHUx=`_|+O1?zv=zBT5*JJ^&Y7dbe0~5QiPjP5Bmw9KQp9ucc7|oM?_LyQe-G zV}dNOPLH;@2XggpDINwMFQQ!`R~w$^zTplG?UZGBkc&PX$!qbq=2Lo$|J^#^64vZnF<1!b7^+It2F*-JXpq(jpL` z0^bkil%Jgw-(-~}f5scZWsUhT-w3e=GbVzEZLoM^oa*yJHOg87^cU21IeI+WpIfLX z&#$fNL|l6f814B3nS#Hd|Al04(8XC5+r?$z5Q4MJiV(>AM;e2FP(C^8i>9y$6OY&* zsU$DdPh-NG1D4jqnpW7-++80|rv7&9DaC@(L?PNzJhIPHLJTXuS~yGBp{wDVFU3vI zfxwF(lP>1h6UVdP%gY`e9W7gr8}$+Yy1*Fs@sGVm;a{NGH?j{~X_3d=srUZJWS((= z_4Lt!=l6|8Qdm}s>?1njEE76<7|Ky`|4q1QJ^=-CT>yjbGxJUf9+%xC;BzD-We>s5N|9K!|Q z@oT0-)uvdp-U0ditz%Jm_v2MY@mnCE{w`|iKc~h5y$$}_M@Ar z`7|ORP?$7m)v}99?wFtNR<6hX>L>4QI$QUxhAh?^mP3Ca89=2Lun;u> zE8}9MlVqU&Y{Q8Pwxl=QHVZVcDaycrrYQ`DD~ldFWygO)P}J{z#_$6S)3i1>_{=#f z;CMzB^|k#WxbqT6EAr%c@Dsu&&e5Sx7{a~%nUCWswF0k)AXmRQUyk*Ketd=Pd> zv0Z^mx&90J&b99!Z59DgP=DC9Hx`8M3S1vIDcHEv3kHsGpuURVvkA+V*5AECjb53Vus?&6nHw^*0K4>E*<+4fD+vPWumTzz( zw3yQNr?bx`B*w-(bFVeyyc#^a@&pugGR|2ZfeAV~H0qi`Ub&~FJhqNDx-q~+JQ|-A zTWyl4W2jmw@Fjqw-jkA%DDbOj_ln_B+G+``<3fs>7V-M-8|#*4XBqeR-J%P(FnD)4 zDGIXjGy%tbz(T14ZNQcZpx)!fSc0_yib?xP=|_yn3q9UL^Y*Z7X4{e>O3SC9SLm+y z{5-w1q?=Tu=MT#hYljo9QY~$+0j+J709aTt;juA*e+4(SOO*?aHVWkrr0EoWiow9D zoBx@>KM4LVhie@JhM>D>dz@oWm}@q1N;!rACYI|D2klEWQQpIxKu*~WU{po_J{+%6*o7^xABLd2)aAy8EkdemA;*f3F z$&Yy1_S-57i+0Dzz}skp1Khj+;{sUT3R}|Zh1r_&58@VHdQ%TtDZl)@TQ)24#{Lzu z^~(YCtde6_!=F^!wJu9H9`ZJ+Kz2wM*lfn2Y8SDeoz!m0Loq$!BhKAMZvD-y*WSFO z5lrO>WfOYNp;>KBL;NtY@~FJja~~*s`mOEyN&?hN3R+#M`2;xrgB}L+&x}1cL?MXA z{pIUaWs5MBE%9hP-G3{EGA+eWiWeKf6W)2`D(PgPSFO2+x0JT@w)?MfUmsa}EvHR% zIOi4QSBwyEY{pw3%@UQ+$MJRCQ(37Km;ZUgk?E(qR=4-NLQjEnq+OH0yqR(kuzE~m zP!iId=EivfoxB~Q5B+yde1D@%uZ-Ju0z*fjD(NEkApjO7Ex^&GYV*kZ+iDKiWul<@ z_gNF5s4t@AaWf_#Y67LNl^=SI%p>L`>Bjfk5#H%`GBMsXLk(ygu9l)a{|!Tpmuabn z|4#ZyWK3$CS^*b4H<4saO>I)j(aNqR_tUx|dO`Gc>Es5|bachPCTz1nb|v7T95}wK z)PNTC>ME|kZeKS#!@B^i0Qguu8EO203buj|mXel`Vy_mIA;|Dh&~kAWaR{NU87m&= z>tva@znU4-0W=|Hq1Eub)Vx`G+ByJM^lyGISDPP5%Dyfijo;ep@2>?S_6&kKxuG)V z44z)ZFR>Xc(^!xa)g*^|7-OZ^rwEP;g#a0L5-e+6tpPx8^@wr6M_rxt!&pzWHBFhw zQ^J6l7zZ6MqCG@RDVSsQ6sqQp{{*XFNMp}`I&%NH)@||4rEJGz16y&(m9T!GEH>zB zcO25maU~6UTO64|xA*iFF0%gS!G1uCUoWgvOxOscPv5V18=w^vULd^R9$r1 z#t4pj<+aRBkrWUb3b_mn96LNb{My!W5STS;Y`{Vq#U{=|S;>*5J8xw1jW2w^%JB$C z=IX~GThYyC^iXu3V5OG%UBSxvVK!al6(n?}D==EB@}JYvRewK|mtV8Iay2VpDznf^ z>zp}OuCMRh@8)^EX?CMz3XbyiM@u{MN%XCujtF3qm{@x%WkiWv4@B}2LhIv(a7_T9^%NOgfyuv)U_V} zQ!L1tbDn0h?x=XaPgXn@4}$nUs!s~-HyKzsel`*wpbrWL#Fh#(cQ(Lsl%1Dlm)2*?S{s{- zLa81(tfE9^qD^}?zru;(`r0nf$_2jcNi3>l2IxA>rm7G=5l4L>rqjtwD?m*jJCFem z%M+LsVPyunn0Y9^O04Y|pgWc)TE-X0{$%-uhvBWXZKWuCun%`tJ`J=FD_ z928&8u*sB09%nE2teA#UTnQl>I_YRG+YpU^pICrqDxMR?m`%o zKYw4A=HXLEKjh69?m3rIV7Qmr2@L9 z{R}bMi|=2ZK_?HCmcrP@=woxbV$&48VspZC3r~Tzu+IyuffHxqJ zmCti2DU+!ggmrbri+E*aWc{`-0QmO`3u}eP8&z^;Mt=*D$^UI!wbdcBh2dJhh@~ih zU%vX*muR3+DtJD-|Um&S-*y=3cB zP|fu(1nzVb`mqS@c5xXXJ9q1KrT6&YSafG3d+do02EsGCn^tZ0Dr{i|XA*Q_m9oQD9?IK--=W2tr08za}h}9d7a#oCtKoiz9&oA5Ry+Za#la zyhs7?mKFEfYuF)@qR*R;AT;3siZ8l*=sA5ID1BRnLbqSmH342nmtoypl**-G6@wS^ zjdko4Q5CRs!i`PK;Ooq7%$^(T>&Lr0-a}JY`iQO}0tl9K9ueFQz**bkRHst(zN*Sa zO$q$Fl%uq^W2aJ=qR*p-RZ>q17*yY+elGw8v1o^E4dlh{e(++!v>6!t)YI3gpgtiYj zzHkHb5+1d$#`;d74ZWjVjMWq`%=P^(GUfjmm}}>muZay($|0Ngd?|S7q)tb)Y9A+v zA2trW^JIV;T=^oQz)`KY{6hW{M1gfM$IUSH zFefQfZ($|!Q5v;;epMEaju^7t=qCm^>Ia8zBza4|zB>q~F5+ry%7u!9c8bYDdYO}t zX>2_w?}!gQD~jrOg6Tt!9#B0Gu8+fN&RH1gd1+)>#$o8q(|-yVp6yjUQC6@m%;uhde|`mba!Y}3DFMXKoVaQ#dpRobDht zgyUL}H9jo4@x8)}%!iAXmIE%)1(pvpJ=Ua^;6w|C^SMhr0IE!iw7ZJ56o5Tm;~T6EDqHvms4b=KJ8j)%w}jQtrki47 zWzFgRe85bh61|_JnuGq5FCA+0pH5aM(ZbreGjtm@5$mE=5}L#iA)}PTjJ1$r2qe*% zoF>bjzeCsXg~cBOLnD@|#3%rl7Z7+0eCndEp&c5u!MZOCNa#Is02iOn$i(h`xB3xHw!xz@*Q|nkZy0HrY0nWp0?S z{<0NCKx6(ZWL9A(SUx;BtO;lf6oORM@3{cFgbgS${DUzWBmM*fgscuJQZxI^El^_^7}+yFOFlHOY{@Q6uGRnKEb&L^Ksf6Y zKp)*Fo9p86FsgGW%(K(MH6V|zLVTaK7ysig%)R@Y8zG^8UIRDBO%);ZVR@QIlJ4XRVTo8j!9kKMKoSFOerFTX-#RwH_D4?sP%?(JDEwVS$C>!N*w zlV9;HfSe8mic%ZXn^kR_NW zSX42R-^z)6iKMSFs*WDTS-MusJ|7^!=^q%)UK)tT^a3LILaTe7pQSh|tL<-ngs>E* zgUQ;9bks|{L@?;+5d*Y*`IK(M;23C?89gin-e-C~7T~^m#EeAKN1P2k)ED1KfnIGw zAAh_iUXDDQ7@~iYCVlcr%y-vsibLE?EK;TG>f{^XGipJ^+Z9$sQ#+fqcl#lEYy0fs zVQcy}^dML8_8v&X{%bKCMATWClksansGkz=TW!Q9Wp6}YeY0G=>BWh>Z_t3Dd{m1i zL%08|0U-%R7qTkjgO(0V60E$auC+G+0tAyhmrK51&-Ie{u`D5i{OlJhgKpMuIRIEHZ<87HV6fO@|6R}2uX4V%$Y{+$rI+6 z^U$pV(do?_Ynr%a52#!wk^9_0-9ay6Cp{zU(-2RH>W=BpAy3uIkAetn3ME{RQQb2G zSgKKKTft0BV$^GIx6|Gep-LeZm@1#_Sl~lGz??m zU^{Aiy^C3WgPTh5u@akt!!h|No#dnMPj=f!V2TtKtFm|PeL&7HX=!WU-ww5gBwJ7j zY?D2`A*D~G`|qkB|LXe#SGSFVrWEhNcUE4VPjMQD8Q%F2RgYWCU;15+`CUc$8EIUO z?Ym%K-Q0A@5QpRx*6mbP)k*kIgf9DXLSqJu^nwfDKu497J__z6L$#7wwx$yJ-Tmz3 z>8V}{Dh;vL94Fwh=4zh$DB)G*@oWQ9KD8v#k+S~YCKYxxx~v?b=O+5ZRg)Q(D&i%*X~G11j3O27b!lr?~H-L zNZd`kovT{eZxLIix|WuCHxIYf-CdVhCuZFjgim*=;y&Ultx=ACl^SjIU*28Ja<3H9 zcqtaP`R~e-evve26-|7eti|lAx$am+be%ax71!W~+=h;lnlHb^cp}3a(~n?J%p*(q zm(Ki8ha)ddu{?@dG1*wi!_-P+~a%wlxwbn}fi6BC!A1QS!Hs^I4wXNf{Q*6AH>R_^#|Dse{10d*#e zz?2O!HQe~7Qg){XC;iON@5wVhhe`2ll}&viNmEr4B5$&tde5yw`uY8EV(DvvXsoBij;Pf09CMAJU}{2k|P$0qq(C{sN<>z-6MS6!@dLP4NWclPn|$uT>R;f6R5 z1+Le(SA1|{?ALK%BC1kK5knp!@bNu9L0Be6B6iBpqP zS%z5CvCZe)LAV6gtTcpt754o?P~%p63PQ~5uw_Fylr^0rz{^Q2=-*Mp-{pH8(@Zx* z3{dLEm=iOjGGi$|h-NZ(?Q3+T7|sF#whmZB4mY=y-K3PkI34&&*{aBP)QcPSR$FX1 zt{=if&k`QSU|%mCgN=NW6P8E#AtV!UfGhP4|rTF&{3Yxoke>XHp)HNhk^$M~w6 zO<@aF@aLM2WPRLx5RKT&uEcfeW{YP>VLW8`n^Aq*a^UZ=@7YaAbiS7A{zx6L`2ala zG$k<(>W$|*9N+|{Xgn1{JY9wN?@JjHtoh0Ci~p=yJUTVFzq~fnGy<$#?KO;q4JHvT zniHJj;PLJD)FXs-pI%rZA(jO7COL9raPb)7Dfe=;S&&G z6>N3)l^XgptM3gRYJ8GvYnC%-r8-sMG{x~R%&c*a%Q>&1^!H4>uO-G^(?51DDxfA*jkw zID#eUBf>nYYOF)1GvT1}4v*x~I8i^#ejf1G$%_ug_SsZ-*CEW;Wwse$9!XVVVWmrJ zOi)NpQ7-EX5+Y9?Dl2g^Bek(nfPXgrfqh_mMbB;}kh^)JWHBdfFzs(X^QWM~rM=XS zV7|sgTfgPgFrw-UqKX}nY0%VKifFBHQ8%2S)R;Dw&PMrsqbZ);!VE403lR!BUuT9kb(&dIHj60M?MN!_w3fBVfHDdNVSfR}mpr4PdZGY{iXF4grh?9Ha#p*>~cmY8(!>9y5|Nt~z>c`-79Sg&ESn6E5}QQV4*9~3?& zC^4xsGkP}|!;@6x85k9#beXA>6%`<)B>f-XC=kZ?Gmbt?npkH!Q^L55#}P1%Okwk> zrgkWoI829t3MK*wNbMCxni^fW5H4J>Oda88hzjraB1hkEW(=0Yr`KV?FfOHELbV_4 z=dF>gSV*4!rU&jvV;GLr=t#srJ9=&Ix9EcXY`E&T&;l&XkBo;9Mg? z@tYrGK~fGwpTE$isi;fQZRAnE43ZygW-`k78l4M<*%N%pgN?w;O&2%*H01=1<46?Ik_bz`y_ZC;VZywXpPDrJaK;HM$|4gn53j7glJIBVv+jKpWi z))X^HaprVm`o|Z-OpeWdCR2L3>N2^i6uLXW^fAYMKP7K15q+4s@6r!>8DsVwNIxGI z#U)FY;o|+J=k;6`*O35xeZ-@`=jl;<#(nyT0vWdd!B6|p$D3caNtG@}mPV2%O~~$u zyKdRV;#$og;|h%Lg5+&%bm2+wZC-)D19zDcA1mnNmRN#<&Xdc(x=2+3nM`cqs~Q^k zD~@jqQq8MZ{Ju~S7*|(kp4XQ+NVgD#h%*sTv2by!ij=yTY`&Pymi*}SLwYkj28BI!LE)6}C|KDLeNh9EDlxeT{@rB~} zaAJ`rSBOO6ga)&ol0b&YbZ&B{CRcKP{HVQw@E6x_R^8gTFJq&eOvs<0AA4l0fh*R^ zRs$^t3ee}&F}lXR{(bSSMz-g`Jgsf=ON*BD<#RoosOiikUNKZI@zPmcaAGN41S*A| z{PIxpuVS4yjbkmWWq)8}2#54Ox>=|c8yH8DAvNh3-k!RW*I|)$|KGds=7N`^UHwp>o8|ZWAkNiZW>zw(S zjM&?K`=DB$(wxpe?L44bDX0yHGC4N68O~s|7ZGgwezU661~0z(e8x+iaMuQZBgMM? zn<~>oRj`BlEWu8M@1y=h`Syj-CNYRdDwkMYnL_~dfTiWZ0BQ#676;*n)$4Z#Xf0ZC zk%ce;ONmUs=9Y`_!{_vet{yHmlDF%ktzS&2*rwhO*><=fp2PaT=J>HPIW)PnIOloC z$-P5ia&RyX9|x&dSJm-TQ}6PXH59ozeIXY9GY1T^nwiQ&1Q`gC-qYh8YcaRFGZl-T zv?Cmv@(?3=2*($~Y@@0&W$f6BIs}b1IaG=bo5^k?iQk7+vqlh{)vgkiD4%y`JoIA} z_`q((9u-pDn;GJGJ!H<)%9bX7dp5Sg3|SeZNqg8W;Kko@9DfZeV3ZrT7|#R?S{~10WeaW4&Rx)jODLWap~-7VeVohVeU$o_L4ml zIRjy)YG);p>RbdO4<_tdjqu=_uc>vBD07u4+ojGQ-2y&=!oN2A^g$FO&N+^-AJ?>% zw$a_R+1>Q*Yv?l@U6b)1droUuz@NsNc8)wSbjx6#BwB9SqRA%f;%KAe!Cs_@g+Ov@ zMn@}iebC>x!OogZNlEaLulzr+2uX`Y?=yNI^mAMs6#F)>`XwftZekaxTm2zteugh- z^@Fe1-S^;wpi#+g(R{Oxqk?i?jNS?9p}m{bG|^4&==>?O`$gnRbJdQ~Wq}{)OQ~OT z8`0fK(F#?CGo6se^DO&5A&s2YXUJx4K72mH=h*#Lg#UZRSW_oE=OkO3BwLdi_w!Nq zH;Ya48TSi`kMadiw~9>*VP@H%wz}iEBk})=L;-)Sty*;6qAeZPA1yQ49(*62-i);2=tg!=7L&n*&J|7}-T>k-xBD819|D18#2cGz=XmhE}mdVARu zdD!D6)|qXca~%1jt3!fXpnmhTgh9)4h`EmlORS@+WcTx-w-a)1bh)}dWok~1JOE(D z-Y!;O4hHrT;{kH?x+m@xtFB1^OgP{otEA8cy-_Q*S`pL z1@b&ok>;<=&Rx=*)q z^LuS~Auk6Hl(gL@+Yknu94me}nTm`)c}%h!PrUBqjl6kX{_Ru!o4l8_T92p2L9hKD z7F(Y;7nwOsx|Gzfgv=-{p7g1Cuh5FxtljOb_}W4BE|#|_>MMZiq3yrI`4~Y_jmI}7 zgK=2jOBnaq$Y1=LKMeY(k%A{AT1fNT`}lgGOn%vG9+><`YyXd|uCw!wOj8H9v?Su> zNA*CZ-+IWUMJf1)Y5k&cgL$Abri*LhP>Emji>WyOYF1g}uO%|6^$`~u85THixp+*I z6r^-7B8-%!vv_xkPMUa)>bg%D#|q6A7VE-ConHrrJ(}~vg+g!r(4x8DO)#}memrwU z?Js|Im?#)G3JbnqKJXq8URgN0ukUjIpV6QxF{V@C{brZ+NP?TgV@ZkP^ugGpur=lO zXT1*=eSuFv3&>rG**c3kGxPIZ?^<4om3c|Q##D5~^=@`}ab0T2`>2fb;5}vDp=W3b zipnw1estvd6CuqKjXzCG|HlO&>=Y2ltEjIgome+(sCjwblGABWHE1--H@BNh_K!HKCBb9(BysoQuJz} zFm#(SW-&t|c==l~Gv1f#+%q>eClew9l=#ax>@>aDj=XZ^o%^k`CU12434TdZ7;+bj z@7#Na%>{oE@9T7Sd-E#sD%Vh#IXOuE$L`h(Ed}n3s=@knAZ&lCXdiCr*{B-n$ zfs#Kb(`r%!smBWIRedHa14SHmU6gs6SBIYo1|HB;X=qXZ`1@bPL>)qbc~SO5P0v|r z<|F_=>K=avK3tJ5(v01-U;TJ&bwbPPi4;l@J9&D$M$k!&=v*xc** z%)?j`Cq6ZGl|nX16gn!Ogj#rpmZGTdu^az zFFFD=>A9qQllzG5m)uTE842~gUbVMyB+1=0Vb>8hgQ>YC-??(XjH4uK%S-66O`aCdhI9z3|ay9Egv z+}+*X{`1|n?h{YU%sQuccU5)mZV=$ED`4xbQ^|RLEs4u^e(6sG{cfhtfDD-B9^dqQ z8G05do}K>O+}kDTbeSP?oEX*iI8~ozQ1$#+mOa|Zm8ovEMcQFQ%bd~p($-cw2;F&c5sJ5}Gtch8{KX zxh{=JJvd?Cw^`+8=Jh^Key5t5(`ux(a241^kA&4~E}iu}XI?T47(Q?=ai3~p@Gg@b zVMT-vPvpJjLSU^ZfoszPb8TX~5)4n*M|#?usF5i8dK}4UFoQJtb;;hUI;eObEk4?X z0}hgxbAjgH{6*Gsx7C1;p4+vI17Y+-vy+L%bdcMN*Bnwmszkkc(dS$g_2Le-FKjYx zR>n!`6g_plts_o(1*L&^oJraJWAUPZ+J5)Pb-jFh_hj8n8sk~vs0Y1v{Xb8Q42@nU zl5Rvr!K=u6?o&;i?1ehVbm$c34u^dWkjJP0x>3*lXe<#`*wQK+Qke+Td!6*A%(y|ase4Mrc4$G_e@(y!tQgT*3BY~KQSGvujfjc*R z7#s*F`$}$IdBVtXCXOc=d|F-kFrW8*ve&!z2JZc@-<|s4PrB#Tq^{2pV5S#E;_Q7s zCR)!=?F)b!8_|r{baYZW+%QD~+8Q43B!?&Sd1RP0UtgbBD#krMH7>1*C8K}FnQT6n zB9k_%)aAOb;|v6ax7xtn2!(ru!Yi@Y`baJg?uPa*x zY=8=z@~})+SD(u0Z@KI}CK+ZRKV6A0ZS--bw=wI`Hrd1&a@OF;JujzHQ=|bh!1sBuBKJ}60@~rFkjP=M0u$gwzf}qBvth*Dpy-fh&wC2AVnAdLeaoc=I>~DQ}_9cKr zlR1;`@~XK8g^OE_i%?K-jeWW6v*mAQ4R2HaPPzx_G6 z$EQJiLj`+;gS+NlRypfwIjV_Rb*%5nRZ4OJxX1zQ-l48#3N=IlvJ#1udP>Moi?6ke1dkuvfB^x>j`pL%nwrwE9WpiD++iUVq)?iU5MTbO z-!8(a7{MQg`p*jwD8 z;Y0IPF#Ewqw2ATzQ5($pcSSE|=eD$50RRAG?vX?J@pC3kRA+rnc0y#sf9g?)T?h6C zrz(ykk~(w~E+1!38LVuuouk#&++oWN8PjW8P;}^$swUt9j}HR#^Fr8Wb z?dII&6>rg|VcyxOYZM8r_$RwSc!x;bt~%~5(Hc)<>^fO=nuFnniSie0-=|ed>S*{b z>grlMjJ|P?pWA_rvEdRbfH`2^_dlPf{E((fh)^nOHMZjM$SHWAza#&QwM7@I26(3@ zE2!Gn<~ht~5-%Fn5rR&cP7Vu;DD43MPXV~PE$HWDsmBf;3=6$0lx$I19{iuDoM{!L zzISFaLh)<@%WY4KQ4(H3L^8rZCs?YRNm_I<9juF0CxcCzxpCU-@=FghXtdfiKR0L8 zaNyyP)1AuliFSUuX62UtFC z|CR&%0EJanv!hc{tB*8J20jKXq(?jTW&34WROjEYc3$6Naq|gVaNOeVcAXU{Q0_~= zZx?W8qB{f#UW6u?Lz0>W%TSA+Btbax^R7dc{Ygsr*~WmEo)`l-qpI2RTuq&85hq1B z)mLp!J+1HS-KRKNU6|)pu1Ci|1oPOR-)lDGWmy=54sfzt5bJj=djI6d%}`-O^!=;X zCQ?^NLqw!P%ayD(-mgywPF%ohu=!rvmq|@c~w(H1li^Ve@f`wyfR9h zNx~#Ag6(#Y+uVZq@!r%ve4|}SwD)~`>%md030juBhUazxz><&2VDA$oSGDv zZVHT)?A&C#%Q(nj&9NSGU%syIVRh-~T9@wp$W)fC>NouP2!##WiYy_L=y-tK5^>aY zu143cYsAf7Z+@p8tk=mX|0!o-B|OBf5=(w-?{=ZYEm zi$l|x4J|zeezm#ISh^17`zbFmMqgXhvdeH@HTOa0syLnbe3tX3r6*jVHpiI0i`e!x z{ouh6JtsG%(*8~rPzN}L;_I#vwW^mCU(JSEm@ z(m;}37wHn^mUBK5B6+(Wm9c{)tNq+ss9}1$ZmC)At(R-=W)}YVh<{fZH&r`ct_lxF zCc?Y6I-By}f$wa*U21%FSUyPU4&N){8n?{xYu*G{OT>w_RGtP6Id2o>Bd_nS&zzdH zrS&&Mb11p+kx?^_I=_2cIm&3cfZItO@FH=##KDXy0fbmaEqRszGp%nbxJ~mk8dm_c zCC^qi%D_%#xd^&Y)&SN1aAmo92FE`kir&Q$p{0K{LUA2rP>+P&csP)!#Y8;$F?DX& zx4PL0XQNj^pT=;p_GkVy`&e+aU|2G{r(-NwB=+7BRka#m()d&Md%W0HOkA+g9wCAY zV^1OA1FQ)wzd*R1MIr4wDL_4#gSP>KK)+Qf0A`9~%QJ2=?W!32!TOQshZROG0T!`-mq9(y;? zoLvD;#I{XcP1xlXTjl6zlzK%L845i>UXz!1%z`_RdD$B5NU20#ZJu7&79K9ZO15xT z#j-A^T#*XuC^kdd;4kX~#b;Q<>E^5;gc&)!3_+PaMn#aRQISVTK!tn-G9->MEV*7# zU1o9U26~LhNp*qEMq{MHZ-Gm1cF)OUghOcXtYfPeZr;(l{94eD0qNu&8mHsuu@>%y zVH^YZf%Ad#)Ed};Z1x&oTGXxd?F6-%`m+q+&jbWYckAz}CbzxBitZiN!v888K=u&h z)xK92-E==@#j|XBQGJW7n|$CWF*qxBSBw=wv$855T1n}e(^+lxBL?r>jM8Z-#{qco zl_1YCGYn`9M?m0nDWm|?+k)Fj(wS>;CjwPSAsJUW%8NPP@FxI+Q_0Zc)&8hN07Y7x zBa@XkSzK0?Ylm$*Tpdhdjwth8u{#Yk2NF6EnTp=f>lO`hv{;POq{Ddn1%PB#+69)z4YEja4Z6emVqG7d1P9CoTu9r%_j+lAP<%Vdp`m6%72wQ* zU%%}rX|5K0H<8+s?%iy#|1Cco9hGc^>vNrC|EI?P_D^HC|NIT{+D+b=Wg!wsgC#dK zGMQu9+?8h=fI-EsHL@&v+p59@3*!$d@TAjH^#O22fxy3iU}!#FNVM9TR3o%Gb~$fo z6hod;i0Rdc_bU^J21SP6u3pul=z+(X(9wRE=3hBMMTYt(@~aRx>Cv5YZg`rz0Q$I5 zN7B*r?5~iEa`Jjh7coQHgt)vbW_nCmb=*rmRL&F*PSzrM?&@mLaPG$G$KVz?%D&mL zSiVnI`s$q4KEe{}=_sdN)GJuPg-+2|X5y7q4!(EGk1UNsl}Ro4#`$T9e#gmt{np>v z?Td_KJO2{U{+R3(ik6gO7N^d8sPqMS+C81;<`h6)v-qCG@{Yx}b8}Ju6X6Bxg^T$a zgHzMUDR66II+spj$MHr`dD4Ewp_9cHD*eUoF9&BDST z+OwVY*8IeP8vl!lJ1$U6++P>Dh(EjJ09a-r5~;bW#*$@J>g@~oDw^{H*h^Iagl#O6 zW3CEijc458yIDHS=Obpt#*Niv>^Q{6Mz)~#2acAnz`#AiTL_a8LW$UU<9<*>TBoH}vFk%ou0ET3M}e;i z!-mVcJ5GFzc`-1I6bPVy^UDDp{sLW;@4CV+cv`7>7x19U@6*8_U{cc6+I$s^V}|T} zn?+`*&b~lZ-h|Nii5f^JN8rLoqQKm%130EDO(d#MnA{5&1K~&`<{Nd(qF#|!wu76~ zKqG5MNjg2gSZ*mLB2^;8<9&g^yBIdkU{CYaDpNcU8>KP@VI-z1<@pG z|AjZfg>JCmGO_K~J_F9JAeu&ruc9Ue;^I0IG%um>2`1AoM4E@myuLilgNd9#paegV zIMwT`TBXp(7l+Xk3bTu)NYYv1gXE_v;ByQO#bFn|b!(yzjL=H36aXn6C4-! zV|)p2)_9{Ua?j7aVRz(l%QEemrJuOBoFXJ&Bp73$SmC$yQqZ}Iu;`QmH?cb^y$zNsZ{q|0mdtbh%pbUa~g{gaF%q)6&Ssw@4XIz*l1 zAy@bd-Epd2fZ*p84jTvf0lIsL5$@c=pMSIJ!a0x(ly?x|qiH&3A-u9~9y=RLsq$=O zAgl(Q2vp?Nx^71qtp}YD%2IZnLL%ESvKG<7u^qm~#Wp~Jp{ktm6j zv_Q#lOVxM>UR^LtMJ5f(w0ek-c$m)S1x zW!7Exl7giAj@!W9E?vR1Lq>P8&?(7@6|CZ}{)7N(U?FxRDWuUV_j=)~#oW%fT#myj zSB~Tzwgmdgmv&rV;thDdK#-JYO`;7QGExbBJ?hA1I${!w2YDZ*k|gWF)cOsyUbAP> z>g1izkjpF1F!o{+?clkzTSDS|pCckX6b9lzZ!_3zt&%F!^gR^FNkhs;wke*6k9V)0 z0p!@X#;sGb4I|=Nnqh={F~DQ{kjlOT(o;X?Nfg+CJA6yA`YTV;WnxBM5D82u?h^rS zsUG`PC+a=7-~XD{3$|Z>=uJKkaX@vpn7V?}98t)Pkova@Ai?k~pyQ&E7Ir4PKgZ<^ zU{;`&QF#QQYjwE47Rw2?X!fQp09JC~RSJ8C+a|5IM%LyEFBcDKm-?H$se*_Awkaen z!Zaqf_H{5_hAvUsyU{**M+EW;IzZyWlmu@=iD8LVPS2^&N$}xN*Wr?gN4>KqZHAS0RP1$lB~IyAqf3=!i$u-Ys@pX&)P@FO)b1kznEIBsTQGQK`I``b5AuhFRk3=8J;3Eo+Z>l?KFB$4q>HPfMuU?}T z%EcG120&?wkTEi4$1nVbt3oNaZW6=+j!c~H1i=vU$-|o^2IPo*6=j>isaP37i+WbA7 zLMR1>{k4p&h{22cDstsxrkq!Thq@F}f|4^SX*DIqC&BUOzihOd--Z^enPLO z+P2)pE!TTo&4d%H%$=@7bfxgj8CXb*+v?3Ta%o;vAIH3+Z;Po^-&;#~P5Hs!V8Is{ z94wVJL5IztlaSwm1{6F?K!L{$62^&co!Z5K_n5Lm$?u5BUH6LUZt?Jw($0-A6XZXP-X)2g7-kTF?DcMo<%LJ`^O)m$ zI6uD$yVS_oQBjYMsh9S7_AouHi!aWmwJy!~UahP>+5%xtfU0Kc4~@CrEH* zW+t|f(yF9;p=uGJk_2XW>SZy%b|D-#kv#aE6ME1GPG8@2Du8=HWC0T& zqDh|TvS(#Ut4Pxf8sUlTnx4ir{k;2|8B$$#m#!Uib;U4`S5g`r8tr4+@&3s3C8$u& zK^wc-3s2$Y;G>h$71d(GXb>UZgsc>Jm6wdGHM>RDA}zIP;m};vfxwA{!MEf zB6OoZ^5A3nEU0=z3C6?r6%ZC3G5Q!&iT^>3HH?!V5$4^Rrg_*3#mV-pd(OI%I&5M! zmAJ*Cpb~StnSnK9r2k!1hR@PAC=LOZ18B#Agy#fBXo|*t@Y|&3oC5Dec(SiEd&X#o zJVe6$Vs%$+uS>r$WuJ&c`o8Z1@v47*kCg-+VZ7vT8DSh= zV1kG5LznW>&P(j&LIZ%{>t9E~v|6d6t|{U?KkNg7M?QkT&hb;BBi^V18_jgw!*#t(w{D&OLG5>pV_RF>+x2s5^?{xg>j49s zl$pY4`j0p*RJFL;@l%5Ss6a{1jsBkEz#E6BUEniS=ZLr3Op=#+pn~!tZE0U*whBA0 zqDqvG6rbR}*rkXA+WN|4$ISIMs&_O)m`ellDQr}xdIl)A_rt}eFju+heVTskOR;-y zxQI|KmaYLmyIDtDgT+=I&Er<1>Y;KGKs~b!D>TRZ*%q;OJmYlaQX?nUS^fIP9#y(Qpo#%iD0qO*nhw2v5Re^RvS#q+OE9H|+0`6-?#pA%Mte_#Oig1Y zhq}ZV({ylPM)#4T^e1!XW2ADIAbPK5VM9afAd+1SU=>>I_cgU|%M! ze|>vlbG{sc_ejaVO+Rem)A$5eWG!#j$sdB#UTpC>QfcH=|2msxp`lAqbZhFfrW_SZ zwJSku#Qh5j^pNoA|4<>-0k(A}k02le?ph=D7Y;IoUeX7xmxQ77G6~QT`X2qya8xC8 zOA;Ft4I(yj%zfT~J%Y98K$idNs}BhO>T+9~$C7`=M2P{#Vsq>3vOt}z{6Sfp6r-82W##XUk^pHYitV7^Uj zyAcDguT(tQ-pHXgfb@#XJS9Zt!yZ?iIxCP#U?fI2Ws@Is zR2&$D!oQz8pun|lq(o}4lVobzh(n2)J>fOMsE;QlhQDzMCY1?sLSXoL11H(+Z6IRK zxk#GE(hF2VhA3D#Y}A+^MKq-1`4y&pX*<6P4T>HQ_>iR+>1A4PV?Dm*qk>O4e=BOZ zdqmwRv|F7cAe%M_bL4iq$%I>TJdCd?$!xXK;a%a8q>9a@Ttw^(MH! zvF!*y1+1NEJeqxKNqU>v!tU0r!!7Yxp?HX`)pMN zHq3F2V4zWOTF@d0IlkBzGaPWWuokop8Lfna3wKl2VgBuZl=Odvp*iX&^Bnw+Smsj4 zvp_>FKU`52IkV@FUKiIU<64}V@MTS&C3Yux(O`>UICI0f8%65Q35Fv|601tH6ybz^ zu$(?pXQrV&lazr!R;9T$z*mqSocro1$@?fww3eD(<2@Kd0f-OsJ7GoR?J%(qHZrA9 zGd^q~X;nbhdRnu{IV@$6WF!+i&Cn)82rWdqSeg$9k%uiBKyPPKb@ny2*6fCSw^OSKU!a8mDDX16)3s zsb;SpVO(6wGBKZjSx7_!4q0u?G0fe#$dB7d(mPDEQ*_ROYzzhhR(4EWSlzgqj;VUb zL-fX83YKsNT=QR&B+X;Xg12J!780gwI`zJt>x@j)+v^o60=E+IUH+BTN3TNJa)0M%e&o zV7q`qsh%I7Agfo5?%)tBk-ptTlY|`)$=OTyi27?Xxg(lv9qSFFEKZvuUHg=AT0^tr zUnquuK$0+(DT1FJtD};JGz}&CA>uDA4E#X4y@!%Mu`xMvXOiem#}J$%L&HhPqAi|COf)LAvs&9KA{svO((9;S zECF?Y?)FfDwkqXIk~KP)5KCaIZgtt(YzH|<&pHX8d+%|!yhUCJxYA0{?H!?N1aJFA zLBEw5>%V#hlc>^3>~#Ms4()n{ap>by_(^s7_mm1kSeWdUQ6kLf2%@Sc`WgG^-#2)U zjOaHy`xWv!XpmvhjE0~Ln@V+n%$N-?{gkc+OSbuaI_ z-0!gleT;*W0QPCSTCIhtMw8B)(_cZEC|~~-b~%Hwa%F{<30pLoyN)zs(5aV7!W#l_ z1NQu)YY=H8x@FSowi-Cgr7F#g1YZZr>ihBY!=2`oNJ?<6%T&%>I6OxVbPWikX#dRq z{u&afSMH9$oe7=xOD^iaw6Hj1>YuJl)lQ6;tBnWqaNXYEp{0I)Ond`4=C?_C^RWIYDeH^v|JZAplDzXi3)(ns5gzc@16ZMw$n1m=;( zYpL}vwZ;%^crvf(+R#x&>}nx)^q2^iDM>=()y&B2PGQx0=kEGeYq8JrJd=1hy!xy* zCk3HqEU(Va9k!_<1!&y!D`TzXfk;%N^M zKZawhg)y45P!GZI%1|?5i4E|2nBr#Slwg-Envfbg(O0En>Hb&d3&4Tm zZf(K1F3BxEMbuIiz?}TwDGIFi5TKhBBEAvZbk+$6e*N*YiqkA+k1FY#ubn(*A4rjB zK+&iAXdg9eqGB8lE(0@wswY9qw+BIuUaSN&VguI+*1D(Jw!Sa18)5XjJIdn4Ev#-e%R;Tw7-v};!X%eGY z(v63!g=Lnlo#GjOeWSOumirBqSbc`)&cND*dnN z;LHyLPfv0H)`C*aI-1t9puV1UXBeMgKv6U#^q zH~NJ|7CiLAdtwv4^>p=ZrQ|3~at07!vYL&$YxrSZbGu~f#GofD;pfdq>;bn=yU+#K zaQznV!r@Mp!TM>1odquSon9cbPH!D6P8&8-l}n-q1HIMnUreIO0XYmxElj9e|79M# z9F_FVr_Lnz4!dFH+hT zfxM`l$caUn?YA_45P=A|fg$iAt^N){^v3;*6vT-;PaYvdOkj@z$s@dZG;2jZ*r z+Dp-^rS}aXO(MMQ>X4@ec7t+w}WLX^z`A5Z)GiiT?H%N=k_RT>l!J!zmUL&l53oZ!tb z!v?d(o@MIiLUn9eF#t5VX~w^kIc=n;j1Ag*jz%^nQD7hq{863aOPUj?(@qVnJ{$wb zAsPmoWw|vYif3GTZ`2T zcLrkTC8|^^fdaJ@!i=6rCkTo|i^D=t7~1dpQ@Us8VY&H*w>OhVJV{Lt<%=84O6t+b zz|iXhAwA-lzx3Am<@!z5od7N%Dxr3lu~~25wMKv%5e}=YV8G?5r(o_ErC86<`(n?l z55D+O)(Z$`Cgg*@JxgK*M$2?1{AE zfOhg6i50ChZ;t*pu{pjC71}ZPaKiCrMub-sA@l8JgC+`(QfH&j20~DcDIW0Cphm-S z{)WX&F*Nw(y$L198Y{sZW}uZ=Or(rjw>fufUL0t)J6jeBaG>2{;3a3kcRN3RG~=r> zI4y()E>fvoABE$r#WGUEP0()ZZ$1tmVrv(3>1YyUvPkrQ7wJLhl{55`K?A*j^!O&4 zlSaAhy^w@ImOI99FO&XyT4)Fp-RBKwA8jOt5`hTMLJCDZu~6tj{;4DmA6G@)>`WGT zOtgDS;LJi-dz|wdxWO%lc6lHrtYpwO5u0jD0S^fM{S}7D_{?VWhUbd zMim55cPetkzCJBeQN+a36vWQ(f{5{j$G_&1X$Mn_@%f9bcwU~j33zrN>^q6Be|_T# z1f(A-Hxef+jY4F@g`!AEK`amalO4b=4YSUeKs=?zqCXcY^a}k`-MO0_v(P$P6FNL; zsiB4haJB*c*rN;E-|A*w?U|^s4o8+X;pO{A+T5uuH@PgvtK7(hgkoywy{w4HL_~cF zCI!5wiBrZ7v=Yzh8%X{=nG+I%%wi#r^wL3T_!ph}Jzm_vk=#;>TF@Fd<%CB&Y6A!M zg`hF7cA_80oIt*;5cp{DDSH%K8C`aRc_}T7z$Nbl5EzmJ~bHKr!frA&6;$G!1v9A)Q+o9o8VJvq~**ZsWp+_x*Vpl2Z??8Suvdj+Btwe z)LX~-g+Ja#hLC6iBHDIyjXp%2iPc;kJz8H;rsh-SvZ)Fkw4GiN;D%eOb-ZgWAnn8o z9&z@Xrg}p!HP&#)I62+%IDi^nxtFY^Fow+|y=?e`0EGb@SQG#zWTZ5(@@D0uN|E*& zy`L-t@@q!ASQINz)SaHeU3LFzB?}YOaEZT&F&d%Ik)|@hnS=HA4JZ)IvI0cG@Hk(A zQdN5oAq+)>)THJVij#{H@S%R?uj*%&Lqw+WRW`1Xcp685IevTSH=@9T$Hn+ycFaW@ zC_HWLXaFPmC{*oITW{!xj1OD}@Ojpxe2f^Ib560Y8Mj9y-;G zHpe6bJLk^OHl*gTh=-2zb6(kF&l9c1wt}Xqo^$EvH}RhlQh=3rsqT>1R|FUF$GKwwsaEb(cx+6yqYX z>7pqD2SXT;$EyEFK=-71c0Z$l+oR~;6BiRAV(DG?&v!wmHt<0n_p_4;|2j{Yf#m8Jr-%Xpxyx&gm;E*uuZ(!QdIch+T(aM6nZ_#BHK zznJdNfK0oY_2n;YJ!&#lBe(2w(d_{nXW+*2sE8G-y9(Y7A`vQCLKS$C9))KydLXl? z$yJ!d8Q0s`%&{PtziQ2uImB%#R@zH9F4L$iRCkHJVr8ceMLAt(l2(9}|z6Ne{t0a(FN!{WJCfzwoB2;3A#Q~VoVBV!d`^&@1f<$uIEMx%ezvlm)C^k+j-+?IyO=BX? zcm5baK#aQ=xD8S2D3=us=6>{Ctt}HHm5_}n`i7}YH(|H9;Rj@eFkQs7*8K1Iczv&O z13{IR|D2)p94B}j4}BFyqe9p=2g#)*IkXy_uqSBV?|UY#}CXy91Bz|c5sIXF&H^h}STtai1K0R0164Y`-h2S&`qJwYbUn)VSP$jh`U|0vBIl`(l$1DyEC7Dng>&?o}B`qrk-# zNpD~yDXdlt{L9idmE44eH$=d0=v~1{3zWL4tgSs<#muclY!(0^cRktZ@zNBk5s(P z9=rWsVt#z=Wpk!I4-!olzpjc1M_B*|G0PMXh;T2Y$ikd)OWI0YR7HB z@zw{3;%1Pl>{gxFzm0y)B?2Z(e0|6_ZGNENh#E>t1k;-y;Z+?_k}L8BC(Hdtv)@C8 zDn$bg@oKIM4_Ag9+f^n{I|qbOhuG<{(|oS5g54Jw;hJ;97?+&6Er#uryQ-n#5))Hg zM&;-i3ULBK7!DC0_WKwrCeDIZF%dP5j&FHi-b+>LYaR$Xe0J&P&JQ9W)n z%h4mlur_|09SD3;-!-E+TZp~iHWRNfE7(}Qm98;fLM18rl)XTRC8u00IQ!!bR#5gH z9{QjTtDFudlmp|Si_Se(EtS|tMd1;MhGrcv__%^leoFP`jUpcB_87P;j6Am}aQo&L zkF%RXF`V^0$eKi=`z);riplmb>&3+J+BsHI`qe;tbaQ<7g_)X-VkGal3-Xp%O(xw#!V;Pk#= z=JMd?wd2w`8blT)$(fab!$W(zsFfm`YGH4{=NZp`f2b1pw11fkE+rH4pAf!YMQ_uPc?rmk=d0_NX`}#mkD3z7#B? z`br~7S*~}5zWV@TcRKSBG$pS>3(XP;I>1NRd?^U6J#BWg4A*KSu!dRuLF%A`qwb)gK|c=D!G-GR-yo6lOu;MtGX^b!cjcHt|RT^yMX^QQ~5 z0}jOu7TE_|kv-jy(v&-B8DbBsB3M}1d@2}My3mv!;Jlp`!13*AJ#~Ef*O~nDJv^*- zO_gl9kx}qUsSX|xuxflS&!3*NCG;>H+~!rH6xgfs+hy`Gu6q0O>M~SbBlE3KgaV4L#%eogAYu9ISUdQ+q>yhNrAFMuKHEr33j(P_zCZ>pn zX>uD0Sehrz=5UGIb6ZSed_0s1c$;`^mzJ7ZNaBAiL##6EcorgWk7!NTU#2gIMBs{X z(i=MPhQ@Dr;piOlmxKdCZE5`^4kF2e!rn-o^4Ze5rXI$HyN4A=VXB$cL!#a4)Akfe zzCTKQp>nB`+5&@W(FHOhwH52N>7YQWzo&%W+{^VklESwHWHg2Wc?XATt)&Nd=g>2b8C-kX;oRGPSkdnq*6#Iu z^)raz$46Vu<*`e%2W*Pb&Q^kvEii7DQ86`H zqOWCOFkmcuy3qW9_%iMKXlz&1R@&C7oNCS|oTrpAbR7r>q&9KAKR^SwTkUIpWn}+q zgFR>$gB>^QTAOY{UR~HsCeHBZy2Y;RZA6OOwr9#I7LDx5{rgT16R>UXwZqRPyum^G z?xBcikUw8=YDdf8F>hw}S})SWsmtGW3ft!-`f*1Q#deT;3avJ>H3CS4WFf)0xj)A$ z+3Kg!Yqm05*5maydOyB?eJai@{qpU$=Y6*!g0l;1jC&&na06eb*Sw_)TilFCoWg)w zHhlO%G^h`UJwFEIFNLRYwr+}T{4R%6*rtF7u<^Q`%eVi&9=lf2sgS-HCcAm3?sG8K z!|-}mpm>&dv43^6x5QbO8vm$RjTw&;qq&EbQ;8dPJg~+PX(xbn*|4l~*;<(mwuKr% z115O&xgv0TRC>}7?|)%B1(}FC5=NR?Nlr>jZ%C)o_|&dep=Ge9Fu2m)>Y7l{-6)Z# z!VtAYuOX_WBr1WOqK=^r4ksHB^7E&!;x}`4Y4b7Lp2v8B9)U;mK4M)yd+!^eL*lUU zY=NZAwkcn~smE6zlC8TQe%hVe=eSnAoJd6x*D-yHuwvWIT-S$HgTi1J+vT)$MOEia zZa>4Z2c?qj-bV4N2Uqr*M6zHQ%h<;N?g-s>$HF3N%jNVp@UdtCAu39@joRm*4_fT$ zpeYe=p5wB}H=}2ob}$VWZR)1x4$gz7${WG&HTis8S^UN`)S!Dn2y|VhO zEoq%bcN<1YL+~(m6$c~4>qF%B)wFSb0mZY24Y#TV3wNt*Jb_TeAIJu7$Lj9BA*o#R zgnvA#gR(rT`ZmXoVJ&`i)^#g<$@->RXoG_i)3$bpgDI<8A1B=3b-QF=b2xR+jKA~< zhXc!oMKAA>))#L<-AmbHAy&~#b*e=EjFAz)j=mj?<0~pV5(&5+OHoi@hO#)vrG22I zaff^{{3z=jjmnA3{hgpE#M7;=#@#VZ?eG6-+0r3^GSC3>4&3k6@BKy!jf<=Yvj#bS z>L+wHwL5;9v+8l+K4tetNiJ9kc64I>55lx(za6EUjB)%=yoI7TtP!g3sep=;q9!UD zvH8!jZ_VvZ6MyY->`B?k6vl|ncp^Fr?opZ};K-g<1-u(gj-X~K!ipR$AJP5ZX7>sC zG{$3Wq#7LhVj1-evr5)CE@sXOObJw7)F6TQNOL^$V72+TxJF-*DGgtr=j7qxTM!%K z!Qs1;&!?$Z!z83*i+nSsfq`wF-?<|Qgh9sQVjRCkxLdfca}%Fmeb%jf)qmg7SXSWR z?tv8aozCLA;7*M&*=XQb1KAi!XyL4Vkp(w@%7hGMAFNjnVRs=bPug+scZ*hp*qw zq?(N^lj0RL^~6`w#x;7{N~3j{SEOngEOq(01>FuN&$F?S-MnWGE9)NxdDF#Jyw;~x zh$I>PZ=SR7JQEon^z7_!@bSYqA1y79S{I+oF+SPNWm9_8qjmNi)88Bf+3 zPjw1Z$G)BKe$Jzl*nbaJlFTpv266*U!HagIf*H>qLa2c&g1)v3G|O?9yO@Me)G6D6 zU+2soKSS5rtu^+r32|++tHI?$G==g8lvhW6K~i%3VnE9FzoL}l^0j5PH0Yot5L`gq)#!J{YU7p?o& zc7N$VJ=n*7rmHJUcLgTQ3iPfyZZgPqzNvgXjVtn{7?jQ5^B1gNEPyvx+UR@Vo9SnH z6(Xf?d};b!3!OR97X)LTM_bO?o>!N`MgfyJSA#-a6TdU#H5At!@~&;cHPqR@5VToy zGIsaEecVrx*IZFHHAb4?`8&W$Rm!SsoLyBA2Qdl;8OM5{>r2(?hyt3GUZ#I@n4<}^ zDA}C#frE?X`v?eIR$$CPJv<+tT+=7-O9 zs6R~v?2hgpb<2eMjm<1IE7$W6*)%%-PKO~dVFu43M6GBZOrN%{?R@8b*KBOtnr(XB zLZvt_pq>k?=JieXb^5Ni~GbsZ~#M)$UBar+pKM za*&c>R;6I#V0wKfoM5pQQPwsE8k9J4-3VMIp2?l#Q}T)#rBacfqw*=>0Jsm<-y zaD6kyn=Ov(pWPlXRSANI=+kJz7J$1p2lih`P9SNUM&Vy=6ID(vGe&?X%o+OBU5D>UK6qdO zZ-XoFg3gYNX?f2=o<~d_#%1b>Lodj)Jd?$*~;&8Hp)9u9Ybt$kG!Si&_U|waf)sj`Bnq# zmx>_jSC&=kSJBo>-y_o7MGI2FldbSuh3?FAeRqtnyx!l;<`3WAx=9|Mo{1)rW8Z~*C7B>ksYub;ofAas z>iG+ibUVlZN%b%xk+4RZV<+5~$PDU10A$9kevv7enfxYaseN&`XD#69Fpb^nV$7D@m4K;hhRz%vsZ z6*1z+Z%kUa58XH~h#IJqK=YD@fn683f2vEICF`359QsP3_?X_;_5uEU(=$jK;Mwc6 z?WEk)iOU?rw@>-^9-YF)a`=)mPJ+wBGMvh_A-1q-UVmn8Bo~%;2d&Ck&(~xATsQ7ZIWeJFgNi3qRBjM`XUZ{E~ zMas)#4-sOTEpoPQ^y^C#ucTu%hy70AD7$uB&-eqCSTAztaMD(TH(44HySwv3^LKQZ zJ8q;eUIz)FwL>;Z3@;bgS!|pXl5Z|v(?MD~gp9g%Dc*iR5W}LxxN0fL$$fICF5O9l zH7b2uqGV2JX)Ccn)JcB>@vo3U1c5k#P^I#p!OCgrX%H%C;@e)gOeVHKmAJhc;v2nJ|5SN>XAu{XflJecK}4dn_P85WJYx4aYZf! zK!shJG0&H4T}ylS?OQ0s_q6#YY>k@rl9R3-u`%|)D(-1*g(cJ~N?HTcYwQrm`7Q(G z{|j^mi}`-N{|vX?`!arifc{B+$koX?%B#-f_Xh|IGhuD9vt>sP(K_Nn2tiGqmAOBf z#G3arXlS%?;#4_TT{(=s8S1%E6ouPwz6z()LqnrYHM$5MLr)ZF`p9mG3`37_Cn0)t zR0Ju>@gye3ar8u);W_>C@^DV)jwrbPy3u4FEMUa2RBi~8D`gdp9w4&G(#Dn@UHyqK zB&c2Z^t-(G(E-h&20#I?P`^Ka6M|!a2pXrxJ@WY5ru*hizdkuNG4kzq_nc~L>u3jT zfk2=)sP*DI;bLTppe{#dp|a59QSa14P`hA!0LOAmOZ0=RZn%CNKA)dYx2vr4W52jj z%S2?|Nv|aXwbiJ}qRz$boS_8*f`MtFZUU1@(KK^<7iEb{();oE^XE<=Ukl+956HOxG^ZD7AnUBNaHaJorJyFUnH%-bnx>PukF~<*49yqdeiLPs91vE=I6LC3OZNa{r`08iApGE~}k^ zY5mAKUW%>N!HU0r0jPD&#Y;Cccg`e3Cx^wV`U1|JJ`TIXjoBRK8Z{!#{^&zD^h-^N z54(Eua3aFhKi%|eLQJ@1(z|mb((B~zzh?&PKitoZ>qa|;5L<u)>!F!k2qb($?0s(f`-aZNTgG^X8hpf$Ca|Y49aUzcZOkFNJkd;dXYg zNlA|Hl6lIzL1$mXC!cwbhDIA7ZOJmYDvunIhCmc8{okMNEiJCgxMuW_FO{JWx`hx5 z=RY?8&!ck&?f5)*wh)23DHDedyL|K|kL4HE47&EJ%PL(?ckH1fMg37F7Q2&^`(_PH z?e}Du$&?7f0!qfzDVJs3Id@9yho5F=tlf|)so?P3Q2=u)pI#?F@|OULa;(dFyZ~Ilk>J*gUi6|HgrgS2#r(Uc3v0zY zqEB43K#eKdmXaJVob~I)ft`Qs^4x379}sD&2?7us-(D!3_3MSRe!a-~YN;49cz{^+ z#I4%TR=#+@0EEe;h&Xdpmt%F>mIF$^e&)9pJTR+O9z$+_UUIKUh&PM4xM-2Jdr47L zRD?(W`tnn&M8mn&A|fK}g71^mFRp6RgduNyvvXER6ygsTt6b8HUi{nQyLD%OznC?1`k2{set5;0XJ6QKd*>&I4^1I2>m@dSc7z9i z^(FwR$?^W=0rBnsefRX7g2HO|`VSA>5*rg~-}BjXFHagjqz%C5^C=FeCoH~itPkK% zuWlQ+?By*F_w*qYMezzDb^(7uWiSEA`1}v4S5F>(ry|6B5W`T&LU73E^&fd;(Z=GB zKKi;Dby&_=MNw9!rzK7~ z!~Ja-h?-G73j7vTOZEV2t5jDH`d;*+7yt42|ClLu2NN(UCMI&|?oSuBOqn?1nh!oX xba#1WQ}m{7c~_K_lw8;fqZhsCMKAtA{2w|sT)MMLOG5wv002ovPDHLkV1lUJ@sa=l diff --git a/logos/logo.svg b/logos/logo.svg deleted file mode 100644 index 31a6c37..0000000 --- a/logos/logo.svg +++ /dev/null @@ -1,129 +0,0 @@ - - - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/package.sh b/package.sh deleted file mode 100755 index 8a7b5ce..0000000 --- a/package.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -SCOURVER="0.26" -cd .. -zip scour/tarballs/scour-$SCOURVER.zip scour/scour.py scour/yocto_css.py scour/svg_regex.py scour/svg_transform.py scour/LICENSE scour/NOTICE scour/README.txt scour/release-notes.html -cd scour -zip tarballs/scour-inkscape-extension-$SCOURVER.zip scour.inx scour.inkscape.py scour.py svg_regex.py svg_transform.py scour/yocto_css.py diff --git a/push.sh b/push.sh deleted file mode 100755 index 7f4e90c..0000000 --- a/push.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# Pushes updates from the trunk -bzr push bzr+ssh://codedread@bazaar.launchpad.net/~scouring/scour/trunk - -# Merge into our branch - diff --git a/python-modules-pre24/fixedpoint.py b/python-modules-pre24/fixedpoint.py deleted file mode 100644 index e83c846..0000000 --- a/python-modules-pre24/fixedpoint.py +++ /dev/null @@ -1,619 +0,0 @@ -#!/usr/bin/env python -""" -FixedPoint objects support decimal arithmetic with a fixed number of -digits (called the object's precision) after the decimal point. The -number of digits before the decimal point is variable & unbounded. - -The precision is user-settable on a per-object basis when a FixedPoint -is constructed, and may vary across FixedPoint objects. The precision -may also be changed after construction via FixedPoint.set_precision(p). -Note that if the precision of a FixedPoint is reduced via set_precision, -information may be lost to rounding. - ->>> x = FixedPoint("5.55") # precision defaults to 2 ->>> print x -5.55 ->>> x.set_precision(1) # round to one fraction digit ->>> print x -5.6 ->>> print FixedPoint("5.55", 1) # same thing setting to 1 in constructor -5.6 ->>> repr(x) # returns constructor string that reproduces object exactly -"FixedPoint('5.6', 1)" ->>> - -When FixedPoint objects of different precision are combined via + - * /, -the result is computed to the larger of the inputs' precisions, which also -becomes the precision of the resulting FixedPoint object. - ->>> print FixedPoint("3.42") + FixedPoint("100.005", 3) -103.425 ->>> - -When a FixedPoint is combined with other numeric types (ints, floats, -strings representing a number) via + - * /, then similarly the computation -is carried out using-- and the result inherits --the FixedPoint's -precision. - ->>> print FixedPoint(1) / 7 -0.14 ->>> print FixedPoint(1, 30) / 7 -0.142857142857142857142857142857 ->>> - -The string produced by str(x) (implictly invoked by "print") always -contains at least one digit before the decimal point, followed by a -decimal point, followed by exactly x.get_precision() digits. If x is -negative, str(x)[0] == "-". - -The FixedPoint constructor can be passed an int, long, string, float, -FixedPoint, or any object convertible to a float via float() or to a -long via long(). Passing a precision is optional; if specified, the -precision must be a non-negative int. There is no inherent limit on -the size of the precision, but if very very large you'll probably run -out of memory. - -Note that conversion of floats to FixedPoint can be surprising, and -should be avoided whenever possible. Conversion from string is exact -(up to final rounding to the requested precision), so is greatly -preferred. - ->>> print FixedPoint(1.1e30) -1099999999999999993725589651456.00 ->>> print FixedPoint("1.1e30") -1100000000000000000000000000000.00 ->>> - -The following Python operators and functions accept FixedPoints in the -expected ways: - - binary + - * / % divmod - with auto-coercion of other types to FixedPoint. - + - % divmod of FixedPoints are always exact. - * / of FixedPoints may lose information to rounding, in - which case the result is the infinitely precise answer - rounded to the result's precision. - divmod(x, y) returns (q, r) where q is a long equal to - floor(x/y) as if x/y were computed to infinite precision, - and r is a FixedPoint equal to x - q * y; no information - is lost. Note that q has the sign of y, and abs(r) < abs(y). - unary - - == != < > <= >= cmp - min max - float int long (int and long truncate) - abs - str repr - hash - use as dict keys - use as boolean (e.g. "if some_FixedPoint:" -- true iff not zero) - -Methods unique to FixedPoints: - .copy() return new FixedPoint with same value - .frac() long(x) + x.frac() == x - .get_precision() return the precision(p) of this FixedPoint object - .set_precision(p) set the precision of this FixedPoint object - -Provided as-is; use at your own risk; no warranty; no promises; enjoy! -""" - -# Released to the public domain 28-Mar-2001, -# by Tim Peters (tim.one@home.com). - - -# 28-Mar-01 ver 0.0,4 -# Use repr() instead of str() inside __str__, because str(long) changed -# since this was first written (used to produce trailing "L", doesn't -# now). -# -# 09-May-99 ver 0,0,3 -# Repaired __sub__(FixedPoint, string); was blowing up. -# Much more careful conversion of float (now best possible). -# Implemented exact % and divmod. -# -# 14-Oct-98 ver 0,0,2 -# Added int, long, frac. Beefed up docs. Removed DECIMAL_POINT -# and MINUS_SIGN globals to discourage bloating this class instead -# of writing formatting wrapper classes (or subclasses) -# -# 11-Oct-98 ver 0,0,1 -# posted to c.l.py - -__copyright__ = "Copyright (C) Python Software Foundation" -__author__ = "Tim Peters" -__version__ = 0, 1, 0 - -def bankersRounding(self, dividend, divisor, quotient, remainder): - """ - rounding via nearest-even - increment the quotient if - the remainder is more than half of the divisor - or the remainder is exactly half the divisor and the quotient is odd - """ - c = cmp(remainder << 1, divisor) - # c < 0 <-> remainder < divisor/2, etc - if c > 0 or (c == 0 and (quotient & 1) == 1): - quotient += 1 - return quotient - -def addHalfAndChop(self, dividend, divisor, quotient, remainder): - """ - the equivalent of 'add half and chop' - increment the quotient if - the remainder is greater than half of the divisor - or the remainder is exactly half the divisor and the quotient is >= 0 - """ - c = cmp(remainder << 1, divisor) - # c < 0 <-> remainder < divisor/2, etc - if c > 0 or (c == 0 and quotient >= 0): - quotient += 1 - return quotient - -# 2002-10-20 dougfort - fake classes for pre 2.2 compatibility -try: - object -except NameError: - class object: - pass - def property(x, y): - return None - -# The default value for the number of decimal digits carried after the -# decimal point. This only has effect at compile-time. -DEFAULT_PRECISION = 2 - -class FixedPoint(object): - """Basic FixedPoint object class, - The exact value is self.n / 10**self.p; - self.n is a long; self.p is an int - """ - __slots__ = ['n', 'p'] - def __init__(self, value=0, precision=DEFAULT_PRECISION): - self.n = self.p = 0 - self.set_precision(precision) - p = self.p - - if isinstance(value, type("42.3e5")): - n, exp = _string2exact(value) - # exact value is n*10**exp = n*10**(exp+p)/10**p - effective_exp = exp + p - if effective_exp > 0: - n = n * _tento(effective_exp) - elif effective_exp < 0: - n = self._roundquotient(n, _tento(-effective_exp)) - self.n = n - return - - if isinstance(value, type(42)) or isinstance(value, type(42L)): - self.n = long(value) * _tento(p) - return - - if isinstance(value, type(self)): - temp = value.copy() - temp.set_precision(p) - self.n, self.p = temp.n, temp.p - return - - if isinstance(value, type(42.0)): - # XXX ignoring infinities and NaNs and overflows for now - import math - f, e = math.frexp(abs(value)) - assert f == 0 or 0.5 <= f < 1.0 - # |value| = f * 2**e exactly - - # Suck up CHUNK bits at a time; 28 is enough so that we suck - # up all bits in 2 iterations for all known binary double- - # precision formats, and small enough to fit in an int. - CHUNK = 28 - top = 0L - # invariant: |value| = (top + f) * 2**e exactly - while f: - f = math.ldexp(f, CHUNK) - digit = int(f) - assert digit >> CHUNK == 0 - top = (top << CHUNK) | digit - f = f - digit - assert 0.0 <= f < 1.0 - e = e - CHUNK - - # now |value| = top * 2**e exactly - # want n such that n / 10**p = top * 2**e, or - # n = top * 10**p * 2**e - top = top * _tento(p) - if e >= 0: - n = top << e - else: - n = self._roundquotient(top, 1L << -e) - if value < 0: - n = -n - self.n = n - return - - if isinstance(value, type(42-42j)): - raise TypeError("can't convert complex to FixedPoint: " + - `value`) - - # can we coerce to a float? - yes = 1 - try: - asfloat = float(value) - except: - yes = 0 - if yes: - self.__init__(asfloat, p) - return - - # similarly for long - yes = 1 - try: - aslong = long(value) - except: - yes = 0 - if yes: - self.__init__(aslong, p) - return - - raise TypeError("can't convert to FixedPoint: " + `value`) - - def get_precision(self): - """Return the precision of this FixedPoint. - - The precision is the number of decimal digits carried after - the decimal point, and is an int >= 0. - """ - - return self.p - - def set_precision(self, precision=DEFAULT_PRECISION): - """Change the precision carried by this FixedPoint to p. - - precision must be an int >= 0, and defaults to - DEFAULT_PRECISION. - - If precision is less than this FixedPoint's current precision, - information may be lost to rounding. - """ - - try: - p = int(precision) - except: - raise TypeError("precision not convertable to int: " + - `precision`) - if p < 0: - raise ValueError("precision must be >= 0: " + `precision`) - - if p > self.p: - self.n = self.n * _tento(p - self.p) - elif p < self.p: - self.n = self._roundquotient(self.n, _tento(self.p - p)) - self.p = p - - precision = property(get_precision, set_precision) - - def __str__(self): - n, p = self.n, self.p - i, f = divmod(abs(n), _tento(p)) - if p: - frac = repr(f)[:-1] - frac = "0" * (p - len(frac)) + frac - else: - frac = "" - return "-"[:n<0] + \ - repr(i)[:-1] + \ - "." + frac - - def __repr__(self): - return "FixedPoint" + `(str(self), self.p)` - - def copy(self): - return _mkFP(self.n, self.p, type(self)) - - __copy__ = copy - - def __deepcopy__(self, memo): - return self.copy() - - def __cmp__(self, other): - xn, yn, p = _norm(self, other, FixedPoint=type(self)) - return cmp(xn, yn) - - def __hash__(self): - """ Caution! == values must have equal hashes, and a FixedPoint - is essentially a rational in unnormalized form. There's - really no choice here but to normalize it, so hash is - potentially expensive. - n, p = self.__reduce() - - Obscurity: if the value is an exact integer, p will be 0 now, - so the hash expression reduces to hash(n). So FixedPoints - that happen to be exact integers hash to the same things as - their int or long equivalents. This is Good. But if a - FixedPoint happens to have a value exactly representable as - a float, their hashes may differ. This is a teensy bit Bad. - """ - n, p = self.__reduce() - return hash(n) ^ hash(p) - - def __nonzero__(self): - """ Returns true if this FixedPoint is not equal to zero""" - return self.n != 0 - - def __neg__(self): - return _mkFP(-self.n, self.p, type(self)) - - def __abs__(self): - """ Returns new FixedPoint containing the absolute value of this FixedPoint""" - if self.n >= 0: - return self.copy() - else: - return -self - - def __add__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - # n1/10**p + n2/10**p = (n1+n2)/10**p - return _mkFP(n1 + n2, p, type(self)) - - __radd__ = __add__ - - def __sub__(self, other): - if not isinstance(other, type(self)): - other = type(self)(other, self.p) - return self.__add__(-other) - - def __rsub__(self, other): - return (-self) + other - - def __mul__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - # n1/10**p * n2/10**p = (n1*n2/10**p)/10**p - return _mkFP(self._roundquotient(n1 * n2, _tento(p)), p, type(self)) - - __rmul__ = __mul__ - - def __div__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - if n2 == 0: - raise ZeroDivisionError("FixedPoint division") - if n2 < 0: - n1, n2 = -n1, -n2 - # n1/10**p / (n2/10**p) = n1/n2 = (n1*10**p/n2)/10**p - return _mkFP(self._roundquotient(n1 * _tento(p), n2), p, type(self)) - - def __rdiv__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - return _mkFP(n2, p, FixedPoint=type(self)) / self - - def __divmod__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - if n2 == 0: - raise ZeroDivisionError("FixedPoint modulo") - # floor((n1/10**p)/(n2*10**p)) = floor(n1/n2) - q = n1 / n2 - # n1/10**p - q * n2/10**p = (n1 - q * n2)/10**p - return q, _mkFP(n1 - q * n2, p, type(self)) - - def __rdivmod__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - return divmod(_mkFP(n2, p), self) - - def __mod__(self, other): - return self.__divmod__(other)[1] - - def __rmod__(self, other): - n1, n2, p = _norm(self, other, FixedPoint=type(self)) - return _mkFP(n2, p, type(self)).__mod__(self) - - def __float__(self): - """Return the floating point representation of this FixedPoint. - Caution! float can lose precision. - """ - n, p = self.__reduce() - return float(n) / float(_tento(p)) - - def __long__(self): - """EJG/DF - Should this round instead? - Note e.g. long(-1.9) == -1L and long(1.9) == 1L in Python - Note that __int__ inherits whatever __long__ does, - and .frac() is affected too - """ - answer = abs(self.n) / _tento(self.p) - if self.n < 0: - answer = -answer - return answer - - def __int__(self): - """Return integer value of FixedPoint object.""" - return int(self.__long__()) - - def frac(self): - """Return fractional portion as a FixedPoint. - - x.frac() + long(x) == x - """ - return self - long(self) - - def _roundquotient(self, x, y): - """ - Divide x by y, - return the result of rounding - Developers may substitute their own 'round' for custom rounding - y must be > 0 - """ - assert y > 0 - n, leftover = divmod(x, y) - return self.round(x, y, n, leftover) - - def __reduce(self): - """ Return n, p s.t. self == n/10**p and n % 10 != 0""" - n, p = self.n, self.p - if n == 0: - p = 0 - while p and n % 10 == 0: - p = p - 1 - n = n / 10 - return n, p - -# 2002-10-04 dougfort - Default to Banker's Rounding for backward compatibility -FixedPoint.round = bankersRounding - -# return 10L**n - -def _tento(n, cache={}): - """Cached computation of 10**n""" - try: - return cache[n] - except KeyError: - answer = cache[n] = 10L ** n - return answer - -def _norm(x, y, isinstance=isinstance, FixedPoint=FixedPoint, - _tento=_tento): - """Return xn, yn, p s.t. - p = max(x.p, y.p) - x = xn / 10**p - y = yn / 10**p - - x must be FixedPoint to begin with; if y is not FixedPoint, - it inherits its precision from x. - - Note that this method is called a lot, so default-arg tricks are helpful. - """ - assert isinstance(x, FixedPoint) - if not isinstance(y, FixedPoint): - y = FixedPoint(y, x.p) - xn, yn = x.n, y.n - xp, yp = x.p, y.p - if xp > yp: - yn = yn * _tento(xp - yp) - p = xp - elif xp < yp: - xn = xn * _tento(yp - xp) - p = yp - else: - p = xp # same as yp - return xn, yn, p - -def _mkFP(n, p, FixedPoint=FixedPoint): - """Make FixedPoint objext - Return a new FixedPoint object with the selected precision.""" - f = FixedPoint() - #print '_mkFP Debug: %s, value=%s' % (type(f),n) - f.n = n - f.p = p - return f - -# crud for parsing strings -import re - -# There's an optional sign at the start, and an optional exponent -# at the end. The exponent has an optional sign and at least one -# digit. In between, must have either at least one digit followed -# by an optional fraction, or a decimal point followed by at least -# one digit. Yuck. - -_parser = re.compile(r""" - \s* - (?P[-+])? - ( - (?P\d+) (\. (?P\d*))? - | - \. (?P\d+) - ) - ([eE](?P[-+]? \d+))? - \s* $ -""", re.VERBOSE).match - -del re - - -def _string2exact(s): - """Return n, p s.t. float string value == n * 10**p exactly.""" - m = _parser(s) - if m is None: - raise ValueError("can't parse as number: " + `s`) - - exp = m.group('exp') - if exp is None: - exp = 0 - else: - exp = int(exp) - - intpart = m.group('int') - if intpart is None: - intpart = "0" - fracpart = m.group('onlyfrac') - else: - fracpart = m.group('frac') - if fracpart is None or fracpart == "": - fracpart = "0" - assert intpart - assert fracpart - - i, f = long(intpart), long(fracpart) - nfrac = len(fracpart) - i = i * _tento(nfrac) + f - exp = exp - nfrac - - if m.group('sign') == "-": - i = -i - - return i, exp - -def _test(): - """Unit testing framework""" - fp = FixedPoint - o = fp("0.1") - assert str(o) == "0.10" - t = fp("-20e-2", 5) - assert str(t) == "-0.20000" - assert t < o - assert o > t - assert min(o, t) == min(t, o) == t - assert max(o, t) == max(t, o) == o - assert o != t - assert --t == t - assert abs(t) > abs(o) - assert abs(o) < abs(t) - assert o == o and t == t - assert t.copy() == t - assert o == -t/2 == -.5 * t - assert abs(t) == o + o - assert abs(o) == o - assert o/t == -0.5 - assert -(t/o) == (-t)/o == t/-o == 2 - assert 1 + o == o + 1 == fp(" +00.000011e+5 ") - assert 1/o == 10 - assert o + t == t + o == -o - assert 2.0 * t == t * 2 == "2" * t == o/o * 2L * t - assert 1 - t == -(t - 1) == fp(6L)/5 - assert t*t == 4*o*o == o*4*o == o*o*4 - assert fp(2) - "1" == 1 - assert float(-1/t) == 5.0 - for p in range(20): - assert 42 + fp("1e-20", p) - 42 == 0 - assert 1/(42 + fp("1e-20", 20) - 42) == fp("100.0E18") - o = fp(".9995", 4) - assert 1 - o == fp("5e-4", 10) - o.set_precision(3) - assert o == 1 - o = fp(".9985", 4) - o.set_precision(3) - assert o == fp(".998", 10) - assert o == o.frac() - o.set_precision(100) - assert o == fp(".998", 10) - o.set_precision(2) - assert o == 1 - x = fp(1.99) - assert long(x) == -long(-x) == 1L - assert int(x) == -int(-x) == 1 - assert x == long(x) + x.frac() - assert -x == long(-x) + (-x).frac() - assert fp(7) % 4 == 7 % fp(4) == 3 - assert fp(-7) % 4 == -7 % fp(4) == 1 - assert fp(-7) % -4 == -7 % fp(-4) == -3 - assert fp(7.0) % "-4.0" == 7 % fp(-4) == -1 - assert fp("5.5") % fp("1.1") == fp("5.5e100") % fp("1.1e100") == 0 - assert divmod(fp("1e100"), 3) == (long(fp("1e100")/3), 1) - -if __name__ == '__main__': - _test() - diff --git a/python-modules-pre24/optparse.py b/python-modules-pre24/optparse.py deleted file mode 100644 index ae3d00d..0000000 --- a/python-modules-pre24/optparse.py +++ /dev/null @@ -1,1569 +0,0 @@ -"""optparse - a powerful, extensible, and easy-to-use option parser. - -By Greg Ward - -Originally distributed as Optik; see http://optik.sourceforge.net/ . - -If you have problems with this module, please do not file bugs, -patches, or feature requests with Python; instead, use Optik's -SourceForge project page: - http://sourceforge.net/projects/optik - -For support, use the optik-users@lists.sourceforge.net mailing list -(http://lists.sourceforge.net/lists/listinfo/optik-users). -""" - -# Python developers: please do not make changes to this file, since -# it is automatically generated from the Optik source code. - -__version__ = "1.5a2" - -__all__ = ['Option', - 'SUPPRESS_HELP', - 'SUPPRESS_USAGE', - 'Values', - 'OptionContainer', - 'OptionGroup', - 'OptionParser', - 'HelpFormatter', - 'IndentedHelpFormatter', - 'TitledHelpFormatter', - 'OptParseError', - 'OptionError', - 'OptionConflictError', - 'OptionValueError', - 'BadOptionError'] - -__copyright__ = """ -Copyright (c) 2001-2004 Gregory P. Ward. All rights reserved. -Copyright (c) 2002-2004 Python Software Foundation. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" - -import sys, os -import textwrap -try: - from gettext import gettext as _ -except ImportError: - _ = lambda arg: arg - -def _repr(self): - return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self) - - -# This file was generated from: -# Id: option_parser.py 421 2004-10-26 00:45:16Z greg -# Id: option.py 422 2004-10-26 00:53:47Z greg -# Id: help.py 367 2004-07-24 23:21:21Z gward -# Id: errors.py 367 2004-07-24 23:21:21Z gward - -class OptParseError (Exception): - def __init__(self, msg): - self.msg = msg - - def __str__(self): - return self.msg - - -class OptionError (OptParseError): - """ - Raised if an Option instance is created with invalid or - inconsistent arguments. - """ - - def __init__(self, msg, option): - self.msg = msg - self.option_id = str(option) - - def __str__(self): - if self.option_id: - return "option %s: %s" % (self.option_id, self.msg) - else: - return self.msg - -class OptionConflictError (OptionError): - """ - Raised if conflicting options are added to an OptionParser. - """ - -class OptionValueError (OptParseError): - """ - Raised if an invalid option value is encountered on the command - line. - """ - -class BadOptionError (OptParseError): - """ - Raised if an invalid or ambiguous option is seen on the command-line. - """ - - -class HelpFormatter: - - """ - Abstract base class for formatting option help. OptionParser - instances should use one of the HelpFormatter subclasses for - formatting help; by default IndentedHelpFormatter is used. - - Instance attributes: - parser : OptionParser - the controlling OptionParser instance - indent_increment : int - the number of columns to indent per nesting level - max_help_position : int - the maximum starting column for option help text - help_position : int - the calculated starting column for option help text; - initially the same as the maximum - width : int - total number of columns for output (pass None to constructor for - this value to be taken from the $COLUMNS environment variable) - level : int - current indentation level - current_indent : int - current indentation level (in columns) - help_width : int - number of columns available for option help text (calculated) - default_tag : str - text to replace with each option's default value, "%default" - by default. Set to false value to disable default value expansion. - option_strings : { Option : str } - maps Option instances to the snippet of help text explaining - the syntax of that option, e.g. "-h, --help" or - "-fFILE, --file=FILE" - _short_opt_fmt : str - format string controlling how short options with values are - printed in help text. Must be either "%s%s" ("-fFILE") or - "%s %s" ("-f FILE"), because those are the two syntaxes that - Optik supports. - _long_opt_fmt : str - similar but for long options; must be either "%s %s" ("--file FILE") - or "%s=%s" ("--file=FILE"). - """ - - NO_DEFAULT_VALUE = "none" - - def __init__(self, - indent_increment, - max_help_position, - width, - short_first): - self.parser = None - self.indent_increment = indent_increment - self.help_position = self.max_help_position = max_help_position - if width is None: - try: - width = int(os.environ['COLUMNS']) - except (KeyError, ValueError): - width = 80 - width -= 2 - self.width = width - self.current_indent = 0 - self.level = 0 - self.help_width = None # computed later - self.short_first = short_first - self.default_tag = "%default" - self.option_strings = {} - self._short_opt_fmt = "%s %s" - self._long_opt_fmt = "%s=%s" - - def set_parser(self, parser): - self.parser = parser - - def set_short_opt_delimiter(self, delim): - if delim not in ("", " "): - raise ValueError( - "invalid metavar delimiter for short options: %r" % delim) - self._short_opt_fmt = "%s" + delim + "%s" - - def set_long_opt_delimiter(self, delim): - if delim not in ("=", " "): - raise ValueError( - "invalid metavar delimiter for long options: %r" % delim) - self._long_opt_fmt = "%s" + delim + "%s" - - def indent(self): - self.current_indent += self.indent_increment - self.level += 1 - - def dedent(self): - self.current_indent -= self.indent_increment - assert self.current_indent >= 0, "Indent decreased below 0." - self.level -= 1 - - def format_usage(self, usage): - raise NotImplementedError, "subclasses must implement" - - def format_heading(self, heading): - raise NotImplementedError, "subclasses must implement" - - def format_description(self, description): - if not description: - return "" - desc_width = self.width - self.current_indent - indent = " "*self.current_indent - return textwrap.fill(description, - desc_width, - initial_indent=indent, - subsequent_indent=indent) + "\n" - - def expand_default(self, option): - if self.parser is None or not self.default_tag: - return option.help - - default_value = self.parser.defaults.get(option.dest) - if default_value is NO_DEFAULT or default_value is None: - default_value = self.NO_DEFAULT_VALUE - - return option.help.replace(self.default_tag, str(default_value)) - - def format_option(self, option): - # The help for each option consists of two parts: - # * the opt strings and metavars - # eg. ("-x", or "-fFILENAME, --file=FILENAME") - # * the user-supplied help string - # eg. ("turn on expert mode", "read data from FILENAME") - # - # If possible, we write both of these on the same line: - # -x turn on expert mode - # - # But if the opt string list is too long, we put the help - # string on a second line, indented to the same column it would - # start in if it fit on the first line. - # -fFILENAME, --file=FILENAME - # read data from FILENAME - result = [] - opts = self.option_strings[option] - opt_width = self.help_position - self.current_indent - 2 - if len(opts) > opt_width: - opts = "%*s%s\n" % (self.current_indent, "", opts) - indent_first = self.help_position - else: # start help on same line as opts - opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts) - indent_first = 0 - result.append(opts) - if option.help: - help_text = self.expand_default(option) - help_lines = textwrap.wrap(help_text, self.help_width) - result.append("%*s%s\n" % (indent_first, "", help_lines[0])) - result.extend(["%*s%s\n" % (self.help_position, "", line) - for line in help_lines[1:]]) - elif opts[-1] != "\n": - result.append("\n") - return "".join(result) - - def store_option_strings(self, parser): - self.indent() - max_len = 0 - for opt in parser.option_list: - strings = self.format_option_strings(opt) - self.option_strings[opt] = strings - max_len = max(max_len, len(strings) + self.current_indent) - self.indent() - for group in parser.option_groups: - for opt in group.option_list: - strings = self.format_option_strings(opt) - self.option_strings[opt] = strings - max_len = max(max_len, len(strings) + self.current_indent) - self.dedent() - self.dedent() - self.help_position = min(max_len + 2, self.max_help_position) - self.help_width = self.width - self.help_position - - def format_option_strings(self, option): - """Return a comma-separated list of option strings & metavariables.""" - if option.takes_value(): - metavar = option.metavar or option.dest.upper() - short_opts = [self._short_opt_fmt % (sopt, metavar) - for sopt in option._short_opts] - long_opts = [self._long_opt_fmt % (lopt, metavar) - for lopt in option._long_opts] - else: - short_opts = option._short_opts - long_opts = option._long_opts - - if self.short_first: - opts = short_opts + long_opts - else: - opts = long_opts + short_opts - - return ", ".join(opts) - -class IndentedHelpFormatter (HelpFormatter): - """Format help with indented section bodies. - """ - - def __init__(self, - indent_increment=2, - max_help_position=24, - width=None, - short_first=1): - HelpFormatter.__init__( - self, indent_increment, max_help_position, width, short_first) - - def format_usage(self, usage): - return _("usage: %s\n") % usage - - def format_heading(self, heading): - return "%*s%s:\n" % (self.current_indent, "", heading) - - -class TitledHelpFormatter (HelpFormatter): - """Format help with underlined section headers. - """ - - def __init__(self, - indent_increment=0, - max_help_position=24, - width=None, - short_first=0): - HelpFormatter.__init__ ( - self, indent_increment, max_help_position, width, short_first) - - def format_usage(self, usage): - return "%s %s\n" % (self.format_heading(_("Usage")), usage) - - def format_heading(self, heading): - return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading)) - - -_builtin_cvt = { "int" : (int, _("integer")), - "long" : (long, _("long integer")), - "float" : (float, _("floating-point")), - "complex" : (complex, _("complex")) } - -def check_builtin(option, opt, value): - (cvt, what) = _builtin_cvt[option.type] - try: - return cvt(value) - except ValueError: - raise OptionValueError( - _("option %s: invalid %s value: %r") % (opt, what, value)) - -def check_choice(option, opt, value): - if value in option.choices: - return value - else: - choices = ", ".join(map(repr, option.choices)) - raise OptionValueError( - _("option %s: invalid choice: %r (choose from %s)") - % (opt, value, choices)) - -# Not supplying a default is different from a default of None, -# so we need an explicit "not supplied" value. -NO_DEFAULT = ("NO", "DEFAULT") - - -class Option: - """ - Instance attributes: - _short_opts : [string] - _long_opts : [string] - - action : string - type : string - dest : string - default : any - nargs : int - const : any - choices : [string] - callback : function - callback_args : (any*) - callback_kwargs : { string : any } - help : string - metavar : string - """ - - # The list of instance attributes that may be set through - # keyword args to the constructor. - ATTRS = ['action', - 'type', - 'dest', - 'default', - 'nargs', - 'const', - 'choices', - 'callback', - 'callback_args', - 'callback_kwargs', - 'help', - 'metavar'] - - # The set of actions allowed by option parsers. Explicitly listed - # here so the constructor can validate its arguments. - ACTIONS = ("store", - "store_const", - "store_true", - "store_false", - "append", - "count", - "callback", - "help", - "version") - - # The set of actions that involve storing a value somewhere; - # also listed just for constructor argument validation. (If - # the action is one of these, there must be a destination.) - STORE_ACTIONS = ("store", - "store_const", - "store_true", - "store_false", - "append", - "count") - - # The set of actions for which it makes sense to supply a value - # type, ie. which may consume an argument from the command line. - TYPED_ACTIONS = ("store", - "append", - "callback") - - # The set of actions which *require* a value type, ie. that - # always consume an argument from the command line. - ALWAYS_TYPED_ACTIONS = ("store", - "append") - - # The set of known types for option parsers. Again, listed here for - # constructor argument validation. - TYPES = ("string", "int", "long", "float", "complex", "choice") - - # Dictionary of argument checking functions, which convert and - # validate option arguments according to the option type. - # - # Signature of checking functions is: - # check(option : Option, opt : string, value : string) -> any - # where - # option is the Option instance calling the checker - # opt is the actual option seen on the command-line - # (eg. "-a", "--file") - # value is the option argument seen on the command-line - # - # The return value should be in the appropriate Python type - # for option.type -- eg. an integer if option.type == "int". - # - # If no checker is defined for a type, arguments will be - # unchecked and remain strings. - TYPE_CHECKER = { "int" : check_builtin, - "long" : check_builtin, - "float" : check_builtin, - "complex": check_builtin, - "choice" : check_choice, - } - - - # CHECK_METHODS is a list of unbound method objects; they are called - # by the constructor, in order, after all attributes are - # initialized. The list is created and filled in later, after all - # the methods are actually defined. (I just put it here because I - # like to define and document all class attributes in the same - # place.) Subclasses that add another _check_*() method should - # define their own CHECK_METHODS list that adds their check method - # to those from this class. - CHECK_METHODS = None - - - # -- Constructor/initialization methods ---------------------------- - - def __init__(self, *opts, **attrs): - # Set _short_opts, _long_opts attrs from 'opts' tuple. - # Have to be set now, in case no option strings are supplied. - self._short_opts = [] - self._long_opts = [] - opts = self._check_opt_strings(opts) - self._set_opt_strings(opts) - - # Set all other attrs (action, type, etc.) from 'attrs' dict - self._set_attrs(attrs) - - # Check all the attributes we just set. There are lots of - # complicated interdependencies, but luckily they can be farmed - # out to the _check_*() methods listed in CHECK_METHODS -- which - # could be handy for subclasses! The one thing these all share - # is that they raise OptionError if they discover a problem. - for checker in self.CHECK_METHODS: - checker(self) - - def _check_opt_strings(self, opts): - # Filter out None because early versions of Optik had exactly - # one short option and one long option, either of which - # could be None. - opts = filter(None, opts) - if not opts: - raise TypeError("at least one option string must be supplied") - return opts - - def _set_opt_strings(self, opts): - for opt in opts: - if len(opt) < 2: - raise OptionError( - "invalid option string %r: " - "must be at least two characters long" % opt, self) - elif len(opt) == 2: - if not (opt[0] == "-" and opt[1] != "-"): - raise OptionError( - "invalid short option string %r: " - "must be of the form -x, (x any non-dash char)" % opt, - self) - self._short_opts.append(opt) - else: - if not (opt[0:2] == "--" and opt[2] != "-"): - raise OptionError( - "invalid long option string %r: " - "must start with --, followed by non-dash" % opt, - self) - self._long_opts.append(opt) - - def _set_attrs(self, attrs): - for attr in self.ATTRS: - if attrs.has_key(attr): - setattr(self, attr, attrs[attr]) - del attrs[attr] - else: - if attr == 'default': - setattr(self, attr, NO_DEFAULT) - else: - setattr(self, attr, None) - if attrs: - raise OptionError( - "invalid keyword arguments: %s" % ", ".join(attrs.keys()), - self) - - - # -- Constructor validation methods -------------------------------- - - def _check_action(self): - if self.action is None: - self.action = "store" - elif self.action not in self.ACTIONS: - raise OptionError("invalid action: %r" % self.action, self) - - def _check_type(self): - if self.type is None: - if self.action in self.ALWAYS_TYPED_ACTIONS: - if self.choices is not None: - # The "choices" attribute implies "choice" type. - self.type = "choice" - else: - # No type given? "string" is the most sensible default. - self.type = "string" - else: - # Allow type objects as an alternative to their names. - if type(self.type) is type: - self.type = self.type.__name__ - if self.type == "str": - self.type = "string" - - if self.type not in self.TYPES: - raise OptionError("invalid option type: %r" % self.type, self) - if self.action not in self.TYPED_ACTIONS: - raise OptionError( - "must not supply a type for action %r" % self.action, self) - - def _check_choice(self): - if self.type == "choice": - if self.choices is None: - raise OptionError( - "must supply a list of choices for type 'choice'", self) - elif type(self.choices) not in (tuple, list): - raise OptionError( - "choices must be a list of strings ('%s' supplied)" - % str(type(self.choices)).split("'")[1], self) - elif self.choices is not None: - raise OptionError( - "must not supply choices for type %r" % self.type, self) - - def _check_dest(self): - # No destination given, and we need one for this action. The - # self.type check is for callbacks that take a value. - takes_value = (self.action in self.STORE_ACTIONS or - self.type is not None) - if self.dest is None and takes_value: - - # Glean a destination from the first long option string, - # or from the first short option string if no long options. - if self._long_opts: - # eg. "--foo-bar" -> "foo_bar" - self.dest = self._long_opts[0][2:].replace('-', '_') - else: - self.dest = self._short_opts[0][1] - - def _check_const(self): - if self.action != "store_const" and self.const is not None: - raise OptionError( - "'const' must not be supplied for action %r" % self.action, - self) - - def _check_nargs(self): - if self.action in self.TYPED_ACTIONS: - if self.nargs is None: - self.nargs = 1 - elif self.nargs is not None: - raise OptionError( - "'nargs' must not be supplied for action %r" % self.action, - self) - - def _check_callback(self): - if self.action == "callback": - if not callable(self.callback): - raise OptionError( - "callback not callable: %r" % self.callback, self) - if (self.callback_args is not None and - type(self.callback_args) is not tuple): - raise OptionError( - "callback_args, if supplied, must be a tuple: not %r" - % self.callback_args, self) - if (self.callback_kwargs is not None and - type(self.callback_kwargs) is not dict): - raise OptionError( - "callback_kwargs, if supplied, must be a dict: not %r" - % self.callback_kwargs, self) - else: - if self.callback is not None: - raise OptionError( - "callback supplied (%r) for non-callback option" - % self.callback, self) - if self.callback_args is not None: - raise OptionError( - "callback_args supplied for non-callback option", self) - if self.callback_kwargs is not None: - raise OptionError( - "callback_kwargs supplied for non-callback option", self) - - - CHECK_METHODS = [_check_action, - _check_type, - _check_choice, - _check_dest, - _check_const, - _check_nargs, - _check_callback] - - - # -- Miscellaneous methods ----------------------------------------- - - def __str__(self): - return "/".join(self._short_opts + self._long_opts) - - __repr__ = _repr - - def takes_value(self): - return self.type is not None - - def get_opt_string(self): - if self._long_opts: - return self._long_opts[0] - else: - return self._short_opts[0] - - - # -- Processing methods -------------------------------------------- - - def check_value(self, opt, value): - checker = self.TYPE_CHECKER.get(self.type) - if checker is None: - return value - else: - return checker(self, opt, value) - - def convert_value(self, opt, value): - if value is not None: - if self.nargs == 1: - return self.check_value(opt, value) - else: - return tuple([self.check_value(opt, v) for v in value]) - - def process(self, opt, value, values, parser): - - # First, convert the value(s) to the right type. Howl if any - # value(s) are bogus. - value = self.convert_value(opt, value) - - # And then take whatever action is expected of us. - # This is a separate method to make life easier for - # subclasses to add new actions. - return self.take_action( - self.action, self.dest, opt, value, values, parser) - - def take_action(self, action, dest, opt, value, values, parser): - if action == "store": - setattr(values, dest, value) - elif action == "store_const": - setattr(values, dest, self.const) - elif action == "store_true": - setattr(values, dest, True) - elif action == "store_false": - setattr(values, dest, False) - elif action == "append": - values.ensure_value(dest, []).append(value) - elif action == "count": - setattr(values, dest, values.ensure_value(dest, 0) + 1) - elif action == "callback": - args = self.callback_args or () - kwargs = self.callback_kwargs or {} - self.callback(self, opt, value, parser, *args, **kwargs) - elif action == "help": - parser.print_help() - parser.exit() - elif action == "version": - parser.print_version() - parser.exit() - else: - raise RuntimeError, "unknown action %r" % self.action - - return 1 - -# class Option - - -SUPPRESS_HELP = "SUPPRESS"+"HELP" -SUPPRESS_USAGE = "SUPPRESS"+"USAGE" - -# For compatibility with Python 2.2 -try: - True, False -except NameError: - (True, False) = (1, 0) -try: - basestring -except NameError: - basestring = (str, unicode) - - -class Values: - - def __init__(self, defaults=None): - if defaults: - for (attr, val) in defaults.items(): - setattr(self, attr, val) - - def __str__(self): - return str(self.__dict__) - - __repr__ = _repr - - def __eq__(self, other): - if isinstance(other, Values): - return self.__dict__ == other.__dict__ - elif isinstance(other, dict): - return self.__dict__ == other - else: - return False - - def __ne__(self, other): - return not (self == other) - - def _update_careful(self, dict): - """ - Update the option values from an arbitrary dictionary, but only - use keys from dict that already have a corresponding attribute - in self. Any keys in dict without a corresponding attribute - are silently ignored. - """ - for attr in dir(self): - if dict.has_key(attr): - dval = dict[attr] - if dval is not None: - setattr(self, attr, dval) - - def _update_loose(self, dict): - """ - Update the option values from an arbitrary dictionary, - using all keys from the dictionary regardless of whether - they have a corresponding attribute in self or not. - """ - self.__dict__.update(dict) - - def _update(self, dict, mode): - if mode == "careful": - self._update_careful(dict) - elif mode == "loose": - self._update_loose(dict) - else: - raise ValueError, "invalid update mode: %r" % mode - - def read_module(self, modname, mode="careful"): - __import__(modname) - mod = sys.modules[modname] - self._update(vars(mod), mode) - - def read_file(self, filename, mode="careful"): - vars = {} - execfile(filename, vars) - self._update(vars, mode) - - def ensure_value(self, attr, value): - if not hasattr(self, attr) or getattr(self, attr) is None: - setattr(self, attr, value) - return getattr(self, attr) - - -class OptionContainer: - - """ - Abstract base class. - - Class attributes: - standard_option_list : [Option] - list of standard options that will be accepted by all instances - of this parser class (intended to be overridden by subclasses). - - Instance attributes: - option_list : [Option] - the list of Option objects contained by this OptionContainer - _short_opt : { string : Option } - dictionary mapping short option strings, eg. "-f" or "-X", - to the Option instances that implement them. If an Option - has multiple short option strings, it will appears in this - dictionary multiple times. [1] - _long_opt : { string : Option } - dictionary mapping long option strings, eg. "--file" or - "--exclude", to the Option instances that implement them. - Again, a given Option can occur multiple times in this - dictionary. [1] - defaults : { string : any } - dictionary mapping option destination names to default - values for each destination [1] - - [1] These mappings are common to (shared by) all components of the - controlling OptionParser, where they are initially created. - - """ - - def __init__(self, option_class, conflict_handler, description): - # Initialize the option list and related data structures. - # This method must be provided by subclasses, and it must - # initialize at least the following instance attributes: - # option_list, _short_opt, _long_opt, defaults. - self._create_option_list() - - self.option_class = option_class - self.set_conflict_handler(conflict_handler) - self.set_description(description) - - def _create_option_mappings(self): - # For use by OptionParser constructor -- create the master - # option mappings used by this OptionParser and all - # OptionGroups that it owns. - self._short_opt = {} # single letter -> Option instance - self._long_opt = {} # long option -> Option instance - self.defaults = {} # maps option dest -> default value - - - def _share_option_mappings(self, parser): - # For use by OptionGroup constructor -- use shared option - # mappings from the OptionParser that owns this OptionGroup. - self._short_opt = parser._short_opt - self._long_opt = parser._long_opt - self.defaults = parser.defaults - - def set_conflict_handler(self, handler): - if handler not in ("error", "resolve"): - raise ValueError, "invalid conflict_resolution value %r" % handler - self.conflict_handler = handler - - def set_description(self, description): - self.description = description - - def get_description(self): - return self.description - - - # -- Option-adding methods ----------------------------------------- - - def _check_conflict(self, option): - conflict_opts = [] - for opt in option._short_opts: - if self._short_opt.has_key(opt): - conflict_opts.append((opt, self._short_opt[opt])) - for opt in option._long_opts: - if self._long_opt.has_key(opt): - conflict_opts.append((opt, self._long_opt[opt])) - - if conflict_opts: - handler = self.conflict_handler - if handler == "error": - raise OptionConflictError( - "conflicting option string(s): %s" - % ", ".join([co[0] for co in conflict_opts]), - option) - elif handler == "resolve": - for (opt, c_option) in conflict_opts: - if opt.startswith("--"): - c_option._long_opts.remove(opt) - del self._long_opt[opt] - else: - c_option._short_opts.remove(opt) - del self._short_opt[opt] - if not (c_option._short_opts or c_option._long_opts): - c_option.container.option_list.remove(c_option) - - def add_option(self, *args, **kwargs): - """add_option(Option) - add_option(opt_str, ..., kwarg=val, ...) - """ - if type(args[0]) is str: - option = self.option_class(*args, **kwargs) - elif len(args) == 1 and not kwargs: - option = args[0] - if not isinstance(option, Option): - raise TypeError, "not an Option instance: %r" % option - else: - raise TypeError, "invalid arguments" - - self._check_conflict(option) - - self.option_list.append(option) - option.container = self - for opt in option._short_opts: - self._short_opt[opt] = option - for opt in option._long_opts: - self._long_opt[opt] = option - - if option.dest is not None: # option has a dest, we need a default - if option.default is not NO_DEFAULT: - self.defaults[option.dest] = option.default - elif not self.defaults.has_key(option.dest): - self.defaults[option.dest] = None - - return option - - def add_options(self, option_list): - for option in option_list: - self.add_option(option) - - # -- Option query/removal methods ---------------------------------- - - def get_option(self, opt_str): - return (self._short_opt.get(opt_str) or - self._long_opt.get(opt_str)) - - def has_option(self, opt_str): - return (self._short_opt.has_key(opt_str) or - self._long_opt.has_key(opt_str)) - - def remove_option(self, opt_str): - option = self._short_opt.get(opt_str) - if option is None: - option = self._long_opt.get(opt_str) - if option is None: - raise ValueError("no such option %r" % opt_str) - - for opt in option._short_opts: - del self._short_opt[opt] - for opt in option._long_opts: - del self._long_opt[opt] - option.container.option_list.remove(option) - - - # -- Help-formatting methods --------------------------------------- - - def format_option_help(self, formatter): - if not self.option_list: - return "" - result = [] - for option in self.option_list: - if not option.help is SUPPRESS_HELP: - result.append(formatter.format_option(option)) - return "".join(result) - - def format_description(self, formatter): - return formatter.format_description(self.get_description()) - - def format_help(self, formatter): - result = [] - if self.description: - result.append(self.format_description(formatter)) - if self.option_list: - result.append(self.format_option_help(formatter)) - return "\n".join(result) - - -class OptionGroup (OptionContainer): - - def __init__(self, parser, title, description=None): - self.parser = parser - OptionContainer.__init__( - self, parser.option_class, parser.conflict_handler, description) - self.title = title - - def _create_option_list(self): - self.option_list = [] - self._share_option_mappings(self.parser) - - def set_title(self, title): - self.title = title - - # -- Help-formatting methods --------------------------------------- - - def format_help(self, formatter): - result = formatter.format_heading(self.title) - formatter.indent() - result += OptionContainer.format_help(self, formatter) - formatter.dedent() - return result - - -class OptionParser (OptionContainer): - - """ - Class attributes: - standard_option_list : [Option] - list of standard options that will be accepted by all instances - of this parser class (intended to be overridden by subclasses). - - Instance attributes: - usage : string - a usage string for your program. Before it is displayed - to the user, "%prog" will be expanded to the name of - your program (self.prog or os.path.basename(sys.argv[0])). - prog : string - the name of the current program (to override - os.path.basename(sys.argv[0])). - - option_groups : [OptionGroup] - list of option groups in this parser (option groups are - irrelevant for parsing the command-line, but very useful - for generating help) - - allow_interspersed_args : bool = true - if true, positional arguments may be interspersed with options. - Assuming -a and -b each take a single argument, the command-line - -ablah foo bar -bboo baz - will be interpreted the same as - -ablah -bboo -- foo bar baz - If this flag were false, that command line would be interpreted as - -ablah -- foo bar -bboo baz - -- ie. we stop processing options as soon as we see the first - non-option argument. (This is the tradition followed by - Python's getopt module, Perl's Getopt::Std, and other argument- - parsing libraries, but it is generally annoying to users.) - - process_default_values : bool = true - if true, option default values are processed similarly to option - values from the command line: that is, they are passed to the - type-checking function for the option's type (as long as the - default value is a string). (This really only matters if you - have defined custom types; see SF bug #955889.) Set it to false - to restore the behaviour of Optik 1.4.1 and earlier. - - rargs : [string] - the argument list currently being parsed. Only set when - parse_args() is active, and continually trimmed down as - we consume arguments. Mainly there for the benefit of - callback options. - largs : [string] - the list of leftover arguments that we have skipped while - parsing options. If allow_interspersed_args is false, this - list is always empty. - values : Values - the set of option values currently being accumulated. Only - set when parse_args() is active. Also mainly for callbacks. - - Because of the 'rargs', 'largs', and 'values' attributes, - OptionParser is not thread-safe. If, for some perverse reason, you - need to parse command-line arguments simultaneously in different - threads, use different OptionParser instances. - - """ - - standard_option_list = [] - - def __init__(self, - usage=None, - option_list=None, - option_class=Option, - version=None, - conflict_handler="error", - description=None, - formatter=None, - add_help_option=True, - prog=None): - OptionContainer.__init__( - self, option_class, conflict_handler, description) - self.set_usage(usage) - self.prog = prog - self.version = version - self.allow_interspersed_args = True - self.process_default_values = True - if formatter is None: - formatter = IndentedHelpFormatter() - self.formatter = formatter - self.formatter.set_parser(self) - - # Populate the option list; initial sources are the - # standard_option_list class attribute, the 'option_list' - # argument, and (if applicable) the _add_version_option() and - # _add_help_option() methods. - self._populate_option_list(option_list, - add_help=add_help_option) - - self._init_parsing_state() - - # -- Private methods ----------------------------------------------- - # (used by our or OptionContainer's constructor) - - def _create_option_list(self): - self.option_list = [] - self.option_groups = [] - self._create_option_mappings() - - def _add_help_option(self): - self.add_option("-h", "--help", - action="help", - help=_("show this help message and exit")) - - def _add_version_option(self): - self.add_option("--version", - action="version", - help=_("show program's version number and exit")) - - def _populate_option_list(self, option_list, add_help=True): - if self.standard_option_list: - self.add_options(self.standard_option_list) - if option_list: - self.add_options(option_list) - if self.version: - self._add_version_option() - if add_help: - self._add_help_option() - - def _init_parsing_state(self): - # These are set in parse_args() for the convenience of callbacks. - self.rargs = None - self.largs = None - self.values = None - - - # -- Simple modifier methods --------------------------------------- - - def set_usage(self, usage): - if usage is None: - self.usage = _("%prog [options]") - elif usage is SUPPRESS_USAGE: - self.usage = None - # For backwards compatibility with Optik 1.3 and earlier. - elif usage.startswith("usage:" + " "): - self.usage = usage[7:] - else: - self.usage = usage - - def enable_interspersed_args(self): - self.allow_interspersed_args = True - - def disable_interspersed_args(self): - self.allow_interspersed_args = False - - def set_process_default_values(self, process): - self.process_default_values = process - - def set_default(self, dest, value): - self.defaults[dest] = value - - def set_defaults(self, **kwargs): - self.defaults.update(kwargs) - - def _get_all_options(self): - options = self.option_list[:] - for group in self.option_groups: - options.extend(group.option_list) - return options - - def get_default_values(self): - if not self.process_default_values: - # Old, pre-Optik 1.5 behaviour. - return Values(self.defaults) - - defaults = self.defaults.copy() - for option in self._get_all_options(): - default = defaults.get(option.dest) - if isinstance(default, basestring): - opt_str = option.get_opt_string() - defaults[option.dest] = option.check_value(opt_str, default) - - return Values(defaults) - - - # -- OptionGroup methods ------------------------------------------- - - def add_option_group(self, *args, **kwargs): - # XXX lots of overlap with OptionContainer.add_option() - if type(args[0]) is str: - group = OptionGroup(self, *args, **kwargs) - elif len(args) == 1 and not kwargs: - group = args[0] - if not isinstance(group, OptionGroup): - raise TypeError, "not an OptionGroup instance: %r" % group - if group.parser is not self: - raise ValueError, "invalid OptionGroup (wrong parser)" - else: - raise TypeError, "invalid arguments" - - self.option_groups.append(group) - return group - - def get_option_group(self, opt_str): - option = (self._short_opt.get(opt_str) or - self._long_opt.get(opt_str)) - if option and option.container is not self: - return option.container - return None - - - # -- Option-parsing methods ---------------------------------------- - - def _get_args(self, args): - if args is None: - return sys.argv[1:] - else: - return args[:] # don't modify caller's list - - def parse_args(self, args=None, values=None): - """ - parse_args(args : [string] = sys.argv[1:], - values : Values = None) - -> (values : Values, args : [string]) - - Parse the command-line options found in 'args' (default: - sys.argv[1:]). Any errors result in a call to 'error()', which - by default prints the usage message to stderr and calls - sys.exit() with an error message. On success returns a pair - (values, args) where 'values' is an Values instance (with all - your option values) and 'args' is the list of arguments left - over after parsing options. - """ - rargs = self._get_args(args) - if values is None: - values = self.get_default_values() - - # Store the halves of the argument list as attributes for the - # convenience of callbacks: - # rargs - # the rest of the command-line (the "r" stands for - # "remaining" or "right-hand") - # largs - # the leftover arguments -- ie. what's left after removing - # options and their arguments (the "l" stands for "leftover" - # or "left-hand") - self.rargs = rargs - self.largs = largs = [] - self.values = values - - try: - stop = self._process_args(largs, rargs, values) - except (BadOptionError, OptionValueError), err: - self.error(err.msg) - - args = largs + rargs - return self.check_values(values, args) - - def check_values(self, values, args): - """ - check_values(values : Values, args : [string]) - -> (values : Values, args : [string]) - - Check that the supplied option values and leftover arguments are - valid. Returns the option values and leftover arguments - (possibly adjusted, possibly completely new -- whatever you - like). Default implementation just returns the passed-in - values; subclasses may override as desired. - """ - return (values, args) - - def _process_args(self, largs, rargs, values): - """_process_args(largs : [string], - rargs : [string], - values : Values) - - Process command-line arguments and populate 'values', consuming - options and arguments from 'rargs'. If 'allow_interspersed_args' is - false, stop at the first non-option argument. If true, accumulate any - interspersed non-option arguments in 'largs'. - """ - while rargs: - arg = rargs[0] - # We handle bare "--" explicitly, and bare "-" is handled by the - # standard arg handler since the short arg case ensures that the - # len of the opt string is greater than 1. - if arg == "--": - del rargs[0] - return - elif arg[0:2] == "--": - # process a single long option (possibly with value(s)) - self._process_long_opt(rargs, values) - elif arg[:1] == "-" and len(arg) > 1: - # process a cluster of short options (possibly with - # value(s) for the last one only) - self._process_short_opts(rargs, values) - elif self.allow_interspersed_args: - largs.append(arg) - del rargs[0] - else: - return # stop now, leave this arg in rargs - - # Say this is the original argument list: - # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] - # ^ - # (we are about to process arg(i)). - # - # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of - # [arg0, ..., arg(i-1)] (any options and their arguments will have - # been removed from largs). - # - # The while loop will usually consume 1 or more arguments per pass. - # If it consumes 1 (eg. arg is an option that takes no arguments), - # then after _process_arg() is done the situation is: - # - # largs = subset of [arg0, ..., arg(i)] - # rargs = [arg(i+1), ..., arg(N-1)] - # - # If allow_interspersed_args is false, largs will always be - # *empty* -- still a subset of [arg0, ..., arg(i-1)], but - # not a very interesting subset! - - def _match_long_opt(self, opt): - """_match_long_opt(opt : string) -> string - - Determine which long option string 'opt' matches, ie. which one - it is an unambiguous abbrevation for. Raises BadOptionError if - 'opt' doesn't unambiguously match any long option string. - """ - return _match_abbrev(opt, self._long_opt) - - def _process_long_opt(self, rargs, values): - arg = rargs.pop(0) - - # Value explicitly attached to arg? Pretend it's the next - # argument. - if "=" in arg: - (opt, next_arg) = arg.split("=", 1) - rargs.insert(0, next_arg) - had_explicit_value = True - else: - opt = arg - had_explicit_value = False - - opt = self._match_long_opt(opt) - option = self._long_opt[opt] - if option.takes_value(): - nargs = option.nargs - if len(rargs) < nargs: - if nargs == 1: - self.error(_("%s option requires an argument") % opt) - else: - self.error(_("%s option requires %d arguments") - % (opt, nargs)) - elif nargs == 1: - value = rargs.pop(0) - else: - value = tuple(rargs[0:nargs]) - del rargs[0:nargs] - - elif had_explicit_value: - self.error(_("%s option does not take a value") % opt) - - else: - value = None - - option.process(opt, value, values, self) - - def _process_short_opts(self, rargs, values): - arg = rargs.pop(0) - stop = False - i = 1 - for ch in arg[1:]: - opt = "-" + ch - option = self._short_opt.get(opt) - i += 1 # we have consumed a character - - if not option: - self.error(_("no such option: %s") % opt) - if option.takes_value(): - # Any characters left in arg? Pretend they're the - # next arg, and stop consuming characters of arg. - if i < len(arg): - rargs.insert(0, arg[i:]) - stop = True - - nargs = option.nargs - if len(rargs) < nargs: - if nargs == 1: - self.error(_("%s option requires an argument") % opt) - else: - self.error(_("%s option requires %d arguments") - % (opt, nargs)) - elif nargs == 1: - value = rargs.pop(0) - else: - value = tuple(rargs[0:nargs]) - del rargs[0:nargs] - - else: # option doesn't take a value - value = None - - option.process(opt, value, values, self) - - if stop: - break - - - # -- Feedback methods ---------------------------------------------- - - def get_prog_name(self): - if self.prog is None: - return os.path.basename(sys.argv[0]) - else: - return self.prog - - def expand_prog_name(self, s): - return s.replace("%prog", self.get_prog_name()) - - def get_description(self): - return self.expand_prog_name(self.description) - - def exit(self, status=0, msg=None): - if msg: - sys.stderr.write(msg) - sys.exit(status) - - def error(self, msg): - """error(msg : string) - - Print a usage message incorporating 'msg' to stderr and exit. - If you override this in a subclass, it should not return -- it - should either exit or raise an exception. - """ - self.print_usage(sys.stderr) - self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg)) - - def get_usage(self): - if self.usage: - return self.formatter.format_usage( - self.expand_prog_name(self.usage)) - else: - return "" - - def print_usage(self, file=None): - """print_usage(file : file = stdout) - - Print the usage message for the current program (self.usage) to - 'file' (default stdout). Any occurence of the string "%prog" in - self.usage is replaced with the name of the current program - (basename of sys.argv[0]). Does nothing if self.usage is empty - or not defined. - """ - if self.usage: - print >>file, self.get_usage() - - def get_version(self): - if self.version: - return self.expand_prog_name(self.version) - else: - return "" - - def print_version(self, file=None): - """print_version(file : file = stdout) - - Print the version message for this program (self.version) to - 'file' (default stdout). As with print_usage(), any occurence - of "%prog" in self.version is replaced by the current program's - name. Does nothing if self.version is empty or undefined. - """ - if self.version: - print >>file, self.get_version() - - def format_option_help(self, formatter=None): - if formatter is None: - formatter = self.formatter - formatter.store_option_strings(self) - result = [] - result.append(formatter.format_heading(_("options"))) - formatter.indent() - if self.option_list: - result.append(OptionContainer.format_option_help(self, formatter)) - result.append("\n") - for group in self.option_groups: - result.append(group.format_help(formatter)) - result.append("\n") - formatter.dedent() - # Drop the last "\n", or the header if no options or option groups: - return "".join(result[:-1]) - - def format_help(self, formatter=None): - if formatter is None: - formatter = self.formatter - result = [] - if self.usage: - result.append(self.get_usage() + "\n") - if self.description: - result.append(self.format_description(formatter) + "\n") - result.append(self.format_option_help(formatter)) - return "".join(result) - - def print_help(self, file=None): - """print_help(file : file = stdout) - - Print an extended help message, listing all options and any - help text provided with them, to 'file' (default stdout). - """ - if file is None: - file = sys.stdout - file.write(self.format_help()) - -# class OptionParser - - -def _match_abbrev(s, wordmap): - """_match_abbrev(s : string, wordmap : {string : Option}) -> string - - Return the string key in 'wordmap' for which 's' is an unambiguous - abbreviation. If 's' is found to be ambiguous or doesn't match any of - 'words', raise BadOptionError. - """ - # Is there an exact match? - if wordmap.has_key(s): - return s - else: - # Isolate all words with s as a prefix. - possibilities = [word for word in wordmap.keys() - if word.startswith(s)] - # No exact match, so there had better be just one possibility. - if len(possibilities) == 1: - return possibilities[0] - elif not possibilities: - raise BadOptionError(_("no such option: %s") % s) - else: - # More than one possible completion: ambiguous prefix. - raise BadOptionError(_("ambiguous option: %s (%s?)") - % (s, ", ".join(possibilities))) - - -# Some day, there might be many Option classes. As of Optik 1.3, the -# preferred way to instantiate Options is indirectly, via make_option(), -# which will become a factory function when there are many Option -# classes. -make_option = Option diff --git a/python-modules-pre24/textwrap.py b/python-modules-pre24/textwrap.py deleted file mode 100644 index d3bd7c7..0000000 --- a/python-modules-pre24/textwrap.py +++ /dev/null @@ -1,374 +0,0 @@ -"""Text wrapping and filling. -""" - -# Copyright (C) 1999-2001 Gregory P. Ward. -# Copyright (C) 2002, 2003 Python Software Foundation. -# Written by Greg Ward - -__revision__ = "$Id: textwrap.py 46863 2006-06-11 19:42:51Z tim.peters $" - -import string, re - -# Do the right thing with boolean values for all known Python versions -# (so this module can be copied to projects that don't depend on Python -# 2.3, e.g. Optik and Docutils). -try: - True, False -except NameError: - (True, False) = (1, 0) - -__all__ = ['TextWrapper', 'wrap', 'fill'] - -# Hardcode the recognized whitespace characters to the US-ASCII -# whitespace characters. The main reason for doing this is that in -# ISO-8859-1, 0xa0 is non-breaking whitespace, so in certain locales -# that character winds up in string.whitespace. Respecting -# string.whitespace in those cases would 1) make textwrap treat 0xa0 the -# same as any other whitespace char, which is clearly wrong (it's a -# *non-breaking* space), 2) possibly cause problems with Unicode, -# since 0xa0 is not in range(128). -_whitespace = '\t\n\x0b\x0c\r ' - -class TextWrapper: - """ - Object for wrapping/filling text. The public interface consists of - the wrap() and fill() methods; the other methods are just there for - subclasses to override in order to tweak the default behaviour. - If you want to completely replace the main wrapping algorithm, - you'll probably have to override _wrap_chunks(). - - Several instance attributes control various aspects of wrapping: - width (default: 70) - the maximum width of wrapped lines (unless break_long_words - is false) - initial_indent (default: "") - string that will be prepended to the first line of wrapped - output. Counts towards the line's width. - subsequent_indent (default: "") - string that will be prepended to all lines save the first - of wrapped output; also counts towards each line's width. - expand_tabs (default: true) - Expand tabs in input text to spaces before further processing. - Each tab will become 1 .. 8 spaces, depending on its position in - its line. If false, each tab is treated as a single character. - replace_whitespace (default: true) - Replace all whitespace characters in the input text by spaces - after tab expansion. Note that if expand_tabs is false and - replace_whitespace is true, every tab will be converted to a - single space! - fix_sentence_endings (default: false) - Ensure that sentence-ending punctuation is always followed - by two spaces. Off by default because the algorithm is - (unavoidably) imperfect. - break_long_words (default: true) - Break words longer than 'width'. If false, those words will not - be broken, and some lines might be longer than 'width'. - """ - - whitespace_trans = string.maketrans(_whitespace, ' ' * len(_whitespace)) - - unicode_whitespace_trans = {} - uspace = ord(u' ') - for x in map(ord, _whitespace): - unicode_whitespace_trans[x] = uspace - - # This funky little regex is just the trick for splitting - # text up into word-wrappable chunks. E.g. - # "Hello there -- you goof-ball, use the -b option!" - # splits into - # Hello/ /there/ /--/ /you/ /goof-/ball,/ /use/ /the/ /-b/ /option! - # (after stripping out empty strings). - wordsep_re = re.compile( - r'(\s+|' # any whitespace - r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words - r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash - - # XXX this is not locale- or charset-aware -- string.lowercase - # is US-ASCII only (and therefore English-only) - sentence_end_re = re.compile(r'[%s]' # lowercase letter - r'[\.\!\?]' # sentence-ending punct. - r'[\"\']?' # optional end-of-quote - % string.lowercase) - - - def __init__(self, - width=70, - initial_indent="", - subsequent_indent="", - expand_tabs=True, - replace_whitespace=True, - fix_sentence_endings=False, - break_long_words=True): - self.width = width - self.initial_indent = initial_indent - self.subsequent_indent = subsequent_indent - self.expand_tabs = expand_tabs - self.replace_whitespace = replace_whitespace - self.fix_sentence_endings = fix_sentence_endings - self.break_long_words = break_long_words - - - # -- Private methods ----------------------------------------------- - # (possibly useful for subclasses to override) - - def _munge_whitespace(self, text): - """_munge_whitespace(text : string) -> string - - Munge whitespace in text: expand tabs and convert all other - whitespace characters to spaces. Eg. " foo\tbar\n\nbaz" - becomes " foo bar baz". - """ - if self.expand_tabs: - text = text.expandtabs() - if self.replace_whitespace: - if isinstance(text, str): - text = text.translate(self.whitespace_trans) - elif isinstance(text, unicode): - text = text.translate(self.unicode_whitespace_trans) - return text - - - def _split(self, text): - """_split(text : string) -> [string] - - Split the text to wrap into indivisible chunks. Chunks are - not quite the same as words; see wrap_chunks() for full - details. As an example, the text - Look, goof-ball -- use the -b option! - breaks into the following chunks: - 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', - 'use', ' ', 'the', ' ', '-b', ' ', 'option!' - """ - chunks = self.wordsep_re.split(text) - chunks = filter(None, chunks) - return chunks - - def _fix_sentence_endings(self, chunks): - """_fix_sentence_endings(chunks : [string]) - - Correct for sentence endings buried in 'chunks'. Eg. when the - original text contains "... foo.\nBar ...", munge_whitespace() - and split() will convert that to [..., "foo.", " ", "Bar", ...] - which has one too few spaces; this method simply changes the one - space to two. - """ - i = 0 - pat = self.sentence_end_re - while i < len(chunks)-1: - if chunks[i+1] == " " and pat.search(chunks[i]): - chunks[i+1] = " " - i += 2 - else: - i += 1 - - def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): - """_handle_long_word(chunks : [string], - cur_line : [string], - cur_len : int, width : int) - - Handle a chunk of text (most likely a word, not whitespace) that - is too long to fit in any line. - """ - space_left = max(width - cur_len, 1) - - # If we're allowed to break long words, then do so: put as much - # of the next chunk onto the current line as will fit. - if self.break_long_words: - cur_line.append(reversed_chunks[-1][:space_left]) - reversed_chunks[-1] = reversed_chunks[-1][space_left:] - - # Otherwise, we have to preserve the long word intact. Only add - # it to the current line if there's nothing already there -- - # that minimizes how much we violate the width constraint. - elif not cur_line: - cur_line.append(reversed_chunks.pop()) - - # If we're not allowed to break long words, and there's already - # text on the current line, do nothing. Next time through the - # main loop of _wrap_chunks(), we'll wind up here again, but - # cur_len will be zero, so the next line will be entirely - # devoted to the long word that we can't handle right now. - - def _wrap_chunks(self, chunks): - """_wrap_chunks(chunks : [string]) -> [string] - - Wrap a sequence of text chunks and return a list of lines of - length 'self.width' or less. (If 'break_long_words' is false, - some lines may be longer than this.) Chunks correspond roughly - to words and the whitespace between them: each chunk is - indivisible (modulo 'break_long_words'), but a line break can - come between any two chunks. Chunks should not have internal - whitespace; ie. a chunk is either all whitespace or a "word". - Whitespace chunks will be removed from the beginning and end of - lines, but apart from that whitespace is preserved. - """ - lines = [] - if self.width <= 0: - raise ValueError("invalid width %r (must be > 0)" % self.width) - - # Arrange in reverse order so items can be efficiently popped - # from a stack of chucks. - chunks.reverse() - - while chunks: - - # Start the list of chunks that will make up the current line. - # cur_len is just the length of all the chunks in cur_line. - cur_line = [] - cur_len = 0 - - # Figure out which static string will prefix this line. - if lines: - indent = self.subsequent_indent - else: - indent = self.initial_indent - - # Maximum width for this line. - width = self.width - len(indent) - - # First chunk on line is whitespace -- drop it, unless this - # is the very beginning of the text (ie. no lines started yet). - if chunks[-1].strip() == '' and lines: - del chunks[-1] - - while chunks: - l = len(chunks[-1]) - - # Can at least squeeze this chunk onto the current line. - if cur_len + l <= width: - cur_line.append(chunks.pop()) - cur_len += l - - # Nope, this line is full. - else: - break - - # The current line is full, and the next chunk is too big to - # fit on *any* line (not just this one). - if chunks and len(chunks[-1]) > width: - self._handle_long_word(chunks, cur_line, cur_len, width) - - # If the last chunk on this line is all whitespace, drop it. - if cur_line and cur_line[-1].strip() == '': - del cur_line[-1] - - # Convert current line back to a string and store it in list - # of all lines (return value). - if cur_line: - lines.append(indent + ''.join(cur_line)) - - return lines - - - # -- Public interface ---------------------------------------------- - - def wrap(self, text): - """wrap(text : string) -> [string] - - Reformat the single paragraph in 'text' so it fits in lines of - no more than 'self.width' columns, and return a list of wrapped - lines. Tabs in 'text' are expanded with string.expandtabs(), - and all other whitespace characters (including newline) are - converted to space. - """ - text = self._munge_whitespace(text) - chunks = self._split(text) - if self.fix_sentence_endings: - self._fix_sentence_endings(chunks) - return self._wrap_chunks(chunks) - - def fill(self, text): - """fill(text : string) -> string - - Reformat the single paragraph in 'text' to fit in lines of no - more than 'self.width' columns, and return a new string - containing the entire wrapped paragraph. - """ - return "\n".join(self.wrap(text)) - - -# -- Convenience interface --------------------------------------------- - -def wrap(text, width=70, **kwargs): - """Wrap a single paragraph of text, returning a list of wrapped lines. - - Reformat the single paragraph in 'text' so it fits in lines of no - more than 'width' columns, and return a list of wrapped lines. By - default, tabs in 'text' are expanded with string.expandtabs(), and - all other whitespace characters (including newline) are converted to - space. See TextWrapper class for available keyword args to customize - wrapping behaviour. - """ - w = TextWrapper(width=width, **kwargs) - return w.wrap(text) - -def fill(text, width=70, **kwargs): - """Fill a single paragraph of text, returning a new string. - - Reformat the single paragraph in 'text' to fit in lines of no more - than 'width' columns, and return a new string containing the entire - wrapped paragraph. As with wrap(), tabs are expanded and other - whitespace characters converted to space. See TextWrapper class for - available keyword args to customize wrapping behaviour. - """ - w = TextWrapper(width=width, **kwargs) - return w.fill(text) - - -# -- Loosely related functionality ------------------------------------- - -_whitespace_only_re = re.compile('^[ \t]+$', re.MULTILINE) -_leading_whitespace_re = re.compile('(^[ \t]*)(?:[^ \t\n])', re.MULTILINE) - -def dedent(text): - """Remove any common leading whitespace from every line in `text`. - - This can be used to make triple-quoted strings line up with the left - edge of the display, while still presenting them in the source code - in indented form. - - Note that tabs and spaces are both treated as whitespace, but they - are not equal: the lines " hello" and "\thello" are - considered to have no common leading whitespace. (This behaviour is - new in Python 2.5; older versions of this module incorrectly - expanded tabs before searching for common leading whitespace.) - """ - # Look for the longest leading string of spaces and tabs common to - # all lines. - margin = None - text = _whitespace_only_re.sub('', text) - indents = _leading_whitespace_re.findall(text) - for indent in indents: - if margin is None: - margin = indent - - # Current line more deeply indented than previous winner: - # no change (previous winner is still on top). - elif indent.startswith(margin): - pass - - # Current line consistent with and no deeper than previous winner: - # it's the new winner. - elif margin.startswith(indent): - margin = indent - - # Current line and previous winner have no common whitespace: - # there is no margin. - else: - margin = "" - break - - # sanity check (testing/debugging only) - if 0 and margin: - for line in text.split("\n"): - assert not line or line.startswith(margin), \ - "line = %r, margin = %r" % (line, margin) - - if margin: - text = re.sub(r'(?m)^' + margin, '', text) - return text - -if __name__ == "__main__": - #print dedent("\tfoo\n\tbar") - #print dedent(" \thello there\n \t how are you?") - print dedent("Hello there.\n This is indented.") diff --git a/release-notes.html b/release-notes.html deleted file mode 100644 index a320092..0000000 --- a/release-notes.html +++ /dev/null @@ -1,343 +0,0 @@ - - - - Scour Release Notes - - - -

Scour Release Notes

- -

Copyright 2010, Jeff Schiller

- -
-
-

Version 0.26

-
-

2011-05-09

-
    -
  • Fix Bug 702423 to function well in the presence of multiple identical gradients and --disable-style-to-xml.
  • -
  • Fix Bug 722544 to properly optimize transformation matrices. Also optimize more things away in transformation specifications. (Thanks to Johan Sundström for the patch.)
  • -
  • Fix Bug 616150 to run faster using the --create-groups option.
  • -
  • Fix Bug 708515 to handle raster embedding better in the presence of file:// URLs.
  • -
  • Fix Bug 714717 to avoid deleting renderable CurveTo commands in paths, which happen to end where they started.
  • -
  • Per Bug 714727 and Bug 714720, Scour now deletes text attributes, including "text-align", from elements and groups of elements that only contain shapes. (Thanks to Jan Thor for the patches.)
  • -
  • Per Bug 714731, remove the default value of more SVG attributes. (Thanks to Jan Thor for the patch.)
  • -
  • Fix Bug 717826 to emit the correct line terminator (CR LF) in optimized SVG content on the version of Scour used in Inkscape on Windows.
  • -
  • Fix Bug 734933 to avoid deleting renderable LineTo commands in paths, which happen to end where they started, if their stroke-linecap property has the value "round".
  • -
  • Fix Bug 717254 to delete <defs> elements that become empty after unreferenced element removal. (Thanks to Jan Thor for the patch.)
  • -
  • Fix Bug 627372 to future-proof the parameter passing between Scour and Inkscape. (Thanks to Bernd Feige for the patch.)
  • -
  • Fix Bug 638764, which crashed Scour due to Python Issue 2531 regarding floating-point handling in ArcTo path commands. (Thanks to Walther for investigating this bug.)
  • -
  • Per Bug 654759, enable librsvg workarounds by default in Scour.
  • -
  • Added ID change and removal protection options per bug 492277: --protect-ids-noninkscape, --protect-ids-prefix, --protect-ids-list. (Thanks to Jan Thor for this patch.)
  • -
-
- -
-
-

Version 0.25

-
-

2010-07-11

-
    -
  • Fix Bug 541889 to parse polygon/polyline points missing whitespace/comma separating a negative value. Always output points attributes as comma-separated.
  • -
  • Fix Bug 519698 to properly parse move commands that have line segments.
  • -
  • Fix Bug 577940 to include stroke-dasharray into list of style properties turned into XML attributes.
  • -
  • Fix Bug 562784, typo in Inkscape description
  • -
  • Fix Bug 603988, do not commonize attributes if the element is referenced elsewhere.
  • -
  • Fix Bug 604000, correctly remove default overflow attributes.
  • -
  • Fix Bug 603994, fix parsing of <style> element contents when a CDATA is present
  • -
  • Fix Bug 583758, added a bit to the Inkscape help text saying that groups aren't collapsed if IDs are also not stripped.
  • -
  • Fix Bug 583458, another typo in the Inkscape help tab.
  • -
  • Fix Bug 594930, In a <switch>, require one level of <g> if there was a <g> in the file already. Otherwise, only the first subelement of the <g> is chosen and rendered.
  • -
  • Fix Bug 576958, "Viewbox option doesn't work when units are set", when renderer workarounds are disabled.
  • -
  • Added many options: --remove-metadata, --quiet, --enable-comment-stripping, --shorten-ids, --renderer-workaround.
  • -
-
- -
-
-

Version 0.24

-
-

2010-02-05

-
    -
  • Fix Bug 517064 to make XML well-formed again
  • -
  • Fix Bug 503750 fix Inkscape extension to correctly pass --enable-viewboxing
  • -
  • Fix Bug 511186 to allow comments outside of the root <svg> node
  • -
-
- -
-
-

Version 0.23

-
-

2010-01-04

-
    -
  • Fix Bug 482215 by using os.linesep to end lines
  • -
  • Fix unittests to run properly in Windows
  • -
  • Removed default scaling of image to 100%/100% and creating a viewBox. Added --enable-viewboxing option to explicitly turn that on
  • -
  • Fix Bug 503034 by only removing children of a group if the group itself has not been referenced anywhere else in the file
  • -
-
- -
-
-

Version 0.22

-
-

Nov 9th, 2009

-
    -
  • Fix Bug 449803 by ensuring input and output filenames differ.
  • -
  • Fix Bug 453737 by updated Inkscape's scour extension with a UI
  • -
  • Fix whitespace collapsing on non-textual elements that had xml:space="preserve"
  • -
  • Fix Bug 479669 to handle empty <style> elements.
  • -
-
- -
-
-

Version 0.21

-
-

Sep 27th, 2009

-
    -
  • Fix Bug 427309 by updated Scour inkscape extension file to include yocto_css.py
  • -
  • Fix Bug 435689 by properly preserving whitespace in XML serialization
  • -
  • Fix Bug 436569 by getting xlink:href prefix correct with invalid SVG
  • -
-
- -
-
-

Version 0.20

-
-

Aug 31st, 2009

-
    -
  • Fix Bug 368716 by implementing a really tiny CSS parser to find out if any style element have rules referencing gradients, filters, etc
  • -
  • Remove unused attributes from parent elements
  • -
  • Fix a bug with polygon/polyline point parsing if there was whitespace at the end
  • -
-
- -
-
-

Version 0.19

-
-

Aug 13th, 2009

-
    -
  • Fix XML serialization bug: xmlns:XXX prefixes not preserved when not in default namespace
  • -
  • Fix XML serialization bug: remapping to default namespace was not actually removing the old prefix
  • -
  • Move common attributes to ancestor elements
  • -
  • Fix Bug 412754: Elliptical arc commands must have comma/whitespace separating the coordinates
  • -
  • Scour lengths for svg x,y,width,height,*opacity,stroke-width,stroke-miterlimit
  • -
-
- -
-
-

Version 0.18

-
-

Aug 9th, 2009

-
    -
  • Remove attributes of gradients if they contain default values
  • -
  • Reduce bezier/quadratic (c/q) segments to their shorthand equivalents (s/t)
  • -
  • Move to a custom XML serialization such that id/xml:id is printed first (Thanks to Richard Hutch for the suggestion)
  • -
  • Added --indent option to specify indentation type (default='space', other options: 'none', 'tab')
  • -
-
- -
-
-

Version 0.17

-
-

Aug 3rd, 2009

-
    -
  • Only convert to #RRGGBB format if the color name will actually be shorter
  • -
  • Remove duplicate gradients
  • -
  • Remove empty q,a path segments
  • -
  • Scour polyline coordinates just like path/polygon
  • -
  • Scour lengths from most attributes
  • -
  • Remove redundant SVG namespace declarations and prefixes
  • -
-
- -
-
-

Version 0.16

-
-

July 30th, 2009

-
    -
  • Fix Bug 401628: Keep namespace declarations when using --keep-editor-data (Thanks YoNoSoyTu!)
  • -
  • Remove trailing zeros after decimal places for all path coordinates
  • -
  • Use scientific notation in path coordinates if that representation is shorter
  • -
  • Scour polygon coordinates just like path coordinates
  • -
  • Add XML prolog to scour output to ensure valid XML, added --strip-xml-prolog option
  • -
-
- -
-
-

Version 0.15

-
-

July 5th, 2009

-
    -
  • added --keep-editor-data command-line option
  • -
  • Fix Bug 395645: Keep all identified children inside a defs (Thanks Frederik!)
  • -
  • Fix Bug 395647: Do not remove closepath (Z) path segments
  • -
-
- -
-
-

Version 0.14

-
-

June 10th, 2009

-
    -
  • Collapse adjacent commands of the same type
  • -
  • Convert straight curves into line commands
  • -
  • Eliminate last segment in a polygon
  • -
  • Rework command-line argument parsing
  • -
  • Fix bug in embedRasters() caused by new command-line parsing
  • -
  • added --disable-embed-rasters command-line option
  • -
-
- -
-
-

Version 0.13

-
-

May 19th, 2009

-
    -
  • properly deal with fill="url(&quot;#foo&quot;)"
  • -
  • properly handle paths with more than 1 pair of coordinates in the first Move command
  • -
  • remove font/text styles from shape elements (font-weight, font-size, line-height, etc)
  • -
  • remove -inkscape-font-specification styles
  • -
  • added --set-precision argument to set the number of significant digits (defaults to 5 now)
  • -
  • collapse consecutive h,v coords/segments that go in the same direction
  • -
-
- -
-
-

Version 0.12

-
-

May 17th, 2009

-
    -
  • upgraded enthought's path parser to handle scientific notation in path coordinates
  • -
  • convert colors to #RRGGBB format
  • -
  • added option to disable color conversion
  • -
-
- -
-
-

Version 0.11

-
-

April 28th, 2009

-
    -
  • convert gradient stop offsets from percentages to float
  • -
  • convert gradient stop offsets to integers if possible (0 or 1)
  • -
  • fix bug in line-to-hv conversion
  • -
  • handle non-ASCII characters (Unicode)
  • -
  • remove empty line or curve segments from path
  • -
  • added option to prevent style-to-xml conversion
  • -
  • handle compressed svg (svgz) on the input and output
  • -
  • added total time taken to the report
  • -
  • Removed XML pretty printing because of this problem.
  • -
-
- -
-
-

Version 0.10

-
-

April 27th, 2009

-
    -
  • Remove path with empty d attributes
  • -
  • Sanitize path data (remove unnecessary whitespace)
  • -
  • Convert from absolute to relative path data
  • -
  • Remove trailing zeroes from path data
  • -
  • Limit to no more than 6 digits of precision
  • -
  • Remove empty line segments
  • -
  • Convert lines to horiz/vertical line segments where possible
  • -
  • Remove some more default styles (display:none, visibility:visible, overflow:visible, - marker:none)
  • -
-
- -
-
-

Version 0.09

-
-

April 25th, 2009

-
    -
  • Fix bug when removing stroke styles
  • -
  • Remove gradients that are only referenced by one other gradient
  • -
  • Added option to prevent group collapsing
  • -
  • Prevent groups with title/desc children from being collapsed
  • -
  • Remove stroke="none"
  • -
-
- -
-
-

Version 0.08

-
-

April 22nd, 2009

-
    -
  • Remove unnecessary nested <g> elements
  • -
  • Remove duplicate gradient stops (same offset, stop-color, stop-opacity)
  • -
  • Always keep fonts inside <defs>, always keep ids on fonts
  • -
  • made ID stripping optional (disabled by default)
  • -
-
- -
-
-

Version 0.07

-
-

April 15th, 2009

-
    -
  • moved all functionality into a module level function named 'scour' and began adding unit tests
  • -
  • prevent metadata from being removed if they contain only text nodes
  • -
  • Remove unreferenced pattern and gradient elements outside of defs
  • -
  • Removal of extra whitespace, pretty printing of XML
  • -
-
- -
-
-

Version 0.06

-
-

April 13th, 2009

-
    -
  • Prevent error when stroke-width property value has a unit
  • -
  • Convert width/height into a viewBox where possible
  • -
  • Convert all referenced rasters into base64 encoded URLs if the files can be found
  • -
-
- -
-
-

Version 0.05 and earlier

-
-

April 7th, 2009

-
    -
  • Removes unreferenced elements in a <defs>
  • -
  • Removes all inkscape, sodipodi, adobe elements
  • -
  • Removes all inkscape, sodipodi, adobe attributes
  • -
  • Remove all unused namespace declarations on the document element
  • -
  • Removes any empty <defs>, <metadata>, or <g> elements
  • -
  • Style fix-ups: -
    • Fixes any style properties like this: style="fill: url(#linearGradient1000) rgb(0, 0, 0);"
    • -
    • Removes any style property of: opacity: 1;
    • -
    • Removes any stroke properties when stroke=none or stroke-opacity=0 or stroke-width=0
    • -
    • Removes any fill properties when fill=none or fill-opacity=0
    • -
    • Removes all fill/stroke properties when opacity=0
    • -
    • Removes any stop-opacity: 1
    • -
    • Removes any fill-opacity: 1
    • -
    • Removes any stroke-opacity: 1
    • -
  • -
  • Convert style properties into SVG attributes
  • -
- -
- - - diff --git a/scour.inkscape.py b/scour.inkscape.py deleted file mode 100755 index 211d5b8..0000000 --- a/scour.inkscape.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import sys, inkex -from scour import scourString - -class ScourInkscape (inkex.Effect): - - def __init__(self): - inkex.Effect.__init__(self) - self.OptionParser.add_option("--tab", - action="store", type="string", - dest="tab") - self.OptionParser.add_option("--simplify-colors", type="inkbool", - action="store", dest="simple_colors", default=True, - help="won't convert all colors to #RRGGBB format") - self.OptionParser.add_option("--style-to-xml", type="inkbool", - action="store", dest="style_to_xml", default=True, - help="won't convert styles into XML attributes") - self.OptionParser.add_option("--group-collapsing", type="inkbool", - action="store", dest="group_collapse", default=True, - help="won't collapse elements") - self.OptionParser.add_option("--create-groups", type="inkbool", - action="store", dest="group_create", default=False, - help="create elements for runs of elements with identical attributes") - self.OptionParser.add_option("--enable-id-stripping", type="inkbool", - action="store", dest="strip_ids", default=False, - help="remove all un-referenced ID attributes") - self.OptionParser.add_option("--shorten-ids", type="inkbool", - action="store", dest="shorten_ids", default=False, - help="shorten all ID attributes to the least number of letters possible") - self.OptionParser.add_option("--embed-rasters", type="inkbool", - action="store", dest="embed_rasters", default=True, - help="won't embed rasters as base64-encoded data") - self.OptionParser.add_option("--keep-editor-data", type="inkbool", - action="store", dest="keep_editor_data", default=False, - help="won't remove Inkscape, Sodipodi or Adobe Illustrator elements and attributes") - self.OptionParser.add_option("--remove-metadata", type="inkbool", - action="store", dest="remove_metadata", default=False, - help="remove elements (which may contain license metadata etc.)") - self.OptionParser.add_option("--strip-xml-prolog", type="inkbool", - action="store", dest="strip_xml_prolog", default=False, - help="won't output the prolog") - self.OptionParser.add_option("-p", "--set-precision", - action="store", type=int, dest="digits", default=5, - help="set number of significant digits (default: %default)") - self.OptionParser.add_option("--indent", - action="store", type="string", dest="indent_type", default="space", - help="indentation of the output: none, space, tab (default: %default)") - self.OptionParser.add_option("--protect-ids-noninkscape", type="inkbool", - action="store", dest="protect_ids_noninkscape", default=False, - help="don't change IDs not ending with a digit") - self.OptionParser.add_option("--protect-ids-list", - action="store", type="string", dest="protect_ids_list", default=None, - help="don't change IDs given in a comma-separated list") - self.OptionParser.add_option("--protect-ids-prefix", - action="store", type="string", dest="protect_ids_prefix", default=None, - help="don't change IDs starting with the given prefix") - self.OptionParser.add_option("--enable-viewboxing", type="inkbool", - action="store", dest="enable_viewboxing", default=False, - help="changes document width/height to 100%/100% and creates viewbox coordinates") - self.OptionParser.add_option("--enable-comment-stripping", type="inkbool", - action="store", dest="strip_comments", default=False, - help="remove all comments") - self.OptionParser.add_option("--renderer-workaround", type="inkbool", - action="store", dest="renderer_workaround", default=False, - help="work around various renderer bugs (currently only librsvg)") - - def effect(self): - input = file(self.args[0], "r") - self.options.infilename = self.args[0] - sys.stdout.write(scourString(input.read(), self.options).encode("UTF-8")) - input.close() - sys.stdout.close() - - -if __name__ == '__main__': - e = ScourInkscape() - e.affect(output=False) diff --git a/scour.inx b/scour.inx deleted file mode 100644 index 895f446..0000000 --- a/scour.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - <_name>Optimized SVG Output - org.inkscape.output.scour - scour.py - svg_regex.py - yocto_css.py - - - true - true - true - true - true - false - false - false - true - false - false - 5 - - <_item value="space">Space - <_item value="tab">Tab - <_item value="none">None - - - - false - false - false - - - - - <_param name="instructions" type="description" xml:space="preserve">This extension optimizes the SVG file according to the following options: - * Shorten color names: convert all colors to #RRGGBB or #RGB format. - * Convert CSS attributes to XML attributes: convert styles from <style> tags and inline style="" declarations into XML attributes. - * Group collapsing: removes useless <g> elements, promoting their contents up one level. Requires "Remove unused ID names for elements" to be set. - * Create groups for similar attributes: create <g> elements for runs of elements having at least one attribute in common (e.g. fill color, stroke opacity, ...). - * Embed rasters: embed raster images as base64-encoded data URLs. - * Keep editor data: don't remove Inkscape, Sodipodi or Adobe Illustrator elements and attributes. - * Remove metadata: remove <metadata> tags along with all the information in them, which may include license metadata, alternate versions for non-SVG-enabled browsers, etc. - * Remove comments: remove <!-- --> tags. - * Work around renderer bugs: emits slightly larger SVG data, but works around a bug in librsvg's renderer, which is used in Eye of GNOME and other various applications. - * Enable viewboxing: size image to 100%/100% and introduce a viewBox. - * Number of significant digits for coords: all coordinates are output with that number of significant digits. For example, if 3 is specified, the coordinate 3.5153 is output as 3.51 and the coordinate 471.55 is output as 472. - * XML indentation (pretty-printing): either None for no indentation, Space to use one space per nesting level, or Tab to use one tab per nesting level. - - - <_param name="instructions" type="description" xml:space="preserve">Ids specific options: - * Remove unused ID names for elements: remove all unreferenced ID attributes. - * Shorten IDs: reduce the length of all ID attributes, assigning the shortest to the most-referenced elements. For instance, #linearGradient5621, referenced 100 times, can become #a. - * Preserve manually created ID names not ending with digits: usually, optimised SVG output removes these, but if they're needed for referencing (e.g. #middledot), you may use this option. - * Preserve these ID names, comma-separated: you can use this in conjunction with the other preserve options if you wish to preserve some more specific ID names. - * Preserve ID names starting with: usually, optimised SVG output removes all unused ID names, but if all of your preserved ID names start with the same prefix (e.g. #flag-mx, #flag-pt), you may use this option. - - - - .svg - image/svg+xml - <_filetypename>Optimized SVG (*.svg) - <_filetypetooltip>Scalable Vector Graphics - - - diff --git a/scour.py b/scour/scour.py similarity index 100% rename from scour.py rename to scour/scour.py diff --git a/svg_regex.py b/scour/svg_regex.py similarity index 100% rename from svg_regex.py rename to scour/svg_regex.py diff --git a/svg_transform.py b/scour/svg_transform.py similarity index 100% rename from svg_transform.py rename to scour/svg_transform.py diff --git a/yocto_css.py b/scour/yocto_css.py similarity index 100% rename from yocto_css.py rename to scour/yocto_css.py diff --git a/scra.py b/scra.py deleted file mode 100644 index fe5807f..0000000 --- a/scra.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Scour Web -# -# Copyright 2009 Jeff Schiller -# -# This file is part of Scour, http://www.codedread.com/scour/ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -from mod_python import apache -from mod_python import util -from scour import scourString -from optparse import OptionParser - -def form(req): - return """ - - - Scrape Your SVG Files - - - -
-

Scra.py uses Scour to clean SVG files of unnecessary elements and attributes attempting to reduce file size and complexity without a loss in visual quality. For full details, please see the Scour home page.

-

Paste the SVG file below:

- -

Or choose a SVG file to upload:

-

If you care about these things, update your options:

-
-
- Convert styles to XML attributes
- Collapse nested groups when possible
- Strip all unused id attributes
- Simplify colors to #RGB format
- Strip the <?xml ?> prolog
- - -
-

and then just click already!

-

For a more complete description of the options, see the corresponding scour page.

-
- - - """ - -# defaults -class ScourOptions: - simple_colors = True - style_to_xml = True - group_collapse = True - strip_ids = False - digits = 5 - embed_rasters = False - keep_editor_data = False - strip_xml_prolog = False - indent_type = "space" - -# params are the form elements (if a checkbox is unchecked it will not be present) -def fetch(req, indoc,**params): - req.content_type = "image/svg+xml" - fs = req.form - options = ScourOptions() - - # interpret form options - if not params.has_key('convertStyleToXml'): - options.style_to_xml = False - if not params.has_key('collapseGroups'): - options.group_collapse = False - if params.has_key('stripIds'): - options.strip_ids = True - if not params.has_key('simplifyColors'): - options.simple_colors = False - if params.has_key('stripXmlProlog'): - options.strip_xml_prolog = True - options.digits = int(params['digits']) - - fileitem = fs['upload'] - if fileitem.filename: - req.write(scourString(fileitem.file.read(), options)) - else: - req.write(scourString(indoc,options)) diff --git a/statistics.html b/statistics.html deleted file mode 100644 index d0ca1da..0000000 --- a/statistics.html +++ /dev/null @@ -1,388 +0,0 @@ - - - - Scour Statistics - - - - -

Scour Statistics

- -

Copyright 2009, Jeff Schiller

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilenameOriginal Size0.010.020.030.040.050.060.070.080.090.100.110.120.130.140.150.16
Degri_Energy_Saving_Lightbulb.svg13939013730398.50%13513296.95%13310795.49%13297895.40%N/AN/AN/AN/AN/AN/AN/AN/A12621390.55%8340359.83%8269659.33%8269659.33%7263752.11%7067350.70%7067350.70%
GusEinstein_Angel.svg61110960934399.71%60029798.23%58269195.35%58256295.33%55476290.78%58220995.27%58183495.21%58345695.47%58193795.23%34481356.42%34213555.99%34213555.99%28699846.96%28259846.24%28259846.24%
News_Paper.svg2364860236340399.94%232282298.22%231692597.97%231679697.97%N/AN/A231685797.97%231656097.96%231753798.00%231645997.95%132583756.06%131594455.65%131594455.65%107771245.57%106091344.86%106091344.86%
OperaMarketShareEEhover.svg56052455905999.74%55485998.99%55478498.98%55478498.98%55476298.97%55476298.97%55432198.89%N/AN/AN/AN/AN/AN/A30060853.63%30060853.63%24506743.72%23964242.75%23964242.75%
Simon_Printer_on_fire.svg378083687597.53%3438390.94%3140583.06%3127682.72%3127282.71%3127382.72%3103882.09%3182784.18%3132882.86%2473465.42%2395663.36%2395663.36%2200358.20%2185857.81%2185857.81%
Wave.svg964099551399.07%9551399.07%9551399.07%6126563.55%6126563.55%6123463.51%6125263.53%6108863.36%6108863.36%5885861.05%5898561.18%5898561.18%5847460.65%5741659.55%5741659.55%
Web20Map.svg582394831982.97%4537477.91%4029169.18%4016268.96%4206372.22%4206372.22%4272173.35%4505277.36%4425475.99%4425475.99%4313474.06%4313474.06%4313474.06%4313474.06%4313474.06%
acid.svg135141312097.08%1155585.50%967571.59%947670.12%951570.41%951570.41%941069.63%964771.39%949370.25%688350.93%638147.22%638147.22%579042.84%569742.16%569742.16%
apartment.svg159091312097.08%1155585.50%967571.59%947670.12%951570.41%951570.41%941069.63%964771.39%949370.25%688350.93%638147.22%638147.22%579042.84%569742.16%569742.16%
boom.svg380213495191.93%3423390.04%3430890.23%3417289.88%3537293.03%3536993.02%3519992.58%3628695.44%3628695.44%N/AN/AN/AN/AN/AN/A1628642.83%1628642.83%1628642.83%
dragonfly.svg67901867877299.96%66083997.32%66082697.32%66066697.30%66065997.30%66065697.30%66065197.30%66071397.30%66071397.30%N/AN/A60815189.56%60815189.56%60000088.36%60001188.36%60001088.36%
gimp.svg273792540792.80%1436152.45%1250045.66%1241945.36%1221444.61%1221144.60%1204543.99%1271546.44%1169842.73%1070639.10%1013637.02%1013637.02%1001036.56%1000136.53%1000136.53%
notification-audio-next.svg1029879971696.82%9899196.12%9899996.13%9885595.99%9885595.99%9880795.94%36853.58%39193.81%39193.81%34183.43%34183.32%34183.32%34183.32%34013.30%34013.30%
poster3.svg283647N/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/AN/A24372685.93%24372685.93%24019584.68%23974184.52%23974184.52%
strawberry.svg25591825088598.03%19000474.24%14895058.20%14882158.15%14760457.68%14760557.68%14618057.12%15106959.03%14692557.41%11222043.85%11170143.65%11170143.65%10397940.63%10356340.47%10356340.47%
wifi.svg149831436895.90%1087272.56%914361.02%901460.16%895159.74%894859.72%879258.68%914961.06%877858.59%704146.99%693046.25%693046.25%649843.37%647843.24%647843.24%
Median Reduction %98.03%96.12%95.35%89.88%90.78%93.02%82.09%84.18%82.86%59.83%55.99%55.99%45.57%44.05%44.05%
Mean Reduction %96.67%88.57%83.95%81.32%81.80%81.96%75.59%76.86%75.43%63.94%58.41%58.41%50.93%49.94%49.94%
- - - - diff --git a/statistics.xls b/statistics.xls deleted file mode 100644 index 31e0806168c4669e445575a6f6e46549981cb7a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70144 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 diff --git a/testcss.py b/testcss.py deleted file mode 100755 index 243ab35..0000000 --- a/testcss.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Test Harness for Scour -# -# Copyright 2010 Jeff Schiller -# -# This file is part of Scour, http://www.codedread.com/scour/ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -from yocto_css import parseCssString - -class Blank(unittest.TestCase): - def runTest(self): - r = parseCssString('') - self.assertEquals( len(r), 0, 'Blank string returned non-empty list') - self.assertEquals( type(r), type([]), 'Blank string returned non list') - -class ElementSelector(unittest.TestCase): - def runTest(self): - r = parseCssString('foo {}') - self.assertEquals( len(r), 1, 'Element selector not returned') - self.assertEquals( r[0]['selector'], 'foo', 'Selector for foo not returned') - self.assertEquals( len(r[0]['properties']), 0, 'Property list for foo not empty') - -class ElementSelectorWithProperty(unittest.TestCase): - def runTest(self): - r = parseCssString('foo { bar: baz}') - self.assertEquals( len(r), 1, 'Element selector not returned') - self.assertEquals( r[0]['selector'], 'foo', 'Selector for foo not returned') - self.assertEquals( len(r[0]['properties']), 1, 'Property list for foo did not have 1') - self.assertEquals( r[0]['properties']['bar'], 'baz', 'Property bar did not have baz value') - -if __name__ == '__main__': - unittest.main() diff --git a/testscour.py b/testscour.py deleted file mode 100755 index 0167875..0000000 --- a/testscour.py +++ /dev/null @@ -1,1370 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Test Harness for Scour -# -# Copyright 2010 Jeff Schiller -# Copyright 2010 Louis Simard -# -# This file is part of Scour, http://www.codedread.com/scour/ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest -import xml.dom.minidom -from svg_regex import svg_parser -from scour import scourXmlFile, scourString, parse_args, makeWellFormed - -SVGNS = 'http://www.w3.org/2000/svg' - -# I couldn't figure out how to get ElementTree to work with the following XPath -# "//*[namespace-uri()='http://example.com']" -# so I decided to use minidom and this helper function that performs a test on a given node -# and all its children -# func must return either True (if pass) or False (if fail) -def walkTree(elem, func): - if func(elem) == False: return False - for child in elem.childNodes: - if walkTree(child, func) == False: return False - return True - -class ScourOptions: - simple_colors = True - style_to_xml = True - group_collapse = True - strip_ids = False - digits = 5 - embed_rasters = True - keep_editor_data = False - strip_xml_prolog = False - indent_type = "space" - enable_viewboxing = False - shorten_ids = False - strip_comments = False - remove_metadata = False - group_create = False - -class NoInkscapeElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/sodipodi.svg').documentElement, - lambda e: e.namespaceURI != 'http://www.inkscape.org/namespaces/inkscape'), False, - 'Found Inkscape elements' ) - -class NoSodipodiElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/sodipodi.svg').documentElement, - lambda e: e.namespaceURI != 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'), False, - 'Found Sodipodi elements' ) - -class NoAdobeIllustratorElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/AdobeIllustrator/10.0/'), False, - 'Found Adobe Illustrator elements' ) -class NoAdobeGraphsElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/Graphs/1.0/'), False, - 'Found Adobe Graphs elements' ) -class NoAdobeSVGViewerElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/'), False, - 'Found Adobe SVG Viewer elements' ) -class NoAdobeVariablesElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/Variables/1.0/'), False, - 'Found Adobe Variables elements' ) -class NoAdobeSaveForWebElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/SaveForWeb/1.0/'), False, - 'Found Adobe Save For Web elements' ) -class NoAdobeExtensibilityElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/Extensibility/1.0/'), False, - 'Found Adobe Extensibility elements' ) -class NoAdobeFlowsElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/Flows/1.0/'), False, - 'Found Adobe Flows elements' ) -class NoAdobeImageReplacementElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/ImageReplacement/1.0/'), False, - 'Found Adobe Image Replacement elements' ) -class NoAdobeCustomElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/GenericCustomNamespace/1.0/'), False, - 'Found Adobe Custom elements' ) -class NoAdobeXPathElements(unittest.TestCase): - def runTest(self): - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/adobe.svg').documentElement, - lambda e: e.namespaceURI != 'http://ns.adobe.com/XPath/1.0/'), False, - 'Found Adobe XPath elements' ) - -class DoNotRemoveMetadataWithOnlyText(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/metadata-with-text.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'metadata')), 1, - 'Removed metadata element with only text child' ) - -class RemoveEmptyMetadataElement(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/empty-metadata.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'metadata')), 0, - 'Did not remove empty metadata element' ) - -class RemoveEmptyGElements(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/empty-g.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'g')), 1, - 'Did not remove empty g element' ) - -class RemoveUnreferencedPattern(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/unreferenced-pattern.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'pattern')), 0, - 'Unreferenced pattern not removed' ) - -class RemoveUnreferencedLinearGradient(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/unreferenced-linearGradient.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'linearGradient')), 0, - 'Unreferenced linearGradient not removed' ) - -class RemoveUnreferencedRadialGradient(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/unreferenced-radialGradient.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'radialradient')), 0, - 'Unreferenced radialGradient not removed' ) - -class RemoveUnreferencedElementInDefs(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/referenced-elements-1.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'rect')), 1, - 'Unreferenced rect left in defs' ) - -class DoNotRemoveChainedRefsInDefs(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/refs-in-defs.svg') - g = doc.getElementsByTagNameNS(SVGNS, 'g')[0] - self.assertEquals( g.childNodes.length >= 2, True, - 'Chained references not honored in defs' ) - -class KeepTitleInDefs(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/referenced-elements-1.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'title')), 1, - 'Title removed from in defs' ) - -class RemoveNestedDefs(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/nested-defs.svg') - allDefs = doc.getElementsByTagNameNS(SVGNS, 'defs') - self.assertEquals(len(allDefs), 1, 'More than one defs left in doc') - -class KeepUnreferencedIDsWhenEnabled(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/ids-to-strip.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'svg')[0].getAttribute('id'), 'boo', - ' ID stripped when it should be disabled' ) - -class RemoveUnreferencedIDsWhenEnabled(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/ids-to-strip.svg', - scour.parse_args(['--enable-id-stripping'])[0]) - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'svg')[0].getAttribute('id'), '', - ' ID not stripped' ) - -class RemoveUselessNestedGroups(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/nested-useless-groups.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'g')), 1, - 'Useless nested groups not removed' ) - -class DoNotRemoveUselessNestedGroups(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/nested-useless-groups.svg', - scour.parse_args(['--disable-group-collapsing'])[0]) - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'g')), 2, - 'Useless nested groups were removed despite --disable-group-collapsing' ) - -class DoNotRemoveNestedGroupsWithTitle(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/groups-with-title-desc.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'g')), 2, - 'Nested groups with title was removed' ) - -class DoNotRemoveNestedGroupsWithDesc(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/groups-with-title-desc.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'g')), 2, - 'Nested groups with desc was removed' ) - -class RemoveDuplicateLinearGradientStops(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/duplicate-gradient-stops.svg') - grad = doc.getElementsByTagNameNS(SVGNS, 'linearGradient') - self.assertEquals(len(grad[0].getElementsByTagNameNS(SVGNS, 'stop')), 3, - 'Duplicate linear gradient stops not removed' ) - -class RemoveDuplicateLinearGradientStopsPct(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/duplicate-gradient-stops-pct.svg') - grad = doc.getElementsByTagNameNS(SVGNS, 'linearGradient') - self.assertEquals(len(grad[0].getElementsByTagNameNS(SVGNS, 'stop')), 3, - 'Duplicate linear gradient stops with percentages not removed' ) - -class RemoveDuplicateRadialGradientStops(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/duplicate-gradient-stops.svg') - grad = doc.getElementsByTagNameNS(SVGNS, 'radialGradient') - self.assertEquals(len(grad[0].getElementsByTagNameNS(SVGNS, 'stop')), 3, - 'Duplicate radial gradient stops not removed' ) - -class NoSodipodiNamespaceDecl(unittest.TestCase): - def runTest(self): - attrs = scour.scourXmlFile('unittests/sodipodi.svg').documentElement.attributes - for i in range(len(attrs)): - self.assertNotEquals(attrs.item(i).nodeValue, - 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd', - 'Sodipodi namespace declaration found' ) - -class NoInkscapeNamespaceDecl(unittest.TestCase): - def runTest(self): - attrs = scour.scourXmlFile('unittests/inkscape.svg').documentElement.attributes - for i in range(len(attrs)): - self.assertNotEquals(attrs.item(i).nodeValue, - 'http://www.inkscape.org/namespaces/inkscape', - 'Inkscape namespace declaration found' ) - -class NoSodipodiAttributes(unittest.TestCase): - def runTest(self): - def findSodipodiAttr(elem): - attrs = elem.attributes - if attrs == None: return True - for i in range(len(attrs)): - if attrs.item(i).namespaceURI == 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd': - return False - return True - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/sodipodi.svg').documentElement, - findSodipodiAttr), False, - 'Found Sodipodi attributes' ) - -class NoInkscapeAttributes(unittest.TestCase): - def runTest(self): - def findInkscapeAttr(elem): - attrs = elem.attributes - if attrs == None: return True - for i in range(len(attrs)): - if attrs.item(i).namespaceURI == 'http://www.inkscape.org/namespaces/inkscape': - return False - return True - self.assertNotEquals(walkTree(scour.scourXmlFile('unittests/inkscape.svg').documentElement, - findInkscapeAttr), False, - 'Found Inkscape attributes' ) - -class KeepInkscapeNamespaceDeclarationsWhenKeepEditorData(unittest.TestCase): - def runTest(self): - options = ScourOptions - options.keep_editor_data = True - attrs = scour.scourXmlFile('unittests/inkscape.svg', options).documentElement.attributes - FoundNamespace = False - for i in range(len(attrs)): - if attrs.item(i).nodeValue == 'http://www.inkscape.org/namespaces/inkscape': - FoundNamespace = True - break - self.assertEquals(True, FoundNamespace, - "Did not find Inkscape namespace declaration when using --keep-editor-data") - return False - -class KeepSodipodiNamespaceDeclarationsWhenKeepEditorData(unittest.TestCase): - def runTest(self): - options = ScourOptions - options.keep_editor_data = True - attrs = scour.scourXmlFile('unittests/sodipodi.svg', options).documentElement.attributes - FoundNamespace = False - for i in range(len(attrs)): - if attrs.item(i).nodeValue == 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd': - FoundNamespace = True - break - self.assertEquals(True, FoundNamespace, - "Did not find Sodipodi namespace declaration when using --keep-editor-data") - return False - -class KeepReferencedFonts(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/referenced-font.svg') - fonts = doc.documentElement.getElementsByTagNameNS(SVGNS,'font') - self.assertEquals(len(fonts), 1, - 'Font wrongly removed from ' ) - -class ConvertStyleToAttrs(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('style'), '', - 'style attribute not emptied' ) - -class RemoveStrokeWhenStrokeTransparent(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke'), '', - 'stroke attribute not emptied when stroke opacity zero' ) - -class RemoveStrokeWidthWhenStrokeTransparent(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-width'), '', - 'stroke-width attribute not emptied when stroke opacity zero' ) - -class RemoveStrokeLinecapWhenStrokeTransparent(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-linecap'), '', - 'stroke-linecap attribute not emptied when stroke opacity zero' ) - -class RemoveStrokeLinejoinWhenStrokeTransparent(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-linejoin'), '', - 'stroke-linejoin attribute not emptied when stroke opacity zero' ) - -class RemoveStrokeDasharrayWhenStrokeTransparent(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-dasharray'), '', - 'stroke-dasharray attribute not emptied when stroke opacity zero' ) - -class RemoveStrokeDashoffsetWhenStrokeTransparent(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-transparent.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-dashoffset'), '', - 'stroke-dashoffset attribute not emptied when stroke opacity zero' ) - -class RemoveStrokeWhenStrokeWidthZero(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-nowidth.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke'), '', - 'stroke attribute not emptied when width zero' ) - -class RemoveStrokeOpacityWhenStrokeWidthZero(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-nowidth.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-opacity'), '', - 'stroke-opacity attribute not emptied when width zero' ) - -class RemoveStrokeLinecapWhenStrokeWidthZero(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-nowidth.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-linecap'), '', - 'stroke-linecap attribute not emptied when width zero' ) - -class RemoveStrokeLinejoinWhenStrokeWidthZero(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-nowidth.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-linejoin'), '', - 'stroke-linejoin attribute not emptied when width zero' ) - -class RemoveStrokeDasharrayWhenStrokeWidthZero(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-nowidth.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-dasharray'), '', - 'stroke-dasharray attribute not emptied when width zero' ) - -class RemoveStrokeDashoffsetWhenStrokeWidthZero(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-nowidth.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-dashoffset'), '', - 'stroke-dashoffset attribute not emptied when width zero' ) - -class RemoveStrokeWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke'), '', - 'stroke attribute not emptied when no stroke' ) - -class RemoveStrokeWidthWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-width'), '', - 'stroke-width attribute not emptied when no stroke' ) - -class RemoveStrokeOpacityWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-opacity'), '', - 'stroke-opacity attribute not emptied when no stroke' ) - -class RemoveStrokeLinecapWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-linecap'), '', - 'stroke-linecap attribute not emptied when no stroke' ) - -class RemoveStrokeLinejoinWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-linejoin'), '', - 'stroke-linejoin attribute not emptied when no stroke' ) - -class RemoveStrokeDasharrayWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-dasharray'), '', - 'stroke-dasharray attribute not emptied when no stroke' ) - -class RemoveStrokeDashoffsetWhenStrokeNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/stroke-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('stroke-dashoffset'), '', - 'stroke-dashoffset attribute not emptied when no stroke' ) - -class RemoveFillRuleWhenFillNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/fill-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('fill-rule'), '', - 'fill-rule attribute not emptied when no fill' ) - -class RemoveFillOpacityWhenFillNone(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/fill-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('fill-opacity'), '', - 'fill-opacity attribute not emptied when no fill' ) - -class ConvertFillPropertyToAttr(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/fill-none.svg', - scour.parse_args(['--disable-simplify-colors'])[0]) - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[1].getAttribute('fill'), 'black', - 'fill property not converted to XML attribute' ) - -class ConvertFillOpacityPropertyToAttr(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/fill-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[1].getAttribute('fill-opacity'), '.5', - 'fill-opacity property not converted to XML attribute' ) - -class ConvertFillRuleOpacityPropertyToAttr(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/fill-none.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'path')[1].getAttribute('fill-rule'), 'evenodd', - 'fill-rule property not converted to XML attribute' ) - -class CollapseSinglyReferencedGradients(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/collapse-gradients.svg') - self.assertEquals(len(doc.getElementsByTagNameNS(SVGNS, 'linearGradient')), 0, - 'Singly-referenced linear gradient not collapsed' ) - -class InheritGradientUnitsUponCollapsing(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/collapse-gradients.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'radialGradient')[0].getAttribute('gradientUnits'), - 'userSpaceOnUse', - 'gradientUnits not properly inherited when collapsing gradients' ) - -class OverrideGradientUnitsUponCollapsing(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/collapse-gradients-gradientUnits.svg') - self.assertEquals(doc.getElementsByTagNameNS(SVGNS, 'radialGradient')[0].getAttribute('gradientUnits'), '', - 'gradientUnits not properly overrode when collapsing gradients' ) - -class DoNotCollapseMultiplyReferencedGradients(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/dont-collapse-gradients.svg') - self.assertNotEquals(len(doc.getElementsByTagNameNS(SVGNS, 'linearGradient')), 0, - 'Multiply-referenced linear gradient collapsed' ) - -class RemoveTrailingZerosFromPath(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-truncate-zeros.svg') - path = doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d') - self.assertEquals(path[:4] == 'm300' and path[4] != '.', True, - 'Trailing zeros not removed from path data' ) - -class RemoveTrailingZerosFromPathAfterCalculation(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-truncate-zeros-calc.svg') - path = doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d') - self.assertEquals(path, 'm5.81 0h0.1', - 'Trailing zeros not removed from path data after calculation' ) - -class RemoveDelimiterBeforeNegativeCoordsInPath(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-truncate-zeros.svg') - path = doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d') - self.assertEquals(path[4], '-', - 'Delimiters not removed before negative coordinates in path data' ) - -class UseScientificNotationToShortenCoordsInPath(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-use-scientific-notation.svg') - path = doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d') - self.assertEquals(path, 'm1e4 0', - 'Not using scientific notation for path coord when representation is shorter') - -class ConvertAbsoluteToRelativePathCommands(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-abs-to-rel.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(path[1][0], 'v', - 'Absolute V command not converted to relative v command') - self.assertEquals(float(path[1][1][0]), -20.0, - 'Absolute V value not converted to relative v value') - -class RoundPathData(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-precision.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(float(path[0][1][0]), 100.0, - 'Not rounding down' ) - self.assertEquals(float(path[0][1][1]), 100.0, - 'Not rounding up' ) - -class LimitPrecisionInPathData(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-precision.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(float(path[1][1][0]), 100.01, - 'Not correctly limiting precision on path data' ) - -class RemoveEmptyLineSegmentsFromPath(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-line-optimize.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(path[4][0], 'z', - 'Did not remove an empty line segment from path' ) - -# Do not remove empty segments if round linecaps. -class DoNotRemoveEmptySegmentsFromPathWithRoundLineCaps(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-with-caps.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(len(path), 2, - 'Did not preserve empty segments when path had round linecaps' ) - -class ChangeLineToHorizontalLineSegmentInPath(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-line-optimize.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(path[1][0], 'h', - 'Did not change line to horizontal line segment in path' ) - self.assertEquals(float(path[1][1][0]), 200.0, - 'Did not calculate horizontal line segment in path correctly' ) - -class ChangeLineToVerticalLineSegmentInPath(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-line-optimize.svg') - path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d')) - self.assertEquals(path[2][0], 'v', - 'Did not change line to vertical line segment in path' ) - self.assertEquals(float(path[2][1][0]), 100.0, - 'Did not calculate vertical line segment in path correctly' ) - -class ChangeBezierToShorthandInPath(unittest.TestCase): - def runTest(self): - path = scour.scourXmlFile('unittests/path-bez-optimize.svg').getElementsByTagNameNS(SVGNS, 'path')[0] - self.assertEquals(path.getAttribute('d'), 'm10 100c50-50 50 50 100 0s50 50 100 0', - 'Did not change bezier curves into shorthand curve segments in path') - -class ChangeQuadToShorthandInPath(unittest.TestCase): - def runTest(self): - path = scour.scourXmlFile('unittests/path-quad-optimize.svg').getElementsByTagNameNS(SVGNS, 'path')[0] - self.assertEquals(path.getAttribute('d'), 'm10 100q50-50 100 0t100 0', - 'Did not change quadratic curves into shorthand curve segments in path') - -class HandleNonAsciiUtf8(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/utf8.svg') - desc = unicode(doc.getElementsByTagNameNS(SVGNS, 'desc')[0].firstChild.wholeText).strip() - self.assertEquals( desc, u'ú', - 'Did not handle non-ASCII characters' ) - -class HandleSciNoInPathData(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/path-sn.svg') - self.assertEquals( len(doc.getElementsByTagNameNS(SVGNS, 'path')), 1, - 'Did not handle scientific notation in path data' ) - -class TranslateRGBIntoHex(unittest.TestCase): - def runTest(self): - elem = scour.scourXmlFile('unittests/color-formats.svg').getElementsByTagNameNS(SVGNS, 'rect')[0] - self.assertEquals( elem.getAttribute('fill'), '#0f1011', - 'Not converting rgb into hex') - -class TranslateRGBPctIntoHex(unittest.TestCase): - def runTest(self): - elem = scour.scourXmlFile('unittests/color-formats.svg').getElementsByTagNameNS(SVGNS, 'stop')[0] - self.assertEquals( elem.getAttribute('stop-color'), '#7f0000', - 'Not converting rgb pct into hex') - -class TranslateColorNamesIntoHex(unittest.TestCase): - def runTest(self): - elem = scour.scourXmlFile('unittests/color-formats.svg').getElementsByTagNameNS(SVGNS, 'rect')[0] - self.assertEquals( elem.getAttribute('stroke'), '#a9a9a9', - 'Not converting standard color names into hex') - -class TranslateExtendedColorNamesIntoHex(unittest.TestCase): - def runTest(self): - elem = scour.scourXmlFile('unittests/color-formats.svg').getElementsByTagNameNS(SVGNS, 'solidColor')[0] - self.assertEquals( elem.getAttribute('solid-color'), '#fafad2', - 'Not converting extended color names into hex') - -class TranslateLongHexColorIntoShortHex(unittest.TestCase): - def runTest(self): - elem = scour.scourXmlFile('unittests/color-formats.svg').getElementsByTagNameNS(SVGNS, 'ellipse')[0] - self.assertEquals( elem.getAttribute('fill'), '#fff', - 'Not converting long hex color into short hex') - -class DoNotConvertShortColorNames(unittest.TestCase): - def runTest(self): - elem = scour.scourXmlFile('unittests/dont-convert-short-color-names.svg').getElementsByTagNameNS(SVGNS, 'rect')[0] - self.assertEquals( 'red', elem.getAttribute('fill'), - 'Converted short color name to longer hex string') - -class AllowQuotEntitiesInUrl(unittest.TestCase): - def runTest(self): - grads = scour.scourXmlFile('unittests/quot-in-url.svg').getElementsByTagNameNS(SVGNS, 'linearGradient') - self.assertEquals( len(grads), 1, - 'Removed referenced gradient when " was in the url') - -class RemoveFontStylesFromNonTextShapes(unittest.TestCase): - def runTest(self): - r = scour.scourXmlFile('unittests/font-styles.svg').getElementsByTagNameNS(SVGNS, 'rect')[0] - self.assertEquals( r.getAttribute('font-size'), '', - 'font-size not removed from rect' ) - -class CollapseConsecutiveHLinesSegments(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/consecutive-hlines.svg').getElementsByTagNameNS(SVGNS, 'path')[0] - self.assertEquals( p.getAttribute('d'), 'm100 100h200v100h-200z', - 'Did not collapse consecutive hlines segments') - -class CollapseConsecutiveHLinesCoords(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/consecutive-hlines.svg').getElementsByTagNameNS(SVGNS, 'path')[1] - self.assertEquals( p.getAttribute('d'), 'm100 300h200v100h-200z', - 'Did not collapse consecutive hlines coordinates') - -class DoNotCollapseConsecutiveHLinesSegsWithDifferingSigns(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/consecutive-hlines.svg').getElementsByTagNameNS(SVGNS, 'path')[2] - self.assertEquals( p.getAttribute('d'), 'm100 500h300-100v100h-200z', - 'Collapsed consecutive hlines segments with differing signs') - -class ConvertStraightCurvesToLines(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/straight-curve.svg').getElementsByTagNameNS(SVGNS, 'path')[0] - self.assertEquals(p.getAttribute('d'), 'm10 10l40 40 40-40z', - 'Did not convert straight curves into lines') - -class RemoveUnnecessaryPolygonEndPoint(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polygon.svg').getElementsByTagNameNS(SVGNS, 'polygon')[0] - self.assertEquals(p.getAttribute('points'), '50 50 150 50 150 150 50 150', - 'Unnecessary polygon end point not removed' ) - -class DoNotRemovePolgonLastPoint(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polygon.svg').getElementsByTagNameNS(SVGNS, 'polygon')[1] - self.assertEquals(p.getAttribute('points'), '200 50 300 50 300 150 200 150', - 'Last point of polygon removed' ) - -class ScourPolygonCoordsSciNo(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polygon-coord.svg').getElementsByTagNameNS(SVGNS, 'polygon')[0] - self.assertEquals(p.getAttribute('points'), '1e4 50', - 'Polygon coordinates not scoured') - -class ScourPolylineCoordsSciNo(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polyline-coord.svg').getElementsByTagNameNS(SVGNS, 'polyline')[0] - self.assertEquals(p.getAttribute('points'), '1e4 50', - 'Polyline coordinates not scoured') - -class ScourPolygonNegativeCoords(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polygon-coord-neg.svg').getElementsByTagNameNS(SVGNS, 'polygon')[0] - # points="100,-100,100-100,100-100-100,-100-100,200" /> - self.assertEquals(p.getAttribute('points'), '100 -100 100 -100 100 -100 -100 -100 -100 200', - 'Negative polygon coordinates not properly parsed') - -class ScourPolylineNegativeCoords(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polyline-coord-neg.svg').getElementsByTagNameNS(SVGNS, 'polyline')[0] - self.assertEquals(p.getAttribute('points'), '100 -100 100 -100 100 -100 -100 -100 -100 200', - 'Negative polyline coordinates not properly parsed') - -class ScourPolygonNegativeCoordFirst(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polygon-coord-neg-first.svg').getElementsByTagNameNS(SVGNS, 'polygon')[0] - # points="-100,-100,100-100,100-100-100,-100-100,200" /> - self.assertEquals(p.getAttribute('points'), '-100 -100 100 -100 100 -100 -100 -100 -100 200', - 'Negative polygon coordinates not properly parsed') - -class ScourPolylineNegativeCoordFirst(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/polyline-coord-neg-first.svg').getElementsByTagNameNS(SVGNS, 'polyline')[0] - self.assertEquals(p.getAttribute('points'), '-100 -100 100 -100 100 -100 -100 -100 -100 200', - 'Negative polyline coordinates not properly parsed') - -class DoNotRemoveGroupsWithIDsInDefs(unittest.TestCase): - def runTest(self): - f = scour.scourXmlFile('unittests/important-groups-in-defs.svg') - self.assertEquals(len(f.getElementsByTagNameNS(SVGNS, 'linearGradient')), 1, - 'Group in defs with id\'ed element removed') - -class AlwaysKeepClosePathSegments(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/path-with-closepath.svg').getElementsByTagNameNS(SVGNS, 'path')[0] - self.assertEquals(p.getAttribute('d'), 'm10 10h100v100h-100z', - 'Path with closepath not preserved') - -class RemoveDuplicateLinearGradients(unittest.TestCase): - def runTest(self): - svgdoc = scour.scourXmlFile('unittests/remove-duplicate-gradients.svg') - lingrads = svgdoc.getElementsByTagNameNS(SVGNS, 'linearGradient') - self.assertEquals(1, lingrads.length, - 'Duplicate linear gradient not removed') - -class RereferenceForLinearGradient(unittest.TestCase): - def runTest(self): - svgdoc = scour.scourXmlFile('unittests/remove-duplicate-gradients.svg') - rects = svgdoc.getElementsByTagNameNS(SVGNS, 'rect') - self.assertEquals(rects[0].getAttribute('fill'), rects[1].getAttribute('stroke'), - 'Rect not changed after removing duplicate linear gradient') - self.assertEquals(rects[0].getAttribute('fill'), rects[4].getAttribute('fill'), - 'Rect not changed after removing duplicate linear gradient') - -class RemoveDuplicateRadialGradients(unittest.TestCase): - def runTest(self): - svgdoc = scour.scourXmlFile('unittests/remove-duplicate-gradients.svg') - radgrads = svgdoc.getElementsByTagNameNS(SVGNS, 'radialGradient') - self.assertEquals(1, radgrads.length, - 'Duplicate radial gradient not removed') - -class RereferenceForRadialGradient(unittest.TestCase): - def runTest(self): - svgdoc = scour.scourXmlFile('unittests/remove-duplicate-gradients.svg') - rects = svgdoc.getElementsByTagNameNS(SVGNS, 'rect') - self.assertEquals(rects[2].getAttribute('stroke'), rects[3].getAttribute('fill'), - 'Rect not changed after removing duplicate radial gradient') - -class CollapseSamePathPoints(unittest.TestCase): - def runTest(self): - p = scour.scourXmlFile('unittests/collapse-same-path-points.svg').getElementsByTagNameNS(SVGNS, 'path')[0]; - self.assertEquals(p.getAttribute('d'), "m100 100l100.12 100.12c14.88 4.88-15.12-5.12 0 0z", - 'Did not collapse same path points') - -class ScourUnitlessLengths(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/scour-lengths.svg') - r = doc.getElementsByTagNameNS(SVGNS, 'rect')[0]; - svg = doc.documentElement - self.assertEquals(svg.getAttribute('x'), '1', - 'Did not scour x attribute of svg element with unitless number') - self.assertEquals(r.getAttribute('x'), '123.46', - 'Did not scour x attribute of rect with unitless number') - self.assertEquals(r.getAttribute('y'), '123', - 'Did not scour y attribute of rect unitless number') - self.assertEquals(r.getAttribute('width'), '300', - 'Did not scour width attribute of rect with unitless number') - self.assertEquals(r.getAttribute('height'), '100', - 'Did not scour height attribute of rect with unitless number') - -class ScourLengthsWithUnits(unittest.TestCase): - def runTest(self): - r = scour.scourXmlFile('unittests/scour-lengths.svg').getElementsByTagNameNS(SVGNS, 'rect')[1]; - self.assertEquals(r.getAttribute('x'), '123.46px', - 'Did not scour x attribute with unit') - self.assertEquals(r.getAttribute('y'), '35ex', - 'Did not scour y attribute with unit') - self.assertEquals(r.getAttribute('width'), '300pt', - 'Did not scour width attribute with unit') - self.assertEquals(r.getAttribute('height'), '50%', - 'Did not scour height attribute with unit') - -class RemoveRedundantSvgNamespaceDeclaration(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/redundant-svg-namespace.svg').documentElement - self.assertNotEquals( doc.getAttribute('xmlns:svg'), 'http://www.w3.org/2000/svg', - 'Redundant svg namespace declaration not removed') - -class RemoveRedundantSvgNamespacePrefix(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/redundant-svg-namespace.svg').documentElement - r = doc.getElementsByTagNameNS(SVGNS, 'rect')[1] - self.assertEquals( r.tagName, 'rect', - 'Redundant svg: prefix not removed') - - -class RemoveDefaultGradX1Value(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[0] - self.assertEquals( g.getAttribute('x1'), '', - 'x1="0" not removed') - -class RemoveDefaultGradY1Value(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[0] - self.assertEquals( g.getAttribute('y1'), '', - 'y1="0" not removed') - -class RemoveDefaultGradX2Value(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[0] - self.assertEquals( g.getAttribute('x2'), '', - 'x2="100%" not removed') - -class RemoveDefaultGradY2Value(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[0] - self.assertEquals( g.getAttribute('y2'), '', - 'y2="0" not removed') - -class RemoveDefaultGradGradientUnitsValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[0] - self.assertEquals( g.getAttribute('gradientUnits'), '', - 'gradientUnits="objectBoundingBox" not removed') - -class RemoveDefaultGradSpreadMethodValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[0] - self.assertEquals( g.getAttribute('spreadMethod'), '', - 'spreadMethod="pad" not removed') - -class RemoveDefaultGradCXValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'radialGradient')[0] - self.assertEquals( g.getAttribute('cx'), '', - 'cx="50%" not removed') - -class RemoveDefaultGradCYValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'radialGradient')[0] - self.assertEquals( g.getAttribute('cy'), '', - 'cy="50%" not removed') - -class RemoveDefaultGradRValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'radialGradient')[0] - self.assertEquals( g.getAttribute('r'), '', - 'r="50%" not removed') - -class RemoveDefaultGradFXValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'radialGradient')[0] - self.assertEquals( g.getAttribute('fx'), '', - 'fx matching cx not removed') - -class RemoveDefaultGradFYValue(unittest.TestCase): - def runTest(self): - g = scour.scourXmlFile('unittests/gradient-default-attrs.svg').getElementsByTagNameNS(SVGNS, 'radialGradient')[0] - self.assertEquals( g.getAttribute('fy'), '', - 'fy matching cy not removed') - -class CDATAInXml(unittest.TestCase): - def runTest(self): - lines = scour.scourString(open('unittests/cdata.svg').read()).splitlines() - self.assertEquals( lines[3], - " alert('pb&j');", - 'CDATA did not come out correctly') - -class WellFormedXMLLesserThanInAttrValue(unittest.TestCase): - def runTest(self): - wellformed = scour.scourString(open('unittests/xml-well-formed.svg').read()) - self.assert_( wellformed.find('unicode="<"') != -1, - "Improperly serialized < in attribute value") - -class WellFormedXMLAmpersandInAttrValue(unittest.TestCase): - def runTest(self): - wellformed = scour.scourString(open('unittests/xml-well-formed.svg').read()) - self.assert_( wellformed.find('unicode="&"') != -1, - 'Improperly serialized & in attribute value' ) - -class WellFormedXMLLesserThanInTextContent(unittest.TestCase): - def runTest(self): - wellformed = scour.scourString(open('unittests/xml-well-formed.svg').read()) - self.assert_( wellformed.find('2 < 5') != -1, - 'Improperly serialized < in text content') - -class WellFormedXMLAmpersandInTextContent(unittest.TestCase): - def runTest(self): - wellformed = scour.scourString(open('unittests/xml-well-formed.svg').read()) - self.assert_( wellformed.find('Peanut Butter & Jelly') != -1, - 'Improperly serialized & in text content') - -class WellFormedXMLNamespacePrefix(unittest.TestCase): - def runTest(self): - wellformed = scour.scourString(open('unittests/xml-well-formed.svg').read()) - self.assert_( wellformed.find('xmlns:foo=') != -1, - 'Improperly serialized namespace prefix declarations') - -class NamespaceDeclPrefixesInXMLWhenNotInDefaultNamespace(unittest.TestCase): - def runTest(self): - xmlstring = scour.scourString(open('unittests/xml-ns-decl.svg').read()) - self.assert_( xmlstring.find('xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"') != -1, - 'Improperly serialized namespace prefix declarations when not in default namespace') - -class MoveSVGElementsToDefaultNamespace(unittest.TestCase): - def runTest(self): - xmlstring = scour.scourString(open('unittests/xml-ns-decl.svg').read()) - self.assert_( xmlstring.find(' - - This is some messed-up markup - -'''.splitlines() - for i in range(4): - self.assertEquals( s[i], c[i], - 'Whitespace not preserved for line ' + str(i)) - -class DoNotPrettyPrintWhenNestedWhitespacePreserved(unittest.TestCase): - def runTest(self): - s = scour.scourString(open('unittests/whitespace-nested.svg').read()).splitlines() - c = ''' - - Use bold text - -'''.splitlines() - for i in range(4): - self.assertEquals( s[i], c[i], - 'Whitespace not preserved when nested for line ' + str(i)) - -class GetAttrPrefixRight(unittest.TestCase): - def runTest(self): - grad = scour.scourXmlFile('unittests/xml-namespace-attrs.svg').getElementsByTagNameNS(SVGNS, 'linearGradient')[1] - self.assertEquals( grad.getAttributeNS('http://www.w3.org/1999/xlink', 'href'), '#linearGradient841', - 'Did not get xlink:href prefix right') - -class EnsurePreserveWhitespaceOnNonTextElements(unittest.TestCase): - def runTest(self): - s = scour.scourString(open('unittests/no-collapse-lines.svg').read()) - self.assertEquals( len(s.splitlines()), 6, - 'Did not properly preserve whitespace on elements even if they were not textual') - -class HandleEmptyStyleElement(unittest.TestCase): - def runTest(self): - try: - styles = scour.scourXmlFile('unittests/empty-style.svg').getElementsByTagNameNS(SVGNS, 'style') - fail = len(styles) != 1 - except AttributeError: - fail = True - self.assertEquals( fail, False, - 'Could not handle an empty style element') - -class EnsureLineEndings(unittest.TestCase): - def runTest(self): - s = scour.scourString(open('unittests/whitespace-important.svg').read()) - self.assertEquals( len(s.splitlines()), 4, - 'Did not output line ending character correctly') - -class XmlEntities(unittest.TestCase): - def runTest(self): - self.assertEquals( scour.makeWellFormed('<>&"\''), '<>&"'', - 'Incorrectly translated XML entities') - -class DoNotStripCommentsOutsideOfRoot(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/comments.svg') - self.assertEquals( doc.childNodes.length, 4, - 'Did not include all comment children outside of root') - self.assertEquals( doc.childNodes[0].nodeType, 8, 'First node not a comment') - self.assertEquals( doc.childNodes[1].nodeType, 8, 'Second node not a comment') - self.assertEquals( doc.childNodes[3].nodeType, 8, 'Fourth node not a comment') - -class DoNotStripDoctype(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/doctype.svg') - self.assertEquals( doc.childNodes.length, 3, - 'Did not include the DOCROOT') - self.assertEquals( doc.childNodes[0].nodeType, 8, 'First node not a comment') - self.assertEquals( doc.childNodes[1].nodeType, 10, 'Second node not a doctype') - self.assertEquals( doc.childNodes[2].nodeType, 1, 'Third node not the root node') - -class PathImplicitLineWithMoveCommands(unittest.TestCase): - def runTest(self): - path = scour.scourXmlFile('unittests/path-implicit-line.svg').getElementsByTagNameNS(SVGNS, 'path')[0] - self.assertEquals( path.getAttribute('d'), "m100 100v100m200-100h-200m200 100v-100", - "Implicit line segments after move not preserved") - -class RemoveMetadataOption(unittest.TestCase): - def runTest(self): - doc = scour.scourXmlFile('unittests/full-metadata.svg', - scour.parse_args(['--remove-metadata'])[0]) - self.assertEquals(doc.childNodes.length, 1, - 'Did not remove tag with --remove-metadata') - -class EnableCommentStrippingOption(unittest.TestCase): - def runTest(self): - docStr = file('unittests/comment-beside-xml-decl.svg').read() - docStr = scour.scourString(docStr, - scour.parse_args(['--enable-comment-stripping'])[0]) - self.assertEquals(docStr.find(' - - - - - - diff --git a/unittests/comments.svg b/unittests/comments.svg deleted file mode 100644 index 06a75f2..0000000 --- a/unittests/comments.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/commonized-referenced-elements.svg b/unittests/commonized-referenced-elements.svg deleted file mode 100644 index 3a152fb..0000000 --- a/unittests/commonized-referenced-elements.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/unittests/consecutive-hlines.svg b/unittests/consecutive-hlines.svg deleted file mode 100644 index caae623..0000000 --- a/unittests/consecutive-hlines.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/css-reference.svg b/unittests/css-reference.svg deleted file mode 100644 index 6330c60..0000000 --- a/unittests/css-reference.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/unittests/doctype.svg b/unittests/doctype.svg deleted file mode 100644 index d19e074..0000000 --- a/unittests/doctype.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - -]> - diff --git a/unittests/dont-collapse-gradients.svg b/unittests/dont-collapse-gradients.svg deleted file mode 100644 index 00b58f5..0000000 --- a/unittests/dont-collapse-gradients.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/unittests/dont-convert-short-color-names.svg b/unittests/dont-convert-short-color-names.svg deleted file mode 100644 index cbcece7..0000000 --- a/unittests/dont-convert-short-color-names.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/duplicate-gradient-stops-pct.svg b/unittests/duplicate-gradient-stops-pct.svg deleted file mode 100644 index 43c99c4..0000000 --- a/unittests/duplicate-gradient-stops-pct.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/unittests/duplicate-gradient-stops.svg b/unittests/duplicate-gradient-stops.svg deleted file mode 100644 index 4629bd6..0000000 --- a/unittests/duplicate-gradient-stops.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/unittests/duplicate-gradients-update-style.svg b/unittests/duplicate-gradients-update-style.svg deleted file mode 100644 index c28070c..0000000 --- a/unittests/duplicate-gradients-update-style.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/unittests/empty-g.svg b/unittests/empty-g.svg deleted file mode 100644 index ccb7355..0000000 --- a/unittests/empty-g.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/unittests/empty-metadata.svg b/unittests/empty-metadata.svg deleted file mode 100644 index ca3c31f..0000000 --- a/unittests/empty-metadata.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/unittests/empty-style.svg b/unittests/empty-style.svg deleted file mode 100644 index a2d2afd..0000000 --- a/unittests/empty-style.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/fill-none.svg b/unittests/fill-none.svg deleted file mode 100644 index 6442c90..0000000 --- a/unittests/fill-none.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/font-styles.svg b/unittests/font-styles.svg deleted file mode 100644 index e4120df..0000000 --- a/unittests/font-styles.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/full-metadata.svg b/unittests/full-metadata.svg deleted file mode 100644 index f67e01d..0000000 --- a/unittests/full-metadata.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - No One - - - - - - diff --git a/unittests/gradient-default-attrs.svg b/unittests/gradient-default-attrs.svg deleted file mode 100644 index 36fd0e7..0000000 --- a/unittests/gradient-default-attrs.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/unittests/group-creation.svg b/unittests/group-creation.svg deleted file mode 100644 index 96776c0..0000000 --- a/unittests/group-creation.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/group-no-creation.svg b/unittests/group-no-creation.svg deleted file mode 100644 index bea6419..0000000 --- a/unittests/group-no-creation.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/groups-in-switch-with-id.svg b/unittests/groups-in-switch-with-id.svg deleted file mode 100644 index 317cfcc..0000000 --- a/unittests/groups-in-switch-with-id.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/unittests/groups-in-switch.svg b/unittests/groups-in-switch.svg deleted file mode 100644 index 96394fd..0000000 --- a/unittests/groups-in-switch.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/unittests/groups-with-title-desc.svg b/unittests/groups-with-title-desc.svg deleted file mode 100644 index 7983dc0..0000000 --- a/unittests/groups-with-title-desc.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Group 1 - - - - - Group 1 - - - - diff --git a/unittests/ids-to-strip.svg b/unittests/ids-to-strip.svg deleted file mode 100644 index 1ac59bc..0000000 --- a/unittests/ids-to-strip.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - Fooey - - - - - - - diff --git a/unittests/important-groups-in-defs.svg b/unittests/important-groups-in-defs.svg deleted file mode 100644 index 18ba1df..0000000 --- a/unittests/important-groups-in-defs.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/unittests/inkscape.svg b/unittests/inkscape.svg deleted file mode 100644 index a51ad49..0000000 --- a/unittests/inkscape.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/unittests/metadata-with-text.svg b/unittests/metadata-with-text.svg deleted file mode 100644 index 6149b68..0000000 --- a/unittests/metadata-with-text.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - This is a metadata element with only text node children - diff --git a/unittests/move-common-attributes-to-grandparent.svg b/unittests/move-common-attributes-to-grandparent.svg deleted file mode 100644 index 4e202bd..0000000 --- a/unittests/move-common-attributes-to-grandparent.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/unittests/move-common-attributes-to-parent.svg b/unittests/move-common-attributes-to-parent.svg deleted file mode 100644 index f390c89..0000000 --- a/unittests/move-common-attributes-to-parent.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - -Hello -World! -Goodbye -Cruel World! - - diff --git a/unittests/nested-defs.svg b/unittests/nested-defs.svg deleted file mode 100644 index 7091985..0000000 --- a/unittests/nested-defs.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/unittests/nested-useless-groups.svg b/unittests/nested-useless-groups.svg deleted file mode 100644 index 73b5f88..0000000 --- a/unittests/nested-useless-groups.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/unittests/no-collapse-lines.svg b/unittests/no-collapse-lines.svg deleted file mode 100644 index 85da385..0000000 --- a/unittests/no-collapse-lines.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/unittests/overflow-marker.svg b/unittests/overflow-marker.svg deleted file mode 100644 index ec068d9..0000000 --- a/unittests/overflow-marker.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/unittests/overflow-svg.svg b/unittests/overflow-svg.svg deleted file mode 100644 index 8830a80..0000000 --- a/unittests/overflow-svg.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/unittests/path-abs-to-rel.svg b/unittests/path-abs-to-rel.svg deleted file mode 100644 index c9cc803..0000000 --- a/unittests/path-abs-to-rel.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-bez-optimize.svg b/unittests/path-bez-optimize.svg deleted file mode 100644 index 97bfdd1..0000000 --- a/unittests/path-bez-optimize.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-elliptical-arc-parsing.svg b/unittests/path-elliptical-arc-parsing.svg deleted file mode 100644 index 77a8cbd..0000000 --- a/unittests/path-elliptical-arc-parsing.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-empty-move.svg b/unittests/path-empty-move.svg deleted file mode 100644 index d3b63d7..0000000 --- a/unittests/path-empty-move.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/path-implicit-line.svg b/unittests/path-implicit-line.svg deleted file mode 100644 index a42848e..0000000 --- a/unittests/path-implicit-line.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-line-optimize.svg b/unittests/path-line-optimize.svg deleted file mode 100644 index 13cc139..0000000 --- a/unittests/path-line-optimize.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-precision.svg b/unittests/path-precision.svg deleted file mode 100644 index 8e1e267..0000000 --- a/unittests/path-precision.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-quad-optimize.svg b/unittests/path-quad-optimize.svg deleted file mode 100644 index bbe3bc9..0000000 --- a/unittests/path-quad-optimize.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-simple-triangle.svg b/unittests/path-simple-triangle.svg deleted file mode 100644 index 94ab17e..0000000 --- a/unittests/path-simple-triangle.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/unittests/path-sn.svg b/unittests/path-sn.svg deleted file mode 100644 index 0b9f7d2..0000000 --- a/unittests/path-sn.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-truncate-zeros-calc.svg b/unittests/path-truncate-zeros-calc.svg deleted file mode 100644 index c889fff..0000000 --- a/unittests/path-truncate-zeros-calc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-truncate-zeros.svg b/unittests/path-truncate-zeros.svg deleted file mode 100644 index ad1c6d5..0000000 --- a/unittests/path-truncate-zeros.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-use-scientific-notation.svg b/unittests/path-use-scientific-notation.svg deleted file mode 100644 index afbbf05..0000000 --- a/unittests/path-use-scientific-notation.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-with-caps.svg b/unittests/path-with-caps.svg deleted file mode 100644 index 0e7ab1a..0000000 --- a/unittests/path-with-caps.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/path-with-closepath.svg b/unittests/path-with-closepath.svg deleted file mode 100644 index 80858ca..0000000 --- a/unittests/path-with-closepath.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/polygon-coord-neg-first.svg b/unittests/polygon-coord-neg-first.svg deleted file mode 100644 index 9f87a3e..0000000 --- a/unittests/polygon-coord-neg-first.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/polygon-coord-neg.svg b/unittests/polygon-coord-neg.svg deleted file mode 100644 index 73fe0b9..0000000 --- a/unittests/polygon-coord-neg.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/polygon-coord.svg b/unittests/polygon-coord.svg deleted file mode 100644 index 15940d4..0000000 --- a/unittests/polygon-coord.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/polygon.svg b/unittests/polygon.svg deleted file mode 100644 index d927a00..0000000 --- a/unittests/polygon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/polyline-coord-neg-first.svg b/unittests/polyline-coord-neg-first.svg deleted file mode 100644 index 41d1981..0000000 --- a/unittests/polyline-coord-neg-first.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/polyline-coord-neg.svg b/unittests/polyline-coord-neg.svg deleted file mode 100644 index da82dad..0000000 --- a/unittests/polyline-coord-neg.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/polyline-coord.svg b/unittests/polyline-coord.svg deleted file mode 100644 index fc209ed..0000000 --- a/unittests/polyline-coord.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/protection.svg b/unittests/protection.svg deleted file mode 100644 index f2930f5..0000000 --- a/unittests/protection.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/unittests/quot-in-url.svg b/unittests/quot-in-url.svg deleted file mode 100644 index 6d82567..0000000 --- a/unittests/quot-in-url.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/unittests/redundant-svg-namespace.svg b/unittests/redundant-svg-namespace.svg deleted file mode 100644 index 5022693..0000000 --- a/unittests/redundant-svg-namespace.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Test - - - diff --git a/unittests/referenced-elements-1.svg b/unittests/referenced-elements-1.svg deleted file mode 100644 index e779080..0000000 --- a/unittests/referenced-elements-1.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - Fooey - - - - - - - diff --git a/unittests/referenced-font.svg b/unittests/referenced-font.svg deleted file mode 100644 index 7d992ec..0000000 --- a/unittests/referenced-font.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - Text - diff --git a/unittests/refs-in-defs.svg b/unittests/refs-in-defs.svg deleted file mode 100644 index 8636c5a..0000000 --- a/unittests/refs-in-defs.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/unittests/remove-duplicate-gradients.svg b/unittests/remove-duplicate-gradients.svg deleted file mode 100644 index f986bdd..0000000 --- a/unittests/remove-duplicate-gradients.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/unittests/remove-unused-attributes-on-parent.svg b/unittests/remove-unused-attributes-on-parent.svg deleted file mode 100644 index 7f68d15..0000000 --- a/unittests/remove-unused-attributes-on-parent.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/unittests/scour-lengths.svg b/unittests/scour-lengths.svg deleted file mode 100644 index f5c0d5c..0000000 --- a/unittests/scour-lengths.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/shorten-ids.svg b/unittests/shorten-ids.svg deleted file mode 100644 index 7852c57..0000000 --- a/unittests/shorten-ids.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/unittests/sodipodi.svg b/unittests/sodipodi.svg deleted file mode 100644 index 935884a..0000000 --- a/unittests/sodipodi.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/unittests/straight-curve.svg b/unittests/straight-curve.svg deleted file mode 100644 index 95cd862..0000000 --- a/unittests/straight-curve.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/stroke-none.svg b/unittests/stroke-none.svg deleted file mode 100644 index 4582a85..0000000 --- a/unittests/stroke-none.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/stroke-nowidth.svg b/unittests/stroke-nowidth.svg deleted file mode 100644 index 2ca5809..0000000 --- a/unittests/stroke-nowidth.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/stroke-transparent.svg b/unittests/stroke-transparent.svg deleted file mode 100644 index 4ff39a2..0000000 --- a/unittests/stroke-transparent.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/style-cdata.svg b/unittests/style-cdata.svg deleted file mode 100644 index 4740da9..0000000 --- a/unittests/style-cdata.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - diff --git a/unittests/style-to-attr.svg b/unittests/style-to-attr.svg deleted file mode 100644 index 3bbe3a0..0000000 --- a/unittests/style-to-attr.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/unittests/transform-matrix-is-identity.svg b/unittests/transform-matrix-is-identity.svg deleted file mode 100644 index 9764b28..0000000 --- a/unittests/transform-matrix-is-identity.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/unittests/transform-matrix-is-rotate-135.svg b/unittests/transform-matrix-is-rotate-135.svg deleted file mode 100644 index a0583bc..0000000 --- a/unittests/transform-matrix-is-rotate-135.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-rotate-225.svg b/unittests/transform-matrix-is-rotate-225.svg deleted file mode 100644 index 1aa21ef..0000000 --- a/unittests/transform-matrix-is-rotate-225.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-rotate-45.svg b/unittests/transform-matrix-is-rotate-45.svg deleted file mode 100644 index 1749d98..0000000 --- a/unittests/transform-matrix-is-rotate-45.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-rotate-90.svg b/unittests/transform-matrix-is-rotate-90.svg deleted file mode 100644 index 269d526..0000000 --- a/unittests/transform-matrix-is-rotate-90.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-rotate-neg-45.svg b/unittests/transform-matrix-is-rotate-neg-45.svg deleted file mode 100644 index 37b46e8..0000000 --- a/unittests/transform-matrix-is-rotate-neg-45.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-rotate-neg-90.svg b/unittests/transform-matrix-is-rotate-neg-90.svg deleted file mode 100644 index 8fbbd4f..0000000 --- a/unittests/transform-matrix-is-rotate-neg-90.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-scale-2-3.svg b/unittests/transform-matrix-is-scale-2-3.svg deleted file mode 100644 index 7a04ce5..0000000 --- a/unittests/transform-matrix-is-scale-2-3.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/unittests/transform-matrix-is-scale-neg-1.svg b/unittests/transform-matrix-is-scale-neg-1.svg deleted file mode 100644 index d402058..0000000 --- a/unittests/transform-matrix-is-scale-neg-1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-matrix-is-translate.svg b/unittests/transform-matrix-is-translate.svg deleted file mode 100644 index 0dfcd9d..0000000 --- a/unittests/transform-matrix-is-translate.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/unittests/transform-rotate-fold-3args.svg b/unittests/transform-rotate-fold-3args.svg deleted file mode 100644 index 0139610..0000000 --- a/unittests/transform-rotate-fold-3args.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/transform-rotate-is-identity.svg b/unittests/transform-rotate-is-identity.svg deleted file mode 100644 index 198ba11..0000000 --- a/unittests/transform-rotate-is-identity.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/unittests/transform-rotate-trim-range-719.5.svg b/unittests/transform-rotate-trim-range-719.5.svg deleted file mode 100644 index f0bb947..0000000 --- a/unittests/transform-rotate-trim-range-719.5.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/transform-rotate-trim-range-neg-540.0.svg b/unittests/transform-rotate-trim-range-neg-540.0.svg deleted file mode 100644 index 3e857f6..0000000 --- a/unittests/transform-rotate-trim-range-neg-540.0.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/transform-skewX-is-identity.svg b/unittests/transform-skewX-is-identity.svg deleted file mode 100644 index b038c6e..0000000 --- a/unittests/transform-skewX-is-identity.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-skewY-is-identity.svg b/unittests/transform-skewY-is-identity.svg deleted file mode 100644 index 27da015..0000000 --- a/unittests/transform-skewY-is-identity.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/unittests/transform-translate-is-identity.svg b/unittests/transform-translate-is-identity.svg deleted file mode 100644 index 6c62d23..0000000 --- a/unittests/transform-translate-is-identity.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/unittests/unreferenced-font.svg b/unittests/unreferenced-font.svg deleted file mode 100644 index 560c83f..0000000 --- a/unittests/unreferenced-font.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - Text - diff --git a/unittests/unreferenced-linearGradient.svg b/unittests/unreferenced-linearGradient.svg deleted file mode 100644 index f588eac..0000000 --- a/unittests/unreferenced-linearGradient.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/unreferenced-pattern.svg b/unittests/unreferenced-pattern.svg deleted file mode 100644 index 7bcff58..0000000 --- a/unittests/unreferenced-pattern.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/unreferenced-radialGradient.svg b/unittests/unreferenced-radialGradient.svg deleted file mode 100644 index bfa35c8..0000000 --- a/unittests/unreferenced-radialGradient.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/useless-defs.svg b/unittests/useless-defs.svg deleted file mode 100644 index f4663ff..0000000 --- a/unittests/useless-defs.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/unittests/utf8.svg b/unittests/utf8.svg deleted file mode 100644 index 6c77d7a..0000000 --- a/unittests/utf8.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - ú - diff --git a/unittests/whitespace-defs.svg b/unittests/whitespace-defs.svg deleted file mode 100644 index a32fcb4..0000000 --- a/unittests/whitespace-defs.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/unittests/whitespace-important.svg b/unittests/whitespace-important.svg deleted file mode 100644 index 6918044..0000000 --- a/unittests/whitespace-important.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - This is some messed-up markup - diff --git a/unittests/whitespace-nested.svg b/unittests/whitespace-nested.svg deleted file mode 100644 index 3b99356..0000000 --- a/unittests/whitespace-nested.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - Use bold text - diff --git a/unittests/xml-namespace-attrs.svg b/unittests/xml-namespace-attrs.svg deleted file mode 100644 index 81c5fb4..0000000 --- a/unittests/xml-namespace-attrs.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/unittests/xml-ns-decl.svg b/unittests/xml-ns-decl.svg deleted file mode 100644 index 0f057a7..0000000 --- a/unittests/xml-ns-decl.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - image/svg+xml - - Open Clip Art Logo - 10-01-2004 - - - Andreas Nilsson - - - - - - Jon Phillips, Tobias Jakobs - - - This is one version of the official Open Clip Art Library logo. - logo, open clip art library logo, logotype - - - - - - - - - diff --git a/unittests/xml-well-formed.svg b/unittests/xml-well-formed.svg deleted file mode 100644 index 705a288..0000000 --- a/unittests/xml-well-formed.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - 2 < 5 - Peanut Butter & Jelly - - - ΉTML & CSS - diff --git a/webscour.py b/webscour.py deleted file mode 100644 index 6305c01..0000000 --- a/webscour.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/python2.4 -# -*- coding: utf-8 -*- - -# Scour Web -# -# Copyright 2009 Jeff Schiller -# -# This file is part of Scour, http://www.codedread.com/scour/ -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import cgi -import cgitb -cgitb.enable() -from scour import scourString - -def main(): - # From what I can make out, cgi.FieldStorage() abstracts away whether this is a GET/POST - # From http://www.linuxjournal.com/article/3616 it says that POST actually comes in via stdin - # and GET comes in QUERY_STRING environment variable. - form = cgi.FieldStorage() - - if not form.has_key('indoc'): - doGet() - else: - doPut(form) - -def doPut(form): - print "Content-type: image/svg+xml\n" - print scourString(form['indoc'].value, None) - -def doGet(): - print "Content-type: text/html\n" - - print """ - - - - Scour it! - - -
-

Paste the SVG file here

- -

Click "Go!" to Scour