Image do logo axustable.
|
@ -1,7 +1,8 @@
|
||||||
|Content', 'Main content|^site--templates--_main-php:/site/templates/_main.php
|
|Content', 'Main content|^site--templates--_main-php:/site/templates/_main.php
|
||||||
|en', 'HTML language code|Skip to content', 'bypass|Menu', 'Navigation menu|^site--templates--_head-php:/site/templates/_head.php
|
|en', 'HTML language code|Skip to content', 'bypass|Logo of Praia de Seselle Tourist Apartments', 'Site logo|Open/Close menu', 'Menu Switch|Menu', 'Navigation menu|^site--templates--_head-php:/site/templates/_head.php
|
||||||
|Footer', 'Page footer|All rights reserved', 'copyright|Designed and Developed by', 'developer|^site--templates--_foot-php:/site/templates/_foot.php
|
|Footer', 'Page footer|All rights reserved', 'copyright|Designed and Developed by', 'developer|^site--templates--_foot-php:/site/templates/_foot.php
|
||||||
|Info|SQL file|ZIP file|Backup|Delete|Restore|Cancel|Upload|Description|Valid?|Date/Time|Exported by|File size|Filename|Database name|Which tables?|Num tables exported|Num tables created|Num rows|Export time (seconds)|file', 'th|date', 'th|tables', 'th|rows', 'th|size', 'th|actions', 'th|(all)|No database backup files yet.|Delete checked|Add new SQL database dump file|Upload File|Added file: %s|Yes! Confirmed valid begin and end of file.|All Tables|Unable to confirm if valid file (likely not created by this tool)|bytes', 'file-details|Backup name|This will be used for the backup filename. The extension .sql will be added to it automatically.|If omitted, a unique filename will be automatically generated.|Backup description|Backup all tables?|Tables|By default, the export will include all tables. If you only want certain tables to be included, select them below.|Please be patient after clicking submit. Backups may take some time, depending on how much there is to backup.|Saved new backup:|Failed to create ZIP file: %s|Delete Backup|Delete %s?|Check the box to confirm|Restore Backup|Restored: %s|Error restoring: %s|Warning: the current database will be destroyed and replaced (this has potential to break your site!)|Restore %s?|Drop all tables from current database before restore?|Deleted: %s|^site--modules--processdatabasebackups--processdatabasebackups-module:/site/modules/ProcessDatabaseBackups/ProcessDatabaseBackups.module
|
|Info|SQL file|ZIP file|Backup|Delete|Restore|Cancel|Upload|Description|Valid?|Date/Time|Exported by|File size|Filename|Database name|Which tables?|Num tables exported|Num tables created|Num rows|Export time (seconds)|file', 'th|date', 'th|tables', 'th|rows', 'th|size', 'th|actions', 'th|(all)|No database backup files yet.|Delete checked|Add new SQL database dump file|Upload File|Added file: %s|Yes! Confirmed valid begin and end of file.|All Tables|Unable to confirm if valid file (likely not created by this tool)|bytes', 'file-details|Backup name|This will be used for the backup filename. The extension .sql will be added to it automatically.|If omitted, a unique filename will be automatically generated.|Backup description|Backup all tables?|Tables|By default, the export will include all tables. If you only want certain tables to be included, select them below.|Please be patient after clicking submit. Backups may take some time, depending on how much there is to backup.|Saved new backup:|Failed to create ZIP file: %s|Delete Backup|Delete %s?|Check the box to confirm|Restore Backup|Restored: %s|Error restoring: %s|Warning: the current database will be destroyed and replaced (this has potential to break your site!)|Restore %s?|Drop all tables from current database before restore?|Deleted: %s|^site--modules--processdatabasebackups--processdatabasebackups-module:/site/modules/ProcessDatabaseBackups/ProcessDatabaseBackups.module
|
||||||
|
|Remove remote references?|This will stop HTTP leaks but can increase the time it takes to sanitize.|Minify sanitized SVG files?|This will perform minification on whitespace in the sanitized SVG markup, potentially reducing the file size somewhat.|Add or remove tags (1 per line)|To add whitelisted tags, enter one per line. To remove tags, do the same but prefix line with a minus sign.|Add or remove attributes (1 per line)|To add whitelisted attributes, enter one per line. To remove attributes, do the same but prefix line with a minus sign.|^site--modules--filevalidatorsvgsanitizer-master--filevalidatorsvgsanitizer-config-php:/site/modules/FileValidatorSvgSanitizer-master/FileValidatorSvgSanitizer.config.php
|
||||||
|Check for upgrades on superuser login?|If "No" is selected, then upgrades will only be checked manually when you click to Setup > Upgrades.|Automatic upgrade check requires ProcessWire 3.0.123 or newer.|Yes|No|^site--modules--processwireupgrade--processwireupgradecheck-config-php:/site/modules/ProcessWireUpgrade/ProcessWireUpgradeCheck.config.php
|
|Check for upgrades on superuser login?|If "No" is selected, then upgrades will only be checked manually when you click to Setup > Upgrades.|Automatic upgrade check requires ProcessWire 3.0.123 or newer.|Yes|No|^site--modules--processwireupgrade--processwireupgradecheck-config-php:/site/modules/ProcessWireUpgrade/ProcessWireUpgradeCheck.config.php
|
||||||
|Remove|Continue|Module title|Module name|Installed|Latest|Status|Links|Up-to-date|Upgrade available|Not in directory|Refreshed module versions data|Removed: %s|Permission error removing path (please remove manually): %s|Download Now|Abort|Backup Database Now|Skip Database Backup|Confirm|Install|Core upgrade|Refresh|N/A|Last refresh: %s|^site--modules--processwireupgrade--processwireupgrade-module:/site/modules/ProcessWireUpgrade/ProcessWireUpgrade.module
|
|Remove|Continue|Module title|Module name|Installed|Latest|Status|Links|Up-to-date|Upgrade available|Not in directory|Refreshed module versions data|Removed: %s|Permission error removing path (please remove manually): %s|Download Now|Abort|Backup Database Now|Skip Database Backup|Confirm|Install|Core upgrade|Refresh|N/A|Last refresh: %s|^site--modules--processwireupgrade--processwireupgrade-module:/site/modules/ProcessWireUpgrade/ProcessWireUpgrade.module
|
||||||
|A ProcessWire core upgrade is available|Your ProcessWire core is up-to-date|An upgrade for %s is available|Your modules are up-to-date|Error retrieving modules directory data|Error loading GitHub branches|HTTP error(s):|Check that HTTP requests are not blocked by your server.|^site--modules--processwireupgrade--processwireupgradecheck-module:/site/modules/ProcessWireUpgrade/ProcessWireUpgradeCheck.module
|
|A ProcessWire core upgrade is available|Your ProcessWire core is up-to-date|An upgrade for %s is available|Your modules are up-to-date|Error retrieving modules directory data|Error loading GitHub branches|HTTP error(s):|Check that HTTP requests are not blocked by your server.|^site--modules--processwireupgrade--processwireupgradecheck-module:/site/modules/ProcessWireUpgrade/ProcessWireUpgradeCheck.module
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
"01bea08b9a838113ed66226778ce6108": {
|
"01bea08b9a838113ed66226778ce6108": {
|
||||||
"text": "Saltar al contenido"
|
"text": "Saltar al contenido"
|
||||||
},
|
},
|
||||||
|
"9a59fd41dc60086c1ba0b5ef77e05d4e": {
|
||||||
|
"text": "Logotipo de Praia de Seselle Apartamentos Tur\u00edsticos"
|
||||||
|
},
|
||||||
|
"4da98e72b078f4590386d08a0a363404": {
|
||||||
|
"text": "Abrir\/Cerrar el men\u00fa"
|
||||||
|
},
|
||||||
"6772cbe29a38577eeabce0d6ca81817d": {
|
"6772cbe29a38577eeabce0d6ca81817d": {
|
||||||
"text": "Men\u00fa"
|
"text": "Men\u00fa"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
"01bea08b9a838113ed66226778ce6108": {
|
"01bea08b9a838113ed66226778ce6108": {
|
||||||
"text": "Ir ao contido"
|
"text": "Ir ao contido"
|
||||||
},
|
},
|
||||||
|
"9a59fd41dc60086c1ba0b5ef77e05d4e": {
|
||||||
|
"text": "Logotipo de Praia de Seselle Apartamentos Tur\u00edsticos"
|
||||||
|
},
|
||||||
|
"4da98e72b078f4590386d08a0a363404": {
|
||||||
|
"text": "Abrir\/Pechar o men\u00fa"
|
||||||
|
},
|
||||||
"6772cbe29a38577eeabce0d6ca81817d": {
|
"6772cbe29a38577eeabce0d6ca81817d": {
|
||||||
"text": "Men\u00fa"
|
"text": "Men\u00fa"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,12 @@
|
||||||
"01bea08b9a838113ed66226778ce6108": {
|
"01bea08b9a838113ed66226778ce6108": {
|
||||||
"text": "Skip to content"
|
"text": "Skip to content"
|
||||||
},
|
},
|
||||||
|
"9a59fd41dc60086c1ba0b5ef77e05d4e": {
|
||||||
|
"text": "Logo of Praia de Seselle Tourist Apartments"
|
||||||
|
},
|
||||||
|
"4da98e72b078f4590386d08a0a363404": {
|
||||||
|
"text": "Open\/Close menu"
|
||||||
|
},
|
||||||
"6772cbe29a38577eeabce0d6ca81817d": {
|
"6772cbe29a38577eeabce0d6ca81817d": {
|
||||||
"text": "Menu"
|
"text": "Menu"
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 37 KiB |
BIN
site/assets/files/1030/playa_chanteiro_ares.0x260.jpg
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
site/assets/files/1030/playa_chanteiro_ares.350x195.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
site/assets/files/1030/playa_chanteiro_ares.jpg
Normal file
After Width: | Height: | Size: 315 KiB |
|
@ -0,0 +1,29 @@
|
||||||
|
<?php namespace ProcessWire;
|
||||||
|
|
||||||
|
$config = array(
|
||||||
|
'removeRemoteReferences' => array(
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'label' => __('Remove remote references?'),
|
||||||
|
'description' => __('This will stop HTTP leaks but can increase the time it takes to sanitize.'),
|
||||||
|
'value' => 1
|
||||||
|
),
|
||||||
|
'minify' => array(
|
||||||
|
'type' => 'checkbox',
|
||||||
|
'label' => __('Minify sanitized SVG files?'),
|
||||||
|
'description' => __('This will perform minification on whitespace in the sanitized SVG markup, potentially reducing the file size somewhat.'),
|
||||||
|
'value' => 0
|
||||||
|
),
|
||||||
|
'customTags' => array(
|
||||||
|
'type' => 'textarea',
|
||||||
|
'label' => __('Add or remove tags (1 per line)'),
|
||||||
|
'description' => __('To add whitelisted tags, enter one per line. To remove tags, do the same but prefix line with a minus sign.'),
|
||||||
|
'collapsed' => Inputfield::collapsedBlank
|
||||||
|
),
|
||||||
|
'customAttrs' => array(
|
||||||
|
'type' => 'textarea',
|
||||||
|
'label' => __('Add or remove attributes (1 per line)'),
|
||||||
|
'description' => __('To add whitelisted attributes, enter one per line. To remove attributes, do the same but prefix line with a minus sign.'),
|
||||||
|
'collapsed' => Inputfield::collapsedBlank
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php namespace ProcessWire;
|
||||||
|
|
||||||
|
class FileValidatorSvgSanitizerData {
|
||||||
|
protected static $data = array();
|
||||||
|
public static function add($data) {
|
||||||
|
if(!is_array($data)) {
|
||||||
|
$data = trim($data);
|
||||||
|
$data = str_replace(' ', "\n", $data);
|
||||||
|
$data = explode("\n", $data);
|
||||||
|
}
|
||||||
|
foreach($data as $line) {
|
||||||
|
$line = trim($line);
|
||||||
|
if(strlen($line)) self::$data[] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function process(array $data) {
|
||||||
|
foreach(self::$data as $line) {
|
||||||
|
if(strpos($line, '-') === 0) { // remove
|
||||||
|
$key = array_search(trim($line, '- '), $data);
|
||||||
|
if($key !== false) unset($data[$key]);
|
||||||
|
} else { // add
|
||||||
|
$data[] = ltrim($line, '+ ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileValidatorSvgSanitizerAttributes extends FileValidatorSvgSanitizerData implements \enshrined\svgSanitize\data\AttributeInterface {
|
||||||
|
public static function getAttributes() {
|
||||||
|
$data = \enshrined\svgSanitize\data\AllowedAttributes::getAttributes();
|
||||||
|
return self::process($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileValidatorSvgSanitizerTags extends FileValidatorSvgSanitizerData implements \enshrined\svgSanitize\data\TagInterface {
|
||||||
|
public static function getTags() {
|
||||||
|
$data = \enshrined\svgSanitize\data\AllowedTags::getTags();
|
||||||
|
return self::process($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
<?php namespace ProcessWire;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates and/or sanitizes SVG files in ProcessWire
|
||||||
|
*
|
||||||
|
* Uses the svg-sanitizer library:
|
||||||
|
* https://github.com/darylldoyle/svg-sanitizer
|
||||||
|
*
|
||||||
|
* The FileValidatorModule interface and this module file are MIT licensed,
|
||||||
|
* while the svg-sanitizer library in the /svgSanitize/ dir is GPL 2.0.
|
||||||
|
* As a result, if your installation does not support GPL code, you should
|
||||||
|
* inquire with the developer of the sanitizer lib before using this module
|
||||||
|
* in your project: https://github.com/darylldoyle
|
||||||
|
*
|
||||||
|
* Originally developed by Adrian and Ryan in 2015 and updated in 2020
|
||||||
|
* to change the SVG sanitizer library this module uses. Additional updates
|
||||||
|
* were also made in 2021.
|
||||||
|
*
|
||||||
|
* @property int|bool $removeRemoteReferences
|
||||||
|
* @property int|bool $minify
|
||||||
|
* @property string $customTags
|
||||||
|
* @property string $customAttrs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class FileValidatorSvgSanitizer extends FileValidatorModule {
|
||||||
|
|
||||||
|
public static function getModuleInfo() {
|
||||||
|
return array(
|
||||||
|
'title' => 'SVG File Sanitizer/Validator',
|
||||||
|
'summary' => 'Validates and/or sanitizes uploaded SVG files.',
|
||||||
|
'version' => 5,
|
||||||
|
'author' => 'Adrian and Ryan',
|
||||||
|
'autoload' => false,
|
||||||
|
'singular' => false,
|
||||||
|
'validates' => array('svg'),
|
||||||
|
'requires' => 'ProcessWire>=3.0.148',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \enshrined\svgSanitize\Sanitizer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected $svgSanitizer = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$this->set('removeRemoteReferences', 1);
|
||||||
|
$this->set('minify', 0);
|
||||||
|
$this->set('customTags', '');
|
||||||
|
$this->set('customAttrs', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module init
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function init() {
|
||||||
|
$this->getSvgSanitizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SVG Sanitizer instance
|
||||||
|
*
|
||||||
|
* @return \enshrined\svgSanitize\Sanitizer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getSvgSanitizer() {
|
||||||
|
if($this->svgSanitizer !== null) return $this->svgSanitizer;
|
||||||
|
$ns = 'enshrined\svgSanitize';
|
||||||
|
$classLoader = $this->wire()->classLoader;
|
||||||
|
if(!$classLoader->hasNamespace($ns)) $classLoader->addNamespace($ns, __DIR__ . '/svgSanitize/');
|
||||||
|
$className = $ns . '\Sanitizer';
|
||||||
|
$this->svgSanitizer = new $className();
|
||||||
|
$this->svgSanitizer->removeRemoteReferences((bool) $this->removeRemoteReferences);
|
||||||
|
$this->svgSanitizer->minify((bool) $this->minify);
|
||||||
|
list($tags, $attrs) = array($this->customTags, $this->customAttrs);
|
||||||
|
if($tags || $attrs) {
|
||||||
|
require_once(__DIR__ . '/FileValidatorSvgSanitizer.data.php');
|
||||||
|
if($tags) {
|
||||||
|
FileValidatorSvgSanitizerTags::add($tags);
|
||||||
|
$this->svgSanitizer->setAllowedTags(new FileValidatorSvgSanitizerTags());
|
||||||
|
}
|
||||||
|
if($attrs) {
|
||||||
|
FileValidatorSvgSanitizerAttributes::add($attrs);
|
||||||
|
$this->svgSanitizer->setAllowedAttrs(new FileValidatorSvgSanitizerAttributes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->svgSanitizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the given SVG file valid?
|
||||||
|
*
|
||||||
|
* This is for implementation of PW's FileValidator interface.
|
||||||
|
*
|
||||||
|
* This method should return:
|
||||||
|
* - boolean TRUE if file is valid
|
||||||
|
* - boolean FALSE if file is not valid
|
||||||
|
* - integer 1 if file is valid as a result of sanitization performed by this method
|
||||||
|
*
|
||||||
|
* If method wants to explain why the file is not valid, it should call $this->error('reason why not valid').
|
||||||
|
*
|
||||||
|
* @param string $filename Full path and filename to the file
|
||||||
|
* @return bool|int
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function isValidFile($filename) {
|
||||||
|
|
||||||
|
$svgSanitizer = $this->getSvgSanitizer();
|
||||||
|
$svgDirty = file_get_contents($filename);
|
||||||
|
$svgClean = $svgSanitizer->sanitize($svgDirty);
|
||||||
|
$svgIssues = $svgSanitizer->getXmlIssues();
|
||||||
|
|
||||||
|
if(!empty($svgIssues)) {
|
||||||
|
// log found issues
|
||||||
|
$issues = array();
|
||||||
|
foreach($svgIssues as $issue) {
|
||||||
|
$issue = "$issue[message] (line $issue[line])";
|
||||||
|
$issues[$issue] = $issue;
|
||||||
|
}
|
||||||
|
if($svgClean === false) {
|
||||||
|
foreach($issues as $issue) $this->error($issue);
|
||||||
|
} else if(count($issues)) {
|
||||||
|
$this->log("SvgSanitizer: " . basename($filename) . ": " . implode(', ', $issues));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($svgClean === false) {
|
||||||
|
// sanitize failed
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else if($svgDirty === $svgClean) {
|
||||||
|
// no changes after sanitization, file is ok. this is sort of unlikely
|
||||||
|
// as SvgSanitizer seems to apply minor changes either way
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write new sanitized svg file
|
||||||
|
$files = $this->wire()->files;
|
||||||
|
$files->unlink($filename);
|
||||||
|
if($files->filePutContents($filename, $svgClean) === false) return false;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the data from the default whitelist
|
||||||
|
*
|
||||||
|
* This method doesn’t do anything for this module, it is just here if you want to
|
||||||
|
* know what are the whitelisted tags and attributes.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getDefaultWhitelist() {
|
||||||
|
return array(
|
||||||
|
'tags' => \enshrined\svgSanitize\data\AllowedTags::getTags(),
|
||||||
|
'attributes' => \enshrined\svgSanitize\data\AllowedAttributes::getAttributes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return data from the customized whitelist
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function getWhitelist() {
|
||||||
|
$this->getSvgSanitizer();
|
||||||
|
return array(
|
||||||
|
'tags' => FileValidatorSvgSanitizerTags::getTags(),
|
||||||
|
'attributes' => FileValidatorSvgSanitizerAttributes::getAttributes(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install
|
||||||
|
*
|
||||||
|
* @throws WireException
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function ___install() {
|
||||||
|
$exts = get_loaded_extensions();
|
||||||
|
if(!in_array('dom', $exts)) {
|
||||||
|
throw new WireException('This module requires the PHP “dom” extension (ext-dom)');
|
||||||
|
}
|
||||||
|
if(!in_array('libxml', $exts)) {
|
||||||
|
throw new WireException('This module requires the PHP “libxml” extension (ext-libxml)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
100
site/modules/FileValidatorSvgSanitizer-master/README.md
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
# ProcessWire SVG Sanitizer
|
||||||
|
|
||||||
|
## A FileValidator module for ProcessWire 3.x
|
||||||
|
|
||||||
|
Installation of this module is recommended if using SVG file uploads
|
||||||
|
in ProcessWire, as SVG files can easily contain malicious code. On the other hand,
|
||||||
|
if you do not need SVG file uploads then you should simply prevent their use by
|
||||||
|
never adding "svg" as a file extension to your file/image fields.
|
||||||
|
|
||||||
|
When installed, this module will automatically sanitize SVG files uploaded to file
|
||||||
|
or image fields in ProcessWire (InputfieldFile and InputfieldImage). It will also
|
||||||
|
apply to anything else that calls the `$sanitizer->validateFile()` API method.
|
||||||
|
|
||||||
|
This module does not guarantee that SVG files are safe, but it does help to
|
||||||
|
significantly reduce the risks associated with SVG files by sanitizing them from
|
||||||
|
known problematic tabs and attributes that can be present in SVG files. If you
|
||||||
|
want to be 100% safe then do not allow SVG file uploads at all.
|
||||||
|
|
||||||
|
The FileValidatorModule interface and this module file are MIT licensed,
|
||||||
|
while the svg-sanitizer library in the /svgSanitize/ dir is GPL 2.0.
|
||||||
|
As a result, if your usage does not support GPL code, you should inquire with
|
||||||
|
the developer of the sanitizer lib before using this module in your project:
|
||||||
|
<https://github.com/darylldoyle>
|
||||||
|
|
||||||
|
This module was developed by @adrianbj and @ryancramerdesign in 2015 and updated
|
||||||
|
in 2020 to replace the existing SVG library with a more up-to-date version located
|
||||||
|
at: <https://github.com/darylldoyle/svg-sanitizer>
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- ProcessWire 3.0.148 or newer (3.0.164+ recommended).
|
||||||
|
- PHP must have the "dom" and "libxml" extensions (most already do).
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
1. Copy all of the files for this module into a new directory named:
|
||||||
|
`/site/modules/FileValidatorSvgSanitizer/`
|
||||||
|
2. In your ProcessWire admin, navigate to: “Modules > Refresh”
|
||||||
|
3. Click “Install” for module “SVG File Sanitizer/Validator”.
|
||||||
|
|
||||||
|
|
||||||
|
## Upgrade
|
||||||
|
|
||||||
|
To upgrade the module, remove your old FileValidatorSvgSanitizer directory
|
||||||
|
(or hide it by placing a period in front of it) and then follow steps 1
|
||||||
|
and 2 of the Install directions above.
|
||||||
|
|
||||||
|
Because of the SVG library change, please note the following feature changes
|
||||||
|
in version 2+ relative to version 1:
|
||||||
|
|
||||||
|
1. It does not use a `$config->FileValidatorSvgSanitizer` config array.
|
||||||
|
2. Whitelists of tags and attributes are configurable in module settings.
|
||||||
|
3. It only rejects SVG files that cannot be made valid through sanitization.
|
||||||
|
4. Sanitization seems to be quite a bit better than the previous.
|
||||||
|
5. It optionally includes the ability to minify whitespace in an SVG file.
|
||||||
|
6. It performs more verbose logging of issues in the file-validator log.
|
||||||
|
|
||||||
|
|
||||||
|
## General usage
|
||||||
|
|
||||||
|
This module is used automatically on any SVG files uploaded to file or image
|
||||||
|
fields in ProcessWire that use InputfieldFile or InputfieldImage. It is also
|
||||||
|
used on any SVG files passed to `$sanitizer->validateFile()`.
|
||||||
|
|
||||||
|
Activity for this module can be found in “Setup > Logs > File-validator”.
|
||||||
|
It logs any issues it identifies and cleans out of SVG files.
|
||||||
|
|
||||||
|
## API usage
|
||||||
|
|
||||||
|
To use the module directly:
|
||||||
|
~~~~~
|
||||||
|
$validator = $modules->get('FileValidatorSvgSanitizer');
|
||||||
|
$result = $validator->isValid('/path/to/file.svg');
|
||||||
|
|
||||||
|
if($result === true) {
|
||||||
|
// true: file is valid as-is
|
||||||
|
} else if($result) {
|
||||||
|
// 1: file was made valid through sanitization
|
||||||
|
} else {
|
||||||
|
// false: file is not valid svg
|
||||||
|
}
|
||||||
|
~~~~~
|
||||||
|
To use the module through the `$sanitizer` API var, you can validate
|
||||||
|
in the same way as any other file type:
|
||||||
|
~~~~~
|
||||||
|
$result = $sanitizer->validateFile('/path/to/file.svg');
|
||||||
|
|
||||||
|
if($result === null) {
|
||||||
|
// null: no FileValidator module available for given file type
|
||||||
|
} else if($result) {
|
||||||
|
// true: file is valid or was made valid
|
||||||
|
} else {
|
||||||
|
// false: file is not valid
|
||||||
|
}
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\ElementReference;
|
||||||
|
|
||||||
|
use enshrined\svgSanitize\data\XPath;
|
||||||
|
use enshrined\svgSanitize\Exceptions\NestingException;
|
||||||
|
use enshrined\svgSanitize\Helper;
|
||||||
|
|
||||||
|
class Resolver
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var XPath
|
||||||
|
*/
|
||||||
|
protected $xPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Subject[]
|
||||||
|
*/
|
||||||
|
protected $subjects = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array DOMElement[]
|
||||||
|
*/
|
||||||
|
protected $elementsToRemove = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useNestingLimit;
|
||||||
|
|
||||||
|
public function __construct(XPath $xPath, $useNestingLimit)
|
||||||
|
{
|
||||||
|
$this->xPath = $xPath;
|
||||||
|
$this->useNestingLimit = $useNestingLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function collect()
|
||||||
|
{
|
||||||
|
$this->collectIdentifiedElements();
|
||||||
|
$this->processReferences();
|
||||||
|
$this->determineInvalidSubjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves one subject by element.
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @param bool $considerChildren Whether to search in Subject's children as well
|
||||||
|
* @return Subject|null
|
||||||
|
*/
|
||||||
|
public function findByElement(\DOMElement $element, $considerChildren = false)
|
||||||
|
{
|
||||||
|
foreach ($this->subjects as $subject) {
|
||||||
|
if (
|
||||||
|
$element === $subject->getElement()
|
||||||
|
|| $considerChildren && Helper::isElementContainedIn($element, $subject->getElement())
|
||||||
|
) {
|
||||||
|
return $subject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves subjects (plural!) by element id - in theory malformed
|
||||||
|
* DOM might have same ids assigned to different elements and leaving
|
||||||
|
* it to client/browser implementation which element to actually use.
|
||||||
|
*
|
||||||
|
* @param string $elementId
|
||||||
|
* @return Subject[]
|
||||||
|
*/
|
||||||
|
public function findByElementId($elementId)
|
||||||
|
{
|
||||||
|
return array_filter(
|
||||||
|
$this->subjects,
|
||||||
|
function (Subject $subject) use ($elementId) {
|
||||||
|
return $elementId === $subject->getElementId();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects elements having `id` attribute (those that can be referenced).
|
||||||
|
*/
|
||||||
|
protected function collectIdentifiedElements()
|
||||||
|
{
|
||||||
|
/** @var \DOMNodeList|\DOMElement[] $elements */
|
||||||
|
$elements = $this->xPath->query('//*[@id]');
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
$this->subjects[$element->getAttribute('id')] = new Subject($element, $this->useNestingLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes references from and to elements having `id` attribute concerning
|
||||||
|
* their occurrence in `<use ... xlink:href="#identifier">` statements.
|
||||||
|
*/
|
||||||
|
protected function processReferences()
|
||||||
|
{
|
||||||
|
$useNodeName = $this->xPath->createNodeName('use');
|
||||||
|
foreach ($this->subjects as $subject) {
|
||||||
|
$useElements = $this->xPath->query(
|
||||||
|
$useNodeName . '[@href or @xlink:href]',
|
||||||
|
$subject->getElement()
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var \DOMElement $useElement */
|
||||||
|
foreach ($useElements as $useElement) {
|
||||||
|
$useId = Helper::extractIdReferenceFromHref(
|
||||||
|
Helper::getElementHref($useElement)
|
||||||
|
);
|
||||||
|
if ($useId === null || !isset($this->subjects[$useId])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$subject->addUse($this->subjects[$useId]);
|
||||||
|
$this->subjects[$useId]->addUsedIn($subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines and tags infinite loops.
|
||||||
|
*/
|
||||||
|
protected function determineInvalidSubjects()
|
||||||
|
{
|
||||||
|
foreach ($this->subjects as $subject) {
|
||||||
|
|
||||||
|
if (in_array($subject->getElement(), $this->elementsToRemove)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$useId = Helper::extractIdReferenceFromHref(
|
||||||
|
Helper::getElementHref($subject->getElement())
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($useId === $subject->getElementId()) {
|
||||||
|
$this->markSubjectAsInvalid($subject);
|
||||||
|
} elseif ($subject->hasInfiniteLoop()) {
|
||||||
|
$this->markSubjectAsInvalid($subject);
|
||||||
|
}
|
||||||
|
} catch (NestingException $e) {
|
||||||
|
$this->elementsToRemove[] = $e->getElement();
|
||||||
|
$this->markSubjectAsInvalid($subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the elements that caused a nesting exception.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getElementsToRemove() {
|
||||||
|
return $this->elementsToRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Subject is invalid for some reason, therefore we should
|
||||||
|
* remove it and all it's child usages.
|
||||||
|
*
|
||||||
|
* @param Subject $subject
|
||||||
|
*/
|
||||||
|
protected function markSubjectAsInvalid(Subject $subject) {
|
||||||
|
$this->elementsToRemove = array_merge(
|
||||||
|
$this->elementsToRemove,
|
||||||
|
$subject->clearInternalAndGetAffectedElements()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\ElementReference;
|
||||||
|
|
||||||
|
class Subject
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \DOMElement
|
||||||
|
*/
|
||||||
|
protected $element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Usage[]
|
||||||
|
*/
|
||||||
|
protected $useCollection = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Usage[]
|
||||||
|
*/
|
||||||
|
protected $usedInCollection = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useNestingLimit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject constructor.
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @param int $useNestingLimit
|
||||||
|
*/
|
||||||
|
public function __construct(\DOMElement $element, $useNestingLimit)
|
||||||
|
{
|
||||||
|
$this->element = $element;
|
||||||
|
$this->useNestingLimit = $useNestingLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DOMElement
|
||||||
|
*/
|
||||||
|
public function getElement()
|
||||||
|
{
|
||||||
|
return $this->element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getElementId()
|
||||||
|
{
|
||||||
|
return $this->element->getAttribute('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $subjects Previously processed subjects
|
||||||
|
* @param int $level The current level of nesting.
|
||||||
|
* @return bool
|
||||||
|
* @throws \enshrined\svgSanitize\Exceptions\NestingException
|
||||||
|
*/
|
||||||
|
public function hasInfiniteLoop(array $subjects = [], $level = 1)
|
||||||
|
{
|
||||||
|
if ($level > $this->useNestingLimit) {
|
||||||
|
throw new \enshrined\svgSanitize\Exceptions\NestingException('Nesting level too high, aborting', 1570713498, null, $this->getElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($this, $subjects, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$subjects[] = $this;
|
||||||
|
foreach ($this->useCollection as $usage) {
|
||||||
|
if ($usage->getSubject()->hasInfiniteLoop($subjects, $level + 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Subject $subject
|
||||||
|
*/
|
||||||
|
public function addUse(Subject $subject)
|
||||||
|
{
|
||||||
|
if ($subject === $this) {
|
||||||
|
throw new \LogicException('Cannot add self usage', 1570713416);
|
||||||
|
}
|
||||||
|
$identifier = $subject->getElementId();
|
||||||
|
if (isset($this->useCollection[$identifier])) {
|
||||||
|
$this->useCollection[$identifier]->increment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->useCollection[$identifier] = new Usage($subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Subject $subject
|
||||||
|
*/
|
||||||
|
public function addUsedIn(Subject $subject)
|
||||||
|
{
|
||||||
|
if ($subject === $this) {
|
||||||
|
throw new \LogicException('Cannot add self as usage', 1570713417);
|
||||||
|
}
|
||||||
|
$identifier = $subject->getElementId();
|
||||||
|
if (isset($this->usedInCollection[$identifier])) {
|
||||||
|
$this->usedInCollection[$identifier]->increment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->usedInCollection[$identifier] = new Usage($subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $accumulated
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function countUse($accumulated = false)
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
foreach ($this->useCollection as $use) {
|
||||||
|
$useCount = $use->getSubject()->countUse();
|
||||||
|
$count += $use->getCount() * ($accumulated ? 1 + $useCount : max(1, $useCount));
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function countUsedIn()
|
||||||
|
{
|
||||||
|
$count = 0;
|
||||||
|
foreach ($this->usedInCollection as $usedIn) {
|
||||||
|
$count += $usedIn->getCount() * max(1, $usedIn->getSubject()->countUsedIn());
|
||||||
|
}
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the internal arrays (to free up memory as they can get big)
|
||||||
|
* and return all the child usages DOMElement's
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function clearInternalAndGetAffectedElements()
|
||||||
|
{
|
||||||
|
$elements = array_map(function(Usage $usage) {
|
||||||
|
return $usage->getSubject()->getElement();
|
||||||
|
}, $this->useCollection);
|
||||||
|
|
||||||
|
$this->usedInCollection = [];
|
||||||
|
$this->useCollection = [];
|
||||||
|
|
||||||
|
return $elements;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\ElementReference;
|
||||||
|
|
||||||
|
class Usage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Subject
|
||||||
|
*/
|
||||||
|
protected $subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Subject $subject
|
||||||
|
* @param int $count
|
||||||
|
*/
|
||||||
|
public function __construct(Subject $subject, $count = 1)
|
||||||
|
{
|
||||||
|
$this->subject = $subject;
|
||||||
|
$this->count = (int)$count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $by
|
||||||
|
*/
|
||||||
|
public function increment($by = 1)
|
||||||
|
{
|
||||||
|
$this->count += (int)$by;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Subject
|
||||||
|
*/
|
||||||
|
public function getSubject()
|
||||||
|
{
|
||||||
|
return $this->subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getCount()
|
||||||
|
{
|
||||||
|
return $this->count;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace enshrined\svgSanitize\Exceptions;
|
||||||
|
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class NestingException extends \Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \DOMElement
|
||||||
|
*/
|
||||||
|
protected $element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NestingException constructor.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param int $code
|
||||||
|
* @param Exception|null $previous
|
||||||
|
* @param \DOMElement|null $element
|
||||||
|
*/
|
||||||
|
public function __construct($message = "", $code = 0, Exception $previous = null, \DOMElement $element = null)
|
||||||
|
{
|
||||||
|
$this->element = $element;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the element that caused the exception.
|
||||||
|
*
|
||||||
|
* @return \DOMElement
|
||||||
|
*/
|
||||||
|
public function getElement()
|
||||||
|
{
|
||||||
|
return $this->element;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize;
|
||||||
|
|
||||||
|
class Helper
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function getElementHref(\DOMElement $element)
|
||||||
|
{
|
||||||
|
if ($element->hasAttribute('href')) {
|
||||||
|
return $element->getAttribute('href');
|
||||||
|
}
|
||||||
|
if ($element->hasAttributeNS('http://www.w3.org/1999/xlink', 'href')) {
|
||||||
|
return $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $href
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public static function extractIdReferenceFromHref($href)
|
||||||
|
{
|
||||||
|
if (!is_string($href) || strpos($href, '#') !== 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return substr($href, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DOMElement $needle
|
||||||
|
* @param \DOMElement $haystack
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isElementContainedIn(\DOMElement $needle, \DOMElement $haystack)
|
||||||
|
{
|
||||||
|
if ($needle === $haystack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach ($haystack->childNodes as $childNode) {
|
||||||
|
if (!$childNode instanceof \DOMElement) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (self::isElementContainedIn($needle, $childNode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
{description}
|
||||||
|
Copyright (C) {year} {fullname}
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
{signature of Ty Coon}, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
# svg-sanitizer
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/darylldoyle/svg-sanitizer.svg?branch=master)](https://travis-ci.org/darylldoyle/svg-sanitizer) [![Test Coverage](https://codeclimate.com/github/darylldoyle/svg-sanitizer/badges/coverage.svg)](https://codeclimate.com/github/darylldoyle/svg-sanitizer/coverage)
|
||||||
|
|
||||||
|
This is my attempt at building a decent SVG sanitizer in PHP. The work is laregely borrowed from [DOMPurify](https://github.com/cure53/DOMPurify).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Either require `enshrined/svg-sanitize` through composer or download the repo and include the old way!
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Using this is fairly easy. Create a new instance of `enshrined\svgSanitize\Sanitizer` and then call the `sanitize` whilst passing in your dirty SVG/XML
|
||||||
|
|
||||||
|
**Basic Example**
|
||||||
|
|
||||||
|
```php
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
|
||||||
|
// Create a new sanitizer instance
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
|
||||||
|
// Load the dirty svg
|
||||||
|
$dirtySVG = file_get_contents('filthy.svg');
|
||||||
|
|
||||||
|
// Pass it to the sanitizer and get it back clean
|
||||||
|
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||||
|
|
||||||
|
// Now do what you want with your clean SVG/XML data
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
This will either return a sanitized SVG/XML string or boolean `false` if XML parsing failed (usually due to a badly formatted file).
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
You may pass your own whitelist of tags and attributes by using the `Sanitizer::setAllowedTags` and `Sanitizer::setAllowedAttrs` methods respectively.
|
||||||
|
|
||||||
|
These methods require that you implement the `enshrined\svgSanitize\data\TagInterface` or `enshrined\svgSanitize\data\AttributeInterface`.
|
||||||
|
|
||||||
|
## Remove remote references
|
||||||
|
|
||||||
|
You have the option to remove attributes that reference remote files, this will stop HTTP leaks but will add an overhead to the sanitizer.
|
||||||
|
|
||||||
|
This defaults to false, set to true to remove references.
|
||||||
|
|
||||||
|
`$sanitizer->removeRemoteReferences(true);`
|
||||||
|
|
||||||
|
## Viewing Sanitization Issues
|
||||||
|
|
||||||
|
You may use the `getXmlIssues()` method to return an array of issues that occurred during sanitization.
|
||||||
|
|
||||||
|
This may be useful for logging or providing feedback to the user on why an SVG was refused.
|
||||||
|
|
||||||
|
`$issues = $sanitizer->getXmlIssues();`
|
||||||
|
|
||||||
|
## Minification
|
||||||
|
|
||||||
|
You can minify the XML output by calling `$sanitizer->minify(true);`.
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
There is a demo available at: [http://svg.enshrined.co.uk/](http://svg.enshrined.co.uk/)
|
||||||
|
|
||||||
|
## WordPress
|
||||||
|
|
||||||
|
I've just released a WordPress plugin containing this code so you can sanitize your WordPress uploads. It's available from the WordPress plugin directory: [https://wordpress.org/plugins/safe-svg/](https://wordpress.org/plugins/safe-svg/)
|
||||||
|
|
||||||
|
## Drupal
|
||||||
|
|
||||||
|
[Michael Potter](https://github.com/heyMP) has kindly created a Drupal module for this library which is available at: [https://www.drupal.org/project/svg_sanitizer](https://www.drupal.org/project/svg_sanitizer)
|
||||||
|
|
||||||
|
## TYPO3
|
||||||
|
|
||||||
|
An integration for TYPO3 CMS of this library is available as composer package `t3g/svg-sanitizer` at [https://github.com/TYPO3GmbH/svg_sanitizer](https://github.com/TYPO3GmbH/svg_sanitizer)
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
You can run these by running `vendor/bin/phpunit` from the base directory of this package.
|
||||||
|
|
||||||
|
## Standalone scanning of files via CLI
|
||||||
|
|
||||||
|
Thanks to the work by [gudmdharalds](https://github.com/gudmdharalds) there's now a standalone scanner that can be used via the CLI.
|
||||||
|
|
||||||
|
Any errors will be output in JSON format. See [the PR](https://github.com/darylldoyle/svg-sanitizer/pull/25) for an example.
|
||||||
|
|
||||||
|
Use it as follows: `php svg-scanner.php ~/svgs/myfile.svg`
|
||||||
|
|
||||||
|
## To-Do
|
||||||
|
|
||||||
|
More extensive testing for the SVGs/XML would be lovely, I'll try and add these soon. If you feel like doing it for me, please do and make a PR!
|
|
@ -0,0 +1,630 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace enshrined\svgSanitize;
|
||||||
|
|
||||||
|
use enshrined\svgSanitize\data\AllowedAttributes;
|
||||||
|
use enshrined\svgSanitize\data\AllowedTags;
|
||||||
|
use enshrined\svgSanitize\data\AttributeInterface;
|
||||||
|
use enshrined\svgSanitize\data\TagInterface;
|
||||||
|
use enshrined\svgSanitize\data\XPath;
|
||||||
|
use enshrined\svgSanitize\ElementReference\Resolver;
|
||||||
|
use enshrined\svgSanitize\ElementReference\Subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Sanitizer
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize
|
||||||
|
*/
|
||||||
|
class Sanitizer
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \DOMDocument
|
||||||
|
*/
|
||||||
|
protected $xmlDocument;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $allowedTags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $allowedAttrs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
protected $xmlLoaderValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $minifyXML = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $removeRemoteReferences = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useThreshold = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $removeXMLTag = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $xmlOptions = LIBXML_NOEMPTYTAG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $xmlIssues = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Resolver
|
||||||
|
*/
|
||||||
|
protected $elementReferenceResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $useNestingLimit = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
// Load default tags/attributes
|
||||||
|
$this->allowedAttrs = array_map('strtolower', AllowedAttributes::getAttributes());
|
||||||
|
$this->allowedTags = array_map('strtolower', AllowedTags::getTags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the DOMDocument
|
||||||
|
*/
|
||||||
|
protected function resetInternal()
|
||||||
|
{
|
||||||
|
$this->xmlDocument = new \DOMDocument();
|
||||||
|
$this->xmlDocument->preserveWhiteSpace = false;
|
||||||
|
$this->xmlDocument->strictErrorChecking = false;
|
||||||
|
$this->xmlDocument->formatOutput = !$this->minifyXML;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set XML options to use when saving XML
|
||||||
|
* See: DOMDocument::saveXML
|
||||||
|
*
|
||||||
|
* @param int $xmlOptions
|
||||||
|
*/
|
||||||
|
public function setXMLOptions($xmlOptions)
|
||||||
|
{
|
||||||
|
$this->xmlOptions = $xmlOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get XML options to use when saving XML
|
||||||
|
* See: DOMDocument::saveXML
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getXMLOptions()
|
||||||
|
{
|
||||||
|
return $this->xmlOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array of allowed tags
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedTags()
|
||||||
|
{
|
||||||
|
return $this->allowedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom allowed tags
|
||||||
|
*
|
||||||
|
* @param TagInterface $allowedTags
|
||||||
|
*/
|
||||||
|
public function setAllowedTags(TagInterface $allowedTags)
|
||||||
|
{
|
||||||
|
$this->allowedTags = array_map('strtolower', $allowedTags::getTags());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array of allowed attributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedAttrs()
|
||||||
|
{
|
||||||
|
return $this->allowedAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set custom allowed attributes
|
||||||
|
*
|
||||||
|
* @param AttributeInterface $allowedAttrs
|
||||||
|
*/
|
||||||
|
public function setAllowedAttrs(AttributeInterface $allowedAttrs)
|
||||||
|
{
|
||||||
|
$this->allowedAttrs = array_map('strtolower', $allowedAttrs::getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we remove references to remote files?
|
||||||
|
*
|
||||||
|
* @param bool $removeRemoteRefs
|
||||||
|
*/
|
||||||
|
public function removeRemoteReferences($removeRemoteRefs = false)
|
||||||
|
{
|
||||||
|
$this->removeRemoteReferences = $removeRemoteRefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get XML issues.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getXmlIssues() {
|
||||||
|
return $this->xmlIssues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize the passed string
|
||||||
|
*
|
||||||
|
* @param string $dirty
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function sanitize($dirty)
|
||||||
|
{
|
||||||
|
// Don't run on an empty string
|
||||||
|
if (empty($dirty)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip php tags
|
||||||
|
$dirty = preg_replace('/<\?(=|php)(.+?)\?>/i', '', $dirty);
|
||||||
|
|
||||||
|
$this->resetInternal();
|
||||||
|
$this->setUpBefore();
|
||||||
|
|
||||||
|
$loaded = $this->xmlDocument->loadXML($dirty);
|
||||||
|
|
||||||
|
// If we couldn't parse the XML then we go no further. Reset and return false
|
||||||
|
if (!$loaded) {
|
||||||
|
$this->resetAfter();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-process all identified elements
|
||||||
|
$xPath = new XPath($this->xmlDocument);
|
||||||
|
$this->elementReferenceResolver = new Resolver($xPath, $this->useNestingLimit);
|
||||||
|
$this->elementReferenceResolver->collect();
|
||||||
|
$elementsToRemove = $this->elementReferenceResolver->getElementsToRemove();
|
||||||
|
|
||||||
|
// Grab all the elements
|
||||||
|
$allElements = $this->xmlDocument->getElementsByTagName("*");
|
||||||
|
|
||||||
|
// remove doctype after node elements have been analyzed
|
||||||
|
$this->removeDoctype();
|
||||||
|
// Start the cleaning proccess
|
||||||
|
$this->startClean($allElements, $elementsToRemove);
|
||||||
|
|
||||||
|
// Save cleaned XML to a variable
|
||||||
|
if ($this->removeXMLTag) {
|
||||||
|
$clean = $this->xmlDocument->saveXML($this->xmlDocument->documentElement, $this->xmlOptions);
|
||||||
|
} else {
|
||||||
|
$clean = $this->xmlDocument->saveXML($this->xmlDocument, $this->xmlOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resetAfter();
|
||||||
|
|
||||||
|
// Remove any extra whitespaces when minifying
|
||||||
|
if ($this->minifyXML) {
|
||||||
|
$clean = preg_replace('/\s+/', ' ', $clean);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return result
|
||||||
|
return $clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up libXML before we start
|
||||||
|
*/
|
||||||
|
protected function setUpBefore()
|
||||||
|
{
|
||||||
|
// This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is
|
||||||
|
// disabled by default, so this function is no longer needed to protect against XXE attacks.
|
||||||
|
if (\LIBXML_VERSION < 20900) {
|
||||||
|
// Turn off the entity loader
|
||||||
|
$this->xmlLoaderValue = libxml_disable_entity_loader(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suppress the errors because we don't really have to worry about formation before cleansing
|
||||||
|
libxml_use_internal_errors(true);
|
||||||
|
|
||||||
|
// Reset array of altered XML
|
||||||
|
$this->xmlIssues = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the class after use
|
||||||
|
*/
|
||||||
|
protected function resetAfter()
|
||||||
|
{
|
||||||
|
// This function has been deprecated in PHP 8.0 because in libxml 2.9.0, external entity loading is
|
||||||
|
// disabled by default, so this function is no longer needed to protect against XXE attacks.
|
||||||
|
if (\LIBXML_VERSION < 20900) {
|
||||||
|
// Reset the entity loader
|
||||||
|
libxml_disable_entity_loader($this->xmlLoaderValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the XML Doctype
|
||||||
|
* It may be caught later on output but that seems to be buggy, so we need to make sure it's gone
|
||||||
|
*/
|
||||||
|
protected function removeDoctype()
|
||||||
|
{
|
||||||
|
foreach ($this->xmlDocument->childNodes as $child) {
|
||||||
|
if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
|
||||||
|
$child->parentNode->removeChild($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the cleaning with tags, then we move onto attributes and hrefs later
|
||||||
|
*
|
||||||
|
* @param \DOMNodeList $elements
|
||||||
|
* @param array $elementsToRemove
|
||||||
|
*/
|
||||||
|
protected function startClean(\DOMNodeList $elements, array $elementsToRemove)
|
||||||
|
{
|
||||||
|
// loop through all elements
|
||||||
|
// we do this backwards so we don't skip anything if we delete a node
|
||||||
|
// see comments at: http://php.net/manual/en/class.domnamednodemap.php
|
||||||
|
for ($i = $elements->length - 1; $i >= 0; $i--) {
|
||||||
|
/** @var \DOMElement $currentElement */
|
||||||
|
$currentElement = $elements->item($i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the element has exceeded the nesting limit, we should remove it.
|
||||||
|
*
|
||||||
|
* As it's only <use> elements that cause us issues with nesting DOS attacks
|
||||||
|
* we should check what the element is before removing it. For now we'll only
|
||||||
|
* remove <use> elements.
|
||||||
|
*/
|
||||||
|
if (in_array($currentElement, $elementsToRemove) && 'use' === $currentElement->nodeName) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Invalid \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the tag isn't in the whitelist, remove it and continue with next iteration
|
||||||
|
if (!in_array(strtolower($currentElement->tagName), $this->allowedTags)) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious tag \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cleanHrefs($currentElement);
|
||||||
|
|
||||||
|
$this->cleanXlinkHrefs($currentElement);
|
||||||
|
|
||||||
|
$this->cleanAttributesOnWhitelist($currentElement);
|
||||||
|
|
||||||
|
if (strtolower($currentElement->tagName) === 'use') {
|
||||||
|
if ($this->isUseTagDirty($currentElement)
|
||||||
|
|| $this->isUseTagExceedingThreshold($currentElement)
|
||||||
|
) {
|
||||||
|
$currentElement->parentNode->removeChild($currentElement);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious \'' . $currentElement->tagName . '\'',
|
||||||
|
'line' => $currentElement->getLineNo(),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only allow attributes that are on the whitelist
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
*/
|
||||||
|
protected function cleanAttributesOnWhitelist(\DOMElement $element)
|
||||||
|
{
|
||||||
|
for ($x = $element->attributes->length - 1; $x >= 0; $x--) {
|
||||||
|
// get attribute name
|
||||||
|
$attrName = $element->attributes->item($x)->name;
|
||||||
|
|
||||||
|
// Remove attribute if not in whitelist
|
||||||
|
if (!in_array(strtolower($attrName), $this->allowedAttrs) && !$this->isAriaAttribute(strtolower($attrName)) && !$this->isDataAttribute(strtolower($attrName))) {
|
||||||
|
|
||||||
|
$element->removeAttribute($attrName);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'' . $attrName . '\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used for when a namespace isn't imported properly.
|
||||||
|
* Such as xlink:href when the xlink namespace isn't imported.
|
||||||
|
* We have to do this as the link is still ran in this case.
|
||||||
|
*/
|
||||||
|
if (false !== strpos($attrName, 'href')) {
|
||||||
|
$href = $element->getAttribute($attrName);
|
||||||
|
if (false === $this->isHrefSafeValue($href)) {
|
||||||
|
$element->removeAttribute($attrName);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'href\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we want to strip remote references?
|
||||||
|
if($this->removeRemoteReferences) {
|
||||||
|
// Remove attribute if it has a remote reference
|
||||||
|
if (isset($element->attributes->item($x)->value) && $this->hasRemoteReference($element->attributes->item($x)->value)) {
|
||||||
|
$element->removeAttribute($attrName);
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'' . $attrName . '\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean the xlink:hrefs of script and data embeds
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
*/
|
||||||
|
protected function cleanXlinkHrefs(\DOMElement $element)
|
||||||
|
{
|
||||||
|
$xlinks = $element->getAttributeNS('http://www.w3.org/1999/xlink', 'href');
|
||||||
|
if (false === $this->isHrefSafeValue($xlinks)) {
|
||||||
|
$element->removeAttributeNS( 'http://www.w3.org/1999/xlink', 'href' );
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'href\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean the hrefs of script and data embeds
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
*/
|
||||||
|
protected function cleanHrefs(\DOMElement $element)
|
||||||
|
{
|
||||||
|
$href = $element->getAttribute('href');
|
||||||
|
if (false === $this->isHrefSafeValue($href)) {
|
||||||
|
$element->removeAttribute('href');
|
||||||
|
$this->xmlIssues[] = array(
|
||||||
|
'message' => 'Suspicious attribute \'href\'',
|
||||||
|
'line' => $element->getLineNo(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only allow whitelisted starts to be within the href.
|
||||||
|
*
|
||||||
|
* This will stop scripts etc from being passed through, with or without attempting to hide bypasses.
|
||||||
|
* This stops the need for us to use a complicated script regex.
|
||||||
|
*
|
||||||
|
* @param $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isHrefSafeValue($value) {
|
||||||
|
|
||||||
|
// Allow empty values
|
||||||
|
if (empty($value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow fragment identifiers.
|
||||||
|
if ('#' === substr($value, 0, 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow relative URIs.
|
||||||
|
if ('/' === substr($value, 0, 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow HTTPS domains.
|
||||||
|
if ('https://' === substr($value, 0, 8)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow HTTP domains.
|
||||||
|
if ('http://' === substr($value, 0, 7)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow known data URIs.
|
||||||
|
if (in_array(substr($value, 0, 14), array(
|
||||||
|
'data:image/png', // PNG
|
||||||
|
'data:image/gif', // GIF
|
||||||
|
'data:image/jpg', // JPG
|
||||||
|
'data:image/jpe', // JPEG
|
||||||
|
'data:image/pjp', // PJPEG
|
||||||
|
))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow known short data URIs.
|
||||||
|
if (in_array(substr($value, 0, 12), array(
|
||||||
|
'data:img/png', // PNG
|
||||||
|
'data:img/gif', // GIF
|
||||||
|
'data:img/jpg', // JPG
|
||||||
|
'data:img/jpe', // JPEG
|
||||||
|
'data:img/pjp', // PJPEG
|
||||||
|
))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes non-printable ASCII characters from string & trims it
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function removeNonPrintableCharacters($value)
|
||||||
|
{
|
||||||
|
return trim(preg_replace('/[^ -~]/xu','',$value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this attribute value have a remote reference?
|
||||||
|
*
|
||||||
|
* @param $value
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function hasRemoteReference($value)
|
||||||
|
{
|
||||||
|
$value = $this->removeNonPrintableCharacters($value);
|
||||||
|
|
||||||
|
$wrapped_in_url = preg_match('~^url\(\s*[\'"]\s*(.*)\s*[\'"]\s*\)$~xi', $value, $match);
|
||||||
|
if (!$wrapped_in_url){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = trim($match[1], '\'"');
|
||||||
|
|
||||||
|
return preg_match('~^((https?|ftp|file):)?//~xi', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we minify the output?
|
||||||
|
*
|
||||||
|
* @param bool $shouldMinify
|
||||||
|
*/
|
||||||
|
public function minify($shouldMinify = false)
|
||||||
|
{
|
||||||
|
$this->minifyXML = (bool) $shouldMinify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we remove the XML tag in the header?
|
||||||
|
*
|
||||||
|
* @param bool $removeXMLTag
|
||||||
|
*/
|
||||||
|
public function removeXMLTag($removeXMLTag = false)
|
||||||
|
{
|
||||||
|
$this->removeXMLTag = (bool) $removeXMLTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether `<use ... xlink:href="#identifier">` elements shall be
|
||||||
|
* removed in case expansion would exceed this threshold.
|
||||||
|
*
|
||||||
|
* @param int $useThreshold
|
||||||
|
*/
|
||||||
|
public function useThreshold($useThreshold = 1000)
|
||||||
|
{
|
||||||
|
$this->useThreshold = (int)$useThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if an attribute is an aria attribute or not
|
||||||
|
*
|
||||||
|
* @param $attributeName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isAriaAttribute($attributeName)
|
||||||
|
{
|
||||||
|
return strpos($attributeName, 'aria-') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if an attribute is an data attribute or not
|
||||||
|
*
|
||||||
|
* @param $attributeName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isDataAttribute($attributeName)
|
||||||
|
{
|
||||||
|
return strpos($attributeName, 'data-') === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure our use tag is only referencing internal resources
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isUseTagDirty(\DOMElement $element)
|
||||||
|
{
|
||||||
|
$href = Helper::getElementHref($element);
|
||||||
|
return $href && strpos($href, '#') !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether `<use ... xlink:href="#identifier">` is expanded
|
||||||
|
* recursively in order to create DoS scenarios. The amount of a actually
|
||||||
|
* used element needs to be below `$this->useThreshold`.
|
||||||
|
*
|
||||||
|
* @param \DOMElement $element
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isUseTagExceedingThreshold(\DOMElement $element)
|
||||||
|
{
|
||||||
|
if ($this->useThreshold <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$useId = Helper::extractIdReferenceFromHref(
|
||||||
|
Helper::getElementHref($element)
|
||||||
|
);
|
||||||
|
if ($useId === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach ($this->elementReferenceResolver->findByElementId($useId) as $subject) {
|
||||||
|
if ($subject->countUse() >= $this->useThreshold) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the nesting limit for <use> tags.
|
||||||
|
*
|
||||||
|
* @param $limit
|
||||||
|
*/
|
||||||
|
public function setUseNestingLimit($limit)
|
||||||
|
{
|
||||||
|
$this->useNestingLimit = (int) $limit;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,357 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AllowedAttributes
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\data
|
||||||
|
*/
|
||||||
|
class AllowedAttributes implements AttributeInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of attributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getAttributes()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
// HTML
|
||||||
|
'about',
|
||||||
|
'accept',
|
||||||
|
'action',
|
||||||
|
'align',
|
||||||
|
'alt',
|
||||||
|
'autocomplete',
|
||||||
|
'background',
|
||||||
|
'bgcolor',
|
||||||
|
'border',
|
||||||
|
'cellpadding',
|
||||||
|
'cellspacing',
|
||||||
|
'checked',
|
||||||
|
'cite',
|
||||||
|
'class',
|
||||||
|
'clear',
|
||||||
|
'color',
|
||||||
|
'cols',
|
||||||
|
'colspan',
|
||||||
|
'coords',
|
||||||
|
'crossorigin',
|
||||||
|
'datetime',
|
||||||
|
'default',
|
||||||
|
'dir',
|
||||||
|
'disabled',
|
||||||
|
'download',
|
||||||
|
'enctype',
|
||||||
|
'encoding',
|
||||||
|
'face',
|
||||||
|
'for',
|
||||||
|
'headers',
|
||||||
|
'height',
|
||||||
|
'hidden',
|
||||||
|
'high',
|
||||||
|
'href',
|
||||||
|
'hreflang',
|
||||||
|
'id',
|
||||||
|
'integrity',
|
||||||
|
'ismap',
|
||||||
|
'label',
|
||||||
|
'lang',
|
||||||
|
'list',
|
||||||
|
'loop',
|
||||||
|
'low',
|
||||||
|
'max',
|
||||||
|
'maxlength',
|
||||||
|
'media',
|
||||||
|
'method',
|
||||||
|
'min',
|
||||||
|
'multiple',
|
||||||
|
'name',
|
||||||
|
'noshade',
|
||||||
|
'novalidate',
|
||||||
|
'nowrap',
|
||||||
|
'open',
|
||||||
|
'optimum',
|
||||||
|
'pattern',
|
||||||
|
'placeholder',
|
||||||
|
'poster',
|
||||||
|
'preload',
|
||||||
|
'pubdate',
|
||||||
|
'radiogroup',
|
||||||
|
'readonly',
|
||||||
|
'rel',
|
||||||
|
'required',
|
||||||
|
'rev',
|
||||||
|
'reversed',
|
||||||
|
'role',
|
||||||
|
'rows',
|
||||||
|
'rowspan',
|
||||||
|
'spellcheck',
|
||||||
|
'scope',
|
||||||
|
'selected',
|
||||||
|
'shape',
|
||||||
|
'size',
|
||||||
|
'sizes',
|
||||||
|
'span',
|
||||||
|
'srclang',
|
||||||
|
'start',
|
||||||
|
'src',
|
||||||
|
'srcset',
|
||||||
|
'step',
|
||||||
|
'style',
|
||||||
|
'summary',
|
||||||
|
'tabindex',
|
||||||
|
'title',
|
||||||
|
'type',
|
||||||
|
'usemap',
|
||||||
|
'valign',
|
||||||
|
'value',
|
||||||
|
'version',
|
||||||
|
'width',
|
||||||
|
'xmlns',
|
||||||
|
|
||||||
|
// SVG
|
||||||
|
'accent-height',
|
||||||
|
'accumulate',
|
||||||
|
'additivive',
|
||||||
|
'alignment-baseline',
|
||||||
|
'ascent',
|
||||||
|
'attributename',
|
||||||
|
'attributetype',
|
||||||
|
'azimuth',
|
||||||
|
'basefrequency',
|
||||||
|
'baseline-shift',
|
||||||
|
'begin',
|
||||||
|
'bias',
|
||||||
|
'by',
|
||||||
|
'class',
|
||||||
|
'clip',
|
||||||
|
'clip-path',
|
||||||
|
'clip-rule',
|
||||||
|
'color',
|
||||||
|
'color-interpolation',
|
||||||
|
'color-interpolation-filters',
|
||||||
|
'color-profile',
|
||||||
|
'color-rendering',
|
||||||
|
'cx',
|
||||||
|
'cy',
|
||||||
|
'd',
|
||||||
|
'dx',
|
||||||
|
'dy',
|
||||||
|
'diffuseconstant',
|
||||||
|
'direction',
|
||||||
|
'display',
|
||||||
|
'divisor',
|
||||||
|
'dur',
|
||||||
|
'edgemode',
|
||||||
|
'elevation',
|
||||||
|
'end',
|
||||||
|
'fill',
|
||||||
|
'fill-opacity',
|
||||||
|
'fill-rule',
|
||||||
|
'filter',
|
||||||
|
'flood-color',
|
||||||
|
'flood-opacity',
|
||||||
|
'font-family',
|
||||||
|
'font-size',
|
||||||
|
'font-size-adjust',
|
||||||
|
'font-stretch',
|
||||||
|
'font-style',
|
||||||
|
'font-variant',
|
||||||
|
'font-weight',
|
||||||
|
'fx',
|
||||||
|
'fy',
|
||||||
|
'g1',
|
||||||
|
'g2',
|
||||||
|
'glyph-name',
|
||||||
|
'glyphref',
|
||||||
|
'gradientunits',
|
||||||
|
'gradienttransform',
|
||||||
|
'height',
|
||||||
|
'href',
|
||||||
|
'id',
|
||||||
|
'image-rendering',
|
||||||
|
'in',
|
||||||
|
'in2',
|
||||||
|
'k',
|
||||||
|
'k1',
|
||||||
|
'k2',
|
||||||
|
'k3',
|
||||||
|
'k4',
|
||||||
|
'kerning',
|
||||||
|
'keypoints',
|
||||||
|
'keysplines',
|
||||||
|
'keytimes',
|
||||||
|
'lang',
|
||||||
|
'lengthadjust',
|
||||||
|
'letter-spacing',
|
||||||
|
'kernelmatrix',
|
||||||
|
'kernelunitlength',
|
||||||
|
'lighting-color',
|
||||||
|
'local',
|
||||||
|
'marker-end',
|
||||||
|
'marker-mid',
|
||||||
|
'marker-start',
|
||||||
|
'markerheight',
|
||||||
|
'markerunits',
|
||||||
|
'markerwidth',
|
||||||
|
'maskcontentunits',
|
||||||
|
'maskunits',
|
||||||
|
'max',
|
||||||
|
'mask',
|
||||||
|
'media',
|
||||||
|
'method',
|
||||||
|
'mode',
|
||||||
|
'min',
|
||||||
|
'name',
|
||||||
|
'numoctaves',
|
||||||
|
'offset',
|
||||||
|
'operator',
|
||||||
|
'opacity',
|
||||||
|
'order',
|
||||||
|
'orient',
|
||||||
|
'orientation',
|
||||||
|
'origin',
|
||||||
|
'overflow',
|
||||||
|
'paint-order',
|
||||||
|
'path',
|
||||||
|
'pathlength',
|
||||||
|
'patterncontentunits',
|
||||||
|
'patterntransform',
|
||||||
|
'patternunits',
|
||||||
|
'points',
|
||||||
|
'preservealpha',
|
||||||
|
'preserveaspectratio',
|
||||||
|
'r',
|
||||||
|
'rx',
|
||||||
|
'ry',
|
||||||
|
'radius',
|
||||||
|
'refx',
|
||||||
|
'refy',
|
||||||
|
'repeatcount',
|
||||||
|
'repeatdur',
|
||||||
|
'restart',
|
||||||
|
'result',
|
||||||
|
'rotate',
|
||||||
|
'scale',
|
||||||
|
'seed',
|
||||||
|
'shape-rendering',
|
||||||
|
'specularconstant',
|
||||||
|
'specularexponent',
|
||||||
|
'spreadmethod',
|
||||||
|
'stddeviation',
|
||||||
|
'stitchtiles',
|
||||||
|
'stop-color',
|
||||||
|
'stop-opacity',
|
||||||
|
'stroke-dasharray',
|
||||||
|
'stroke-dashoffset',
|
||||||
|
'stroke-linecap',
|
||||||
|
'stroke-linejoin',
|
||||||
|
'stroke-miterlimit',
|
||||||
|
'stroke-opacity',
|
||||||
|
'stroke',
|
||||||
|
'stroke-width',
|
||||||
|
'style',
|
||||||
|
'surfacescale',
|
||||||
|
'tabindex',
|
||||||
|
'targetx',
|
||||||
|
'targety',
|
||||||
|
'transform',
|
||||||
|
'text-anchor',
|
||||||
|
'text-decoration',
|
||||||
|
'text-rendering',
|
||||||
|
'textlength',
|
||||||
|
'type',
|
||||||
|
'u1',
|
||||||
|
'u2',
|
||||||
|
'unicode',
|
||||||
|
'values',
|
||||||
|
'viewbox',
|
||||||
|
'visibility',
|
||||||
|
'vert-adv-y',
|
||||||
|
'vert-origin-x',
|
||||||
|
'vert-origin-y',
|
||||||
|
'width',
|
||||||
|
'word-spacing',
|
||||||
|
'wrap',
|
||||||
|
'writing-mode',
|
||||||
|
'xchannelselector',
|
||||||
|
'ychannelselector',
|
||||||
|
'x',
|
||||||
|
'x1',
|
||||||
|
'x2',
|
||||||
|
'xmlns',
|
||||||
|
'y',
|
||||||
|
'y1',
|
||||||
|
'y2',
|
||||||
|
'z',
|
||||||
|
'zoomandpan',
|
||||||
|
|
||||||
|
// MathML
|
||||||
|
'accent',
|
||||||
|
'accentunder',
|
||||||
|
'align',
|
||||||
|
'bevelled',
|
||||||
|
'close',
|
||||||
|
'columnsalign',
|
||||||
|
'columnlines',
|
||||||
|
'columnspan',
|
||||||
|
'denomalign',
|
||||||
|
'depth',
|
||||||
|
'dir',
|
||||||
|
'display',
|
||||||
|
'displaystyle',
|
||||||
|
'fence',
|
||||||
|
'frame',
|
||||||
|
'height',
|
||||||
|
'href',
|
||||||
|
'id',
|
||||||
|
'largeop',
|
||||||
|
'length',
|
||||||
|
'linethickness',
|
||||||
|
'lspace',
|
||||||
|
'lquote',
|
||||||
|
'mathbackground',
|
||||||
|
'mathcolor',
|
||||||
|
'mathsize',
|
||||||
|
'mathvariant',
|
||||||
|
'maxsize',
|
||||||
|
'minsize',
|
||||||
|
'movablelimits',
|
||||||
|
'notation',
|
||||||
|
'numalign',
|
||||||
|
'open',
|
||||||
|
'rowalign',
|
||||||
|
'rowlines',
|
||||||
|
'rowspacing',
|
||||||
|
'rowspan',
|
||||||
|
'rspace',
|
||||||
|
'rquote',
|
||||||
|
'scriptlevel',
|
||||||
|
'scriptminsize',
|
||||||
|
'scriptsizemultiplier',
|
||||||
|
'selection',
|
||||||
|
'separator',
|
||||||
|
'separators',
|
||||||
|
'slope',
|
||||||
|
'stretchy',
|
||||||
|
'subscriptshift',
|
||||||
|
'supscriptshift',
|
||||||
|
'symmetric',
|
||||||
|
'voffset',
|
||||||
|
'width',
|
||||||
|
'xmlns',
|
||||||
|
|
||||||
|
// XML
|
||||||
|
'xlink:href',
|
||||||
|
'xml:id',
|
||||||
|
'xlink:title',
|
||||||
|
'xml:space',
|
||||||
|
'xmlns:xlink',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AllowedTags
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\data
|
||||||
|
*/
|
||||||
|
class AllowedTags implements TagInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of tags
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getTags()
|
||||||
|
{
|
||||||
|
return array (
|
||||||
|
// HTML
|
||||||
|
'a',
|
||||||
|
'abbr',
|
||||||
|
'acronym',
|
||||||
|
'address',
|
||||||
|
'area',
|
||||||
|
'article',
|
||||||
|
'aside',
|
||||||
|
'audio',
|
||||||
|
'b',
|
||||||
|
'bdi',
|
||||||
|
'bdo',
|
||||||
|
'big',
|
||||||
|
'blink',
|
||||||
|
'blockquote',
|
||||||
|
'body',
|
||||||
|
'br',
|
||||||
|
'button',
|
||||||
|
'canvas',
|
||||||
|
'caption',
|
||||||
|
'center',
|
||||||
|
'cite',
|
||||||
|
'code',
|
||||||
|
'col',
|
||||||
|
'colgroup',
|
||||||
|
'content',
|
||||||
|
'data',
|
||||||
|
'datalist',
|
||||||
|
'dd',
|
||||||
|
'decorator',
|
||||||
|
'del',
|
||||||
|
'details',
|
||||||
|
'dfn',
|
||||||
|
'dir',
|
||||||
|
'div',
|
||||||
|
'dl',
|
||||||
|
'dt',
|
||||||
|
'element',
|
||||||
|
'em',
|
||||||
|
'fieldset',
|
||||||
|
'figcaption',
|
||||||
|
'figure',
|
||||||
|
'font',
|
||||||
|
'footer',
|
||||||
|
'form',
|
||||||
|
'h1',
|
||||||
|
'h2',
|
||||||
|
'h3',
|
||||||
|
'h4',
|
||||||
|
'h5',
|
||||||
|
'h6',
|
||||||
|
'head',
|
||||||
|
'header',
|
||||||
|
'hgroup',
|
||||||
|
'hr',
|
||||||
|
'html',
|
||||||
|
'i',
|
||||||
|
'image',
|
||||||
|
'img',
|
||||||
|
'input',
|
||||||
|
'ins',
|
||||||
|
'kbd',
|
||||||
|
'label',
|
||||||
|
'legend',
|
||||||
|
'li',
|
||||||
|
'main',
|
||||||
|
'map',
|
||||||
|
'mark',
|
||||||
|
'marquee',
|
||||||
|
'menu',
|
||||||
|
'menuitem',
|
||||||
|
'meter',
|
||||||
|
'nav',
|
||||||
|
'nobr',
|
||||||
|
'ol',
|
||||||
|
'optgroup',
|
||||||
|
'option',
|
||||||
|
'output',
|
||||||
|
'p',
|
||||||
|
'pre',
|
||||||
|
'progress',
|
||||||
|
'q',
|
||||||
|
'rp',
|
||||||
|
'rt',
|
||||||
|
'ruby',
|
||||||
|
's',
|
||||||
|
'samp',
|
||||||
|
'section',
|
||||||
|
'select',
|
||||||
|
'shadow',
|
||||||
|
'small',
|
||||||
|
'source',
|
||||||
|
'spacer',
|
||||||
|
'span',
|
||||||
|
'strike',
|
||||||
|
'strong',
|
||||||
|
'style',
|
||||||
|
'sub',
|
||||||
|
'summary',
|
||||||
|
'sup',
|
||||||
|
'table',
|
||||||
|
'tbody',
|
||||||
|
'td',
|
||||||
|
'template',
|
||||||
|
'textarea',
|
||||||
|
'tfoot',
|
||||||
|
'th',
|
||||||
|
'thead',
|
||||||
|
'time',
|
||||||
|
'tr',
|
||||||
|
'track',
|
||||||
|
'tt',
|
||||||
|
'u',
|
||||||
|
'ul',
|
||||||
|
'var',
|
||||||
|
'video',
|
||||||
|
'wbr',
|
||||||
|
|
||||||
|
// SVG
|
||||||
|
'svg',
|
||||||
|
'altglyph',
|
||||||
|
'altglyphdef',
|
||||||
|
'altglyphitem',
|
||||||
|
'animatecolor',
|
||||||
|
'animatemotion',
|
||||||
|
'animatetransform',
|
||||||
|
'circle',
|
||||||
|
'clippath',
|
||||||
|
'defs',
|
||||||
|
'desc',
|
||||||
|
'ellipse',
|
||||||
|
'filter',
|
||||||
|
'font',
|
||||||
|
'g',
|
||||||
|
'glyph',
|
||||||
|
'glyphref',
|
||||||
|
'hkern',
|
||||||
|
'image',
|
||||||
|
'line',
|
||||||
|
'lineargradient',
|
||||||
|
'marker',
|
||||||
|
'mask',
|
||||||
|
'metadata',
|
||||||
|
'mpath',
|
||||||
|
'path',
|
||||||
|
'pattern',
|
||||||
|
'polygon',
|
||||||
|
'polyline',
|
||||||
|
'radialgradient',
|
||||||
|
'rect',
|
||||||
|
'stop',
|
||||||
|
'switch',
|
||||||
|
'symbol',
|
||||||
|
'text',
|
||||||
|
'textpath',
|
||||||
|
'title',
|
||||||
|
'tref',
|
||||||
|
'tspan',
|
||||||
|
'use',
|
||||||
|
'view',
|
||||||
|
'vkern',
|
||||||
|
|
||||||
|
// SVG Filters
|
||||||
|
'feBlend',
|
||||||
|
'feColorMatrix',
|
||||||
|
'feComponentTransfer',
|
||||||
|
'feComposite',
|
||||||
|
'feConvolveMatrix',
|
||||||
|
'feDiffuseLighting',
|
||||||
|
'feDisplacementMap',
|
||||||
|
'feDistantLight',
|
||||||
|
'feFlood',
|
||||||
|
'feFuncA',
|
||||||
|
'feFuncB',
|
||||||
|
'feFuncG',
|
||||||
|
'feFuncR',
|
||||||
|
'feGaussianBlur',
|
||||||
|
'feMerge',
|
||||||
|
'feMergeNode',
|
||||||
|
'feMorphology',
|
||||||
|
'feOffset',
|
||||||
|
'fePointLight',
|
||||||
|
'feSpecularLighting',
|
||||||
|
'feSpotLight',
|
||||||
|
'feTile',
|
||||||
|
'feTurbulence',
|
||||||
|
|
||||||
|
//MathML
|
||||||
|
'math',
|
||||||
|
'menclose',
|
||||||
|
'merror',
|
||||||
|
'mfenced',
|
||||||
|
'mfrac',
|
||||||
|
'mglyph',
|
||||||
|
'mi',
|
||||||
|
'mlabeledtr',
|
||||||
|
'mmuliscripts',
|
||||||
|
'mn',
|
||||||
|
'mo',
|
||||||
|
'mover',
|
||||||
|
'mpadded',
|
||||||
|
'mphantom',
|
||||||
|
'mroot',
|
||||||
|
'mrow',
|
||||||
|
'ms',
|
||||||
|
'mpspace',
|
||||||
|
'msqrt',
|
||||||
|
'mystyle',
|
||||||
|
'msub',
|
||||||
|
'msup',
|
||||||
|
'msubsup',
|
||||||
|
'mtable',
|
||||||
|
'mtd',
|
||||||
|
'mtext',
|
||||||
|
'mtr',
|
||||||
|
'munder',
|
||||||
|
'munderover',
|
||||||
|
|
||||||
|
//text
|
||||||
|
'#text'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AttributeInterface
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\data
|
||||||
|
*/
|
||||||
|
interface AttributeInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of attributes
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getAttributes();
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface TagInterface
|
||||||
|
*
|
||||||
|
* @package enshrined\svgSanitize\tags
|
||||||
|
*/
|
||||||
|
interface TagInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of tags
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getTags();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
namespace enshrined\svgSanitize\data;
|
||||||
|
|
||||||
|
class XPath extends \DOMXPath
|
||||||
|
{
|
||||||
|
const DEFAULT_NAMESPACE_PREFIX = 'svg';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $defaultNamespaceURI;
|
||||||
|
|
||||||
|
public function __construct(\DOMDocument $doc)
|
||||||
|
{
|
||||||
|
parent::__construct($doc);
|
||||||
|
$this->handleDefaultNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $nodeName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function createNodeName($nodeName)
|
||||||
|
{
|
||||||
|
if (empty($this->defaultNamespaceURI)) {
|
||||||
|
return $nodeName;
|
||||||
|
}
|
||||||
|
return self::DEFAULT_NAMESPACE_PREFIX . ':' . $nodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleDefaultNamespace()
|
||||||
|
{
|
||||||
|
$rootElements = $this->getRootElements();
|
||||||
|
|
||||||
|
if (count($rootElements) !== 1) {
|
||||||
|
throw new \LogicException(
|
||||||
|
sprintf('Got %d svg elements, expected exactly one', count($rootElements)),
|
||||||
|
1570870568
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->defaultNamespaceURI = (string)$rootElements[0]->namespaceURI;
|
||||||
|
|
||||||
|
if ($this->defaultNamespaceURI !== '') {
|
||||||
|
$this->registerNamespace(self::DEFAULT_NAMESPACE_PREFIX, $this->defaultNamespaceURI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DOMElement[]
|
||||||
|
*/
|
||||||
|
protected function getRootElements()
|
||||||
|
{
|
||||||
|
$rootElements = [];
|
||||||
|
$elements = $this->document->getElementsByTagName('svg');
|
||||||
|
/** @var \DOMElement $element */
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
if ($element->parentNode !== $this->document) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$rootElements[] = $element;
|
||||||
|
}
|
||||||
|
return $rootElements;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,10 +20,9 @@
|
||||||
<link rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates; ?>css/fonts.css" />
|
<link rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates; ?>css/fonts.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates; ?>css/colors.css" />
|
<link rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates; ?>css/colors.css" />
|
||||||
<link title="Praia de Seselle" rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates?>css/style.css" />
|
<link title="Praia de Seselle" rel="stylesheet" type="text/css" href="<?php echo $config->urls->templates?>css/style.css" />
|
||||||
<link rel="alternate" hreflang="es" href="https://praiadeseselle.com" />
|
|
||||||
<?php foreach($languages as $idioma): ?>
|
<?php foreach($languages as $idioma): ?>
|
||||||
<?php if(!$page->viewable($idioma)): continue; endif; ?>
|
<?php if(!$page->viewable($idioma)): continue; endif; ?>
|
||||||
<link rel="alternate" hreflang="<?php echo $inicio->getLanguageValue($idioma, 'name'); ?>" href="<?php echo $page->localHttpUrl($idioma); ?>" />
|
<link rel="alternate" hreflang="<?php echo $inicio->getLanguageValue($idioma, 'name'); ?>" href="<?php echo $page->httpUrl($idioma); ?>" />
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -31,8 +30,12 @@
|
||||||
<header id="cabeceira">
|
<header id="cabeceira">
|
||||||
<div class="contedor">
|
<div class="contedor">
|
||||||
<div id="logo">
|
<div id="logo">
|
||||||
<h1 class="visually-hidden"><?php echo $configuracion['nome_sitio']; ?></h1>
|
<picture>
|
||||||
<p class="visually-hidden"><?php echo $configuracion['descripcion_sitio']; ?></p>
|
<source srcset="<?php echo $config->urls->templates?>images/logo-praia-seselle-150x116.jpg" media="(max-width: 767px)">
|
||||||
|
<source srcset="<?php echo $config->urls->templates?>images/logo-praia-seselle-230x179.jpg" media="(min-width: 768px)">
|
||||||
|
<img src="<?php echo $config->urls->templates?>images/logo-praia-seselle.svg" alt="<?php echo _x('Logo of Praia de Seselle Tourist Apartments', 'Site logo'); ?>">
|
||||||
|
</picture>
|
||||||
|
<h1 class="visually-hidden"><?php echo $configuracion['nome_sitio']; ?> <?php echo $configuracion['descripcion_sitio']; ?></h1>
|
||||||
</div>
|
</div>
|
||||||
<label class="visually-hidden" for="interruptor"><?php echo _x('Open/Close menu', 'Menu Switch'); ?></label><input type="checkbox" name="interruptor" id="interruptor">
|
<label class="visually-hidden" for="interruptor"><?php echo _x('Open/Close menu', 'Menu Switch'); ?></label><input type="checkbox" name="interruptor" id="interruptor">
|
||||||
<div class="interruptor">
|
<div class="interruptor">
|
||||||
|
|
|
@ -73,6 +73,18 @@ img
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
picture
|
||||||
|
{
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
picture img
|
||||||
|
{
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
header#cabeceira
|
header#cabeceira
|
||||||
{
|
{
|
||||||
margin-bottom: 1.125rem;
|
margin-bottom: 1.125rem;
|
||||||
|
@ -84,8 +96,6 @@ div#logo
|
||||||
{
|
{
|
||||||
width: 230px !important;
|
width: 230px !important;
|
||||||
height: 169px;
|
height: 169px;
|
||||||
|
|
||||||
background-image: url(../images/logo.jpg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header#cabeceira input#interruptor
|
header#cabeceira input#interruptor
|
||||||
|
@ -396,6 +406,14 @@ footer#pe a
|
||||||
color: rgb(var(--color_60));
|
color: rgb(var(--color_60));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width:768px)
|
||||||
|
{
|
||||||
|
picture img
|
||||||
|
{
|
||||||
|
width: 230px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-height: 768px) and (orientation: landscape)
|
@media (max-height: 768px) and (orientation: landscape)
|
||||||
{
|
{
|
||||||
ul#idiomas
|
ul#idiomas
|
||||||
|
|
BIN
site/templates/images/logo-praia-seselle-150x116.jpg
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
site/templates/images/logo-praia-seselle-230x179.jpg
Normal file
After Width: | Height: | Size: 17 KiB |
215
site/templates/images/logo-praia-seselle.svg
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 200.72621 155.22454"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg227"
|
||||||
|
sodipodi:docname="PraiaSeselle_logo.svg"
|
||||||
|
width="53.108814mm"
|
||||||
|
height="41.069828mm"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs231" /><sodipodi:namedview
|
||||||
|
id="namedview229"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
showgrid="true"
|
||||||
|
units="mm"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:lockguides="false"
|
||||||
|
fit-margin-top="4"
|
||||||
|
fit-margin-left="4"
|
||||||
|
fit-margin-right="4"
|
||||||
|
fit-margin-bottom="4"
|
||||||
|
inkscape:zoom="3.853235"
|
||||||
|
inkscape:cx="122.49448"
|
||||||
|
inkscape:cy="92.130379"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1020"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="25"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg227"><inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid321"
|
||||||
|
originx="-50.751291"
|
||||||
|
originy="-26.268549" /></sodipodi:namedview>
|
||||||
|
<style
|
||||||
|
type="text/css"
|
||||||
|
id="style145">
|
||||||
|
.st0{fill:#00A099;}
|
||||||
|
</style>
|
||||||
|
<g
|
||||||
|
id="Capa_1"
|
||||||
|
transform="translate(-197.28189,-343.34357)">
|
||||||
|
<g
|
||||||
|
id="g224">
|
||||||
|
<g
|
||||||
|
id="g176">
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 262.02,378.78 c -0.68,3.06 -2.09,5.83 -4.23,8.31 -2.14,2.48 -4.64,4.54 -7.5,6.17 -2.86,1.63 -5.88,2.75 -9.08,3.37 -3.2,0.61 -6.22,0.55 -9.08,-0.2 -0.95,2.38 -1.73,4.45 -2.35,6.22 -0.62,1.77 -0.85,2.92 -0.71,3.47 v 0.61 c 0,0.41 0.1,0.82 0.31,1.22 0.14,0.34 0.07,0.68 -0.2,1.02 -0.27,0.34 -0.65,0.34 -1.12,0 -0.2,-0.14 -0.53,-0.44 -0.97,-0.92 -0.44,-0.48 -0.83,-1.12 -1.17,-1.94 -0.34,-0.82 -0.56,-1.79 -0.66,-2.91 -0.1,-1.12 0.05,-2.46 0.46,-4.03 0.14,-0.68 0.36,-1.44 0.66,-2.29 0.31,-0.85 0.66,-1.82 1.07,-2.91 -0.95,-0.88 -1.79,-2.11 -2.5,-3.67 -0.71,-1.56 -0.87,-3.6 -0.46,-6.12 0.34,-2.24 1.21,-4.3 2.6,-6.17 1.39,-1.87 2.89,-3.47 4.49,-4.79 1.6,-1.33 3.08,-2.4 4.44,-3.21 1.36,-0.82 2.21,-1.29 2.55,-1.43 0.61,-0.27 1.31,-0.46 2.09,-0.56 0.78,-0.1 1.38,-0.05 1.78,0.15 0.34,0.14 0.61,0.6 0.82,1.38 0.2,0.78 -0.04,1.92 -0.71,3.42 -0.95,2.18 -1.97,4.39 -3.06,6.63 -0.95,1.97 -1.97,4.18 -3.06,6.63 -1.09,2.45 -2.11,4.86 -3.06,7.24 l 1.63,0.31 c 2.24,0.27 4.5,-0.02 6.78,-0.87 2.28,-0.85 4.4,-2.06 6.38,-3.62 1.97,-1.56 3.69,-3.37 5.15,-5.41 1.46,-2.04 2.53,-4.15 3.21,-6.32 0.54,-1.7 0.61,-3.54 0.2,-5.51 -0.41,-1.97 -1.24,-3.77 -2.5,-5.41 -1.26,-1.63 -2.92,-3.01 -5,-4.13 -2.08,-1.12 -4.5,-1.75 -7.29,-1.89 -2.31,-0.07 -4.73,0.25 -7.24,0.97 -2.52,0.71 -4.93,1.77 -7.24,3.16 -2.31,1.39 -4.35,3.04 -6.12,4.95 -1.77,1.9 -3.06,4.01 -3.88,6.32 -0.2,0.75 -0.24,1.46 -0.1,2.14 0.14,0.68 0.36,1.28 0.66,1.79 0.3,0.51 0.65,0.95 1.02,1.33 0.37,0.37 0.66,0.6 0.87,0.66 l 0.2,0.1 h 0.1 v 0.1 c 0,0.14 -0.04,0.27 -0.1,0.41 -0.07,0.14 -0.14,0.27 -0.2,0.41 -0.14,0.14 -0.24,0.27 -0.31,0.41 -0.75,0.82 -1.46,1.26 -2.14,1.33 -0.68,0.07 -1.29,-0.03 -1.84,-0.31 -0.61,-0.27 -1.19,-0.75 -1.73,-1.43 -0.82,-1.09 -1.21,-2.26 -1.17,-3.52 0.03,-1.26 0.29,-2.46 0.76,-3.62 0.48,-1.16 1.04,-2.21 1.68,-3.16 0.65,-0.95 1.17,-1.67 1.58,-2.14 0.88,-0.88 2.12,-2.04 3.72,-3.47 1.6,-1.43 3.55,-2.8 5.87,-4.13 2.31,-1.33 4.91,-2.43 7.8,-3.31 2.89,-0.88 6.07,-1.26 9.54,-1.12 3.81,0.14 7.02,0.8 9.64,1.99 2.62,1.19 4.67,2.72 6.17,4.59 1.5,1.87 2.45,4 2.86,6.38 0.4,2.37 0.3,4.82 -0.31,7.33 z m -33.97,1.63 c -0.48,0.75 -0.85,1.6 -1.12,2.55 -0.27,0.95 -0.41,1.92 -0.41,2.91 0,0.99 0.15,1.96 0.46,2.91 0.31,0.95 0.83,1.84 1.58,2.65 0.82,-1.97 1.68,-4.04 2.6,-6.22 0.92,-2.17 1.75,-4.15 2.5,-5.92 0.88,-2.11 1.8,-4.11 2.75,-6.02 0.14,-0.2 0.24,-0.44 0.31,-0.71 0.14,-0.48 0.07,-0.68 -0.2,-0.61 -0.07,0 -0.41,0.24 -1.02,0.71 -0.61,0.48 -1.36,1.11 -2.24,1.89 -0.88,0.78 -1.8,1.68 -2.75,2.7 -0.96,1.02 -1.78,2.08 -2.46,3.16 z"
|
||||||
|
id="path148" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 275.58,395.1 c 0.14,0.07 0.29,0.25 0.46,0.56 0.17,0.31 -0.05,0.83 -0.66,1.58 -1.16,1.43 -2.31,2.67 -3.47,3.72 -1.16,1.06 -1.9,1.75 -2.24,2.09 -0.95,0.68 -1.75,1.07 -2.4,1.17 -0.65,0.1 -1.14,0.12 -1.48,0.05 -0.61,0 -1.11,-0.17 -1.48,-0.51 -0.37,-0.34 -0.65,-0.78 -0.82,-1.33 -0.17,-0.54 -0.25,-1.1 -0.25,-1.68 0,-0.58 0.03,-1.14 0.1,-1.68 0,-0.14 0.03,-0.34 0.1,-0.61 0.07,-0.27 0.13,-0.54 0.2,-0.82 0.07,-0.27 0.13,-0.54 0.2,-0.82 v 0.1 c 0.34,-1.29 0.82,-2.74 1.43,-4.33 0.61,-1.6 1.46,-3.42 2.55,-5.46 0.07,-0.27 0.2,-0.54 0.41,-0.82 0.13,-0.27 0.31,-0.56 0.51,-0.87 0.2,-0.31 0.41,-0.63 0.61,-0.97 -0.68,0.14 -1.33,0.24 -1.94,0.31 -0.61,0.07 -1.19,0.14 -1.73,0.2 -0.34,0.07 -0.65,0.1 -0.92,0.1 -0.27,0 -0.58,0.04 -0.92,0.1 -0.48,1.7 -1.05,3.26 -1.73,4.69 -0.68,1.43 -1.38,2.7 -2.09,3.83 -0.71,1.12 -1.41,2.09 -2.09,2.91 -0.68,0.82 -1.22,1.46 -1.63,1.94 -0.41,0.41 -0.71,0.54 -0.92,0.41 -0.13,0 -0.27,-0.07 -0.41,-0.2 -0.27,-0.27 -0.34,-0.51 -0.2,-0.71 0,-0.14 0.07,-0.27 0.2,-0.41 0.75,-0.82 1.85,-2.24 3.32,-4.28 1.47,-2.04 2.7,-4.62 3.72,-7.75 0.07,-0.07 0.1,-0.17 0.1,-0.31 h -0.1 c -0.27,0.07 -0.6,0.12 -0.97,0.15 -0.37,0.04 -0.76,0.02 -1.17,-0.05 -0.68,-0.07 -1.28,-0.24 -1.79,-0.51 -0.51,-0.27 -0.8,-0.75 -0.87,-1.43 0,-1.02 0.2,-1.87 0.61,-2.55 0.41,-0.68 0.88,-1.22 1.43,-1.63 0.54,-0.41 1.1,-0.7 1.68,-0.87 0.58,-0.17 1,-0.29 1.27,-0.36 h 0.1 c 0.68,-0.14 1.21,-0.07 1.58,0.2 0.37,0.27 0.63,0.61 0.76,1.02 0.2,0.48 0.27,1.02 0.2,1.63 0,0.34 -0.07,0.85 -0.2,1.53 l -0.1,0.61 c 1.22,-0.14 2.45,-0.37 3.67,-0.71 1.22,-0.34 2.07,-0.58 2.55,-0.71 h 0.2 0.51 c 0.34,0.14 0.78,0.34 1.33,0.61 0.54,0.27 1.04,0.61 1.48,1.02 0.44,0.41 0.77,0.85 0.97,1.33 0.2,0.48 0.17,0.99 -0.1,1.53 -0.48,0.88 -1.27,2.26 -2.4,4.13 -1.12,1.87 -2.13,3.79 -3.01,5.76 -0.14,0.27 -0.34,0.75 -0.61,1.43 -0.54,1.16 -0.97,2.14 -1.28,2.96 -0.31,0.82 -0.39,1.29 -0.25,1.43 0.2,0 0.37,-0.03 0.51,-0.1 0.34,-0.14 0.82,-0.44 1.43,-0.92 0.61,-0.48 1.24,-1.04 1.89,-1.68 0.65,-0.65 1.29,-1.31 1.94,-1.99 0.65,-0.68 1.14,-1.26 1.48,-1.73 l 0.2,-0.2 c 0.16,-0.13 0.33,-0.17 0.53,-0.1 z m -17.03,-13.36 c 0,-0.07 0.17,-0.36 0.51,-0.87 0.34,-0.51 0.88,-1 1.63,-1.48 l 1.22,-0.71 -1.43,0.51 c -0.41,0.14 -0.75,0.34 -1.02,0.61 -0.27,0.2 -0.53,0.46 -0.76,0.77 -0.24,0.31 -0.39,0.66 -0.46,1.07 l -0.1,0.92 z m 3.77,-1.94 c -0.14,0.14 -0.31,0.34 -0.51,0.61 -0.2,0.27 -0.39,0.58 -0.56,0.92 -0.17,0.34 -0.25,0.66 -0.25,0.97 0,0.31 0.1,0.53 0.31,0.66 0.41,0.27 0.92,0.38 1.53,0.31 0.34,-1.29 0.47,-2.14 0.41,-2.55 0,-0.27 -0.07,-0.53 -0.2,-0.77 -0.15,-0.23 -0.39,-0.28 -0.73,-0.15 z"
|
||||||
|
id="path150" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 275.38,391.84 c 0.88,-1.43 1.87,-2.79 2.96,-4.08 1.09,-1.29 2.14,-2.38 3.16,-3.26 1.02,-0.88 1.99,-1.51 2.91,-1.89 0.92,-0.37 1.68,-0.36 2.29,0.05 0.61,0.41 1.17,0.8 1.68,1.17 0.51,0.38 0.93,0.7 1.27,0.97 0.41,0.27 0.78,0.55 1.12,0.82 0.14,-0.41 0.31,-0.78 0.51,-1.12 0.13,-0.34 0.25,-0.68 0.36,-1.02 0.1,-0.34 0.15,-0.65 0.15,-0.92 0,-0.07 0.03,-0.14 0.1,-0.2 l 0.2,-0.2 c 0.2,0 0.48,0.1 0.82,0.31 0.41,0.2 0.85,0.51 1.33,0.92 0.47,0.41 0.92,0.87 1.33,1.38 0.41,0.51 0.68,1.04 0.82,1.58 0.14,0.54 0.03,1.12 -0.31,1.73 -0.41,0.75 -1,1.9 -1.79,3.47 -0.78,1.57 -1.55,3.15 -2.29,4.74 -0.75,1.6 -1.36,3.03 -1.84,4.28 -0.48,1.26 -0.61,1.96 -0.41,2.09 0.14,0.14 0.51,-0.02 1.12,-0.46 0.61,-0.44 1.31,-1.02 2.09,-1.73 0.78,-0.71 1.53,-1.46 2.24,-2.24 0.71,-0.78 1.27,-1.44 1.68,-1.99 0,-0.07 0.07,-0.14 0.2,-0.2 0.2,-0.2 0.41,-0.24 0.61,-0.1 0.14,0.07 0.27,0.25 0.41,0.56 0.13,0.31 -0.1,0.83 -0.71,1.58 -1.16,1.43 -2.31,2.67 -3.47,3.72 -1.16,1.05 -1.9,1.75 -2.24,2.09 -0.95,0.68 -1.73,1.07 -2.35,1.17 -0.61,0.1 -1.09,0.12 -1.43,0.05 -1.22,-0.2 -1.99,-0.75 -2.29,-1.63 -0.31,-0.88 -0.39,-1.9 -0.25,-3.06 0.13,-1.16 0.46,-2.38 0.97,-3.67 0.51,-1.29 0.97,-2.41 1.38,-3.37 -0.75,0.88 -1.62,1.89 -2.6,3.01 -0.99,1.12 -1.97,2.21 -2.96,3.26 -0.99,1.05 -1.87,2.01 -2.65,2.86 -0.78,0.85 -1.28,1.41 -1.48,1.68 -0.41,0.47 -1.19,0.54 -2.35,0.2 -1.16,-0.34 -2.04,-0.88 -2.65,-1.63 -0.61,-0.68 -0.78,-2 -0.51,-3.98 0.28,-1.98 1.24,-4.29 2.87,-6.94 z m 3.67,7.75 c 0.61,-0.41 1.51,-1.27 2.7,-2.6 1.19,-1.33 2.36,-2.7 3.52,-4.13 1.36,-1.7 2.86,-3.5 4.49,-5.41 -0.95,-0.61 -1.89,-0.71 -2.8,-0.31 -0.91,0.4 -1.68,0.99 -2.29,1.73 -0.61,0.75 -1.55,2.01 -2.81,3.77 -1.26,1.77 -2.33,3.61 -3.21,5.51 -0.34,0.61 -0.46,1.04 -0.36,1.28 0.1,0.24 0.22,0.36 0.36,0.36 0.14,0 0.24,-0.03 0.31,-0.1 0.05,0 0.09,-0.03 0.09,-0.1 z"
|
||||||
|
id="path152" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 296.29,403.06 c -0.34,-0.48 -0.49,-1.16 -0.46,-2.04 0.04,-0.88 0.17,-1.87 0.41,-2.96 0.24,-1.09 0.56,-2.24 0.97,-3.47 0.41,-1.22 0.85,-2.45 1.33,-3.67 1.09,-2.79 2.45,-5.81 4.08,-9.08 0.07,-0.13 0.1,-0.22 0.1,-0.25 0,-0.03 0.03,-0.12 0.1,-0.25 0,-0.07 0.07,-0.14 0.2,-0.2 0.2,-0.07 0.51,-0.07 0.92,0 0.41,0.2 0.83,0.51 1.28,0.92 0.44,0.41 0.83,0.87 1.17,1.38 0.34,0.51 0.56,1.07 0.66,1.68 0.1,0.61 0.02,1.16 -0.25,1.63 -0.41,0.88 -1.12,2.16 -2.14,3.83 -1.02,1.67 -1.9,3.49 -2.65,5.46 -0.34,0.54 -0.55,1.02 -0.61,1.43 -0.48,1.16 -0.83,2.14 -1.07,2.96 -0.24,0.82 -0.29,1.29 -0.15,1.43 h 0.41 c 0.34,-0.13 0.8,-0.46 1.38,-0.97 0.58,-0.51 1.19,-1.09 1.84,-1.73 0.65,-0.65 1.26,-1.31 1.84,-1.99 0.58,-0.68 1.07,-1.26 1.48,-1.73 l 0.2,-0.2 c 0.07,-0.07 0.24,-0.1 0.51,-0.1 0.2,0.07 0.37,0.27 0.51,0.61 0.14,0.34 -0.1,0.88 -0.71,1.63 -1.02,1.36 -2.09,2.57 -3.21,3.62 -1.12,1.06 -1.89,1.75 -2.29,2.09 -0.88,0.68 -1.63,1.07 -2.24,1.17 -0.61,0.1 -1.09,0.12 -1.43,0.05 h -0.1 c -0.27,0 -0.54,-0.1 -0.82,-0.31 -0.58,-0.23 -0.99,-0.54 -1.26,-0.94 z M 307.3,374.8 c 0.75,0.34 1.43,0.99 2.04,1.94 0.61,0.95 0.65,1.94 0.1,2.96 -0.14,0.27 -0.24,0.51 -0.31,0.71 -0.07,0.2 -0.27,0.58 -0.61,1.12 -0.14,0.27 -0.44,0.41 -0.92,0.41 -0.2,0 -0.41,-0.07 -0.61,-0.2 -0.14,-0.14 -0.41,-0.39 -0.82,-0.76 -0.41,-0.37 -0.78,-0.7 -1.12,-0.97 -0.54,-0.41 -0.78,-0.85 -0.71,-1.33 0.27,-0.48 0.56,-1.05 0.87,-1.73 0.31,-0.68 0.63,-1.36 0.97,-2.04 0,-0.07 0.07,-0.14 0.2,-0.2 0.21,-0.15 0.51,-0.11 0.92,0.09 z"
|
||||||
|
id="path154" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 308.02,391.84 c 0.88,-1.43 1.87,-2.79 2.96,-4.08 1.09,-1.29 2.14,-2.38 3.16,-3.26 1.02,-0.88 1.99,-1.51 2.91,-1.89 0.92,-0.37 1.68,-0.36 2.29,0.05 0.61,0.41 1.17,0.8 1.68,1.17 0.51,0.38 0.93,0.7 1.27,0.97 0.41,0.27 0.78,0.55 1.12,0.82 0.14,-0.41 0.31,-0.78 0.51,-1.12 0.13,-0.34 0.25,-0.68 0.36,-1.02 0.1,-0.34 0.15,-0.65 0.15,-0.92 0,-0.07 0.03,-0.14 0.1,-0.2 l 0.2,-0.2 c 0.2,0 0.48,0.1 0.82,0.31 0.41,0.2 0.85,0.51 1.33,0.92 0.47,0.41 0.92,0.87 1.33,1.38 0.41,0.51 0.68,1.04 0.82,1.58 0.14,0.54 0.03,1.12 -0.31,1.73 -0.41,0.75 -1,1.9 -1.79,3.47 -0.78,1.57 -1.55,3.15 -2.29,4.74 -0.75,1.6 -1.36,3.03 -1.84,4.28 -0.48,1.26 -0.61,1.96 -0.41,2.09 0.14,0.14 0.51,-0.02 1.12,-0.46 0.61,-0.44 1.31,-1.02 2.09,-1.73 0.78,-0.71 1.53,-1.46 2.24,-2.24 0.71,-0.78 1.27,-1.44 1.68,-1.99 0,-0.07 0.07,-0.14 0.2,-0.2 0.2,-0.2 0.41,-0.24 0.61,-0.1 0.14,0.07 0.27,0.25 0.41,0.56 0.13,0.31 -0.1,0.83 -0.71,1.58 -1.16,1.43 -2.31,2.67 -3.47,3.72 -1.16,1.05 -1.9,1.75 -2.24,2.09 -0.95,0.68 -1.73,1.07 -2.35,1.17 -0.61,0.1 -1.09,0.12 -1.43,0.05 -1.22,-0.2 -1.99,-0.75 -2.29,-1.63 -0.31,-0.88 -0.39,-1.9 -0.25,-3.06 0.13,-1.16 0.46,-2.38 0.97,-3.67 0.51,-1.29 0.97,-2.41 1.38,-3.37 -0.75,0.88 -1.62,1.89 -2.6,3.01 -0.99,1.12 -1.97,2.21 -2.96,3.26 -0.99,1.05 -1.87,2.01 -2.65,2.86 -0.78,0.85 -1.28,1.41 -1.48,1.68 -0.41,0.47 -1.19,0.54 -2.35,0.2 -1.16,-0.34 -2.04,-0.88 -2.65,-1.63 -0.61,-0.68 -0.78,-2 -0.51,-3.98 0.28,-1.98 1.23,-4.29 2.87,-6.94 z m 3.67,7.75 c 0.61,-0.41 1.51,-1.27 2.7,-2.6 1.19,-1.33 2.36,-2.7 3.52,-4.13 1.36,-1.7 2.86,-3.5 4.49,-5.41 -0.95,-0.61 -1.89,-0.71 -2.8,-0.31 -0.91,0.4 -1.68,0.99 -2.29,1.73 -0.61,0.75 -1.55,2.01 -2.81,3.77 -1.26,1.77 -2.33,3.61 -3.21,5.51 -0.34,0.61 -0.46,1.04 -0.36,1.28 0.1,0.24 0.22,0.36 0.36,0.36 0.14,0 0.24,-0.03 0.31,-0.1 0.05,0 0.09,-0.03 0.09,-0.1 z"
|
||||||
|
id="path156" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 356.16,393.37 c -0.75,0.88 -1.63,1.9 -2.65,3.06 -1.02,1.16 -2.02,2.28 -3.01,3.37 -0.99,1.09 -1.91,2.06 -2.75,2.91 -0.85,0.85 -1.41,1.38 -1.68,1.58 -0.41,0.34 -1.14,0.36 -2.19,0.05 -1.05,-0.31 -1.89,-0.83 -2.5,-1.58 -0.61,-0.68 -0.76,-2 -0.46,-3.98 0.31,-1.97 1.28,-4.28 2.91,-6.94 0.88,-1.43 1.85,-2.79 2.91,-4.08 1.05,-1.29 2.11,-2.38 3.16,-3.26 1.05,-0.88 2.04,-1.51 2.96,-1.89 0.92,-0.37 1.68,-0.36 2.29,0.05 1.16,0.75 2.07,1.39 2.75,1.94 0.68,0.54 1.09,0.88 1.22,1.02 1.09,-2.04 2.11,-4.03 3.06,-5.97 0.95,-1.94 1.79,-3.74 2.5,-5.41 0.71,-1.67 1.31,-3.13 1.79,-4.39 0.47,-1.26 0.85,-2.26 1.12,-3.01 0.27,-0.75 0.53,-1.46 0.76,-2.14 0.24,-0.68 0.46,-1.46 0.66,-2.35 v -0.2 l 0.31,-0.2 c 0.07,0 0.34,0.07 0.82,0.2 0.95,0.61 1.72,1.19 2.29,1.73 0.58,0.54 0.98,1.12 1.22,1.73 0.24,0.61 0.27,1.29 0.1,2.04 -0.17,0.75 -0.56,1.67 -1.17,2.75 -0.34,0.75 -1,2.14 -1.99,4.18 -0.99,2.04 -1.99,4.15 -3.01,6.32 -1.22,2.59 -2.55,5.34 -3.98,8.26 -1.16,2.52 -2.14,4.73 -2.96,6.63 -0.75,1.7 -1.39,3.23 -1.94,4.59 -0.54,1.36 -0.75,2.11 -0.61,2.24 0.2,0.14 0.61,-0.02 1.22,-0.46 0.61,-0.44 1.29,-1.02 2.04,-1.73 0.75,-0.71 1.5,-1.46 2.24,-2.24 0.75,-0.78 1.33,-1.44 1.73,-1.99 l 0.2,-0.2 c 0.13,-0.14 0.31,-0.17 0.51,-0.1 0.14,0.07 0.29,0.25 0.46,0.56 0.17,0.31 -0.09,0.83 -0.76,1.58 -1.16,1.43 -2.3,2.67 -3.42,3.72 -1.12,1.05 -1.89,1.75 -2.3,2.09 -0.88,0.68 -1.65,1.07 -2.29,1.17 -0.65,0.1 -1.14,0.12 -1.48,0.05 -1.16,-0.2 -1.9,-0.75 -2.24,-1.63 -0.34,-0.88 -0.43,-1.9 -0.25,-3.06 0.17,-1.16 0.49,-2.38 0.97,-3.67 0.49,-1.27 0.96,-2.39 1.44,-3.34 z m -9.18,4.79 c -0.34,0.61 -0.46,1.04 -0.36,1.28 0.1,0.24 0.22,0.36 0.36,0.36 0.14,0 0.24,-0.03 0.31,-0.1 0.07,0 0.14,-0.03 0.2,-0.1 0.54,-0.41 1.41,-1.27 2.6,-2.6 1.19,-1.33 2.36,-2.7 3.52,-4.13 1.36,-1.7 2.79,-3.5 4.28,-5.41 -0.95,-0.61 -1.85,-0.71 -2.7,-0.31 -0.85,0.41 -1.58,0.99 -2.19,1.73 -0.27,0.41 -0.66,0.94 -1.17,1.58 -0.51,0.65 -1.04,1.38 -1.58,2.19 -0.54,0.82 -1.11,1.7 -1.68,2.65 -0.59,0.96 -1.12,1.91 -1.59,2.86 z"
|
||||||
|
id="path158" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 364.62,400.81 c -0.27,-1.22 -0.29,-2.46 -0.05,-3.72 0.24,-1.26 0.61,-2.46 1.12,-3.62 0.51,-1.16 1.07,-2.19 1.68,-3.11 0.61,-0.92 1.19,-1.68 1.73,-2.29 0.88,-0.95 1.73,-1.79 2.55,-2.5 0.82,-0.71 1.5,-1.28 2.04,-1.68 0.68,-0.47 1.29,-0.85 1.84,-1.12 1.43,-0.82 2.52,-0.95 3.26,-0.41 0.54,0.41 1,0.78 1.38,1.12 0.37,0.34 0.73,0.65 1.07,0.92 l 0.1,0.1 c 0.07,0.14 0.17,0.31 0.31,0.51 0.14,0.2 0.2,0.48 0.2,0.82 0,1.5 -0.37,2.89 -1.12,4.18 -0.75,1.29 -1.7,2.45 -2.86,3.47 -1.36,1.22 -2.81,2.07 -4.33,2.55 -1.53,0.48 -2.7,0.58 -3.52,0.31 -0.54,1.22 -0.82,2.21 -0.82,2.96 0,0.75 0.07,1.36 0.2,1.84 0.2,0.54 0.48,0.95 0.82,1.22 0.82,0.55 1.73,0.63 2.75,0.26 1.02,-0.37 2,-0.93 2.96,-1.68 0.95,-0.75 1.87,-1.55 2.75,-2.4 0.88,-0.85 1.63,-1.55 2.24,-2.09 0.14,-0.14 0.31,-0.24 0.51,-0.31 0.48,-0.14 0.78,-0.1 0.92,0.1 0.14,0.07 0.2,0.17 0.2,0.31 0,0.34 -0.14,0.65 -0.41,0.92 -1.77,1.84 -3.28,3.4 -4.54,4.69 -1.26,1.29 -2.16,2.01 -2.7,2.14 -1.84,0.61 -3.37,0.88 -4.59,0.82 -1.22,-0.07 -2.23,-0.32 -3.01,-0.77 -0.78,-0.44 -1.38,-0.98 -1.79,-1.63 -0.41,-0.65 -0.71,-1.24 -0.92,-1.79 v -0.12 z m 13.16,-10.3 c 0.88,-1.02 1.46,-1.8 1.73,-2.35 0.27,-0.54 0.36,-0.92 0.25,-1.12 -0.1,-0.2 -0.27,-0.31 -0.51,-0.31 -0.24,0 -0.39,0 -0.46,0 -0.54,0.14 -1.16,0.41 -1.84,0.82 -0.55,0.34 -1.17,0.83 -1.89,1.48 -0.71,0.65 -1.45,1.45 -2.19,2.4 -0.34,0.48 -0.65,0.92 -0.92,1.33 -0.27,0.41 -0.55,0.82 -0.82,1.22 0.47,0.07 1.14,0 1.99,-0.2 0.85,-0.2 1.79,-0.71 2.8,-1.53 0.27,-0.2 0.53,-0.41 0.76,-0.61 0.24,-0.2 0.49,-0.47 0.77,-0.82 z"
|
||||||
|
id="path160" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 250.03,427.45 c 5.1,0.48 9.52,0.24 13.26,-0.71 3.74,-0.95 6.82,-2.16 9.23,-3.62 2.41,-1.46 4.16,-2.97 5.25,-4.54 1.09,-1.56 1.56,-2.72 1.43,-3.47 -0.41,-1.5 -2.06,-2.65 -4.95,-3.47 -2.89,-0.82 -6.89,-0.82 -11.99,0 -2.52,0.41 -4.86,1.12 -7.04,2.14 -2.18,1.02 -4.08,2.23 -5.71,3.62 -1.63,1.39 -2.92,2.87 -3.88,4.44 -0.95,1.57 -1.5,3.1 -1.63,4.59 -0.14,1.5 -0.04,2.72 0.31,3.67 0.34,0.95 0.9,1.79 1.68,2.5 0.78,0.71 1.82,1.38 3.11,1.99 1.29,0.61 2.82,1.26 4.59,1.94 2.31,0.95 4.45,1.75 6.43,2.4 1.97,0.65 3.43,1.48 4.39,2.5 2.31,-0.48 4.1,-0.78 5.35,-0.92 1.26,-0.13 2.4,-0.27 3.42,-0.41 0.41,0 0.75,0.04 1.02,0.1 0.61,0.14 0.78,0.44 0.51,0.92 -0.34,0.41 -0.63,0.8 -0.87,1.17 -0.24,0.38 -0.94,0.66 -2.09,0.87 -1.29,0.14 -2.48,0.31 -3.57,0.51 -1.09,0.2 -2.21,0.38 -3.37,0.51 v 0.41 c 0,0.75 -0.22,1.58 -0.66,2.5 -0.44,0.92 -1.11,1.84 -1.99,2.75 -0.88,0.92 -2.01,1.79 -3.37,2.6 -1.36,0.82 -2.96,1.46 -4.79,1.94 -2.58,0.75 -4.81,1.09 -6.68,1.02 -1.87,-0.07 -3.37,-0.41 -4.49,-1.02 -1.12,-0.61 -1.85,-1.39 -2.19,-2.35 -0.34,-0.95 -0.27,-1.94 0.2,-2.96 0.27,-0.61 0.95,-1.24 2.04,-1.89 1.09,-0.65 2.4,-1.26 3.93,-1.84 1.53,-0.58 3.23,-1.12 5.1,-1.63 1.87,-0.51 3.79,-0.97 5.76,-1.38 -1.09,-0.61 -2.64,-1.33 -4.64,-2.14 -2.01,-0.82 -4.54,-1.87 -7.6,-3.16 -6.53,-2.58 -9.38,-6.59 -8.57,-12.04 0.2,-1.22 0.76,-2.74 1.68,-4.54 0.92,-1.8 2.29,-3.6 4.13,-5.41 1.84,-1.8 4.15,-3.45 6.94,-4.95 2.79,-1.5 6.08,-2.58 9.89,-3.26 3.47,-0.61 6.51,-0.78 9.13,-0.51 2.62,0.27 4.85,0.77 6.68,1.48 1.83,0.71 3.26,1.62 4.28,2.7 1.02,1.09 1.67,2.14 1.94,3.16 0.61,2.18 0.49,4.39 -0.36,6.63 -0.85,2.24 -3.08,4.66 -6.68,7.24 -2.18,1.63 -4.37,2.89 -6.58,3.77 -2.21,0.88 -4.23,1.53 -6.07,1.94 -2.18,0.48 -4.25,0.75 -6.22,0.82 -0.82,0 -1.58,-0.27 -2.29,-0.82 -0.71,-0.54 -1.34,-1.16 -1.89,-1.84 -0.54,-0.68 -1,-1.36 -1.38,-2.04 -0.38,-0.68 -0.63,-1.19 -0.76,-1.53 0,-0.07 0.07,-0.17 0.2,-0.31 0.07,0 0.17,-0.03 0.31,-0.1 h 0.12 z m -6.01,23.77 c 1.29,0.13 2.7,0.03 4.23,-0.31 1.53,-0.34 2.99,-0.8 4.39,-1.38 1.39,-0.58 2.67,-1.24 3.82,-1.99 1.16,-0.75 2.04,-1.49 2.65,-2.24 -3.81,0.82 -6.72,1.58 -8.72,2.29 -2.01,0.71 -3.49,1.34 -4.44,1.89 -1.15,0.68 -1.8,1.26 -1.93,1.74 z"
|
||||||
|
id="path162" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 273.08,445.81 c -0.27,-1.22 -0.29,-2.46 -0.05,-3.72 0.24,-1.26 0.61,-2.46 1.12,-3.62 0.51,-1.16 1.07,-2.19 1.68,-3.11 0.61,-0.92 1.19,-1.68 1.73,-2.29 0.88,-0.95 1.73,-1.79 2.55,-2.5 0.82,-0.71 1.5,-1.28 2.04,-1.68 0.68,-0.47 1.29,-0.85 1.84,-1.12 1.43,-0.82 2.52,-0.95 3.26,-0.41 0.54,0.41 1,0.78 1.38,1.12 0.37,0.34 0.73,0.65 1.07,0.92 l 0.1,0.1 c 0.07,0.14 0.17,0.31 0.31,0.51 0.14,0.2 0.2,0.48 0.2,0.82 0,1.5 -0.37,2.89 -1.12,4.18 -0.75,1.29 -1.7,2.45 -2.86,3.47 -1.36,1.22 -2.81,2.07 -4.33,2.55 -1.53,0.48 -2.7,0.58 -3.52,0.31 -0.54,1.22 -0.82,2.21 -0.82,2.96 0,0.75 0.07,1.36 0.2,1.84 0.2,0.54 0.48,0.95 0.82,1.22 0.82,0.55 1.73,0.63 2.75,0.26 1.02,-0.37 2,-0.93 2.96,-1.68 0.95,-0.75 1.87,-1.55 2.75,-2.4 0.88,-0.85 1.63,-1.55 2.24,-2.09 0.14,-0.14 0.31,-0.24 0.51,-0.31 0.48,-0.14 0.78,-0.1 0.92,0.1 0.14,0.07 0.2,0.17 0.2,0.31 0,0.34 -0.14,0.65 -0.41,0.92 -1.77,1.84 -3.28,3.4 -4.54,4.69 -1.26,1.29 -2.16,2.01 -2.7,2.14 -1.84,0.61 -3.37,0.88 -4.59,0.82 -1.22,-0.07 -2.23,-0.32 -3.01,-0.77 -0.78,-0.44 -1.38,-0.98 -1.79,-1.63 -0.41,-0.65 -0.71,-1.24 -0.92,-1.79 v -0.12 z m 13.16,-10.3 c 0.88,-1.02 1.46,-1.8 1.73,-2.35 0.27,-0.54 0.36,-0.92 0.25,-1.12 -0.1,-0.2 -0.27,-0.31 -0.51,-0.31 -0.24,0 -0.39,0 -0.46,0 -0.54,0.14 -1.16,0.41 -1.84,0.82 -0.55,0.34 -1.17,0.83 -1.89,1.48 -0.71,0.65 -1.45,1.45 -2.19,2.4 -0.34,0.48 -0.65,0.92 -0.92,1.33 -0.27,0.41 -0.55,0.82 -0.82,1.22 0.47,0.07 1.14,0 1.99,-0.2 0.85,-0.2 1.79,-0.71 2.8,-1.53 0.27,-0.2 0.53,-0.41 0.76,-0.61 0.24,-0.2 0.49,-0.47 0.77,-0.82 z"
|
||||||
|
id="path164" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 303.99,438.47 c -0.68,0.14 -1.17,0.25 -1.48,0.36 -0.31,0.1 -1.11,0.32 -2.4,0.66 0.34,1.16 0.59,2.33 0.76,3.52 0.17,1.19 0.1,2.28 -0.2,3.26 -0.31,0.99 -0.94,1.84 -1.89,2.55 -0.95,0.71 -2.38,1.17 -4.28,1.38 -1.57,0.07 -2.96,-0.04 -4.18,-0.31 -1.02,-0.2 -1.95,-0.6 -2.81,-1.17 -0.85,-0.58 -1.27,-1.44 -1.27,-2.6 0,-0.95 0.54,-1.94 1.63,-2.96 0.48,-0.61 0.95,-1.36 1.43,-2.24 0.48,-0.88 0.92,-1.79 1.33,-2.7 0.41,-0.91 0.76,-1.78 1.07,-2.6 0.31,-0.82 0.56,-1.39 0.76,-1.73 -0.34,-1.29 -0.31,-2.53 0.1,-3.72 0.41,-1.19 1.02,-2.24 1.84,-3.16 0.82,-0.92 1.73,-1.68 2.75,-2.29 1.02,-0.61 2,-1.02 2.96,-1.22 1.36,-0.27 2.58,-0.42 3.67,-0.46 1.09,-0.03 2,-0.02 2.75,0.05 0.07,0 0.13,0.04 0.2,0.1 0.2,0.2 0.31,0.34 0.31,0.41 0,0.14 -0.02,0.25 -0.05,0.36 -0.04,0.1 -0.22,0.29 -0.56,0.56 -0.68,0.48 -1.46,1.07 -2.35,1.79 -0.88,0.71 -1.7,1.5 -2.45,2.35 -0.75,0.85 -1.38,1.75 -1.89,2.7 -0.51,0.95 -0.76,1.9 -0.76,2.86 0.07,0.48 0.17,1.04 0.31,1.68 0.14,0.65 0.27,1.28 0.41,1.89 0.47,-0.13 0.85,-0.24 1.12,-0.31 0.27,-0.07 0.54,-0.14 0.82,-0.2 0.27,-0.07 0.58,-0.14 0.92,-0.2 0.34,-0.07 0.82,-0.17 1.43,-0.31 h 0.61 c 0.48,0 0.71,0.17 0.71,0.51 0,0.41 -0.19,0.7 -0.56,0.87 -0.37,0.13 -0.63,0.25 -0.76,0.32 z m -13.16,4.69 c -0.68,0.48 -1.16,0.92 -1.43,1.33 -0.27,0.34 -0.41,0.71 -0.41,1.12 0,0.41 0.31,0.78 0.92,1.12 0.88,0.34 1.73,0.51 2.55,0.51 0.68,0 1.38,-0.19 2.09,-0.56 0.71,-0.37 1.24,-1.14 1.58,-2.3 0.14,-0.27 0.2,-0.58 0.2,-0.92 0,-0.75 -0.14,-1.67 -0.41,-2.75 -1.09,0.34 -2.08,0.71 -2.96,1.12 -0.87,0.41 -1.59,0.86 -2.13,1.33 z m 2.76,-6.93 c -0.2,0.41 -0.51,0.99 -0.92,1.73 -0.41,0.75 -0.78,1.6 -1.12,2.55 0.54,-0.27 1.1,-0.54 1.68,-0.82 0.58,-0.27 1.24,-0.54 1.99,-0.82 -0.34,-0.75 -0.63,-1.26 -0.87,-1.53 -0.24,-0.26 -0.49,-0.64 -0.76,-1.11 z"
|
||||||
|
id="path166" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 303.68,445.81 c -0.27,-1.22 -0.29,-2.46 -0.05,-3.72 0.24,-1.26 0.61,-2.46 1.12,-3.62 0.51,-1.16 1.07,-2.19 1.68,-3.11 0.61,-0.92 1.19,-1.68 1.73,-2.29 0.88,-0.95 1.73,-1.79 2.55,-2.5 0.82,-0.71 1.5,-1.28 2.04,-1.68 0.68,-0.47 1.29,-0.85 1.84,-1.12 1.43,-0.82 2.52,-0.95 3.26,-0.41 0.54,0.41 1,0.78 1.38,1.12 0.37,0.34 0.73,0.65 1.07,0.92 l 0.1,0.1 c 0.07,0.14 0.17,0.31 0.31,0.51 0.14,0.2 0.2,0.48 0.2,0.82 0,1.5 -0.37,2.89 -1.12,4.18 -0.75,1.29 -1.7,2.45 -2.86,3.47 -1.36,1.22 -2.81,2.07 -4.33,2.55 -1.53,0.48 -2.7,0.58 -3.52,0.31 -0.54,1.22 -0.82,2.21 -0.82,2.96 0,0.75 0.07,1.36 0.2,1.84 0.2,0.54 0.48,0.95 0.82,1.22 0.82,0.55 1.73,0.63 2.75,0.26 1.02,-0.37 2,-0.93 2.96,-1.68 0.95,-0.75 1.87,-1.55 2.75,-2.4 0.88,-0.85 1.63,-1.55 2.24,-2.09 0.14,-0.14 0.31,-0.24 0.51,-0.31 0.48,-0.14 0.78,-0.1 0.92,0.1 0.14,0.07 0.2,0.17 0.2,0.31 0,0.34 -0.14,0.65 -0.41,0.92 -1.77,1.84 -3.28,3.4 -4.54,4.69 -1.26,1.29 -2.16,2.01 -2.7,2.14 -1.84,0.61 -3.37,0.88 -4.59,0.82 -1.22,-0.07 -2.23,-0.32 -3.01,-0.77 -0.78,-0.44 -1.38,-0.98 -1.79,-1.63 -0.41,-0.65 -0.71,-1.24 -0.92,-1.79 v -0.12 z m 13.16,-10.3 c 0.88,-1.02 1.46,-1.8 1.73,-2.35 0.27,-0.54 0.36,-0.92 0.25,-1.12 -0.1,-0.2 -0.27,-0.31 -0.51,-0.31 -0.24,0 -0.39,0 -0.46,0 -0.54,0.14 -1.16,0.41 -1.84,0.82 -0.55,0.34 -1.17,0.83 -1.89,1.48 -0.71,0.65 -1.45,1.45 -2.19,2.4 -0.34,0.48 -0.65,0.92 -0.92,1.33 -0.27,0.41 -0.55,0.82 -0.82,1.22 0.47,0.07 1.14,0 1.99,-0.2 0.85,-0.2 1.79,-0.71 2.8,-1.53 0.27,-0.2 0.53,-0.41 0.76,-0.61 0.24,-0.2 0.49,-0.47 0.77,-0.82 z"
|
||||||
|
id="path168" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 335.91,406.34 c 0.41,0.27 0.88,0.61 1.43,1.02 0.54,0.41 1.02,0.88 1.43,1.43 0.41,0.54 0.68,1.12 0.82,1.73 0.13,0.61 0.03,1.22 -0.31,1.84 -1.43,3.54 -2.99,7.02 -4.69,10.46 -1.7,3.43 -3.43,6.92 -5.2,10.46 v 0.1 c -1.16,2.45 -2.14,4.62 -2.96,6.53 -0.75,1.63 -1.39,3.15 -1.94,4.54 -0.54,1.39 -0.75,2.16 -0.61,2.29 0.2,0.14 0.61,-0.02 1.22,-0.46 0.61,-0.44 1.29,-1 2.04,-1.68 0.75,-0.68 1.5,-1.41 2.24,-2.19 0.75,-0.78 1.33,-1.48 1.73,-2.09 l 0.2,-0.2 c 0.07,-0.07 0.24,-0.1 0.51,-0.1 0.14,0.07 0.29,0.27 0.46,0.61 0.17,0.34 -0.09,0.88 -0.76,1.63 -1.16,1.36 -2.29,2.58 -3.42,3.67 -1.12,1.09 -1.89,1.77 -2.29,2.04 -0.95,0.68 -1.73,1.09 -2.35,1.22 -0.61,0.13 -1.09,0.13 -1.43,0 -1.22,-0.2 -2,-0.73 -2.35,-1.58 -0.34,-0.85 -0.44,-1.85 -0.31,-3.01 0.14,-1.16 0.44,-2.36 0.92,-3.62 0.48,-1.26 0.95,-2.36 1.43,-3.31 0.47,-1.09 0.97,-2.21 1.48,-3.37 0.51,-1.16 1,-2.28 1.48,-3.37 0.47,-1.09 0.9,-2.06 1.28,-2.91 0.37,-0.85 0.66,-1.48 0.87,-1.89 1.84,-4.08 3.26,-7.33 4.28,-9.74 1.02,-2.41 1.77,-4.23 2.24,-5.46 0.27,-0.68 0.51,-1.39 0.71,-2.14 0.2,-0.75 0.44,-1.53 0.71,-2.35 v -0.2 l 0.31,-0.2 c 0.22,-0.01 0.49,0.09 0.83,0.3 z"
|
||||||
|
id="path170" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 346.11,406.34 c 0.41,0.27 0.88,0.61 1.43,1.02 0.54,0.41 1.02,0.88 1.43,1.43 0.41,0.54 0.68,1.12 0.82,1.73 0.13,0.61 0.03,1.22 -0.31,1.84 -1.43,3.54 -2.99,7.02 -4.69,10.46 -1.7,3.43 -3.43,6.92 -5.2,10.46 v 0.1 c -1.16,2.45 -2.14,4.62 -2.96,6.53 -0.75,1.63 -1.39,3.15 -1.94,4.54 -0.54,1.39 -0.75,2.16 -0.61,2.29 0.2,0.14 0.61,-0.02 1.22,-0.46 0.61,-0.44 1.29,-1 2.04,-1.68 0.75,-0.68 1.5,-1.41 2.24,-2.19 0.75,-0.78 1.33,-1.48 1.73,-2.09 l 0.2,-0.2 c 0.07,-0.07 0.24,-0.1 0.51,-0.1 0.14,0.07 0.29,0.27 0.46,0.61 0.17,0.34 -0.09,0.88 -0.76,1.63 -1.16,1.36 -2.29,2.58 -3.42,3.67 -1.12,1.09 -1.89,1.77 -2.29,2.04 -0.95,0.68 -1.73,1.09 -2.35,1.22 -0.61,0.13 -1.09,0.13 -1.43,0 -1.22,-0.2 -2,-0.73 -2.35,-1.58 -0.34,-0.85 -0.44,-1.85 -0.31,-3.01 0.14,-1.16 0.44,-2.36 0.92,-3.62 0.48,-1.26 0.95,-2.36 1.43,-3.31 0.47,-1.09 0.97,-2.21 1.48,-3.37 0.51,-1.16 1,-2.28 1.48,-3.37 0.47,-1.09 0.9,-2.06 1.28,-2.91 0.37,-0.85 0.66,-1.48 0.87,-1.89 1.84,-4.08 3.26,-7.33 4.28,-9.74 1.02,-2.41 1.77,-4.23 2.24,-5.46 0.27,-0.68 0.51,-1.39 0.71,-2.14 0.2,-0.75 0.44,-1.53 0.71,-2.35 v -0.2 l 0.31,-0.2 c 0.22,-0.01 0.49,0.09 0.83,0.3 z"
|
||||||
|
id="path172" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 340.6,445.81 c -0.27,-1.22 -0.29,-2.46 -0.05,-3.72 0.24,-1.26 0.61,-2.46 1.12,-3.62 0.51,-1.16 1.07,-2.19 1.68,-3.11 0.61,-0.92 1.19,-1.68 1.73,-2.29 0.88,-0.95 1.73,-1.79 2.55,-2.5 0.82,-0.71 1.5,-1.28 2.04,-1.68 0.68,-0.47 1.29,-0.85 1.84,-1.12 1.43,-0.82 2.52,-0.95 3.26,-0.41 0.54,0.41 1,0.78 1.38,1.12 0.37,0.34 0.73,0.65 1.07,0.92 l 0.1,0.1 c 0.07,0.14 0.17,0.31 0.31,0.51 0.14,0.2 0.2,0.48 0.2,0.82 0,1.5 -0.37,2.89 -1.12,4.18 -0.75,1.29 -1.7,2.45 -2.86,3.47 -1.36,1.22 -2.81,2.07 -4.33,2.55 -1.53,0.48 -2.7,0.58 -3.52,0.31 -0.54,1.22 -0.82,2.21 -0.82,2.96 0,0.75 0.07,1.36 0.2,1.84 0.2,0.54 0.48,0.95 0.82,1.22 0.82,0.55 1.73,0.63 2.75,0.26 1.02,-0.37 2,-0.93 2.96,-1.68 0.95,-0.75 1.87,-1.55 2.75,-2.4 0.88,-0.85 1.63,-1.55 2.24,-2.09 0.14,-0.14 0.31,-0.24 0.51,-0.31 0.48,-0.14 0.78,-0.1 0.92,0.1 0.14,0.07 0.2,0.17 0.2,0.31 0,0.34 -0.14,0.65 -0.41,0.92 -1.77,1.84 -3.28,3.4 -4.54,4.69 -1.26,1.29 -2.16,2.01 -2.7,2.14 -1.84,0.61 -3.37,0.88 -4.59,0.82 -1.22,-0.07 -2.23,-0.32 -3.01,-0.77 -0.78,-0.44 -1.38,-0.98 -1.79,-1.63 -0.41,-0.65 -0.71,-1.24 -0.92,-1.79 v -0.12 z m 13.16,-10.3 c 0.88,-1.02 1.46,-1.8 1.73,-2.35 0.27,-0.54 0.36,-0.92 0.25,-1.12 -0.1,-0.2 -0.27,-0.31 -0.51,-0.31 -0.24,0 -0.39,0 -0.46,0 -0.54,0.14 -1.16,0.41 -1.84,0.82 -0.55,0.34 -1.17,0.83 -1.89,1.48 -0.71,0.65 -1.45,1.45 -2.19,2.4 -0.34,0.48 -0.65,0.92 -0.92,1.33 -0.27,0.41 -0.55,0.82 -0.82,1.22 0.47,0.07 1.14,0 1.99,-0.2 0.85,-0.2 1.79,-0.71 2.8,-1.53 0.27,-0.2 0.53,-0.41 0.76,-0.61 0.24,-0.2 0.49,-0.47 0.77,-0.82 z"
|
||||||
|
id="path174" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g222">
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 213.08,472.79 c 0.18,-0.37 0.43,-0.68 0.74,-0.92 0.31,-0.24 0.68,-0.41 1.1,-0.53 0.42,-0.11 0.88,-0.17 1.39,-0.17 0.39,0 0.77,0.04 1.16,0.11 0.38,0.07 0.73,0.21 1.04,0.42 0.31,0.21 0.55,0.49 0.75,0.86 0.19,0.37 0.29,0.85 0.29,1.44 v 4.66 c 0,0.43 0.21,0.65 0.63,0.65 0.12,0 0.24,-0.02 0.34,-0.07 v 0.9 c -0.12,0.02 -0.24,0.04 -0.33,0.05 -0.1,0.01 -0.22,0.02 -0.37,0.02 -0.27,0 -0.49,-0.04 -0.65,-0.11 -0.16,-0.07 -0.29,-0.18 -0.38,-0.31 -0.09,-0.13 -0.15,-0.3 -0.18,-0.48 -0.03,-0.19 -0.04,-0.39 -0.04,-0.62 h -0.03 c -0.19,0.28 -0.39,0.54 -0.59,0.76 -0.2,0.22 -0.42,0.41 -0.66,0.55 -0.24,0.15 -0.52,0.26 -0.83,0.34 -0.31,0.08 -0.68,0.12 -1.11,0.12 -0.41,0 -0.79,-0.05 -1.15,-0.14 -0.36,-0.1 -0.67,-0.25 -0.94,-0.46 -0.27,-0.21 -0.48,-0.48 -0.63,-0.8 -0.15,-0.32 -0.23,-0.71 -0.23,-1.15 0,-0.61 0.14,-1.09 0.41,-1.44 0.27,-0.35 0.63,-0.61 1.08,-0.79 0.45,-0.18 0.95,-0.31 1.51,-0.38 0.56,-0.07 1.13,-0.14 1.71,-0.21 0.23,-0.02 0.42,-0.05 0.59,-0.08 0.17,-0.03 0.31,-0.09 0.43,-0.18 0.11,-0.08 0.2,-0.2 0.26,-0.35 0.06,-0.15 0.09,-0.34 0.09,-0.58 0,-0.36 -0.06,-0.66 -0.18,-0.89 -0.12,-0.23 -0.28,-0.42 -0.49,-0.55 -0.21,-0.14 -0.45,-0.23 -0.73,-0.28 -0.28,-0.05 -0.58,-0.08 -0.89,-0.08 -0.68,0 -1.24,0.16 -1.67,0.48 -0.43,0.32 -0.66,0.84 -0.68,1.56 h -1.07 c 0.02,-0.53 0.13,-0.97 0.31,-1.35 z m 5.36,2.62 c -0.07,0.12 -0.2,0.22 -0.39,0.27 -0.19,0.06 -0.36,0.1 -0.51,0.12 -0.45,0.08 -0.92,0.15 -1.4,0.21 -0.48,0.06 -0.92,0.16 -1.32,0.28 -0.4,0.12 -0.72,0.3 -0.98,0.54 -0.25,0.23 -0.38,0.56 -0.38,0.99 0,0.27 0.05,0.51 0.16,0.72 0.11,0.21 0.25,0.39 0.43,0.54 0.18,0.15 0.39,0.27 0.63,0.35 0.24,0.08 0.48,0.12 0.73,0.12 0.41,0 0.8,-0.06 1.17,-0.19 0.37,-0.13 0.7,-0.31 0.98,-0.54 0.28,-0.24 0.5,-0.53 0.66,-0.87 0.16,-0.34 0.25,-0.72 0.25,-1.16 v -1.39 h -0.03 z"
|
||||||
|
id="path178" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 222.67,471.43 v 1.67 h 0.03 c 0.25,-0.61 0.65,-1.08 1.22,-1.42 0.56,-0.33 1.2,-0.5 1.91,-0.5 0.67,0 1.25,0.12 1.74,0.37 0.49,0.25 0.9,0.59 1.23,1.01 0.33,0.42 0.57,0.92 0.73,1.48 0.16,0.56 0.24,1.15 0.24,1.78 0,0.63 -0.08,1.21 -0.24,1.78 -0.16,0.56 -0.4,1.05 -0.73,1.48 -0.33,0.43 -0.74,0.76 -1.23,1 -0.49,0.24 -1.07,0.37 -1.74,0.37 -0.32,0 -0.63,-0.04 -0.95,-0.12 -0.32,-0.08 -0.61,-0.2 -0.88,-0.36 -0.27,-0.16 -0.51,-0.36 -0.72,-0.59 -0.21,-0.23 -0.37,-0.52 -0.48,-0.83 h -0.03 v 4.9 h -1.07 v -12 h 0.97 z m 5.87,3.04 c -0.11,-0.45 -0.28,-0.85 -0.51,-1.2 -0.23,-0.35 -0.53,-0.64 -0.89,-0.86 -0.36,-0.22 -0.8,-0.33 -1.31,-0.33 -0.59,0 -1.08,0.1 -1.48,0.31 -0.4,0.2 -0.71,0.48 -0.95,0.82 -0.24,0.34 -0.41,0.74 -0.5,1.19 -0.1,0.45 -0.14,0.93 -0.14,1.43 0,0.45 0.05,0.9 0.16,1.35 0.11,0.45 0.28,0.85 0.53,1.2 0.24,0.35 0.56,0.64 0.95,0.86 0.39,0.22 0.87,0.33 1.44,0.33 0.51,0 0.95,-0.11 1.31,-0.33 0.36,-0.22 0.66,-0.51 0.89,-0.86 0.23,-0.35 0.4,-0.75 0.51,-1.2 0.11,-0.45 0.16,-0.9 0.16,-1.35 0,-0.45 -0.06,-0.92 -0.17,-1.36 z"
|
||||||
|
id="path180" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 231.66,472.79 c 0.18,-0.37 0.43,-0.68 0.74,-0.92 0.31,-0.24 0.68,-0.41 1.1,-0.53 0.42,-0.11 0.88,-0.17 1.39,-0.17 0.39,0 0.77,0.04 1.16,0.11 0.38,0.07 0.73,0.21 1.04,0.42 0.31,0.21 0.55,0.49 0.75,0.86 0.19,0.37 0.29,0.85 0.29,1.44 v 4.66 c 0,0.43 0.21,0.65 0.63,0.65 0.12,0 0.24,-0.02 0.34,-0.07 v 0.9 c -0.12,0.02 -0.24,0.04 -0.33,0.05 -0.1,0.01 -0.22,0.02 -0.37,0.02 -0.27,0 -0.49,-0.04 -0.65,-0.11 -0.16,-0.07 -0.29,-0.18 -0.38,-0.31 -0.09,-0.13 -0.15,-0.3 -0.18,-0.48 -0.03,-0.19 -0.04,-0.39 -0.04,-0.62 h -0.03 c -0.19,0.28 -0.39,0.54 -0.59,0.76 -0.2,0.22 -0.42,0.41 -0.66,0.55 -0.24,0.15 -0.52,0.26 -0.83,0.34 -0.31,0.08 -0.68,0.12 -1.11,0.12 -0.41,0 -0.79,-0.05 -1.15,-0.14 -0.36,-0.1 -0.67,-0.25 -0.94,-0.46 -0.27,-0.21 -0.48,-0.48 -0.63,-0.8 -0.15,-0.32 -0.23,-0.71 -0.23,-1.15 0,-0.61 0.14,-1.09 0.41,-1.44 0.27,-0.35 0.63,-0.61 1.08,-0.79 0.45,-0.18 0.95,-0.31 1.51,-0.38 0.56,-0.07 1.13,-0.14 1.71,-0.21 0.23,-0.02 0.42,-0.05 0.59,-0.08 0.17,-0.03 0.31,-0.09 0.43,-0.18 0.11,-0.08 0.2,-0.2 0.26,-0.35 0.06,-0.15 0.09,-0.34 0.09,-0.58 0,-0.36 -0.06,-0.66 -0.18,-0.89 -0.12,-0.23 -0.28,-0.42 -0.49,-0.55 -0.21,-0.14 -0.45,-0.23 -0.73,-0.28 -0.28,-0.05 -0.58,-0.08 -0.89,-0.08 -0.68,0 -1.24,0.16 -1.67,0.48 -0.43,0.32 -0.66,0.84 -0.68,1.56 h -1.07 c 0.02,-0.53 0.13,-0.97 0.31,-1.35 z m 5.36,2.62 c -0.07,0.12 -0.2,0.22 -0.39,0.27 -0.19,0.06 -0.36,0.1 -0.51,0.12 -0.45,0.08 -0.92,0.15 -1.4,0.21 -0.48,0.06 -0.92,0.16 -1.32,0.28 -0.4,0.12 -0.72,0.3 -0.98,0.54 -0.25,0.23 -0.38,0.56 -0.38,0.99 0,0.27 0.05,0.51 0.16,0.72 0.11,0.21 0.25,0.39 0.43,0.54 0.18,0.15 0.39,0.27 0.63,0.35 0.24,0.08 0.48,0.12 0.73,0.12 0.41,0 0.8,-0.06 1.17,-0.19 0.37,-0.13 0.7,-0.31 0.98,-0.54 0.28,-0.24 0.5,-0.53 0.66,-0.87 0.16,-0.34 0.25,-0.72 0.25,-1.16 v -1.39 h -0.03 z"
|
||||||
|
id="path182" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 241.25,471.43 v 2.06 h 0.03 c 0.27,-0.71 0.69,-1.26 1.27,-1.65 0.57,-0.38 1.25,-0.56 2.05,-0.53 v 1.07 c -0.49,-0.02 -0.93,0.04 -1.33,0.2 -0.4,0.15 -0.74,0.37 -1.03,0.65 -0.29,0.28 -0.51,0.62 -0.67,1.01 -0.16,0.39 -0.24,0.82 -0.24,1.28 v 4.67 h -1.07 v -8.77 h 0.99 z"
|
||||||
|
id="path184" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 249.1,471.43 v 0.9 h -1.79 v 5.92 c 0,0.35 0.05,0.63 0.14,0.82 0.1,0.2 0.34,0.31 0.72,0.33 0.31,0 0.61,-0.02 0.92,-0.05 v 0.9 c -0.16,0 -0.32,0.01 -0.48,0.02 -0.16,0.01 -0.32,0.02 -0.48,0.02 -0.71,0 -1.21,-0.14 -1.5,-0.42 -0.28,-0.28 -0.42,-0.79 -0.41,-1.54 v -6 h -1.53 v -0.9 h 1.53 v -2.63 h 1.07 v 2.63 z"
|
||||||
|
id="path186" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 250.87,472.79 c 0.18,-0.37 0.43,-0.68 0.74,-0.92 0.31,-0.24 0.68,-0.41 1.1,-0.53 0.42,-0.11 0.88,-0.17 1.39,-0.17 0.39,0 0.77,0.04 1.16,0.11 0.38,0.07 0.73,0.21 1.04,0.42 0.31,0.21 0.55,0.49 0.75,0.86 0.19,0.37 0.29,0.85 0.29,1.44 v 4.66 c 0,0.43 0.21,0.65 0.63,0.65 0.12,0 0.24,-0.02 0.34,-0.07 v 0.9 c -0.12,0.02 -0.24,0.04 -0.33,0.05 -0.1,0.01 -0.22,0.02 -0.37,0.02 -0.27,0 -0.49,-0.04 -0.65,-0.11 -0.16,-0.07 -0.29,-0.18 -0.38,-0.31 -0.09,-0.13 -0.15,-0.3 -0.18,-0.48 -0.03,-0.19 -0.04,-0.39 -0.04,-0.62 h -0.03 c -0.19,0.28 -0.39,0.54 -0.59,0.76 -0.2,0.22 -0.42,0.41 -0.66,0.55 -0.24,0.15 -0.52,0.26 -0.83,0.34 -0.31,0.08 -0.68,0.12 -1.11,0.12 -0.41,0 -0.79,-0.05 -1.15,-0.14 -0.36,-0.1 -0.67,-0.25 -0.94,-0.46 -0.27,-0.21 -0.48,-0.48 -0.63,-0.8 -0.15,-0.32 -0.23,-0.71 -0.23,-1.15 0,-0.61 0.14,-1.09 0.41,-1.44 0.27,-0.35 0.63,-0.61 1.08,-0.79 0.45,-0.18 0.95,-0.31 1.51,-0.38 0.56,-0.07 1.13,-0.14 1.71,-0.21 0.23,-0.02 0.42,-0.05 0.59,-0.08 0.17,-0.03 0.31,-0.09 0.43,-0.18 0.11,-0.08 0.2,-0.2 0.26,-0.35 0.06,-0.15 0.09,-0.34 0.09,-0.58 0,-0.36 -0.06,-0.66 -0.18,-0.89 -0.12,-0.23 -0.28,-0.42 -0.49,-0.55 -0.21,-0.14 -0.45,-0.23 -0.73,-0.28 -0.28,-0.05 -0.58,-0.08 -0.89,-0.08 -0.68,0 -1.24,0.16 -1.67,0.48 -0.43,0.32 -0.66,0.84 -0.68,1.56 h -1.07 c 0.02,-0.53 0.13,-0.97 0.31,-1.35 z m 5.36,2.62 c -0.07,0.12 -0.2,0.22 -0.39,0.27 -0.19,0.06 -0.36,0.1 -0.51,0.12 -0.45,0.08 -0.92,0.15 -1.4,0.21 -0.48,0.06 -0.92,0.16 -1.32,0.28 -0.4,0.12 -0.72,0.3 -0.98,0.54 -0.25,0.23 -0.38,0.56 -0.38,0.99 0,0.27 0.05,0.51 0.16,0.72 0.11,0.21 0.25,0.39 0.43,0.54 0.18,0.15 0.39,0.27 0.63,0.35 0.24,0.08 0.48,0.12 0.73,0.12 0.41,0 0.8,-0.06 1.17,-0.19 0.37,-0.13 0.7,-0.31 0.98,-0.54 0.28,-0.24 0.5,-0.53 0.66,-0.87 0.16,-0.34 0.25,-0.72 0.25,-1.16 v -1.39 h -0.03 z"
|
||||||
|
id="path188" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 260.46,471.43 v 1.48 h 0.05 c 0.28,-0.54 0.66,-0.97 1.11,-1.28 0.46,-0.31 1.04,-0.46 1.76,-0.46 0.58,0 1.1,0.14 1.57,0.43 0.47,0.28 0.78,0.71 0.94,1.29 0.26,-0.58 0.65,-1.01 1.16,-1.29 0.51,-0.28 1.05,-0.43 1.63,-0.43 1.94,0 2.91,1.03 2.91,3.08 v 5.95 h -1.07 v -5.9 c 0,-0.72 -0.15,-1.28 -0.46,-1.66 -0.31,-0.38 -0.84,-0.57 -1.62,-0.57 -0.46,0 -0.85,0.09 -1.16,0.26 -0.31,0.18 -0.55,0.41 -0.73,0.71 -0.18,0.29 -0.31,0.63 -0.38,1.01 -0.07,0.38 -0.11,0.77 -0.11,1.18 v 4.96 H 265 v -5.95 c 0,-0.29 -0.03,-0.58 -0.09,-0.84 -0.06,-0.27 -0.16,-0.5 -0.31,-0.7 -0.15,-0.2 -0.33,-0.35 -0.57,-0.47 -0.24,-0.12 -0.53,-0.17 -0.87,-0.17 -0.45,0 -0.85,0.08 -1.18,0.25 -0.33,0.17 -0.61,0.39 -0.82,0.68 -0.21,0.29 -0.37,0.63 -0.47,1.02 -0.1,0.39 -0.15,0.82 -0.15,1.28 v 4.9 h -1.07 v -8.77 h 0.99 z"
|
||||||
|
id="path190" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 274.43,477.31 c 0.11,0.41 0.28,0.79 0.52,1.11 0.24,0.33 0.54,0.6 0.9,0.82 0.36,0.21 0.8,0.32 1.31,0.32 0.78,0 1.39,-0.2 1.84,-0.61 0.45,-0.41 0.75,-0.95 0.92,-1.63 h 1.07 c -0.23,1 -0.64,1.77 -1.25,2.31 -0.61,0.54 -1.46,0.82 -2.58,0.82 -0.69,0 -1.29,-0.12 -1.79,-0.37 -0.5,-0.24 -0.92,-0.58 -1.23,-1 -0.32,-0.42 -0.55,-0.92 -0.71,-1.48 -0.15,-0.56 -0.23,-1.15 -0.23,-1.78 0,-0.58 0.08,-1.14 0.23,-1.7 0.15,-0.56 0.39,-1.05 0.71,-1.49 0.32,-0.44 0.73,-0.79 1.23,-1.05 0.5,-0.27 1.1,-0.4 1.79,-0.4 0.7,0 1.3,0.14 1.8,0.43 0.5,0.29 0.9,0.65 1.22,1.11 0.32,0.46 0.54,0.99 0.67,1.58 0.14,0.59 0.19,1.2 0.17,1.81 h -6.75 c -0.01,0.38 0.05,0.78 0.16,1.2 z m 5.3,-3.28 c -0.13,-0.37 -0.31,-0.71 -0.55,-0.99 -0.24,-0.29 -0.53,-0.52 -0.87,-0.7 -0.34,-0.18 -0.73,-0.26 -1.16,-0.26 -0.44,0 -0.83,0.09 -1.17,0.26 -0.34,0.17 -0.63,0.41 -0.87,0.7 -0.24,0.29 -0.43,0.62 -0.57,1 -0.14,0.38 -0.24,0.77 -0.28,1.16 h 5.68 c -0.01,-0.4 -0.08,-0.79 -0.21,-1.17 z"
|
||||||
|
id="path192" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 283.51,471.43 v 1.51 h 0.03 c 0.2,-0.53 0.57,-0.96 1.09,-1.28 0.52,-0.32 1.09,-0.48 1.72,-0.48 0.61,0 1.12,0.08 1.54,0.24 0.41,0.16 0.75,0.38 1,0.67 0.25,0.29 0.42,0.64 0.53,1.06 0.1,0.42 0.15,0.89 0.15,1.41 v 5.64 h -1.07 v -5.47 c 0,-0.37 -0.03,-0.72 -0.1,-1.05 -0.07,-0.33 -0.19,-0.6 -0.36,-0.84 -0.17,-0.24 -0.4,-0.42 -0.69,-0.56 -0.29,-0.14 -0.65,-0.2 -1.08,-0.2 -0.43,0 -0.81,0.08 -1.15,0.23 -0.33,0.15 -0.62,0.36 -0.85,0.63 -0.23,0.27 -0.41,0.58 -0.54,0.95 -0.13,0.37 -0.2,0.77 -0.21,1.2 v 5.12 h -1.07 v -8.77 h 1.06 z"
|
||||||
|
id="path194" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 295.07,471.43 v 0.9 h -1.79 v 5.92 c 0,0.35 0.05,0.63 0.14,0.82 0.1,0.2 0.34,0.31 0.72,0.33 0.31,0 0.61,-0.02 0.92,-0.05 v 0.9 c -0.16,0 -0.32,0.01 -0.48,0.02 -0.16,0.01 -0.32,0.02 -0.48,0.02 -0.71,0 -1.21,-0.14 -1.5,-0.42 -0.28,-0.28 -0.42,-0.79 -0.41,-1.54 v -6 h -1.53 v -0.9 h 1.53 v -2.63 h 1.07 v 2.63 z"
|
||||||
|
id="path196" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 302.1,471.55 c 0.52,0.25 0.95,0.58 1.3,1 0.35,0.42 0.62,0.91 0.8,1.47 0.18,0.56 0.27,1.16 0.27,1.79 0,0.63 -0.09,1.23 -0.27,1.79 -0.18,0.56 -0.45,1.05 -0.8,1.47 -0.35,0.42 -0.78,0.75 -1.3,0.99 -0.52,0.24 -1.11,0.37 -1.78,0.37 -0.67,0 -1.26,-0.12 -1.78,-0.37 -0.52,-0.24 -0.95,-0.57 -1.3,-0.99 -0.35,-0.42 -0.62,-0.91 -0.8,-1.47 -0.18,-0.56 -0.27,-1.16 -0.27,-1.79 0,-0.63 0.09,-1.23 0.27,-1.79 0.18,-0.56 0.45,-1.05 0.8,-1.47 0.35,-0.42 0.78,-0.75 1.3,-1 0.52,-0.25 1.11,-0.37 1.78,-0.37 0.67,0 1.26,0.12 1.78,0.37 z m -3.12,0.85 c -0.38,0.21 -0.71,0.5 -0.96,0.85 -0.25,0.35 -0.45,0.75 -0.58,1.2 -0.13,0.45 -0.2,0.9 -0.2,1.37 0,0.47 0.06,0.92 0.2,1.37 0.13,0.45 0.32,0.85 0.58,1.2 0.25,0.35 0.58,0.63 0.96,0.85 0.39,0.21 0.83,0.32 1.34,0.32 0.51,0 0.96,-0.11 1.34,-0.32 0.38,-0.22 0.71,-0.5 0.96,-0.85 0.25,-0.35 0.45,-0.75 0.58,-1.2 0.13,-0.45 0.2,-0.9 0.2,-1.37 0,-0.47 -0.07,-0.92 -0.2,-1.37 -0.13,-0.45 -0.32,-0.85 -0.58,-1.2 -0.25,-0.35 -0.58,-0.63 -0.96,-0.85 -0.39,-0.22 -0.83,-0.32 -1.34,-0.32 -0.51,0 -0.95,0.11 -1.34,0.32 z"
|
||||||
|
id="path198" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 311.12,473.14 c -0.12,-0.24 -0.29,-0.44 -0.5,-0.6 -0.21,-0.16 -0.45,-0.27 -0.72,-0.35 -0.27,-0.07 -0.56,-0.11 -0.87,-0.11 -0.24,0 -0.48,0.03 -0.72,0.08 -0.24,0.05 -0.47,0.14 -0.67,0.25 -0.2,0.12 -0.37,0.28 -0.49,0.47 -0.12,0.19 -0.19,0.43 -0.19,0.71 0,0.24 0.06,0.44 0.18,0.6 0.12,0.17 0.27,0.3 0.45,0.42 0.18,0.11 0.38,0.21 0.59,0.28 0.21,0.07 0.41,0.13 0.59,0.18 l 1.43,0.32 c 0.31,0.04 0.61,0.13 0.91,0.25 0.3,0.12 0.57,0.27 0.8,0.47 0.23,0.19 0.42,0.43 0.57,0.71 0.15,0.28 0.22,0.62 0.22,1 0,0.48 -0.11,0.88 -0.32,1.22 -0.22,0.33 -0.49,0.61 -0.82,0.82 -0.33,0.21 -0.71,0.36 -1.13,0.45 -0.42,0.09 -0.83,0.14 -1.24,0.14 -1.03,0 -1.87,-0.24 -2.51,-0.73 -0.64,-0.49 -1.01,-1.27 -1.1,-2.35 h 1.07 c 0.05,0.73 0.31,1.27 0.79,1.64 0.48,0.37 1.08,0.55 1.79,0.55 0.26,0 0.53,-0.03 0.81,-0.08 0.28,-0.06 0.54,-0.15 0.77,-0.29 0.24,-0.14 0.43,-0.31 0.59,-0.52 0.15,-0.21 0.23,-0.47 0.23,-0.77 0,-0.26 -0.05,-0.48 -0.16,-0.66 -0.11,-0.17 -0.25,-0.32 -0.43,-0.44 -0.18,-0.12 -0.39,-0.22 -0.62,-0.3 -0.23,-0.08 -0.47,-0.15 -0.71,-0.2 l -1.38,-0.31 c -0.35,-0.09 -0.67,-0.2 -0.97,-0.31 -0.29,-0.12 -0.55,-0.27 -0.77,-0.44 -0.22,-0.18 -0.39,-0.39 -0.52,-0.65 -0.12,-0.25 -0.19,-0.57 -0.19,-0.94 0,-0.44 0.1,-0.82 0.3,-1.14 0.2,-0.32 0.46,-0.57 0.77,-0.76 0.32,-0.19 0.67,-0.33 1.06,-0.42 0.39,-0.09 0.78,-0.14 1.16,-0.14 0.44,0 0.85,0.06 1.23,0.17 0.38,0.11 0.71,0.29 1,0.53 0.29,0.24 0.52,0.53 0.69,0.88 0.17,0.35 0.27,0.77 0.29,1.24 h -1.07 c 0,-0.34 -0.07,-0.63 -0.19,-0.87 z"
|
||||||
|
id="path200" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 322.46,471.43 v 0.9 h -1.79 v 5.92 c 0,0.35 0.05,0.63 0.14,0.82 0.1,0.2 0.34,0.31 0.72,0.33 0.31,0 0.61,-0.02 0.92,-0.05 v 0.9 c -0.16,0 -0.32,0.01 -0.48,0.02 -0.16,0.01 -0.32,0.02 -0.48,0.02 -0.71,0 -1.21,-0.14 -1.5,-0.42 -0.28,-0.28 -0.42,-0.79 -0.41,-1.54 v -6 h -1.53 v -0.9 h 1.53 v -2.63 h 1.07 v 2.63 z"
|
||||||
|
id="path202" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 330.12,480.2 v -1.58 h -0.03 c -0.28,0.59 -0.69,1.04 -1.23,1.35 -0.54,0.31 -1.14,0.47 -1.79,0.47 -0.56,0 -1.03,-0.08 -1.42,-0.23 -0.39,-0.15 -0.71,-0.37 -0.95,-0.66 -0.24,-0.28 -0.42,-0.63 -0.54,-1.04 -0.11,-0.41 -0.17,-0.87 -0.17,-1.39 v -5.7 h 1.07 v 5.71 c 0.02,0.79 0.21,1.39 0.55,1.8 0.34,0.41 0.94,0.61 1.79,0.61 0.46,0 0.86,-0.1 1.19,-0.3 0.33,-0.2 0.6,-0.46 0.82,-0.79 0.22,-0.33 0.37,-0.71 0.48,-1.13 0.1,-0.42 0.15,-0.86 0.15,-1.3 v -4.61 h 1.07 v 8.77 h -0.99 z"
|
||||||
|
id="path204" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 334.12,471.43 v 2.06 h 0.03 c 0.27,-0.71 0.69,-1.26 1.27,-1.65 0.57,-0.38 1.25,-0.56 2.05,-0.53 v 1.07 c -0.49,-0.02 -0.93,0.04 -1.33,0.2 -0.4,0.15 -0.74,0.37 -1.03,0.65 -0.29,0.28 -0.51,0.62 -0.67,1.01 -0.16,0.39 -0.24,0.82 -0.24,1.28 v 4.67 h -1.07 v -8.77 h 0.99 z"
|
||||||
|
id="path206" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 338.03,470.21 1.79,-2.4 h 1.33 l -2.24,2.4 z m 0.48,1.22 h 1.07 v 8.77 h -1.07 z"
|
||||||
|
id="path208" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 346.68,473.14 c -0.12,-0.24 -0.29,-0.44 -0.5,-0.6 -0.21,-0.16 -0.45,-0.27 -0.72,-0.35 -0.27,-0.07 -0.56,-0.11 -0.87,-0.11 -0.24,0 -0.48,0.03 -0.72,0.08 -0.24,0.05 -0.47,0.14 -0.67,0.25 -0.2,0.12 -0.37,0.28 -0.49,0.47 -0.12,0.19 -0.19,0.43 -0.19,0.71 0,0.24 0.06,0.44 0.18,0.6 0.12,0.17 0.27,0.3 0.45,0.42 0.18,0.11 0.38,0.21 0.59,0.28 0.21,0.07 0.41,0.13 0.59,0.18 l 1.43,0.32 c 0.31,0.04 0.61,0.13 0.91,0.25 0.3,0.12 0.57,0.27 0.8,0.47 0.23,0.19 0.42,0.43 0.57,0.71 0.15,0.28 0.22,0.62 0.22,1 0,0.48 -0.11,0.88 -0.32,1.22 -0.22,0.33 -0.49,0.61 -0.82,0.82 -0.33,0.21 -0.71,0.36 -1.13,0.45 -0.42,0.09 -0.83,0.14 -1.24,0.14 -1.03,0 -1.87,-0.24 -2.51,-0.73 -0.64,-0.49 -1.01,-1.27 -1.1,-2.35 h 1.07 c 0.05,0.73 0.31,1.27 0.79,1.64 0.48,0.37 1.08,0.55 1.79,0.55 0.26,0 0.53,-0.03 0.81,-0.08 0.28,-0.06 0.54,-0.15 0.77,-0.29 0.24,-0.14 0.43,-0.31 0.59,-0.52 0.15,-0.21 0.23,-0.47 0.23,-0.77 0,-0.26 -0.05,-0.48 -0.16,-0.66 -0.11,-0.17 -0.25,-0.32 -0.43,-0.44 -0.18,-0.12 -0.39,-0.22 -0.62,-0.3 -0.23,-0.08 -0.47,-0.15 -0.71,-0.2 l -1.38,-0.31 c -0.35,-0.09 -0.67,-0.2 -0.97,-0.31 -0.29,-0.12 -0.55,-0.27 -0.77,-0.44 -0.22,-0.18 -0.39,-0.39 -0.52,-0.65 -0.12,-0.25 -0.19,-0.57 -0.19,-0.94 0,-0.44 0.1,-0.82 0.3,-1.14 0.2,-0.32 0.46,-0.57 0.77,-0.76 0.32,-0.19 0.67,-0.33 1.06,-0.42 0.39,-0.09 0.78,-0.14 1.16,-0.14 0.44,0 0.85,0.06 1.23,0.17 0.38,0.11 0.71,0.29 1,0.53 0.29,0.24 0.52,0.53 0.69,0.88 0.17,0.35 0.27,0.77 0.29,1.24 h -1.07 c 0,-0.34 -0.06,-0.63 -0.19,-0.87 z"
|
||||||
|
id="path210" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 353.29,471.43 v 0.9 h -1.79 v 5.92 c 0,0.35 0.05,0.63 0.14,0.82 0.1,0.2 0.34,0.31 0.72,0.33 0.31,0 0.61,-0.02 0.92,-0.05 v 0.9 c -0.16,0 -0.32,0.01 -0.48,0.02 -0.16,0.01 -0.32,0.02 -0.48,0.02 -0.71,0 -1.21,-0.14 -1.5,-0.42 -0.28,-0.28 -0.42,-0.79 -0.41,-1.54 v -6 h -1.53 v -0.9 h 1.53 v -2.63 h 1.07 v 2.63 z"
|
||||||
|
id="path212" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 355.93,468.07 v 1.72 h -1.07 v -1.72 z m 0,3.36 v 8.77 h -1.07 v -8.77 z"
|
||||||
|
id="path214" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 363.36,472.64 c -0.4,-0.37 -0.95,-0.56 -1.67,-0.56 -0.51,0 -0.96,0.11 -1.34,0.32 -0.38,0.21 -0.71,0.5 -0.96,0.85 -0.25,0.35 -0.45,0.75 -0.58,1.2 -0.13,0.45 -0.2,0.9 -0.2,1.37 0,0.47 0.06,0.92 0.2,1.37 0.13,0.45 0.32,0.85 0.58,1.2 0.25,0.35 0.58,0.63 0.96,0.85 0.39,0.21 0.83,0.32 1.34,0.32 0.33,0 0.64,-0.06 0.94,-0.19 0.3,-0.13 0.55,-0.3 0.78,-0.52 0.23,-0.22 0.41,-0.48 0.56,-0.79 0.15,-0.31 0.24,-0.64 0.27,-1 h 1.07 c -0.15,1.07 -0.54,1.9 -1.17,2.49 -0.63,0.59 -1.45,0.89 -2.45,0.89 -0.67,0 -1.26,-0.12 -1.78,-0.37 -0.52,-0.24 -0.95,-0.57 -1.3,-0.99 -0.35,-0.42 -0.62,-0.91 -0.8,-1.47 -0.18,-0.56 -0.27,-1.16 -0.27,-1.79 0,-0.63 0.09,-1.23 0.27,-1.79 0.18,-0.56 0.45,-1.05 0.8,-1.47 0.35,-0.42 0.78,-0.75 1.3,-1 0.52,-0.25 1.11,-0.37 1.78,-0.37 0.94,0 1.74,0.25 2.39,0.75 0.65,0.5 1.04,1.25 1.17,2.26 h -1.07 c -0.15,-0.67 -0.42,-1.19 -0.82,-1.56 z"
|
||||||
|
id="path216" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 372.29,471.55 c 0.52,0.25 0.95,0.58 1.3,1 0.35,0.42 0.62,0.91 0.8,1.47 0.18,0.56 0.27,1.16 0.27,1.79 0,0.63 -0.09,1.23 -0.27,1.79 -0.18,0.56 -0.45,1.05 -0.8,1.47 -0.35,0.42 -0.78,0.75 -1.3,0.99 -0.52,0.24 -1.11,0.37 -1.78,0.37 -0.67,0 -1.26,-0.12 -1.78,-0.37 -0.52,-0.24 -0.95,-0.57 -1.3,-0.99 -0.35,-0.42 -0.62,-0.91 -0.8,-1.47 -0.18,-0.56 -0.27,-1.16 -0.27,-1.79 0,-0.63 0.09,-1.23 0.27,-1.79 0.18,-0.56 0.45,-1.05 0.8,-1.47 0.35,-0.42 0.78,-0.75 1.3,-1 0.52,-0.25 1.11,-0.37 1.78,-0.37 0.67,0 1.27,0.12 1.78,0.37 z m -3.12,0.85 c -0.38,0.21 -0.71,0.5 -0.96,0.85 -0.25,0.35 -0.45,0.75 -0.58,1.2 -0.13,0.45 -0.2,0.9 -0.2,1.37 0,0.47 0.06,0.92 0.2,1.37 0.13,0.45 0.32,0.85 0.58,1.2 0.25,0.35 0.58,0.63 0.96,0.85 0.39,0.21 0.83,0.32 1.34,0.32 0.51,0 0.96,-0.11 1.34,-0.32 0.38,-0.22 0.71,-0.5 0.96,-0.85 0.25,-0.35 0.45,-0.75 0.58,-1.2 0.13,-0.45 0.2,-0.9 0.2,-1.37 0,-0.47 -0.07,-0.92 -0.2,-1.37 -0.13,-0.45 -0.32,-0.85 -0.58,-1.2 -0.25,-0.35 -0.58,-0.63 -0.96,-0.85 -0.39,-0.22 -0.83,-0.32 -1.34,-0.32 -0.5,0 -0.95,0.11 -1.34,0.32 z"
|
||||||
|
id="path218" />
|
||||||
|
<path
|
||||||
|
class="st0"
|
||||||
|
d="m 381.31,473.14 c -0.12,-0.24 -0.29,-0.44 -0.5,-0.6 -0.21,-0.16 -0.45,-0.27 -0.72,-0.35 -0.27,-0.07 -0.56,-0.11 -0.87,-0.11 -0.24,0 -0.48,0.03 -0.72,0.08 -0.24,0.05 -0.47,0.14 -0.67,0.25 -0.2,0.12 -0.37,0.28 -0.49,0.47 -0.12,0.19 -0.19,0.43 -0.19,0.71 0,0.24 0.06,0.44 0.18,0.6 0.12,0.17 0.27,0.3 0.45,0.42 0.18,0.11 0.38,0.21 0.59,0.28 0.21,0.07 0.41,0.13 0.59,0.18 l 1.43,0.32 c 0.31,0.04 0.61,0.13 0.91,0.25 0.3,0.12 0.57,0.27 0.8,0.47 0.23,0.19 0.42,0.43 0.57,0.71 0.15,0.28 0.22,0.62 0.22,1 0,0.48 -0.11,0.88 -0.32,1.22 -0.22,0.33 -0.49,0.61 -0.82,0.82 -0.33,0.21 -0.71,0.36 -1.13,0.45 -0.42,0.09 -0.83,0.14 -1.24,0.14 -1.03,0 -1.87,-0.24 -2.51,-0.73 -0.64,-0.49 -1.01,-1.27 -1.1,-2.35 h 1.07 c 0.05,0.73 0.31,1.27 0.79,1.64 0.48,0.37 1.08,0.55 1.79,0.55 0.26,0 0.53,-0.03 0.81,-0.08 0.28,-0.06 0.54,-0.15 0.77,-0.29 0.24,-0.14 0.43,-0.31 0.59,-0.52 0.15,-0.21 0.23,-0.47 0.23,-0.77 0,-0.26 -0.05,-0.48 -0.16,-0.66 -0.11,-0.17 -0.25,-0.32 -0.43,-0.44 -0.18,-0.12 -0.39,-0.22 -0.62,-0.3 -0.23,-0.08 -0.47,-0.15 -0.71,-0.2 l -1.38,-0.31 c -0.35,-0.09 -0.67,-0.2 -0.97,-0.31 -0.29,-0.12 -0.55,-0.27 -0.77,-0.44 -0.22,-0.18 -0.39,-0.39 -0.52,-0.65 -0.12,-0.25 -0.19,-0.57 -0.19,-0.94 0,-0.44 0.1,-0.82 0.3,-1.14 0.2,-0.32 0.46,-0.57 0.77,-0.76 0.32,-0.19 0.67,-0.33 1.06,-0.42 0.39,-0.09 0.78,-0.14 1.16,-0.14 0.44,0 0.85,0.06 1.23,0.17 0.38,0.11 0.71,0.29 1,0.53 0.29,0.24 0.52,0.53 0.69,0.88 0.17,0.35 0.27,0.77 0.29,1.24 h -1.07 c 0,-0.34 -0.07,-0.63 -0.19,-0.87 z"
|
||||||
|
id="path220" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g><g
|
||||||
|
id="Capa_2"
|
||||||
|
transform="translate(-50.7513,-26.26855)">
|
||||||
|
</g>
|
||||||
|
|
||||||
|
</svg>
|
After Width: | Height: | Size: 45 KiB |