diff --git a/library/vendor/dompdf/AUTHORS.md b/library/vendor/dompdf/AUTHORS.md new file mode 100644 index 000000000..686147928 --- /dev/null +++ b/library/vendor/dompdf/AUTHORS.md @@ -0,0 +1,24 @@ +Dompdf was designed and developed by Benj Carson. + +### Current Team + +* **Brian Sweeney** (maintainer) +* **Till Berger** + +### Alumni + +* **Benj Carson** (creator) +* **Fabien Ménager** +* **Simon Berger** +* **Orion Richardson** + +### Contributors +* **Gabriel Bull** +* **Barry vd. Heuvel** +* **Ryan H. Masten** +* **Helmut Tischer** +* [and many more...](https://github.com/dompdf/dompdf/graphs/contributors) + +### Thanks + +Dompdf would not have been possible without strong community support. diff --git a/library/vendor/dompdf/README.md b/library/vendor/dompdf/README.md index 40b1bfda8..7546e807e 100644 --- a/library/vendor/dompdf/README.md +++ b/library/vendor/dompdf/README.md @@ -214,12 +214,6 @@ Files accessed through the local file system have the following requirement: ## Limitations (Known Issues) - * Dompdf is not particularly tolerant to poorly-formed HTML input. To avoid - any unexpected rendering issues you should either enable the built-in HTML5 - parser at runtime (`$options->setIsHtml5ParserEnabled(true);`) - or run your HTML through a HTML validator/cleaner (such as - [Tidy](http://tidy.sourceforge.net) or the - [W3C Markup Validation Service](http://validator.w3.org)). * Table cells are not pageable, meaning a table row must fit on a single page. * Elements are rendered on the active page when they are parsed. * Embedding "raw" SVG's (``) isn't working yet, you need to @@ -228,7 +222,8 @@ Files accessed through the local file system have the following requirement: $html = ''; ``` Watch https://github.com/dompdf/dompdf/issues/320 for progress - + * Does not support CSS flexbox. + * Does not support CSS Grid. --- [![Donate button](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](http://goo.gl/DSvWf) diff --git a/library/vendor/dompdf/VERSION b/library/vendor/dompdf/VERSION index 6085e9465..38f77a65b 100644 --- a/library/vendor/dompdf/VERSION +++ b/library/vendor/dompdf/VERSION @@ -1 +1 @@ -1.2.1 +2.0.1 diff --git a/library/vendor/dompdf/autoload.inc.php b/library/vendor/dompdf/autoload.inc.php index 8ff30770a..dc542ab9b 100644 --- a/library/vendor/dompdf/autoload.inc.php +++ b/library/vendor/dompdf/autoload.inc.php @@ -1,40 +1 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -// HMLT5 Parser -//FIXME: replace with masterminds HTML5 -//require_once __DIR__ . '/lib/html5lib/Parser.php'; - -// Sabberworm -spl_autoload_register(function($class) -{ - if (strpos($class, 'Sabberworm') !== false) { - $file = str_replace('\\', DIRECTORY_SEPARATOR, $class); - $file = realpath(__DIR__ . '/lib/php-css-parser/lib/' . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php'); - if (file_exists($file)) { - require_once $file; - return true; - } - } - return false; -}); - -// php-font-lib -require_once __DIR__ . '/lib/php-font-lib/src/FontLib/Autoloader.php'; - -//php-svg-lib -require_once __DIR__ . '/lib/php-svg-lib/src/autoload.php'; - - -/* - * New PHP 5.3.0 namespaced autoloader - */ -require_once __DIR__ . '/src/Autoloader.php'; - -Dompdf\Autoloader::register(); + - [ - 'normal' => $distFontDir . '/Helvetica', - 'bold' => $distFontDir . '/Helvetica-Bold', - 'italic' => $distFontDir . '/Helvetica-Oblique', - 'bold_italic' => $distFontDir . '/Helvetica-BoldOblique' - ], - 'times' => - [ - 'normal' => $distFontDir . '/Times-Roman', - 'bold' => $distFontDir . '/Times-Bold', - 'italic' => $distFontDir . '/Times-Italic', - 'bold_italic' => $distFontDir . '/Times-BoldItalic' - ], - 'times-roman' => - [ - 'normal' => $distFontDir . '/Times-Roman', - 'bold' => $distFontDir . '/Times-Bold', - 'italic' => $distFontDir . '/Times-Italic', - 'bold_italic' => $distFontDir . '/Times-BoldItalic' - ], - 'courier' => - [ - 'normal' => $distFontDir . '/Courier', - 'bold' => $distFontDir . '/Courier-Bold', - 'italic' => $distFontDir . '/Courier-Oblique', - 'bold_italic' => $distFontDir . '/Courier-BoldOblique' - ], - 'helvetica' => - [ - 'normal' => $distFontDir . '/Helvetica', - 'bold' => $distFontDir . '/Helvetica-Bold', - 'italic' => $distFontDir . '/Helvetica-Oblique', - 'bold_italic' => $distFontDir . '/Helvetica-BoldOblique' - ], - 'zapfdingbats' => - [ - 'normal' => $distFontDir . '/ZapfDingbats', - 'bold' => $distFontDir . '/ZapfDingbats', - 'italic' => $distFontDir . '/ZapfDingbats', - 'bold_italic' => $distFontDir . '/ZapfDingbats' - ], - 'symbol' => - [ - 'normal' => $distFontDir . '/Symbol', - 'bold' => $distFontDir . '/Symbol', - 'italic' => $distFontDir . '/Symbol', - 'bold_italic' => $distFontDir . '/Symbol' - ], - 'serif' => - [ - 'normal' => $distFontDir . '/Times-Roman', - 'bold' => $distFontDir . '/Times-Bold', - 'italic' => $distFontDir . '/Times-Italic', - 'bold_italic' => $distFontDir . '/Times-BoldItalic' - ], - 'monospace' => - [ - 'normal' => $distFontDir . '/Courier', - 'bold' => $distFontDir . '/Courier-Bold', - 'italic' => $distFontDir . '/Courier-Oblique', - 'bold_italic' => $distFontDir . '/Courier-BoldOblique' - ], - 'fixed' => - [ - 'normal' => $distFontDir . '/Courier', - 'bold' => $distFontDir . '/Courier-Bold', - 'italic' => $distFontDir . '/Courier-Oblique', - 'bold_italic' => $distFontDir . '/Courier-BoldOblique' - ], - 'dejavu sans' => - [ - 'bold' => $distFontDir . '/DejaVuSans-Bold', - 'bold_italic' => $distFontDir . '/DejaVuSans-BoldOblique', - 'italic' => $distFontDir . '/DejaVuSans-Oblique', - 'normal' => $distFontDir . '/DejaVuSans' - ], - 'dejavu sans mono' => - [ - 'bold' => $distFontDir . '/DejaVuSansMono-Bold', - 'bold_italic' => $distFontDir . '/DejaVuSansMono-BoldOblique', - 'italic' => $distFontDir . '/DejaVuSansMono-Oblique', - 'normal' => $distFontDir . '/DejaVuSansMono' - ], - 'dejavu serif' => - [ - 'bold' => $distFontDir . '/DejaVuSerif-Bold', - 'bold_italic' => $distFontDir . '/DejaVuSerif-BoldItalic', - 'italic' => $distFontDir . '/DejaVuSerif-Italic', - 'normal' => $distFontDir . '/DejaVuSerif' - ] - ]; -}; diff --git a/library/vendor/dompdf/lib/html5lib/Data.php b/library/vendor/dompdf/lib/html5lib/Data.php deleted file mode 100644 index 609e99624..000000000 --- a/library/vendor/dompdf/lib/html5lib/Data.php +++ /dev/null @@ -1,123 +0,0 @@ - 0xFFFD, // REPLACEMENT CHARACTER - 0x0D => 0x000A, // LINE FEED (LF) - 0x80 => 0x20AC, // EURO SIGN ('€') - 0x81 => 0x0081, // - 0x82 => 0x201A, // SINGLE LOW-9 QUOTATION MARK ('‚') - 0x83 => 0x0192, // LATIN SMALL LETTER F WITH HOOK ('ƒ') - 0x84 => 0x201E, // DOUBLE LOW-9 QUOTATION MARK ('„') - 0x85 => 0x2026, // HORIZONTAL ELLIPSIS ('…') - 0x86 => 0x2020, // DAGGER ('†') - 0x87 => 0x2021, // DOUBLE DAGGER ('‡') - 0x88 => 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ') - 0x89 => 0x2030, // PER MILLE SIGN ('‰') - 0x8A => 0x0160, // LATIN CAPITAL LETTER S WITH CARON ('Š') - 0x8B => 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('‹') - 0x8C => 0x0152, // LATIN CAPITAL LIGATURE OE ('Œ') - 0x8D => 0x008D, // - 0x8E => 0x017D, // LATIN CAPITAL LETTER Z WITH CARON ('Ž') - 0x8F => 0x008F, // - 0x90 => 0x0090, // - 0x91 => 0x2018, // LEFT SINGLE QUOTATION MARK ('‘') - 0x92 => 0x2019, // RIGHT SINGLE QUOTATION MARK ('’') - 0x93 => 0x201C, // LEFT DOUBLE QUOTATION MARK ('“') - 0x94 => 0x201D, // RIGHT DOUBLE QUOTATION MARK ('”') - 0x95 => 0x2022, // BULLET ('•') - 0x96 => 0x2013, // EN DASH ('–') - 0x97 => 0x2014, // EM DASH ('—') - 0x98 => 0x02DC, // SMALL TILDE ('˜') - 0x99 => 0x2122, // TRADE MARK SIGN ('™') - 0x9A => 0x0161, // LATIN SMALL LETTER S WITH CARON ('š') - 0x9B => 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('›') - 0x9C => 0x0153, // LATIN SMALL LIGATURE OE ('œ') - 0x9D => 0x009D, // - 0x9E => 0x017E, // LATIN SMALL LETTER Z WITH CARON ('ž') - 0x9F => 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ') - ]; - - protected static $namedCharacterReferences; - - protected static $namedCharacterReferenceMaxLength; - - /** - * Returns the "real" Unicode codepoint of a malformed character - * reference. - */ - public static function getRealCodepoint($ref) { - if (!isset(self::$realCodepointTable[$ref])) { - return false; - } else { - return self::$realCodepointTable[$ref]; - } - } - - public static function getNamedCharacterReferences() { - if (!self::$namedCharacterReferences) { - self::$namedCharacterReferences = unserialize( - file_get_contents(dirname(__FILE__) . '/named-character-references.ser')); - } - return self::$namedCharacterReferences; - } - - /** - * Converts a Unicode codepoint to sequence of UTF-8 bytes. - * @note Shamelessly stolen from HTML Purifier, which is also - * shamelessly stolen from Feyd (which is in public domain). - */ - public static function utf8chr($code) { - /* We don't care: we live dangerously - * if($code > 0x10FFFF or $code < 0x0 or - ($code >= 0xD800 and $code <= 0xDFFF) ) { - // bits are set outside the "valid" range as defined - // by UNICODE 4.1.0 - return "\xEF\xBF\xBD"; - }*/ - - $y = $z = $w = 0; - if ($code < 0x80) { - // regular ASCII character - $x = $code; - } else { - // set up bits for UTF-8 - $x = ($code & 0x3F) | 0x80; - if ($code < 0x800) { - $y = (($code & 0x7FF) >> 6) | 0xC0; - } else { - $y = (($code & 0xFC0) >> 6) | 0x80; - if ($code < 0x10000) { - $z = (($code >> 12) & 0x0F) | 0xE0; - } else { - $z = (($code >> 12) & 0x3F) | 0x80; - $w = (($code >> 18) & 0x07) | 0xF0; - } - } - } - // set up the actual character - $ret = ''; - if ($w) { - $ret .= chr($w); - } - if ($z) { - $ret .= chr($z); - } - if ($y) { - $ret .= chr($y); - } - $ret .= chr($x); - - return $ret; - } - -} diff --git a/library/vendor/dompdf/lib/html5lib/InputStream.php b/library/vendor/dompdf/lib/html5lib/InputStream.php deleted file mode 100644 index dde71942d..000000000 --- a/library/vendor/dompdf/lib/html5lib/InputStream.php +++ /dev/null @@ -1,299 +0,0 @@ - - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -// Some conventions: -// /* */ indicates verbatim text from the HTML 5 specification -// // indicates regular comments - -class HTML5_InputStream { - /** - * The string data we're parsing. - */ - private $data; - - /** - * The current integer byte position we are in $data - */ - private $char; - - /** - * Length of $data; when $char === $data, we are at the end-of-file. - */ - private $EOF; - - /** - * Parse errors. - */ - public $errors = []; - - /** - * @param $data | Data to parse - * @throws Exception - */ - public function __construct($data) { - - /* Given an encoding, the bytes in the input stream must be - converted to Unicode characters for the tokeniser, as - described by the rules for that encoding, except that the - leading U+FEFF BYTE ORDER MARK character, if any, must not - be stripped by the encoding layer (it is stripped by the rule below). - - Bytes or sequences of bytes in the original byte stream that - could not be converted to Unicode characters must be converted - to U+FFFD REPLACEMENT CHARACTER code points. */ - - // XXX currently assuming input data is UTF-8; once we - // build encoding detection this will no longer be the case - // - // We previously had an mbstring implementation here, but that - // implementation is heavily non-conforming, so it's been - // omitted. - if (extension_loaded('iconv')) { - // non-conforming - $data = @iconv('UTF-8', 'UTF-8//IGNORE', $data); - } else { - // we can make a conforming native implementation - throw new Exception('Not implemented, please install iconv'); - } - - /* One leading U+FEFF BYTE ORDER MARK character must be - ignored if any are present. */ - if (substr($data, 0, 3) === "\xEF\xBB\xBF") { - $data = substr($data, 3); - } - - /* All U+0000 NULL characters in the input must be replaced - by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such - characters is a parse error. */ - for ($i = 0, $count = substr_count($data, "\0"); $i < $count; $i++) { - $this->errors[] = [ - 'type' => HTML5_Tokenizer::PARSEERROR, - 'data' => 'null-character' - ]; - } - /* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED - (LF) characters are treated specially. Any CR characters - that are followed by LF characters must be removed, and any - CR characters not followed by LF characters must be converted - to LF characters. Thus, newlines in HTML DOMs are represented - by LF characters, and there are never any CR characters in the - input to the tokenization stage. */ - $data = str_replace( - [ - "\0", - "\r\n", - "\r" - ], - [ - "\xEF\xBF\xBD", - "\n", - "\n" - ], - $data - ); - - /* Any occurrences of any characters in the ranges U+0001 to - U+0008, U+000B, U+000E to U+001F, U+007F to U+009F, - U+D800 to U+DFFF , U+FDD0 to U+FDEF, and - characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF, - U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, - U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, - U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE, - U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and - U+10FFFF are parse errors. (These are all control characters - or permanently undefined Unicode characters.) */ - // Check PCRE is loaded. - if (extension_loaded('pcre')) { - $count = preg_match_all( - '/(?: - [\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F - | - \xC2[\x80-\x9F] # U+0080 to U+009F - | - \xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF - | - \xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF - | - \xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF - | - [\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16}) - )/x', - $data, - $matches - ); - for ($i = 0; $i < $count; $i++) { - $this->errors[] = [ - 'type' => HTML5_Tokenizer::PARSEERROR, - 'data' => 'invalid-codepoint' - ]; - } - } else { - // XXX: Need non-PCRE impl, probably using substr_count - } - - $this->data = $data; - $this->char = 0; - $this->EOF = strlen($data); - } - - /** - * Returns the current line that the tokenizer is at. - * - * @return int - */ - public function getCurrentLine() { - // Check the string isn't empty - if ($this->EOF) { - // Add one to $this->char because we want the number for the next - // byte to be processed. - return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; - } else { - // If the string is empty, we are on the first line (sorta). - return 1; - } - } - - /** - * Returns the current column of the current line that the tokenizer is at. - * - * @return int - */ - public function getColumnOffset() { - // strrpos is weird, and the offset needs to be negative for what we - // want (i.e., the last \n before $this->char). This needs to not have - // one (to make it point to the next character, the one we want the - // position of) added to it because strrpos's behaviour includes the - // final offset byte. - $lastLine = strrpos($this->data, "\n", $this->char - 1 - strlen($this->data)); - - // However, for here we want the length up until the next byte to be - // processed, so add one to the current byte ($this->char). - if ($lastLine !== false) { - $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); - } else { - $findLengthOf = substr($this->data, 0, $this->char); - } - - // Get the length for the string we need. - if (extension_loaded('iconv')) { - return iconv_strlen($findLengthOf, 'utf-8'); - } elseif (extension_loaded('mbstring')) { - return mb_strlen($findLengthOf, 'utf-8'); - } elseif (extension_loaded('xml')) { - return strlen(utf8_decode($findLengthOf)); - } else { - $count = count_chars($findLengthOf); - // 0x80 = 0x7F - 0 + 1 (one added to get inclusive range) - // 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range) - return array_sum(array_slice($count, 0, 0x80)) + - array_sum(array_slice($count, 0xC2, 0x33)); - } - } - - /** - * Retrieve the currently consume character. - * @note This performs bounds checking - * - * @return bool|string - */ - public function char() { - return ($this->char++ < $this->EOF) - ? $this->data[$this->char - 1] - : false; - } - - /** - * Get all characters until EOF. - * @note This performs bounds checking - * - * @return string|bool - */ - public function remainingChars() { - if ($this->char < $this->EOF) { - $data = substr($this->data, $this->char); - $this->char = $this->EOF; - return $data; - } else { - return false; - } - } - - /** - * Matches as far as possible until we reach a certain set of bytes - * and returns the matched substring. - * - * @param $bytes | Bytes to match. - * @param null $max - * @return bool|string - */ - public function charsUntil($bytes, $max = null) { - if ($this->char < $this->EOF) { - if ($max === 0 || $max) { - $len = strcspn($this->data, $bytes, $this->char, $max); - } else { - $len = strcspn($this->data, $bytes, $this->char); - } - $string = (string) substr($this->data, $this->char, $len); - $this->char += $len; - return $string; - } else { - return false; - } - } - - /** - * Matches as far as possible with a certain set of bytes - * and returns the matched substring. - * - * @param $bytes | Bytes to match. - * @param null $max - * @return bool|string - */ - public function charsWhile($bytes, $max = null) { - if ($this->char < $this->EOF) { - if ($max === 0 || $max) { - $len = strspn($this->data, $bytes, $this->char, $max); - } else { - $len = strspn($this->data, $bytes, $this->char); - } - $string = (string) substr($this->data, $this->char, $len); - $this->char += $len; - return $string; - } else { - return false; - } - } - - /** - * Unconsume one character. - */ - public function unget() { - if ($this->char <= $this->EOF) { - $this->char--; - } - } -} diff --git a/library/vendor/dompdf/lib/html5lib/Parser.php b/library/vendor/dompdf/lib/html5lib/Parser.php deleted file mode 100644 index b48ce6830..000000000 --- a/library/vendor/dompdf/lib/html5lib/Parser.php +++ /dev/null @@ -1,37 +0,0 @@ -parse(); - return $tokenizer->save(); - } - - /** - * Parses an HTML fragment. - * @param $text | HTML text to parse - * @param $context String name of context element to pretend parsing is in. - * @param $builder | Custom builder implementation - * @return DOMDocument|DOMNodeList Parsed HTML as DOMDocument - */ - public static function parseFragment($text, $context = null, $builder = null) { - $tokenizer = new HTML5_Tokenizer($text, $builder); - $tokenizer->parseFragment($context); - return $tokenizer->save(); - } -} diff --git a/library/vendor/dompdf/lib/html5lib/Tokenizer.php b/library/vendor/dompdf/lib/html5lib/Tokenizer.php deleted file mode 100644 index 9f1f3ae9d..000000000 --- a/library/vendor/dompdf/lib/html5lib/Tokenizer.php +++ /dev/null @@ -1,2470 +0,0 @@ - -Copyright 2008 Edward Z. Yang -Copyright 2009 Geoffrey Sneddon - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -// Some conventions: -// /* */ indicates verbatim text from the HTML 5 specification -// // indicates regular comments - -// all flags are in hyphenated form - -class HTML5_Tokenizer { - /** - * @var HTML5_InputStream - * - * Points to an InputStream object. - */ - protected $stream; - - /** - * @var HTML5_TreeBuilder - * - * Tree builder that the tokenizer emits token to. - */ - private $tree; - - /** - * @var int - * - * Current content model we are parsing as. - */ - protected $content_model; - - /** - * Current token that is being built, but not yet emitted. Also - * is the last token emitted, if applicable. - */ - protected $token; - - // These are constants describing the content model - const PCDATA = 0; - const RCDATA = 1; - const CDATA = 2; - const PLAINTEXT = 3; - - // These are constants describing tokens - // XXX should probably be moved somewhere else, probably the - // HTML5 class. - const DOCTYPE = 0; - const STARTTAG = 1; - const ENDTAG = 2; - const COMMENT = 3; - const CHARACTER = 4; - const SPACECHARACTER = 5; - const EOF = 6; - const PARSEERROR = 7; - - // These are constants representing bunches of characters. - const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - const UPPER_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - const LOWER_ALPHA = 'abcdefghijklmnopqrstuvwxyz'; - const DIGIT = '0123456789'; - const HEX = '0123456789ABCDEFabcdef'; - const WHITESPACE = "\t\n\x0c "; - - /** - * @param $data | Data to parse - * @param HTML5_TreeBuilder|null $builder - */ - public function __construct($data, $builder = null) { - $this->stream = new HTML5_InputStream($data); - if (!$builder) { - $this->tree = new HTML5_TreeBuilder; - } else { - $this->tree = $builder; - } - $this->content_model = self::PCDATA; - } - - /** - * @param null $context - */ - public function parseFragment($context = null) { - $this->tree->setupContext($context); - if ($this->tree->content_model) { - $this->content_model = $this->tree->content_model; - $this->tree->content_model = null; - } - $this->parse(); - } - - // XXX maybe convert this into an iterator? regardless, this function - // and the save function should go into a Parser facade of some sort - /** - * Performs the actual parsing of the document. - */ - public function parse() { - // Current state - $state = 'data'; - // This is used to avoid having to have look-behind in the data state. - $lastFourChars = ''; - /** - * Escape flag as specified by the HTML5 specification: "used to - * control the behavior of the tokeniser. It is either true or - * false, and initially must be set to the false state." - */ - $escape = false; - //echo "\n\n"; - while($state !== null) { - - /*echo $state . ' '; - switch ($this->content_model) { - case self::PCDATA: echo 'PCDATA'; break; - case self::RCDATA: echo 'RCDATA'; break; - case self::CDATA: echo 'CDATA'; break; - case self::PLAINTEXT: echo 'PLAINTEXT'; break; - } - if ($escape) echo " escape"; - echo "\n";*/ - - switch($state) { - case 'data': - - /* Consume the next input character */ - $char = $this->stream->char(); - $lastFourChars .= $char; - if (strlen($lastFourChars) > 4) { - $lastFourChars = substr($lastFourChars, -4); - } - - // see below for meaning - $hyp_cond = - !$escape && - ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ); - $amp_cond = - !$escape && - ( - $this->content_model === self::PCDATA || - $this->content_model === self::RCDATA - ); - $lt_cond = - $this->content_model === self::PCDATA || - ( - ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ) && - !$escape - ); - $gt_cond = - $escape && - ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ); - - if ($char === '&' && $amp_cond === true) { - /* U+0026 AMPERSAND (&) - When the content model flag is set to one of the PCDATA or RCDATA - states and the escape flag is false: switch to the - character reference data state. Otherwise: treat it as per - the "anything else" entry below. */ - $state = 'character reference data'; - - } elseif ( - $char === '-' && - $hyp_cond === true && - $lastFourChars === '' - ) { - /* If the content model flag is set to either the RCDATA state or - the CDATA state, and the escape flag is true, and the last three - characters in the input stream including this one are U+002D - HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN ("-->"), - set the escape flag to false. */ - $escape = false; - - /* In any case, emit the input character as a character token. - Stay in the data state. */ - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => '>' - ]); - // We do the "any case" part as part of "anything else". - - } elseif ($char === false) { - /* EOF - Emit an end-of-file token. */ - $state = null; - $this->tree->emitToken([ - 'type' => self::EOF - ]); - - } elseif ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - // Directly after emitting a token you switch back to the "data - // state". At that point spaceCharacters are important so they are - // emitted separately. - $chars = $this->stream->charsWhile(self::WHITESPACE); - $this->emitToken([ - 'type' => self::SPACECHARACTER, - 'data' => $char . $chars - ]); - $lastFourChars .= $chars; - if (strlen($lastFourChars) > 4) { - $lastFourChars = substr($lastFourChars, -4); - } - } else { - /* Anything else - THIS IS AN OPTIMIZATION: Get as many character that - otherwise would also be treated as a character token and emit it - as a single character token. Stay in the data state. */ - - $mask = ''; - if ($hyp_cond === true) { - $mask .= '-'; - } - if ($amp_cond === true) { - $mask .= '&'; - } - if ($lt_cond === true) { - $mask .= '<'; - } - if ($gt_cond === true) { - $mask .= '>'; - } - - if ($mask === '') { - $chars = $this->stream->remainingChars(); - } else { - $chars = $this->stream->charsUntil($mask); - } - - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => $char . $chars - ]); - - $lastFourChars .= $chars; - if (strlen($lastFourChars) > 4) { - $lastFourChars = substr($lastFourChars, -4); - } - - $state = 'data'; - } - break; - - case 'character reference data': - /* (This cannot happen if the content model flag - is set to the CDATA state.) */ - - /* Attempt to consume a character reference, with no - additional allowed character. */ - $entity = $this->consumeCharacterReference(); - - /* If nothing is returned, emit a U+0026 AMPERSAND - character token. Otherwise, emit the character token that - was returned. */ - // This is all done when consuming the character reference. - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => $entity - ]); - - /* Finally, switch to the data state. */ - $state = 'data'; - break; - - case 'tag open': - $char = $this->stream->char(); - - switch ($this->content_model) { - case self::RCDATA: - case self::CDATA: - /* Consume the next input character. If it is a - U+002F SOLIDUS (/) character, switch to the close - tag open state. Otherwise, emit a U+003C LESS-THAN - SIGN character token and reconsume the current input - character in the data state. */ - // We consumed above. - - if ($char === '/') { - $state = 'close tag open'; - } else { - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => '<' - ]); - - $this->stream->unget(); - - $state = 'data'; - } - break; - - case self::PCDATA: - /* If the content model flag is set to the PCDATA state - Consume the next input character: */ - // We consumed above. - - if ($char === '!') { - /* U+0021 EXCLAMATION MARK (!) - Switch to the markup declaration open state. */ - $state = 'markup declaration open'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the close tag open state. */ - $state = 'close tag open'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new start tag token, set its tag name to the lowercase - version of the input character (add 0x0020 to the character's code - point), then switch to the tag name state. (Don't emit the token - yet; further details will be filled in before it is emitted.) */ - $this->token = [ - 'name' => strtolower($char), - 'type' => self::STARTTAG, - 'attr' => [] - ]; - - $state = 'tag name'; - - } elseif ('a' <= $char && $char <= 'z') { - /* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z - Create a new start tag token, set its tag name to the input - character, then switch to the tag name state. (Don't emit - the token yet; further details will be filled in before it - is emitted.) */ - $this->token = [ - 'name' => $char, - 'type' => self::STARTTAG, - 'attr' => [] - ]; - - $state = 'tag name'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit a U+003C LESS-THAN SIGN character token and a - U+003E GREATER-THAN SIGN character token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-tag-name-but-got-right-bracket' - ]); - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => '<>' - ]); - - $state = 'data'; - - } elseif ($char === '?') { - /* U+003F QUESTION MARK (?) - Parse error. Switch to the bogus comment state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-tag-name-but-got-question-mark' - ]); - $this->token = [ - 'data' => '?', - 'type' => self::COMMENT - ]; - $state = 'bogus comment'; - - } else { - /* Anything else - Parse error. Emit a U+003C LESS-THAN SIGN character token and - reconsume the current input character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-tag-name' - ]); - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => '<' - ]); - - $state = 'data'; - $this->stream->unget(); - } - break; - } - break; - - case 'close tag open': - if ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ) { - /* If the content model flag is set to the RCDATA or CDATA - states... */ - $name = strtolower($this->stream->charsWhile(self::ALPHA)); - $following = $this->stream->char(); - $this->stream->unget(); - if ( - !$this->token || - $this->token['name'] !== $name || - $this->token['name'] === $name && !in_array($following, ["\x09", "\x0A", "\x0C", "\x20", "\x3E", "\x2F", false]) - ) { - /* if no start tag token has ever been emitted by this instance - of the tokenizer (fragment case), or, if the next few - characters do not match the tag name of the last start tag - token emitted (compared in an ASCII case-insensitive manner), - or if they do but they are not immediately followed by one of - the following characters: - - * U+0009 CHARACTER TABULATION - * U+000A LINE FEED (LF) - * U+000C FORM FEED (FF) - * U+0020 SPACE - * U+003E GREATER-THAN SIGN (>) - * U+002F SOLIDUS (/) - * EOF - - ...then emit a U+003C LESS-THAN SIGN character token, a - U+002F SOLIDUS character token, and switch to the data - state to process the next input character. */ - // XXX: Probably ought to replace in_array with $following === x ||... - - // We also need to emit $name now we've consumed that, as we - // know it'll just be emitted as a character token. - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => 'token = [ - 'name' => $name, - 'type' => self::ENDTAG - ]; - - // Change to tag name state. - $state = 'tag name'; - } - } elseif ($this->content_model === self::PCDATA) { - /* Otherwise, if the content model flag is set to the PCDATA - state [...]: */ - $char = $this->stream->char(); - - if ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new end tag token, set its tag name to the lowercase version - of the input character (add 0x0020 to the character's code point), then - switch to the tag name state. (Don't emit the token yet; further details - will be filled in before it is emitted.) */ - $this->token = [ - 'name' => strtolower($char), - 'type' => self::ENDTAG - ]; - - $state = 'tag name'; - - } elseif ('a' <= $char && $char <= 'z') { - /* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z - Create a new end tag token, set its tag name to the - input character, then switch to the tag name state. - (Don't emit the token yet; further details will be - filled in before it is emitted.) */ - $this->token = [ - 'name' => $char, - 'type' => self::ENDTAG - ]; - - $state = 'tag name'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-closing-tag-but-got-right-bracket' - ]); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F - SOLIDUS character token. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-closing-tag-but-got-eof' - ]); - $this->emitToken([ - 'type' => self::CHARACTER, - 'data' => 'stream->unget(); - $state = 'data'; - - } else { - /* Parse error. Switch to the bogus comment state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-closing-tag-but-got-char' - ]); - $this->token = [ - 'data' => $char, - 'type' => self::COMMENT - ]; - $state = 'bogus comment'; - } - } - break; - - case 'tag name': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $state = 'before attribute name'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'self-closing start tag'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Append the lowercase version of the current input - character (add 0x0020 to the character's code point) to - the current tag token's tag name. Stay in the tag name state. */ - $chars = $this->stream->charsWhile(self::UPPER_ALPHA); - - $this->token['name'] .= strtolower($char . $chars); - $state = 'tag name'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-tag-name' - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current tag token's tag name. - Stay in the tag name state. */ - $chars = $this->stream->charsUntil("\t\n\x0C />" . self::UPPER_ALPHA); - - $this->token['name'] .= $char . $chars; - $state = 'tag name'; - } - break; - - case 'before attribute name': - /* Consume the next input character: */ - $char = $this->stream->char(); - - // this conditional is optimized, check bottom - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $state = 'before attribute name'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'self-closing start tag'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Start a new attribute in the current tag token. Set that - attribute's name to the lowercase version of the current - input character (add 0x0020 to the character's code - point), and its value to the empty string. Switch to the - attribute name state.*/ - $this->token['attr'][] = [ - 'name' => strtolower($char), - 'value' => '' - ]; - - $state = 'attribute name'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-attribute-name-but-got-eof' - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - U+003C LESS-THAN SIGN (<) - U+003D EQUALS SIGN (=) - Parse error. Treat it as per the "anything else" entry - below. */ - if ($char === '"' || $char === "'" || $char === '<' || $char === '=') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'invalid-character-in-attribute-name' - ]); - } - - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = [ - 'name' => $char, - 'value' => '' - ]; - - $state = 'attribute name'; - } - break; - - case 'attribute name': - // Consume the next input character: - $char = $this->stream->char(); - - // this conditional is optimized, check bottom - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the after attribute name state. */ - $state = 'after attribute name'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'self-closing start tag'; - - } elseif ($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $state = 'before attribute value'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Append the lowercase version of the current input - character (add 0x0020 to the character's code point) to - the current attribute's name. Stay in the attribute name - state. */ - $chars = $this->stream->charsWhile(self::UPPER_ALPHA); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= strtolower($char . $chars); - - $state = 'attribute name'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-name' - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - U+003C LESS-THAN SIGN (<) - Parse error. Treat it as per the "anything else" - entry below. */ - if ($char === '"' || $char === "'" || $char === '<') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'invalid-character-in-attribute-name' - ]); - } - - /* Anything else - Append the current input character to the current attribute's name. - Stay in the attribute name state. */ - $chars = $this->stream->charsUntil("\t\n\x0C /=>\"'" . self::UPPER_ALPHA); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= $char . $chars; - - $state = 'attribute name'; - } - - /* When the user agent leaves the attribute name state - (and before emitting the tag token, if appropriate), the - complete attribute's name must be compared to the other - attributes on the same token; if there is already an - attribute on the token with the exact same name, then this - is a parse error and the new attribute must be dropped, along - with the value that gets associated with it (if any). */ - // this might be implemented in the emitToken method - break; - - case 'after attribute name': - // Consume the next input character: - $char = $this->stream->char(); - - // this is an optimized conditional, check the bottom - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after attribute name state. */ - $state = 'after attribute name'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'self-closing start tag'; - - } elseif ($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $state = 'before attribute value'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Start a new attribute in the current tag token. Set that - attribute's name to the lowercase version of the current - input character (add 0x0020 to the character's code - point), and its value to the empty string. Switch to the - attribute name state. */ - $this->token['attr'][] = [ - 'name' => strtolower($char), - 'value' => '' - ]; - - $state = 'attribute name'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-end-of-tag-but-got-eof' - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - U+003C LESS-THAN SIGN(<) - Parse error. Treat it as per the "anything else" - entry below. */ - if ($char === '"' || $char === "'" || $char === "<") { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'invalid-character-after-attribute-name' - ]); - } - - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = [ - 'name' => $char, - 'value' => '' - ]; - - $state = 'attribute name'; - } - break; - - case 'before attribute value': - // Consume the next input character: - $char = $this->stream->char(); - - // this is an optimized conditional - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute value state. */ - $state = 'before attribute value'; - - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the attribute value (double-quoted) state. */ - $state = 'attribute value (double-quoted)'; - - } elseif ($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the attribute value (unquoted) state and reconsume - this input character. */ - $this->stream->unget(); - $state = 'attribute value (unquoted)'; - - } elseif ($char === '\'') { - /* U+0027 APOSTROPHE (') - Switch to the attribute value (single-quoted) state. */ - $state = 'attribute value (single-quoted)'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit the current tag token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-attribute-value-but-got-right-bracket' - ]); - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-attribute-value-but-got-eof' - ]); - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+003D EQUALS SIGN (=) - * U+003C LESS-THAN SIGN (<) - Parse error. Treat it as per the "anything else" entry below. */ - if ($char === '=' || $char === '<') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'equals-in-unquoted-attribute-value' - ]); - } - - /* Anything else - Append the current input character to the current attribute's value. - Switch to the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $state = 'attribute value (unquoted)'; - } - break; - - case 'attribute value (double-quoted)': - // Consume the next input character: - $char = $this->stream->char(); - - if ($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the after attribute value (quoted) state. */ - $state = 'after attribute value (quoted)'; - - } elseif ($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the character reference in attribute value - state, with the additional allowed character - being U+0022 QUOTATION MARK ("). */ - $this->characterReferenceInAttributeValue('"'); - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-value-double-quote' - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (double-quoted) state. */ - $chars = $this->stream->charsUntil('"&'); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char . $chars; - - $state = 'attribute value (double-quoted)'; - } - break; - - case 'attribute value (single-quoted)': - // Consume the next input character: - $char = $this->stream->char(); - - if ($char === "'") { - /* U+0022 QUOTATION MARK (') - Switch to the after attribute value state. */ - $state = 'after attribute value (quoted)'; - - } elseif ($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->characterReferenceInAttributeValue("'"); - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-value-single-quote' - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (single-quoted) state. */ - $chars = $this->stream->charsUntil("'&"); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char . $chars; - - $state = 'attribute value (single-quoted)'; - } - break; - - case 'attribute value (unquoted)': - // Consume the next input character: - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $state = 'before attribute name'; - - } elseif ($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state, with the - additional allowed character being U+003E - GREATER-THAN SIGN (>). */ - $this->characterReferenceInAttributeValue('>'); - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-value-no-quotes' - ]); - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - U+003C LESS-THAN SIGN (<) - U+003D EQUALS SIGN (=) - Parse error. Treat it as per the "anything else" - entry below. */ - if ($char === '"' || $char === "'" || $char === '=' || $char == '<') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-character-in-unquoted-attribute-value' - ]); - } - - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (unquoted) state. */ - $chars = $this->stream->charsUntil("\t\n\x0c &>\"'="); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char . $chars; - - $state = 'attribute value (unquoted)'; - } - break; - - case 'after attribute value (quoted)': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $state = 'before attribute name'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'self-closing start tag'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-EOF-after-attribute-value' - ]); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Reconsume the character in the before attribute - name state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-character-after-attribute-value' - ]); - $this->stream->unget(); - $state = 'before attribute name'; - } - break; - - case 'self-closing start tag': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Set the self-closing flag of the current tag token. - Emit the current tag token. Switch to the data state. */ - // not sure if this is the name we want - $this->token['self-closing'] = true; - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Reconsume the EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-eof-after-self-closing' - ]); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Reconsume the character in the before attribute name state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-character-after-self-closing' - ]); - $this->stream->unget(); - $state = 'before attribute name'; - } - break; - - case 'bogus comment': - /* (This can only happen if the content model flag is set to the PCDATA state.) */ - /* Consume every character up to the first U+003E GREATER-THAN SIGN - character (>) or the end of the file (EOF), whichever comes first. Emit - a comment token whose data is the concatenation of all the characters - starting from and including the character that caused the state machine - to switch into the bogus comment state, up to and including the last - consumed character before the U+003E character, if any, or up to the - end of the file otherwise. (If the comment was started by the end of - the file (EOF), the token is empty.) */ - $this->token['data'] .= (string) $this->stream->charsUntil('>'); - $this->stream->char(); - - $this->emitToken($this->token); - - /* Switch to the data state. */ - $state = 'data'; - break; - - case 'markup declaration open': - // Consume for below - $hyphens = $this->stream->charsWhile('-', 2); - if ($hyphens === '-') { - $this->stream->unget(); - } - if ($hyphens !== '--') { - $alpha = $this->stream->charsWhile(self::ALPHA, 7); - } - - /* If the next two characters are both U+002D HYPHEN-MINUS (-) - characters, consume those two characters, create a comment token whose - data is the empty string, and switch to the comment state. */ - if ($hyphens === '--') { - $state = 'comment start'; - $this->token = [ - 'data' => '', - 'type' => self::COMMENT - ]; - - /* Otherwise if the next seven characters are a case-insensitive match - for the word "DOCTYPE", then consume those characters and switch to the - DOCTYPE state. */ - } elseif (strtoupper($alpha) === 'DOCTYPE') { - $state = 'DOCTYPE'; - - // XXX not implemented - /* Otherwise, if the insertion mode is "in foreign content" - and the current node is not an element in the HTML namespace - and the next seven characters are an ASCII case-sensitive - match for the string "[CDATA[" (the five uppercase letters - "CDATA" with a U+005B LEFT SQUARE BRACKET character before - and after), then consume those characters and switch to the - CDATA section state (which is unrelated to the content model - flag's CDATA state). */ - - /* Otherwise, is is a parse error. Switch to the bogus comment state. - The next character that is consumed, if any, is the first character - that will be in the comment. */ - } else { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-dashes-or-doctype' - ]); - $this->token = [ - 'data' => (string) $alpha, - 'type' => self::COMMENT - ]; - $state = 'bogus comment'; - } - break; - - case 'comment start': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment start dash state. */ - $state = 'comment start dash'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit the comment token. Switch to the - data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'incorrect-comment' - ]); - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the - EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment' - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the input character to the comment token's - data. Switch to the comment state. */ - $this->token['data'] .= $char; - $state = 'comment'; - } - break; - - case 'comment start dash': - /* Consume the next input character: */ - $char = $this->stream->char(); - if ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment end state */ - $state = 'comment end'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit the comment token. Switch to the - data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'incorrect-comment' - ]); - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Emit the comment token. Reconsume the - EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment' - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - $this->token['data'] .= '-' . $char; - $state = 'comment'; - } - break; - - case 'comment': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment end dash state */ - $state = 'comment end dash'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment' - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the input character to the comment token's data. Stay in - the comment state. */ - $chars = $this->stream->charsUntil('-'); - - $this->token['data'] .= $char . $chars; - } - break; - - case 'comment end dash': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment end state */ - $state = 'comment end'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment-end-dash' - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append a U+002D HYPHEN-MINUS (-) character and the input - character to the comment token's data. Switch to the comment state. */ - $this->token['data'] .= '-'.$char; - $state = 'comment'; - } - break; - - case 'comment end': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the comment token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Parse error. Append a U+002D HYPHEN-MINUS (-) character - to the comment token's data. Stay in the comment end - state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-dash-after-double-dash-in-comment' - ]); - $this->token['data'] .= '-'; - - } elseif ($char === "\t" || $char === "\n" || $char === "\x0a" || $char === ' ') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-space-after-double-dash-in-comment' - ]); - $this->token['data'] .= '--' . $char; - $state = 'comment end space'; - - } elseif ($char === '!') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-bang-after-double-dash-in-comment' - ]); - $state = 'comment end bang'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the - EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment-double-dash' - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Append two U+002D HYPHEN-MINUS (-) - characters and the input character to the comment token's - data. Switch to the comment state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-comment' - ]); - $this->token['data'] .= '--'.$char; - $state = 'comment'; - } - break; - - case 'comment end bang': - $char = $this->stream->char(); - if ($char === '>') { - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === "-") { - $this->token['data'] .= '--!'; - $state = 'comment end dash'; - } elseif ($char === false) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment-end-bang' - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - $this->token['data'] .= '--!' . $char; - $state = 'comment'; - } - break; - - case 'comment end space': - $char = $this->stream->char(); - if ($char === '>') { - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === '-') { - $state = 'comment end dash'; - } elseif ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - $this->token['data'] .= $char; - } elseif ($char === false) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-eof-in-comment-end-space', - ]); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - $this->token['data'] .= $char; - $state = 'comment'; - } - break; - - case 'DOCTYPE': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before DOCTYPE name state. */ - $state = 'before DOCTYPE name'; - - } elseif ($char === false) { - /* EOF - Parse error. Create a new DOCTYPE token. Set its - force-quirks flag to on. Emit the token. Reconsume the - EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'need-space-after-doctype-but-got-eof' - ]); - $this->emitToken([ - 'name' => '', - 'type' => self::DOCTYPE, - 'force-quirks' => true, - 'error' => true - ]); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Reconsume the current character in the - before DOCTYPE name state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'need-space-after-doctype' - ]); - $this->stream->unget(); - $state = 'before DOCTYPE name'; - } - break; - - case 'before DOCTYPE name': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before DOCTYPE name state. */ - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Create a new DOCTYPE token. Set its - force-quirks flag to on. Emit the token. Switch to the - data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-doctype-name-but-got-right-bracket' - ]); - $this->emitToken([ - 'name' => '', - 'type' => self::DOCTYPE, - 'force-quirks' => true, - 'error' => true - ]); - - $state = 'data'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Create a new DOCTYPE token. Set the token's name to the - lowercase version of the input character (add 0x0020 to - the character's code point). Switch to the DOCTYPE name - state. */ - $this->token = [ - 'name' => strtolower($char), - 'type' => self::DOCTYPE, - 'error' => true - ]; - - $state = 'DOCTYPE name'; - - } elseif ($char === false) { - /* EOF - Parse error. Create a new DOCTYPE token. Set its - force-quirks flag to on. Emit the token. Reconsume the - EOF character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-doctype-name-but-got-eof' - ]); - $this->emitToken([ - 'name' => '', - 'type' => self::DOCTYPE, - 'force-quirks' => true, - 'error' => true - ]); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Create a new DOCTYPE token. Set the token's name to the - current input character. Switch to the DOCTYPE name state. */ - $this->token = [ - 'name' => $char, - 'type' => self::DOCTYPE, - 'error' => true - ]; - - $state = 'DOCTYPE name'; - } - break; - - case 'DOCTYPE name': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the after DOCTYPE name state. */ - $state = 'after DOCTYPE name'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Append the lowercase version of the input character - (add 0x0020 to the character's code point) to the current - DOCTYPE token's name. Stay in the DOCTYPE name state. */ - $this->token['name'] .= strtolower($char); - - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype-name' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's name. Stay in the DOCTYPE name state. */ - $this->token['name'] .= $char; - } - - // XXX this is probably some sort of quirks mode designation, - // check tree-builder to be sure. In general 'error' needs - // to be specc'ified, this probably means removing it at the end - $this->token['error'] = ($this->token['name'] === 'HTML') - ? false - : true; - break; - - case 'after DOCTYPE name': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after DOCTYPE name state. */ - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else */ - - $nextSix = strtoupper($char . $this->stream->charsWhile(self::ALPHA, 5)); - if ($nextSix === 'PUBLIC') { - /* If the next six characters are an ASCII - case-insensitive match for the word "PUBLIC", then - consume those characters and switch to the before - DOCTYPE public identifier state. */ - $state = 'before DOCTYPE public identifier'; - - } elseif ($nextSix === 'SYSTEM') { - /* Otherwise, if the next six characters are an ASCII - case-insensitive match for the word "SYSTEM", then - consume those characters and switch to the before - DOCTYPE system identifier state. */ - $state = 'before DOCTYPE system identifier'; - - } else { - /* Otherwise, this is the parse error. Set the DOCTYPE - token's force-quirks flag to on. Switch to the bogus - DOCTYPE state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-space-or-right-bracket-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->token['error'] = true; - $state = 'bogus DOCTYPE'; - } - } - break; - - case 'before DOCTYPE public identifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before DOCTYPE public identifier state. */ - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Set the DOCTYPE token's public identifier to the empty - string (not missing), then switch to the DOCTYPE public - identifier (double-quoted) state. */ - $this->token['public'] = ''; - $state = 'DOCTYPE public identifier (double-quoted)'; - } elseif ($char === "'") { - /* U+0027 APOSTROPHE (') - Set the DOCTYPE token's public identifier to the empty - string (not missing), then switch to the DOCTYPE public - identifier (single-quoted) state. */ - $this->token['public'] = ''; - $state = 'DOCTYPE public identifier (single-quoted)'; - } elseif ($char === '>') { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Switch to the bogus DOCTYPE state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - ]); - $this->token['force-quirks'] = true; - $state = 'bogus DOCTYPE'; - } - break; - - case 'DOCTYPE public identifier (double-quoted)': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the after DOCTYPE public identifier state. */ - $state = 'after DOCTYPE public identifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's public identifier. Stay in the DOCTYPE - public identifier (double-quoted) state. */ - $this->token['public'] .= $char; - } - break; - - case 'DOCTYPE public identifier (single-quoted)': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "'") { - /* U+0027 APOSTROPHE (') - Switch to the after DOCTYPE public identifier state. */ - $state = 'after DOCTYPE public identifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's public identifier. Stay in the DOCTYPE - public identifier (double-quoted) state. */ - $this->token['public'] .= $char; - } - break; - - case 'after DOCTYPE public identifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after DOCTYPE public identifier state. */ - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Set the DOCTYPE token's system identifier to the - empty string (not missing), then switch to the DOCTYPE - system identifier (double-quoted) state. */ - $this->token['system'] = ''; - $state = 'DOCTYPE system identifier (double-quoted)'; - } elseif ($char === "'") { - /* U+0027 APOSTROPHE (') - Set the DOCTYPE token's system identifier to the - empty string (not missing), then switch to the DOCTYPE - system identifier (single-quoted) state. */ - $this->token['system'] = ''; - $state = 'DOCTYPE system identifier (single-quoted)'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Switch to the bogus DOCTYPE state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - ]); - $this->token['force-quirks'] = true; - $state = 'bogus DOCTYPE'; - } - break; - - case 'before DOCTYPE system identifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before DOCTYPE system identifier state. */ - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Set the DOCTYPE token's system identifier to the empty - string (not missing), then switch to the DOCTYPE system - identifier (double-quoted) state. */ - $this->token['system'] = ''; - $state = 'DOCTYPE system identifier (double-quoted)'; - } elseif ($char === "'") { - /* U+0027 APOSTROPHE (') - Set the DOCTYPE token's system identifier to the empty - string (not missing), then switch to the DOCTYPE system - identifier (single-quoted) state. */ - $this->token['system'] = ''; - $state = 'DOCTYPE system identifier (single-quoted)'; - } elseif ($char === '>') { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Switch to the bogus DOCTYPE state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - ]); - $this->token['force-quirks'] = true; - $state = 'bogus DOCTYPE'; - } - break; - - case 'DOCTYPE system identifier (double-quoted)': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the after DOCTYPE system identifier state. */ - $state = 'after DOCTYPE system identifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's system identifier. Stay in the DOCTYPE - system identifier (double-quoted) state. */ - $this->token['system'] .= $char; - } - break; - - case 'DOCTYPE system identifier (single-quoted)': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "'") { - /* U+0027 APOSTROPHE (') - Switch to the after DOCTYPE system identifier state. */ - $state = 'after DOCTYPE system identifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's system identifier. Stay in the DOCTYPE - system identifier (double-quoted) state. */ - $this->token['system'] .= $char; - } - break; - - case 'after DOCTYPE system identifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after DOCTYPE system identifier state. */ - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - ]); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Parse error. Switch to the bogus DOCTYPE state. - (This does not set the DOCTYPE token's force-quirks - flag to on.) */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - ]); - $state = 'bogus DOCTYPE'; - } - break; - - case 'bogus DOCTYPE': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Emit the DOCTYPE token. Reconsume the EOF character in - the data state. */ - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Stay in the bogus DOCTYPE state. */ - } - break; - - // case 'cdataSection': - } - } - } - - /** - * Returns a serialized representation of the tree. - * - * @return DOMDocument|DOMNodeList - */ - public function save() { - return $this->tree->save(); - } - - /** - * @return HTML5_TreeBuilder The tree - */ - public function getTree() - { - return $this->tree; - } - - - /** - * Returns the input stream. - * - * @return HTML5_InputStream - */ - public function stream() { - return $this->stream; - } - - /** - * @param bool $allowed - * @param bool $inattr - * @return string - */ - private function consumeCharacterReference($allowed = false, $inattr = false) { - // This goes quite far against spec, and is far closer to the Python - // impl., mainly because we don't do the large unconsuming the spec - // requires. - - // All consumed characters. - $chars = $this->stream->char(); - - /* This section defines how to consume a character - reference. This definition is used when parsing character - references in text and in attributes. - - The behavior depends on the identity of the next character - (the one immediately after the U+0026 AMPERSAND character): */ - - if ( - $chars[0] === "\x09" || - $chars[0] === "\x0A" || - $chars[0] === "\x0C" || - $chars[0] === "\x20" || - $chars[0] === '<' || - $chars[0] === '&' || - $chars === false || - $chars[0] === $allowed - ) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - U+003C LESS-THAN SIGN - U+0026 AMPERSAND - EOF - The additional allowed character, if there is one - Not a character reference. No characters are consumed, - and nothing is returned. (This is not an error, either.) */ - // We already consumed, so unconsume. - $this->stream->unget(); - return '&'; - } elseif ($chars[0] === '#') { - /* Consume the U+0023 NUMBER SIGN. */ - // Um, yeah, we already did that. - /* The behavior further depends on the character after - the U+0023 NUMBER SIGN: */ - $chars .= $this->stream->char(); - if (isset($chars[1]) && ($chars[1] === 'x' || $chars[1] === 'X')) { - /* U+0078 LATIN SMALL LETTER X - U+0058 LATIN CAPITAL LETTER X */ - /* Consume the X. */ - // Um, yeah, we already did that. - /* Follow the steps below, but using the range of - characters U+0030 DIGIT ZERO through to U+0039 DIGIT - NINE, U+0061 LATIN SMALL LETTER A through to U+0066 - LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER - A, through to U+0046 LATIN CAPITAL LETTER F (in other - words, 0123456789, ABCDEF, abcdef). */ - $char_class = self::HEX; - /* When it comes to interpreting the - number, interpret it as a hexadecimal number. */ - $hex = true; - } else { - /* Anything else */ - // Unconsume because we shouldn't have consumed this. - $chars = $chars[0]; - $this->stream->unget(); - /* Follow the steps below, but using the range of - characters U+0030 DIGIT ZERO through to U+0039 DIGIT - NINE (i.e. just 0123456789). */ - $char_class = self::DIGIT; - /* When it comes to interpreting the number, - interpret it as a decimal number. */ - $hex = false; - } - - /* Consume as many characters as match the range of characters given above. */ - $consumed = $this->stream->charsWhile($char_class); - if ($consumed === '' || $consumed === false) { - /* If no characters match the range, then don't consume - any characters (and unconsume the U+0023 NUMBER SIGN - character and, if appropriate, the X character). This - is a parse error; nothing is returned. */ - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-numeric-entity' - ]); - return '&' . $chars; - } else { - /* Otherwise, if the next character is a U+003B SEMICOLON, - consume that too. If it isn't, there is a parse error. */ - if ($this->stream->char() !== ';') { - $this->stream->unget(); - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'numeric-entity-without-semicolon' - ]); - } - - /* If one or more characters match the range, then take - them all and interpret the string of characters as a number - (either hexadecimal or decimal as appropriate). */ - $codepoint = $hex ? hexdec($consumed) : (int) $consumed; - - /* If that number is one of the numbers in the first column - of the following table, then this is a parse error. Find the - row with that number in the first column, and return a - character token for the Unicode character given in the - second column of that row. */ - $new_codepoint = HTML5_Data::getRealCodepoint($codepoint); - if ($new_codepoint) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'illegal-windows-1252-entity' - ]); - return HTML5_Data::utf8chr($new_codepoint); - } else { - /* Otherwise, if the number is greater than 0x10FFFF, then - * this is a parse error. Return a U+FFFD REPLACEMENT - * CHARACTER. */ - if ($codepoint > 0x10FFFF) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'overlong-character-entity' // XXX probably not correct - ]); - return "\xEF\xBF\xBD"; - } - /* Otherwise, return a character token for the Unicode - * character whose code point is that number. If the - * number is in the range 0x0001 to 0x0008, 0x000E to - * 0x001F, 0x007F to 0x009F, 0xD800 to 0xDFFF, 0xFDD0 to - * 0xFDEF, or is one of 0x000B, 0xFFFE, 0xFFFF, 0x1FFFE, - * 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE, - * 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE, - * 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, - * 0xAFFFF, 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE, - * 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE, - * or 0x10FFFF, then this is a parse error. */ - // && has higher precedence than || - if ( - $codepoint >= 0x0000 && $codepoint <= 0x0008 || - $codepoint === 0x000B || - $codepoint >= 0x000E && $codepoint <= 0x001F || - $codepoint >= 0x007F && $codepoint <= 0x009F || - $codepoint >= 0xD800 && $codepoint <= 0xDFFF || - $codepoint >= 0xFDD0 && $codepoint <= 0xFDEF || - ($codepoint & 0xFFFE) === 0xFFFE || - $codepoint == 0x10FFFF || $codepoint == 0x10FFFE - ) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'illegal-codepoint-for-numeric-entity' - ]); - } - return HTML5_Data::utf8chr($codepoint); - } - } - } else { - /* Anything else */ - - /* Consume the maximum number of characters possible, - with the consumed characters matching one of the - identifiers in the first column of the named character - references table (in a case-sensitive manner). */ - // What we actually do here is consume as much as we can while it - // matches the start of one of the identifiers in the first column. - - $refs = HTML5_Data::getNamedCharacterReferences(); - - // Get the longest string which is the start of an identifier - // ($chars) as well as the longest identifier which matches ($id) - // and its codepoint ($codepoint). - $codepoint = false; - $char = $chars; - while ($char !== false && isset($refs[$char])) { - $refs = $refs[$char]; - if (isset($refs['codepoint'])) { - $id = $chars; - $codepoint = $refs['codepoint']; - } - $chars .= $char = $this->stream->char(); - } - - // Unconsume the one character we just took which caused the while - // statement to fail. This could be anything and could cause state - // changes (as if it matches the while loop it must be - // alphanumeric so we can just concat it to whatever we get later). - $this->stream->unget(); - if ($char !== false) { - $chars = substr($chars, 0, -1); - } - - /* If no match can be made, then this is a parse error. - No characters are consumed, and nothing is returned. */ - if (!$codepoint) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'expected-named-entity' - ]); - return '&' . $chars; - } - - /* If the last character matched is not a U+003B SEMICOLON - (;), there is a parse error. */ - $semicolon = true; - if (substr($id, -1) !== ';') { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'named-entity-without-semicolon' - ]); - $semicolon = false; - } - - /* If the character reference is being consumed as part of - an attribute, and the last character matched is not a - U+003B SEMICOLON (;), and the next character is in the - range U+0030 DIGIT ZERO to U+0039 DIGIT NINE, U+0041 - LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z, - or U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z, - then, for historical reasons, all the characters that were - matched after the U+0026 AMPERSAND (&) must be unconsumed, - and nothing is returned. */ - if ($inattr && !$semicolon) { - // The next character is either the next character in $chars or in the stream. - if (strlen($chars) > strlen($id)) { - $next = substr($chars, strlen($id), 1); - } else { - $next = $this->stream->char(); - $this->stream->unget(); - } - if ( - '0' <= $next && $next <= '9' || - 'A' <= $next && $next <= 'Z' || - 'a' <= $next && $next <= 'z' - ) { - return '&' . $chars; - } - } - - /* Otherwise, return a character token for the character - corresponding to the character reference name (as given - by the second column of the named character references table). */ - return HTML5_Data::utf8chr($codepoint) . substr($chars, strlen($id)); - } - } - - /** - * @param bool $allowed - */ - private function characterReferenceInAttributeValue($allowed = false) { - /* Attempt to consume a character reference. */ - $entity = $this->consumeCharacterReference($allowed, true); - - /* If nothing is returned, append a U+0026 AMPERSAND - character to the current attribute's value. - - Otherwise, append the returned character token to the - current attribute's value. */ - $char = (!$entity) - ? '&' - : $entity; - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - /* Finally, switch back to the attribute value state that you - were in when were switched into this state. */ - } - - /** - * Emits a token, passing it on to the tree builder. - * - * @param $token - * @param bool $checkStream - * @param bool $dry - */ - protected function emitToken($token, $checkStream = true, $dry = false) { - if ($checkStream === true) { - // Emit errors from input stream. - while ($this->stream->errors) { - $this->emitToken(array_shift($this->stream->errors), false); - } - } - if ($token['type'] === self::ENDTAG && !empty($token['attr'])) { - for ($i = 0; $i < count($token['attr']); $i++) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'attributes-in-end-tag' - ]); - } - } - if ($token['type'] === self::ENDTAG && !empty($token['self-closing'])) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'self-closing-flag-on-end-tag', - ]); - } - if ($token['type'] === self::STARTTAG) { - // This could be changed to actually pass the tree-builder a hash - $hash = []; - foreach ($token['attr'] as $keypair) { - if (isset($hash[$keypair['name']])) { - $this->emitToken([ - 'type' => self::PARSEERROR, - 'data' => 'duplicate-attribute', - ]); - } else { - $hash[$keypair['name']] = $keypair['value']; - } - } - } - - if ($dry === false) { - // the current structure of attributes is not a terribly good one - $this->tree->emitToken($token); - } - - if ($dry === false && is_int($this->tree->content_model)) { - $this->content_model = $this->tree->content_model; - $this->tree->content_model = null; - - } elseif ($token['type'] === self::ENDTAG) { - $this->content_model = self::PCDATA; - } - } -} - diff --git a/library/vendor/dompdf/lib/html5lib/TreeBuilder.php b/library/vendor/dompdf/lib/html5lib/TreeBuilder.php deleted file mode 100644 index 74cf8702e..000000000 --- a/library/vendor/dompdf/lib/html5lib/TreeBuilder.php +++ /dev/null @@ -1,3989 +0,0 @@ - -Copyright 2009 Edward Z. Yang - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -// Tags for FIX ME!!!: (in order of priority) -// XXX - should be fixed NAO! -// XERROR - with regards to parse errors -// XSCRIPT - with regards to scripting mode -// XENCODING - with regards to encoding (for reparsing tests) -// XDOM - DOM specific code (tagName is explicitly not marked). -// this is not (yet) in helper functions. - -class HTML5_TreeBuilder { - public $stack = []; - public $content_model; - - private $mode; - private $original_mode; - private $secondary_mode; - private $dom; - // Whether or not normal insertion of nodes should actually foster - // parent (used in one case in spec) - private $foster_parent = false; - private $a_formatting = []; - - private $head_pointer = null; - private $form_pointer = null; - - private $flag_frameset_ok = true; - private $flag_force_quirks = false; - private $ignored = false; - private $quirks_mode = null; - // this gets to 2 when we want to ignore the next lf character, and - // is decrement at the beginning of each processed token (this way, - // code can check for (bool)$ignore_lf_token, but it phases out - // appropriately) - private $ignore_lf_token = 0; - private $fragment = false; - private $root; - - private $scoping = ['applet','button','caption','html','marquee','object','table','td','th', 'svg:foreignObject']; - private $formatting = ['a','b','big','code','em','font','i','nobr','s','small','strike','strong','tt','u']; - // dl and ds are speculative - private $special = ['address','area','article','aside','base','basefont','bgsound', - 'blockquote','body','br','center','col','colgroup','command','dc','dd','details','dir','div','dl','ds', - 'dt','embed','fieldset','figure','footer','form','frame','frameset','h1','h2','h3','h4','h5', - 'h6','head','header','hgroup','hr','iframe','img','input','isindex','li','link', - 'listing','menu','meta','nav','noembed','noframes','noscript','ol', - 'p','param','plaintext','pre','script','select','spacer','style', - 'tbody','textarea','tfoot','thead','title','tr','ul','wbr']; - - private $pendingTableCharacters; - private $pendingTableCharactersDirty; - - // Tree construction modes - const INITIAL = 0; - const BEFORE_HTML = 1; - const BEFORE_HEAD = 2; - const IN_HEAD = 3; - const IN_HEAD_NOSCRIPT = 4; - const AFTER_HEAD = 5; - const IN_BODY = 6; - const IN_CDATA_RCDATA = 7; - const IN_TABLE = 8; - const IN_TABLE_TEXT = 9; - const IN_CAPTION = 10; - const IN_COLUMN_GROUP = 11; - const IN_TABLE_BODY = 12; - const IN_ROW = 13; - const IN_CELL = 14; - const IN_SELECT = 15; - const IN_SELECT_IN_TABLE= 16; - const IN_FOREIGN_CONTENT= 17; - const AFTER_BODY = 18; - const IN_FRAMESET = 19; - const AFTER_FRAMESET = 20; - const AFTER_AFTER_BODY = 21; - const AFTER_AFTER_FRAMESET = 22; - - /** - * Converts a magic number to a readable name. Use for debugging. - */ - private function strConst($number) { - static $lookup; - if (!$lookup) { - $lookup = []; - $r = new ReflectionClass('HTML5_TreeBuilder'); - $consts = $r->getConstants(); - foreach ($consts as $const => $num) { - if (!is_int($num)) { - continue; - } - $lookup[$num] = $const; - } - } - return $lookup[$number]; - } - - // The different types of elements. - const SPECIAL = 100; - const SCOPING = 101; - const FORMATTING = 102; - const PHRASING = 103; - - // Quirks modes in $quirks_mode - const NO_QUIRKS = 200; - const QUIRKS_MODE = 201; - const LIMITED_QUIRKS_MODE = 202; - - // Marker to be placed in $a_formatting - const MARKER = 300; - - // Namespaces for foreign content - const NS_HTML = null; // to prevent DOM from requiring NS on everything - const NS_MATHML = 'http://www.w3.org/1998/Math/MathML'; - const NS_SVG = 'http://www.w3.org/2000/svg'; - const NS_XLINK = 'http://www.w3.org/1999/xlink'; - const NS_XML = 'http://www.w3.org/XML/1998/namespace'; - const NS_XMLNS = 'http://www.w3.org/2000/xmlns/'; - - // Different types of scopes to test for elements - const SCOPE = 0; - const SCOPE_LISTITEM = 1; - const SCOPE_TABLE = 2; - - /** - * HTML5_TreeBuilder constructor. - */ - public function __construct() { - $this->mode = self::INITIAL; - $this->dom = new DOMDocument; - - $this->dom->encoding = 'UTF-8'; - $this->dom->preserveWhiteSpace = true; - $this->dom->substituteEntities = true; - $this->dom->strictErrorChecking = false; - } - - public function getQuirksMode(){ - return $this->quirks_mode; - } - - /** - * Process tag tokens - * - * @param $token - * @param null $mode - */ - public function emitToken($token, $mode = null) { - // XXX: ignore parse errors... why are we emitting them, again? - if ($token['type'] === HTML5_Tokenizer::PARSEERROR) { - return; - } - if ($mode === null) { - $mode = $this->mode; - } - - /* - $backtrace = debug_backtrace(); - if ($backtrace[1]['class'] !== 'HTML5_TreeBuilder') echo "--\n"; - echo $this->strConst($mode); - if ($this->original_mode) echo " (originally ".$this->strConst($this->original_mode).")"; - echo "\n "; - token_dump($token); - $this->printStack(); - $this->printActiveFormattingElements(); - if ($this->foster_parent) echo " -> this is a foster parent mode\n"; - if ($this->flag_frameset_ok) echo " -> frameset ok\n"; - */ - - if ($this->ignore_lf_token) { - $this->ignore_lf_token--; - } - $this->ignored = false; - - switch ($mode) { - case self::INITIAL: - - /* A character token that is one of U+0009 CHARACTER TABULATION, - * U+000A LINE FEED (LF), U+000C FORM FEED (FF), or U+0020 SPACE */ - if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Ignore the token. */ - $this->ignored = true; - } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - if ( - $token['name'] !== 'html' || !empty($token['public']) || - !empty($token['system']) || $token !== 'about:legacy-compat' - ) { - /* If the DOCTYPE token's name is not a case-sensitive match - * for the string "html", or if the token's public identifier - * is not missing, or if the token's system identifier is - * neither missing nor a case-sensitive match for the string - * "about:legacy-compat", then there is a parse error (this - * is the DOCTYPE parse error). */ - // DOCTYPE parse error - } - /* Append a DocumentType node to the Document node, with the name - * attribute set to the name given in the DOCTYPE token, or the - * empty string if the name was missing; the publicId attribute - * set to the public identifier given in the DOCTYPE token, or - * the empty string if the public identifier was missing; the - * systemId attribute set to the system identifier given in the - * DOCTYPE token, or the empty string if the system identifier - * was missing; and the other attributes specific to - * DocumentType objects set to null and empty lists as - * appropriate. Associate the DocumentType node with the - * Document object so that it is returned as the value of the - * doctype attribute of the Document object. */ - if (!isset($token['public'])) { - $token['public'] = ""; - } - if (!isset($token['system'])) { - $token['system'] = ""; - } - // XDOM - // Yes this is hacky. I'm kind of annoyed that I can't appendChild - // a doctype to DOMDocument. Maybe I haven't chanted the right - // syllables. - $impl = new DOMImplementation(); - // This call can fail for particularly pathological cases (namely, - // the qualifiedName parameter ($token['name']) could be missing. - if ($token['name']) { - $doctype = $impl->createDocumentType($token['name'], $token['public'], $token['system']); - $this->dom->appendChild($doctype); - } else { - // It looks like libxml's not actually *able* to express this case. - // So... don't. - $this->dom->emptyDoctype = true; - } - $public = strtolower($token['public']); - $system = $token['system'] === "" ? false : strtolower($token['system']); - $publicStartsWithForQuirks = [ - "+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//", - ]; - $publicSetToForQuirks = [ - "-//w3o//dtd w3 html strict 3.0//", - "-/w3c/dtd html 4.0 transitional/en", - "html", - ]; - $publicStartsWithAndSystemForQuirks = [ - "-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//", - ]; - $publicStartsWithForLimitedQuirks = [ - "-//w3c//dtd xhtml 1.0 frameset//", - "-//w3c//dtd xhtml 1.0 transitional//", - ]; - $publicStartsWithAndSystemForLimitedQuirks = [ - "-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//", - ]; - // first, do easy checks - if ( - !empty($token['force-quirks']) || - strtolower($token['name']) !== 'html' - ) { - $this->quirks_mode = self::QUIRKS_MODE; - } else { - do { - if ($system) { - foreach ($publicStartsWithAndSystemForQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - } - if (!is_null($this->quirks_mode)) { - break; - } - foreach ($publicStartsWithAndSystemForLimitedQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::LIMITED_QUIRKS_MODE; - break; - } - } - if (!is_null($this->quirks_mode)) { - break; - } - } - foreach ($publicSetToForQuirks as $x) { - if ($public === $x) { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - } - if (!is_null($this->quirks_mode)) { - break; - } - foreach ($publicStartsWithForLimitedQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::LIMITED_QUIRKS_MODE; - } - } - if (!is_null($this->quirks_mode)) { - break; - } - if ($system === "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - foreach ($publicStartsWithForQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - } - if (is_null($this->quirks_mode)) { - $this->quirks_mode = self::NO_QUIRKS; - } - } while (false); - } - $this->mode = self::BEFORE_HTML; - } else { - // parse error - /* Switch the insertion mode to "before html", then reprocess the - * current token. */ - $this->mode = self::BEFORE_HTML; - $this->quirks_mode = self::QUIRKS_MODE; - $this->emitToken($token); - } - break; - - case self::BEFORE_HTML: - /* A DOCTYPE token */ - if ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - // Parse error. Ignore the token. - $this->ignored = true; - - /* A comment token */ - } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - // XDOM - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Ignore the token. */ - $this->ignored = true; - - /* A start tag whose tag name is "html" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] == 'html') { - /* Create an element for the token in the HTML namespace. Append it - * to the Document object. Put this element in the stack of open - * elements. */ - // XDOM - $html = $this->insertElement($token, false); - $this->dom->appendChild($html); - $this->stack[] = $html; - - $this->mode = self::BEFORE_HEAD; - - } else { - /* Create an html element. Append it to the Document object. Put - * this element in the stack of open elements. */ - // XDOM - $html = $this->dom->createElementNS(self::NS_HTML, 'html'); - $this->dom->appendChild($html); - $this->stack[] = $html; - - /* Switch the insertion mode to "before head", then reprocess the - * current token. */ - $this->mode = self::BEFORE_HEAD; - $this->emitToken($token); - } - break; - - case self::BEFORE_HEAD: - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Ignore the token. */ - $this->ignored = true; - - /* A comment token */ - } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A DOCTYPE token */ - } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - /* Parse error. Ignore the token */ - $this->ignored = true; - // parse error - - /* A start tag token with the tag name "html" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') { - /* Process the token using the rules for the "in body" - * insertion mode. */ - $this->processWithRulesFor($token, self::IN_BODY); - - /* A start tag token with the tag name "head" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') { - /* Insert an HTML element for the token. */ - $element = $this->insertElement($token); - - /* Set the head element pointer to this new element node. */ - $this->head_pointer = $element; - - /* Change the insertion mode to "in head". */ - $this->mode = self::IN_HEAD; - - /* An end tag whose tag name is one of: "head", "body", "html", "br" */ - } elseif ( - $token['type'] === HTML5_Tokenizer::ENDTAG && ( - $token['name'] === 'head' || $token['name'] === 'body' || - $token['name'] === 'html' || $token['name'] === 'br' - )) { - /* Act as if a start tag token with the tag name "head" and no - * attributes had been seen, then reprocess the current token. */ - $this->emitToken([ - 'name' => 'head', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => [] - ]); - $this->emitToken($token); - - /* Any other end tag */ - } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG) { - /* Parse error. Ignore the token. */ - $this->ignored = true; - - } else { - /* Act as if a start tag token with the tag name "head" and no - * attributes had been seen, then reprocess the current token. - * Note: This will result in an empty head element being - * generated, with the current token being reprocessed in the - * "after head" insertion mode. */ - $this->emitToken([ - 'name' => 'head', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => [] - ]); - $this->emitToken($token); - } - break; - - case self::IN_HEAD: - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. */ - if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Insert the character into the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A DOCTYPE token */ - } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - /* Parse error. Ignore the token. */ - $this->ignored = true; - // parse error - - /* A start tag whose tag name is "html" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && - $token['name'] === 'html') { - $this->processWithRulesFor($token, self::IN_BODY); - - /* A start tag whose tag name is one of: "base", "command", "link" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && - ($token['name'] === 'base' || $token['name'] === 'command' || - $token['name'] === 'link')) { - /* Insert an HTML element for the token. Immediately pop the - * current node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - - /* A start tag whose tag name is "meta" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'meta') { - /* Insert an HTML element for the token. Immediately pop the - * current node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - // XERROR: Acknowledge the token's self-closing flag, if it is set. - - // XENCODING: If the element has a charset attribute, and its value is a - // supported encoding, and the confidence is currently tentative, - // then change the encoding to the encoding given by the value of - // the charset attribute. - // - // Otherwise, if the element has a content attribute, and applying - // the algorithm for extracting an encoding from a Content-Type to - // its value returns a supported encoding encoding, and the - // confidence is currently tentative, then change the encoding to - // the encoding encoding. - - /* A start tag with the tag name "title" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'title') { - $this->insertRCDATAElement($token); - - /* A start tag whose tag name is "noscript", if the scripting flag is enabled, or - * A start tag whose tag name is one of: "noframes", "style" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && - ($token['name'] === 'noscript' || $token['name'] === 'noframes' || $token['name'] === 'style')) { - // XSCRIPT: Scripting flag not respected - $this->insertCDATAElement($token); - - // XSCRIPT: Scripting flag disable not implemented - - /* A start tag with the tag name "script" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'script') { - /* 1. Create an element for the token in the HTML namespace. */ - $node = $this->insertElement($token, false); - - /* 2. Mark the element as being "parser-inserted" */ - // Uhhh... XSCRIPT - - /* 3. If the parser was originally created for the HTML - * fragment parsing algorithm, then mark the script element as - * "already executed". (fragment case) */ - // ditto... XSCRIPT - - /* 4. Append the new element to the current node and push it onto - * the stack of open elements. */ - end($this->stack)->appendChild($node); - $this->stack[] = $node; - // I guess we could squash these together - - /* 6. Let the original insertion mode be the current insertion mode. */ - $this->original_mode = $this->mode; - /* 7. Switch the insertion mode to "in CDATA/RCDATA" */ - $this->mode = self::IN_CDATA_RCDATA; - /* 5. Switch the tokeniser's content model flag to the CDATA state. */ - $this->content_model = HTML5_Tokenizer::CDATA; - - /* An end tag with the tag name "head" */ - } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'head') { - /* Pop the current node (which will be the head element) off the stack of open elements. */ - array_pop($this->stack); - - /* Change the insertion mode to "after head". */ - $this->mode = self::AFTER_HEAD; - - // Slight logic inversion here to minimize duplication - /* A start tag with the tag name "head". */ - /* An end tag whose tag name is not one of: "body", "html", "br" */ - } elseif (($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] !== 'html' && - $token['name'] !== 'body' && $token['name'] !== 'br')) { - // Parse error. Ignore the token. - $this->ignored = true; - - /* Anything else */ - } else { - /* Act as if an end tag token with the tag name "head" had been - * seen, and reprocess the current token. */ - $this->emitToken([ - 'name' => 'head', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - - /* Then, reprocess the current token. */ - $this->emitToken($token); - } - break; - - case self::IN_HEAD_NOSCRIPT: - if ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - // parse error - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') { - $this->processWithRulesFor($token, self::IN_BODY); - } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'noscript') { - /* Pop the current node (which will be a noscript element) from the - * stack of open elements; the new current node will be a head - * element. */ - array_pop($this->stack); - $this->mode = self::IN_HEAD; - } elseif ( - ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) || - ($token['type'] === HTML5_Tokenizer::COMMENT) || - ($token['type'] === HTML5_Tokenizer::STARTTAG && ( - $token['name'] === 'link' || $token['name'] === 'meta' || - $token['name'] === 'noframes' || $token['name'] === 'style'))) { - $this->processWithRulesFor($token, self::IN_HEAD); - // inverted logic - } elseif ( - ($token['type'] === HTML5_Tokenizer::STARTTAG && ( - $token['name'] === 'head' || $token['name'] === 'noscript')) || - ($token['type'] === HTML5_Tokenizer::ENDTAG && - $token['name'] !== 'br')) { - // parse error - } else { - // parse error - $this->emitToken([ - 'type' => HTML5_Tokenizer::ENDTAG, - 'name' => 'noscript', - ]); - $this->emitToken($token); - } - break; - - case self::AFTER_HEAD: - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - // parse error - - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') { - $this->processWithRulesFor($token, self::IN_BODY); - - /* A start tag token with the tag name "body" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'body') { - $this->insertElement($token); - - /* Set the frameset-ok flag to "not ok". */ - $this->flag_frameset_ok = false; - - /* Change the insertion mode to "in body". */ - $this->mode = self::IN_BODY; - - /* A start tag token with the tag name "frameset" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'frameset') { - /* Insert a frameset element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in frameset". */ - $this->mode = self::IN_FRAMESET; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title" */ - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'], - ['base', 'link', 'meta', 'noframes', 'script', 'style', 'title'])) { - // parse error - /* Push the node pointed to by the head element pointer onto the - * stack of open elements. */ - $this->stack[] = $this->head_pointer; - $this->processWithRulesFor($token, self::IN_HEAD); - array_splice($this->stack, array_search($this->head_pointer, $this->stack, true), 1); - - // inversion of specification - } elseif ( - ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5_Tokenizer::ENDTAG && - $token['name'] !== 'body' && $token['name'] !== 'html' && - $token['name'] !== 'br')) { - // parse error - - /* Anything else */ - } else { - $this->emitToken([ - 'name' => 'body', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => [] - ]); - $this->flag_frameset_ok = true; - $this->emitToken($token); - } - break; - - case self::IN_BODY: - /* Handle the token as follows: */ - - switch($token['type']) { - /* A character token */ - case HTML5_Tokenizer::CHARACTER: - case HTML5_Tokenizer::SPACECHARACTER: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - - /* If the token is not one of U+0009 CHARACTER TABULATION, - * U+000A LINE FEED (LF), U+000C FORM FEED (FF), or U+0020 - * SPACE, then set the frameset-ok flag to "not ok". */ - // i.e., if any of the characters is not whitespace - if (strlen($token['data']) !== strspn($token['data'], HTML5_Tokenizer::WHITESPACE)) { - $this->flag_frameset_ok = false; - } - break; - - /* A comment token */ - case HTML5_Tokenizer::COMMENT: - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - break; - - case HTML5_Tokenizer::DOCTYPE: - // parse error - break; - - case HTML5_Tokenizer::EOF: - // parse error - break; - - case HTML5_Tokenizer::STARTTAG: - switch($token['name']) { - case 'html': - // parse error - /* For each attribute on the token, check to see if the - * attribute is already present on the top element of the - * stack of open elements. If it is not, add the attribute - * and its corresponding value to that element. */ - foreach($token['attr'] as $attr) { - if (!$this->stack[0]->hasAttribute($attr['name'])) { - $this->stack[0]->setAttribute($attr['name'], $attr['value']); - } - } - break; - - case 'base': case 'command': case 'link': case 'meta': case 'noframes': - case 'script': case 'style': case 'title': - /* Process the token as if the insertion mode had been "in - head". */ - $this->processWithRulesFor($token, self::IN_HEAD); - break; - - /* A start tag token with the tag name "body" */ - case 'body': - /* Parse error. If the second element on the stack of open - elements is not a body element, or, if the stack of open - elements has only one node on it, then ignore the token. - (fragment case) */ - if (count($this->stack) === 1 || $this->stack[1]->tagName !== 'body') { - $this->ignored = true; - // Ignore - - /* Otherwise, for each attribute on the token, check to see - if the attribute is already present on the body element (the - second element) on the stack of open elements. If it is not, - add the attribute and its corresponding value to that - element. */ - } else { - foreach($token['attr'] as $attr) { - if (!$this->stack[1]->hasAttribute($attr['name'])) { - $this->stack[1]->setAttribute($attr['name'], $attr['value']); - } - } - } - break; - - case 'frameset': - // parse error - /* If the second element on the stack of open elements is - * not a body element, or, if the stack of open elements - * has only one node on it, then ignore the token. - * (fragment case) */ - if (count($this->stack) === 1 || $this->stack[1]->tagName !== 'body') { - $this->ignored = true; - // Ignore - } elseif (!$this->flag_frameset_ok) { - $this->ignored = true; - // Ignore - } else { - /* 1. Remove the second element on the stack of open - * elements from its parent node, if it has one. */ - if ($this->stack[1]->parentNode) { - $this->stack[1]->parentNode->removeChild($this->stack[1]); - } - - /* 2. Pop all the nodes from the bottom of the stack of - * open elements, from the current node up to the root - * html element. */ - array_splice($this->stack, 1); - - $this->insertElement($token); - $this->mode = self::IN_FRAMESET; - } - break; - - // in spec, there is a diversion here - - case 'address': case 'article': case 'aside': case 'blockquote': - case 'center': case 'datagrid': case 'details': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'figure': case 'footer': - case 'header': case 'hgroup': case 'menu': case 'nav': - case 'ol': case 'p': case 'section': case 'ul': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* If the current node is an element whose tag name is one - * of "h1", "h2", "h3", "h4", "h5", or "h6", then this is a - * parse error; pop the current node off the stack of open - * elements. */ - $peek = array_pop($this->stack); - if (in_array($peek->tagName, ["h1", "h2", "h3", "h4", "h5", "h6"])) { - // parse error - } else { - $this->stack[] = $peek; - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - case 'pre': case 'listing': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - $this->insertElement($token); - /* If the next token is a U+000A LINE FEED (LF) character - * token, then ignore that token and move on to the next - * one. (Newlines at the start of pre blocks are ignored as - * an authoring convenience.) */ - $this->ignore_lf_token = 2; - $this->flag_frameset_ok = false; - break; - - /* A start tag whose tag name is "form" */ - case 'form': - /* If the form element pointer is not null, ignore the - token with a parse error. */ - if ($this->form_pointer !== null) { - $this->ignored = true; - // Ignore. - - /* Otherwise: */ - } else { - /* If the stack of open elements has a p element in - scope, then act as if an end tag with the tag name p - had been seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Insert an HTML element for the token, and set the - form element pointer to point to the element created. */ - $element = $this->insertElement($token); - $this->form_pointer = $element; - } - break; - - // condensed specification - case 'li': case 'dc': case 'dd': case 'ds': case 'dt': - /* 1. Set the frameset-ok flag to "not ok". */ - $this->flag_frameset_ok = false; - - $stack_length = count($this->stack) - 1; - for($n = $stack_length; 0 <= $n; $n--) { - /* 2. Initialise node to be the current node (the - bottommost node of the stack). */ - $stop = false; - $node = $this->stack[$n]; - $cat = $this->getElementCategory($node); - - // for case 'li': - /* 3. If node is an li element, then act as if an end - * tag with the tag name "li" had been seen, then jump - * to the last step. */ - // for case 'dc': case 'dd': case 'ds': case 'dt': - /* If node is a dc, dd, ds or dt element, then act as if an end - * tag with the same tag name as node had been seen, then - * jump to the last step. */ - if (($token['name'] === 'li' && $node->tagName === 'li') || - ($token['name'] !== 'li' && ($node->tagName == 'dc' || $node->tagName === 'dd' || $node->tagName == 'ds' || $node->tagName === 'dt'))) { // limited conditional - $this->emitToken([ - 'type' => HTML5_Tokenizer::ENDTAG, - 'name' => $node->tagName, - ]); - break; - } - - /* 4. If node is not in the formatting category, and is - not in the phrasing category, and is not an address, - div or p element, then stop this algorithm. */ - if ($cat !== self::FORMATTING && $cat !== self::PHRASING && - $node->tagName !== 'address' && $node->tagName !== 'div' && - $node->tagName !== 'p') { - break; - } - - /* 5. Otherwise, set node to the previous entry in the - * stack of open elements and return to step 2. */ - } - - /* 6. This is the last step. */ - - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Finally, insert an HTML element with the same tag - name as the token's. */ - $this->insertElement($token); - break; - - /* A start tag token whose tag name is "plaintext" */ - case 'plaintext': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - $this->content_model = HTML5_Tokenizer::PLAINTEXT; - break; - - // more diversions - - /* A start tag whose tag name is "a" */ - case 'a': - /* If the list of active formatting elements contains - an element whose tag name is "a" between the end of the - list and the last marker on the list (or the start of - the list if there is no marker on the list), then this - is a parse error; act as if an end tag with the tag name - "a" had been seen, then remove that element from the list - of active formatting elements and the stack of open - elements if the end tag didn't already remove it (it - might not have if the element is not in table scope). */ - $leng = count($this->a_formatting); - - for ($n = $leng - 1; $n >= 0; $n--) { - if ($this->a_formatting[$n] === self::MARKER) { - break; - - } elseif ($this->a_formatting[$n]->tagName === 'a') { - $a = $this->a_formatting[$n]; - $this->emitToken([ - 'name' => 'a', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - if (in_array($a, $this->a_formatting)) { - $a_i = array_search($a, $this->a_formatting, true); - if ($a_i !== false) { - array_splice($this->a_formatting, $a_i, 1); - } - } - if (in_array($a, $this->stack)) { - $a_i = array_search($a, $this->stack, true); - if ($a_i !== false) { - array_splice($this->stack, $a_i, 1); - } - } - break; - } - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - case 'b': case 'big': case 'code': case 'em': case 'font': case 'i': - case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - case 'nobr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* If the stack of open elements has a nobr element in - * scope, then this is a parse error; act as if an end tag - * with the tag name "nobr" had been seen, then once again - * reconstruct the active formatting elements, if any. */ - if ($this->elementInScope('nobr')) { - $this->emitToken([ - 'name' => 'nobr', - 'type' => HTML5_Tokenizer::ENDTAG, - ]); - $this->reconstructActiveFormattingElements(); - } - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - // another diversion - - /* A start tag token whose tag name is "button" */ - case 'button': - /* If the stack of open elements has a button element in scope, - then this is a parse error; act as if an end tag with the tag - name "button" had been seen, then reprocess the token. (We don't - do that. Unnecessary.) (I hope you're right! -- ezyang) */ - if ($this->elementInScope('button')) { - $this->emitToken([ - 'name' => 'button', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - $this->flag_frameset_ok = false; - break; - - case 'applet': case 'marquee': case 'object': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - $this->flag_frameset_ok = false; - break; - - // spec diversion - - /* A start tag whose tag name is "table" */ - case 'table': - /* If the Document is not set to quirks mode, and the - * stack of open elements has a p element in scope, then - * act as if an end tag with the tag name "p" had been - * seen. */ - if ($this->quirks_mode !== self::QUIRKS_MODE && - $this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - $this->flag_frameset_ok = false; - - /* Change the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - break; - - /* A start tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'img': case 'input': case 'keygen': case 'spacer': - case 'wbr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - - $this->flag_frameset_ok = false; - break; - - case 'param': case 'source': - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - break; - - /* A start tag whose tag name is "hr" */ - case 'hr': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if ($this->elementInScope('p')) { - $this->emitToken([ - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - - $this->flag_frameset_ok = false; - break; - - /* A start tag whose tag name is "image" */ - case 'image': - /* Parse error. Change the token's tag name to "img" and - reprocess it. (Don't ask.) */ - $token['name'] = 'img'; - $this->emitToken($token); - break; - - /* A start tag whose tag name is "isindex" */ - case 'isindex': - /* Parse error. */ - - /* If the form element pointer is not null, - then ignore the token. */ - if ($this->form_pointer === null) { - /* Act as if a start tag token with the tag name "form" had - been seen. */ - /* If the token has an attribute called "action", set - * the action attribute on the resulting form - * element to the value of the "action" attribute of - * the token. */ - $attr = []; - $action = $this->getAttr($token, 'action'); - if ($action !== false) { - $attr[] = ['name' => 'action', 'value' => $action]; - } - $this->emitToken([ - 'name' => 'form', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => $attr - ]); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->emitToken([ - 'name' => 'hr', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => [] - ]); - - /* Act as if a start tag token with the tag name "label" - had been seen. */ - $this->emitToken([ - 'name' => 'label', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => [] - ]); - - /* Act as if a stream of character tokens had been seen. */ - $prompt = $this->getAttr($token, 'prompt'); - if ($prompt === false) { - $prompt = 'This is a searchable index. '. - 'Insert your search keywords here: '; - } - $this->emitToken([ - 'data' => $prompt, - 'type' => HTML5_Tokenizer::CHARACTER, - ]); - - /* Act as if a start tag token with the tag name "input" - had been seen, with all the attributes from the "isindex" - token, except with the "name" attribute set to the value - "isindex" (ignoring any explicit "name" attribute). */ - $attr = []; - foreach ($token['attr'] as $keypair) { - if ($keypair['name'] === 'name' || $keypair['name'] === 'action' || - $keypair['name'] === 'prompt') { - continue; - } - $attr[] = $keypair; - } - $attr[] = ['name' => 'name', 'value' => 'isindex']; - - $this->emitToken([ - 'name' => 'input', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => $attr - ]); - - /* Act as if an end tag token with the tag name "label" - had been seen. */ - $this->emitToken([ - 'name' => 'label', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->emitToken([ - 'name' => 'hr', - 'type' => HTML5_Tokenizer::STARTTAG - ]); - - /* Act as if an end tag token with the tag name "form" had - been seen. */ - $this->emitToken([ - 'name' => 'form', - 'type' => HTML5_Tokenizer::ENDTAG - ]); - } else { - $this->ignored = true; - } - break; - - /* A start tag whose tag name is "textarea" */ - case 'textarea': - $this->insertElement($token); - - /* If the next token is a U+000A LINE FEED (LF) - * character token, then ignore that token and move on to - * the next one. (Newlines at the start of textarea - * elements are ignored as an authoring convenience.) - * need flag, see also
 */
-                            $this->ignore_lf_token = 2;
-
-                            $this->original_mode = $this->mode;
-                            $this->flag_frameset_ok = false;
-                            $this->mode = self::IN_CDATA_RCDATA;
-
-                            /* Switch the tokeniser's content model flag to the
-                            RCDATA state. */
-                            $this->content_model = HTML5_Tokenizer::RCDATA;
-                        break;
-
-                        /* A start tag token whose tag name is "xmp" */
-                        case 'xmp':
-                            /* If the stack of open elements has a p element in
-                            scope, then act as if an end tag with the tag name
-                            "p" has been seen. */
-                            if ($this->elementInScope('p')) {
-                                $this->emitToken([
-                                    'name' => 'p',
-                                    'type' => HTML5_Tokenizer::ENDTAG
-                                ]);
-                            }
-
-                            /* Reconstruct the active formatting elements, if any. */
-                            $this->reconstructActiveFormattingElements();
-
-                            $this->flag_frameset_ok = false;
-
-                            $this->insertCDATAElement($token);
-                        break;
-
-                        case 'iframe':
-                            $this->flag_frameset_ok = false;
-                            $this->insertCDATAElement($token);
-                        break;
-
-                        case 'noembed': case 'noscript':
-                            // XSCRIPT: should check scripting flag
-                            $this->insertCDATAElement($token);
-                        break;
-
-                        /* A start tag whose tag name is "select" */
-                        case 'select':
-                            /* Reconstruct the active formatting elements, if any. */
-                            $this->reconstructActiveFormattingElements();
-
-                            /* Insert an HTML element for the token. */
-                            $this->insertElement($token);
-
-                            $this->flag_frameset_ok = false;
-
-                            /* If the insertion mode is one of in table", "in caption",
-                             * "in column group", "in table body", "in row", or "in
-                             * cell", then switch the insertion mode to "in select in
-                             * table". Otherwise, switch the insertion mode  to "in
-                             * select". */
-                            if (
-                                $this->mode === self::IN_TABLE || $this->mode === self::IN_CAPTION ||
-                                $this->mode === self::IN_COLUMN_GROUP || $this->mode ==+self::IN_TABLE_BODY ||
-                                $this->mode === self::IN_ROW || $this->mode === self::IN_CELL
-                            ) {
-                                $this->mode = self::IN_SELECT_IN_TABLE;
-                            } else {
-                                $this->mode = self::IN_SELECT;
-                            }
-                        break;
-
-                        case 'option': case 'optgroup':
-                            if ($this->elementInScope('option')) {
-                                $this->emitToken([
-                                    'name' => 'option',
-                                    'type' => HTML5_Tokenizer::ENDTAG,
-                                ]);
-                            }
-                            $this->reconstructActiveFormattingElements();
-                            $this->insertElement($token);
-                        break;
-
-                        case 'rp': case 'rt':
-                            /* If the stack of open elements has a ruby element in scope, then generate
-                             * implied end tags. If the current node is not then a ruby element, this is
-                             * a parse error; pop all the nodes from the current node up to the node
-                             * immediately before the bottommost ruby element on the stack of open elements.
-                             */
-                            if ($this->elementInScope('ruby')) {
-                                $this->generateImpliedEndTags();
-                            }
-                            $peek = false;
-                            do {
-                                /*if ($peek) {
-                                    // parse error
-                                }*/
-                                $peek = array_pop($this->stack);
-                            } while ($peek->tagName !== 'ruby');
-                            $this->stack[] = $peek; // we popped one too many
-                            $this->insertElement($token);
-                        break;
-
-                        // spec diversion
-
-                        case 'math':
-                            $this->reconstructActiveFormattingElements();
-                            $token = $this->adjustMathMLAttributes($token);
-                            $token = $this->adjustForeignAttributes($token);
-                            $this->insertForeignElement($token, self::NS_MATHML);
-                            if (isset($token['self-closing'])) {
-                                // XERROR: acknowledge the token's self-closing flag
-                                array_pop($this->stack);
-                            }
-                            if ($this->mode !== self::IN_FOREIGN_CONTENT) {
-                                $this->secondary_mode = $this->mode;
-                                $this->mode = self::IN_FOREIGN_CONTENT;
-                            }
-                        break;
-
-                        case 'svg':
-                            $this->reconstructActiveFormattingElements();
-                            $token = $this->adjustSVGAttributes($token);
-                            $token = $this->adjustForeignAttributes($token);
-                            $this->insertForeignElement($token, self::NS_SVG);
-                            if (isset($token['self-closing'])) {
-                                // XERROR: acknowledge the token's self-closing flag
-                                array_pop($this->stack);
-                            }
-                            if ($this->mode !== self::IN_FOREIGN_CONTENT) {
-                                $this->secondary_mode = $this->mode;
-                                $this->mode = self::IN_FOREIGN_CONTENT;
-                            }
-                        break;
-
-                        case 'caption': case 'col': case 'colgroup': case 'frame': case 'head':
-                        case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': case 'tr':
-                            // parse error
-                        break;
-
-                        /* A start tag token not covered by the previous entries */
-                        default:
-                            /* Reconstruct the active formatting elements, if any. */
-                            $this->reconstructActiveFormattingElements();
-
-                            $this->insertElement($token);
-                            /* This element will be a phrasing  element. */
-                        break;
-                    }
-                    break;
-
-                    case HTML5_Tokenizer::ENDTAG:
-                    switch ($token['name']) {
-                        /* An end tag with the tag name "body" */
-                        case 'body':
-                            /* If the stack of open elements does not have a body
-                             * element in scope, this is a parse error; ignore the
-                             * token. */
-                            if (!$this->elementInScope('body')) {
-                                $this->ignored = true;
-
-                            /* Otherwise, if there is a node in the stack of open
-                             * elements that is not either a dc element, a dd element,
-                             * a ds element, a dt element, an li element, an optgroup
-                             * element, an option element, a p element, an rp element,
-                             * an rt element, a tbody element, a td element, a tfoot
-                             * element, a th element, a thead element, a tr element,
-                             * the body element, or the html element, then this is a
-                             * parse error.
-                             */
-                            } else {
-                                // XERROR: implement this check for parse error
-                            }
-
-                            /* Change the insertion mode to "after body". */
-                            $this->mode = self::AFTER_BODY;
-                        break;
-
-                        /* An end tag with the tag name "html" */
-                        case 'html':
-                            /* Act as if an end tag with tag name "body" had been seen,
-                            then, if that token wasn't ignored, reprocess the current
-                            token. */
-                            $this->emitToken([
-                                'name' => 'body',
-                                'type' => HTML5_Tokenizer::ENDTAG
-                            ]);
-
-                            if (!$this->ignored) {
-                                $this->emitToken($token);
-                            }
-                        break;
-
-                        case 'address': case 'article': case 'aside': case 'blockquote':
-                        case 'center': case 'datagrid': case 'details': case 'dir':
-                        case 'div': case 'dl': case 'fieldset': case 'footer':
-                        case 'header': case 'hgroup': case 'listing': case 'menu':
-                        case 'nav': case 'ol': case 'pre': case 'section': case 'ul':
-                            /* If the stack of open elements has an element in scope
-                            with the same tag name as that of the token, then generate
-                            implied end tags. */
-                            if ($this->elementInScope($token['name'])) {
-                                $this->generateImpliedEndTags();
-
-                                /* Now, if the current node is not an element with
-                                the same tag name as that of the token, then this
-                                is a parse error. */
-                                // XERROR: implement parse error logic
-
-                                /* If the stack of open elements has an element in
-                                scope with the same tag name as that of the token,
-                                then pop elements from this stack until an element
-                                with that tag name has been popped from the stack. */
-                                do {
-                                    $node = array_pop($this->stack);
-                                } while ($node->tagName !== $token['name']);
-                            } else {
-                                // parse error
-                            }
-                        break;
-
-                        /* An end tag whose tag name is "form" */
-                        case 'form':
-                            /* Let node be the element that the form element pointer is set to. */
-                            $node = $this->form_pointer;
-                            /* Set the form element pointer  to null. */
-                            $this->form_pointer = null;
-                            /* If node is null or the stack of open elements does not
-                                * have node in scope, then this is a parse error; ignore the token. */
-                            if ($node === null || !in_array($node, $this->stack)) {
-                                // parse error
-                                $this->ignored = true;
-                            } else {
-                                /* 1. Generate implied end tags. */
-                                $this->generateImpliedEndTags();
-                                /* 2. If the current node is not node, then this is a parse error.  */
-                                if (end($this->stack) !== $node) {
-                                    // parse error
-                                }
-                                /* 3. Remove node from the stack of open elements. */
-                                array_splice($this->stack, array_search($node, $this->stack, true), 1);
-                            }
-
-                        break;
-
-                        /* An end tag whose tag name is "p" */
-                        case 'p':
-                            /* If the stack of open elements has a p element in scope,
-                            then generate implied end tags, except for p elements. */
-                            if ($this->elementInScope('p')) {
-                                /* Generate implied end tags, except for elements with
-                                 * the same tag name as the token. */
-                                $this->generateImpliedEndTags(['p']);
-
-                                /* If the current node is not a p element, then this is
-                                a parse error. */
-                                // XERROR: implement
-
-                                /* Pop elements from the stack of open elements  until
-                                 * an element with the same tag name as the token has
-                                 * been popped from the stack. */
-                                do {
-                                    $node = array_pop($this->stack);
-                                } while ($node->tagName !== 'p');
-
-                            } else {
-                                // parse error
-                                $this->emitToken([
-                                    'name' => 'p',
-                                    'type' => HTML5_Tokenizer::STARTTAG,
-                                ]);
-                                $this->emitToken($token);
-                            }
-                        break;
-
-                        /* An end tag whose tag name is "li" */
-                        case 'li':
-                            /* If the stack of open elements does not have an element
-                             * in list item scope with the same tag name as that of the
-                             * token, then this is a parse error; ignore the token. */
-                            if ($this->elementInScope($token['name'], self::SCOPE_LISTITEM)) {
-                                /* Generate implied end tags, except for elements with the
-                                 * same tag name as the token. */
-                                $this->generateImpliedEndTags([$token['name']]);
-                                /* If the current node is not an element with the same tag
-                                 * name as that of the token, then this is a parse error. */
-                                // XERROR: parse error
-                                /* Pop elements from the stack of open elements  until an
-                                 * element with the same tag name as the token has been
-                                 * popped from the stack. */
-                                do {
-                                    $node = array_pop($this->stack);
-                                } while ($node->tagName !== $token['name']);
-                            }
-                            /*else {
-                                // XERROR: parse error
-                            }*/
-                        break;
-
-                        /* An end tag whose tag name is "dc", "dd", "ds", "dt" */
-                        case 'dc': case 'dd': case 'ds': case 'dt':
-                            if ($this->elementInScope($token['name'])) {
-                                $this->generateImpliedEndTags([$token['name']]);
-
-                                /* If the current node is not an element with the same
-                                tag name as the token, then this is a parse error. */
-                                // XERROR: implement parse error
-
-                                /* Pop elements from the stack of open elements  until
-                                 * an element with the same tag name as the token has
-                                 * been popped from the stack. */
-                                do {
-                                    $node = array_pop($this->stack);
-                                } while ($node->tagName !== $token['name']);
-                            }
-                            /*else {
-                                // XERROR: parse error
-                            }*/
-                        break;
-
-                        /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
-                        "h5", "h6" */
-                        case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
-                            $elements = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
-
-                            /* If the stack of open elements has in scope an element whose
-                            tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
-                            generate implied end tags. */
-                            if ($this->elementInScope($elements)) {
-                                $this->generateImpliedEndTags();
-
-                                /* Now, if the current node is not an element with the same
-                                tag name as that of the token, then this is a parse error. */
-                                // XERROR: implement parse error
-
-                                /* If the stack of open elements has in scope an element
-                                whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
-                                "h6", then pop elements from the stack until an element
-                                with one of those tag names has been popped from the stack. */
-                                do {
-                                    $node = array_pop($this->stack);
-                                } while (!in_array($node->tagName, $elements));
-                            }
-                            /*else {
-                                // parse error
-                            }*/
-                        break;
-
-                        /* An end tag whose tag name is one of: "a", "b", "big", "em",
-                        "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
-                        case 'a': case 'b': case 'big': case 'code': case 'em': case 'font':
-                        case 'i': case 'nobr': case 's': case 'small': case 'strike':
-                        case 'strong': case 'tt': case 'u':
-                            // XERROR: generally speaking this needs parse error logic
-                            /* 1. Let the formatting element be the last element in
-                            the list of active formatting elements that:
-                                * is between the end of the list and the last scope
-                                marker in the list, if any, or the start of the list
-                                otherwise, and
-                                * has the same tag name as the token.
-                            */
-                            while (true) {
-                                for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
-                                    if ($this->a_formatting[$a] === self::MARKER) {
-                                        break;
-                                    } elseif ($this->a_formatting[$a]->tagName === $token['name']) {
-                                        $formatting_element = $this->a_formatting[$a];
-                                        $in_stack = in_array($formatting_element, $this->stack, true);
-                                        $fe_af_pos = $a;
-                                        break;
-                                    }
-                                }
-
-                                /* If there is no such node, or, if that node is
-                                also in the stack of open elements but the element
-                                is not in scope, then this is a parse error. Abort
-                                these steps. The token is ignored. */
-                                if (
-                                    !isset($formatting_element) || (
-                                        $in_stack &&
-                                        !$this->elementInScope($token['name'])
-                                    )
-                                ) {
-                                    $this->ignored = true;
-                                    break;
-
-                                /* Otherwise, if there is such a node, but that node
-                                is not in the stack of open elements, then this is a
-                                parse error; remove the element from the list, and
-                                abort these steps. */
-                                } elseif (isset($formatting_element) && !$in_stack) {
-                                    unset($this->a_formatting[$fe_af_pos]);
-                                    $this->a_formatting = array_merge($this->a_formatting);
-                                    break;
-                                }
-
-                                /* Otherwise, there is a formatting element and that
-                                 * element is in the stack and is in scope. If the
-                                 * element is not the current node, this is a parse
-                                 * error. In any case, proceed with the algorithm as
-                                 * written in the following steps. */
-                                // XERROR: implement me
-
-                                /* 2. Let the furthest block be the topmost node in the
-                                stack of open elements that is lower in the stack
-                                than the formatting element, and is not an element in
-                                the phrasing or formatting categories. There might
-                                not be one. */
-                                $fe_s_pos = array_search($formatting_element, $this->stack, true);
-                                $length = count($this->stack);
-
-                                for ($s = $fe_s_pos + 1; $s < $length; $s++) {
-                                    $category = $this->getElementCategory($this->stack[$s]);
-
-                                    if ($category !== self::PHRASING && $category !== self::FORMATTING) {
-                                        $furthest_block = $this->stack[$s];
-                                        break;
-                                    }
-                                }
-
-                                /* 3. If there is no furthest block, then the UA must
-                                skip the subsequent steps and instead just pop all
-                                the nodes from the bottom of the stack of open
-                                elements, from the current node up to the formatting
-                                element, and remove the formatting element from the
-                                list of active formatting elements. */
-                                if (!isset($furthest_block)) {
-                                    for ($n = $length - 1; $n >= $fe_s_pos; $n--) {
-                                        array_pop($this->stack);
-                                    }
-
-                                    unset($this->a_formatting[$fe_af_pos]);
-                                    $this->a_formatting = array_merge($this->a_formatting);
-                                    break;
-                                }
-
-                                /* 4. Let the common ancestor be the element
-                                immediately above the formatting element in the stack
-                                of open elements. */
-                                $common_ancestor = $this->stack[$fe_s_pos - 1];
-
-                                /* 5. Let a bookmark note the position of the
-                                formatting element in the list of active formatting
-                                elements relative to the elements on either side
-                                of it in the list. */
-                                $bookmark = $fe_af_pos;
-
-                                /* 6. Let node and last node  be the furthest block.
-                                Follow these steps: */
-                                $node = $furthest_block;
-                                $last_node = $furthest_block;
-
-                                while (true) {
-                                    for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
-                                        /* 6.1 Let node be the element immediately
-                                        prior to node in the stack of open elements. */
-                                        $node = $this->stack[$n];
-
-                                        /* 6.2 If node is not in the list of active
-                                        formatting elements, then remove node from
-                                        the stack of open elements and then go back
-                                        to step 1. */
-                                        if (!in_array($node, $this->a_formatting, true)) {
-                                            array_splice($this->stack, $n, 1);
-                                        } else {
-                                            break;
-                                        }
-                                    }
-
-                                    /* 6.3 Otherwise, if node is the formatting
-                                    element, then go to the next step in the overall
-                                    algorithm. */
-                                    if ($node === $formatting_element) {
-                                        break;
-
-                                    /* 6.4 Otherwise, if last node is the furthest
-                                    block, then move the aforementioned bookmark to
-                                    be immediately after the node in the list of
-                                    active formatting elements. */
-                                    } elseif ($last_node === $furthest_block) {
-                                        $bookmark = array_search($node, $this->a_formatting, true) + 1;
-                                    }
-
-                                    /* 6.5 Create an element for the token for which
-                                     * the element node was created, replace the entry
-                                     * for node in the list of active formatting
-                                     * elements with an entry for the new element,
-                                     * replace the entry for node in the stack of open
-                                     * elements with an entry for the new element, and
-                                     * let node be the new element. */
-                                    // we don't know what the token is anymore
-                                    // XDOM
-                                    $clone = $node->cloneNode();
-                                    $a_pos = array_search($node, $this->a_formatting, true);
-                                    $s_pos = array_search($node, $this->stack, true);
-                                    $this->a_formatting[$a_pos] = $clone;
-                                    $this->stack[$s_pos] = $clone;
-                                    $node = $clone;
-
-                                    /* 6.6 Insert last node into node, first removing
-                                    it from its previous parent node if any. */
-                                    // XDOM
-                                    if ($last_node->parentNode !== null) {
-                                        $last_node->parentNode->removeChild($last_node);
-                                    }
-
-                                    // XDOM
-                                    $node->appendChild($last_node);
-
-                                    /* 6.7 Let last node be node. */
-                                    $last_node = $node;
-
-                                    /* 6.8 Return to step 1 of this inner set of steps. */
-                                }
-
-                                /* 7. If the common ancestor node is a table, tbody,
-                                 * tfoot, thead, or tr element, then, foster parent
-                                 * whatever last node ended up being in the previous
-                                 * step, first removing it from its previous parent
-                                 * node if any. */
-                                // XDOM
-                                if ($last_node->parentNode) { // common step
-                                    $last_node->parentNode->removeChild($last_node);
-                                }
-                                if (in_array($common_ancestor->tagName, ['table', 'tbody', 'tfoot', 'thead', 'tr'])) {
-                                    $this->fosterParent($last_node);
-                                /* Otherwise, append whatever last node  ended up being
-                                 * in the previous step to the common ancestor node,
-                                 * first removing it from its previous parent node if
-                                 * any. */
-                                } else {
-                                    // XDOM
-                                    $common_ancestor->appendChild($last_node);
-                                }
-
-                                /* 8. Create an element for the token for which the
-                                 * formatting element was created. */
-                                // XDOM
-                                $clone = $formatting_element->cloneNode();
-
-                                /* 9. Take all of the child nodes of the furthest
-                                block and append them to the element created in the
-                                last step. */
-                                // XDOM
-                                while ($furthest_block->hasChildNodes()) {
-                                    $child = $furthest_block->firstChild;
-                                    $furthest_block->removeChild($child);
-                                    $clone->appendChild($child);
-                                }
-
-                                /* 10. Append that clone to the furthest block. */
-                                // XDOM
-                                $furthest_block->appendChild($clone);
-
-                                /* 11. Remove the formatting element from the list
-                                of active formatting elements, and insert the new element
-                                into the list of active formatting elements at the
-                                position of the aforementioned bookmark. */
-                                $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
-                                array_splice($this->a_formatting, $fe_af_pos, 1);
-
-                                $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
-                                $af_part2 = array_slice($this->a_formatting, $bookmark);
-                                $this->a_formatting = array_merge($af_part1, [$clone], $af_part2);
-
-                                /* 12. Remove the formatting element from the stack
-                                of open elements, and insert the new element into the stack
-                                of open elements immediately below the position of the
-                                furthest block in that stack. */
-                                $fe_s_pos = array_search($formatting_element, $this->stack, true);
-                                array_splice($this->stack, $fe_s_pos, 1);
-
-                                $fb_s_pos = array_search($furthest_block, $this->stack, true);
-                                $s_part1 = array_slice($this->stack, 0, $fb_s_pos + 1);
-                                $s_part2 = array_slice($this->stack, $fb_s_pos + 1);
-                                $this->stack = array_merge($s_part1, [$clone], $s_part2);
-
-                                /* 13. Jump back to step 1 in this series of steps. */
-                                unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
-                            }
-                        break;
-
-                        case 'applet': case 'button': case 'marquee': case 'object':
-                            /* If the stack of open elements has an element in scope whose
-                            tag name matches the tag name of the token, then generate implied
-                            tags. */
-                            if ($this->elementInScope($token['name'])) {
-                                $this->generateImpliedEndTags();
-
-                                /* Now, if the current node is not an element with the same
-                                tag name as the token, then this is a parse error. */
-                                // XERROR: implement logic
-
-                                /* Pop elements from the stack of open elements  until
-                                 * an element with the same tag name as the token has
-                                 * been popped from the stack. */
-                                do {
-                                    $node = array_pop($this->stack);
-                                } while ($node->tagName !== $token['name']);
-
-                                /* Clear the list of active formatting elements up to the
-                                 * last marker. */
-                                $keys = array_keys($this->a_formatting, self::MARKER, true);
-                                $marker = end($keys);
-
-                                for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
-                                    array_pop($this->a_formatting);
-                                }
-                            }
-                            /*else {
-                                // parse error
-                            }*/
-                        break;
-
-                        case 'br':
-                            // Parse error
-                            $this->emitToken([
-                                'name' => 'br',
-                                'type' => HTML5_Tokenizer::STARTTAG,
-                            ]);
-                        break;
-
-                        /* An end tag token not covered by the previous entries */
-                        default:
-                            for ($n = count($this->stack) - 1; $n >= 0; $n--) {
-                                /* Initialise node to be the current node (the bottommost
-                                node of the stack). */
-                                $node = $this->stack[$n];
-
-                                /* If node has the same tag name as the end tag token,
-                                then: */
-                                if ($token['name'] === $node->tagName) {
-                                    /* Generate implied end tags. */
-                                    $this->generateImpliedEndTags();
-
-                                    /* If the tag name of the end tag token does not
-                                    match the tag name of the current node, this is a
-                                    parse error. */
-                                    // XERROR: implement this
-
-                                    /* Pop all the nodes from the current node up to
-                                    node, including node, then stop these steps. */
-                                    // XSKETCHY
-                                    do {
-                                        $pop = array_pop($this->stack);
-                                    } while ($pop !== $node);
-                                    break;
-                                } else {
-                                    $category = $this->getElementCategory($node);
-
-                                    if ($category !== self::FORMATTING && $category !== self::PHRASING) {
-                                        /* Otherwise, if node is in neither the formatting
-                                        category nor the phrasing category, then this is a
-                                        parse error. Stop this algorithm. The end tag token
-                                        is ignored. */
-                                        $this->ignored = true;
-                                        break;
-                                        // parse error
-                                    }
-                                }
-                                /* Set node to the previous entry in the stack of open elements. Loop. */
-                            }
-                        break;
-                    }
-                    break;
-                }
-                break;
-
-            case self::IN_CDATA_RCDATA:
-                if (
-                    $token['type'] === HTML5_Tokenizer::CHARACTER ||
-                    $token['type'] === HTML5_Tokenizer::SPACECHARACTER
-                ) {
-                    $this->insertText($token['data']);
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    // parse error
-                    /* If the current node is a script  element, mark the script
-                     * element as "already executed". */
-                    // probably not necessary
-                    array_pop($this->stack);
-                    $this->mode = $this->original_mode;
-                    $this->emitToken($token);
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'script') {
-                    array_pop($this->stack);
-                    $this->mode = $this->original_mode;
-                    // we're ignoring all of the execution stuff
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG) {
-                    array_pop($this->stack);
-                    $this->mode = $this->original_mode;
-                }
-            break;
-
-            case self::IN_TABLE:
-                $clear = ['html', 'table'];
-
-                /* A character token */
-                if ($token['type'] === HTML5_Tokenizer::CHARACTER ||
-                    $token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    /* Let the pending table character tokens
-                     * be an empty list of tokens. */
-                    $this->pendingTableCharacters = "";
-                    $this->pendingTableCharactersDirty = false;
-                    /* Let the original insertion mode be the current
-                     * insertion mode. */
-                    $this->original_mode = $this->mode;
-                    /* Switch the insertion mode to
-                     * "in table text" and
-                     * reprocess the token. */
-                    $this->mode = self::IN_TABLE_TEXT;
-                    $this->emitToken($token);
-
-                /* A comment token */
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the current node with the data
-                    attribute set to the data given in the comment token. */
-                    $this->insertComment($token['data']);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // parse error
-
-                /* A start tag whose tag name is "caption" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'caption') {
-                    /* Clear the stack back to a table context. */
-                    $this->clearStackToTableContext($clear);
-
-                    /* Insert a marker at the end of the list of active
-                    formatting elements. */
-                    $this->a_formatting[] = self::MARKER;
-
-                    /* Insert an HTML element for the token, then switch the
-                    insertion mode to "in caption". */
-                    $this->insertElement($token);
-                    $this->mode = self::IN_CAPTION;
-
-                /* A start tag whose tag name is "colgroup" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'colgroup') {
-                    /* Clear the stack back to a table context. */
-                    $this->clearStackToTableContext($clear);
-
-                    /* Insert an HTML element for the token, then switch the
-                    insertion mode to "in column group". */
-                    $this->insertElement($token);
-                    $this->mode = self::IN_COLUMN_GROUP;
-
-                /* A start tag whose tag name is "col" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'col') {
-                    $this->emitToken([
-                        'name' => 'colgroup',
-                        'type' => HTML5_Tokenizer::STARTTAG,
-                        'attr' => []
-                    ]);
-
-                    $this->emitToken($token);
-
-                /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-                ['tbody', 'tfoot', 'thead'])) {
-                    /* Clear the stack back to a table context. */
-                    $this->clearStackToTableContext($clear);
-
-                    /* Insert an HTML element for the token, then switch the insertion
-                    mode to "in table body". */
-                    $this->insertElement($token);
-                    $this->mode = self::IN_TABLE_BODY;
-
-                /* A start tag whose tag name is one of: "td", "th", "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                in_array($token['name'], ['td', 'th', 'tr'])) {
-                    /* Act as if a start tag token with the tag name "tbody" had been
-                    seen, then reprocess the current token. */
-                    $this->emitToken([
-                        'name' => 'tbody',
-                        'type' => HTML5_Tokenizer::STARTTAG,
-                        'attr' => []
-                    ]);
-
-                    $this->emitToken($token);
-
-                /* A start tag whose tag name is "table" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'table') {
-                    /* Parse error. Act as if an end tag token with the tag name "table"
-                    had been seen, then, if that token wasn't ignored, reprocess the
-                    current token. */
-                    $this->emitToken([
-                        'name' => 'table',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ]);
-
-                    if (!$this->ignored) {
-                        $this->emitToken($token);
-                    }
-
-                /* An end tag whose tag name is "table" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'table') {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as the token, this is a parse error.
-                    Ignore the token. (fragment case) */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        $this->ignored = true;
-                    } else {
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== 'table');
-
-                        /* Reset the insertion mode appropriately. */
-                        $this->resetInsertionMode();
-                    }
-
-                /* An end tag whose tag name is one of: "body", "caption", "col",
-                "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-                ['body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td',
-                'tfoot', 'th', 'thead', 'tr'])) {
-                    // Parse error. Ignore the token.
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                ($token['name'] === 'style' || $token['name'] === 'script')) {
-                    $this->processWithRulesFor($token, self::IN_HEAD);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'input' &&
-                // assignment is intentional
-                /* If the token does not have an attribute with the name "type", or
-                 * if it does, but that attribute's value is not an ASCII
-                 * case-insensitive match for the string "hidden", then: act as
-                 * described in the "anything else" entry below. */
-                ($type = $this->getAttr($token, 'type')) && strtolower($type) === 'hidden') {
-                    // I.e., if its an input with the type attribute == 'hidden'
-                    /* Otherwise */
-                    // parse error
-                    $this->insertElement($token);
-                    array_pop($this->stack);
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    /* If the current node is not the root html element, then this is a parse error. */
-                    if (end($this->stack)->tagName !== 'html') {
-                        // Note: It can only be the current node in the fragment case.
-                        // parse error
-                    }
-                    /* Stop parsing. */
-                /* Anything else */
-                } else {
-                    /* Parse error. Process the token as if the insertion mode was "in
-                    body", with the following exception: */
-
-                    $old = $this->foster_parent;
-                    $this->foster_parent = true;
-                    $this->processWithRulesFor($token, self::IN_BODY);
-                    $this->foster_parent = $old;
-                }
-            break;
-
-            case self::IN_TABLE_TEXT:
-                /* A character token */
-                if ($token['type'] === HTML5_Tokenizer::CHARACTER) {
-                    /* Append the character token to the pending table
-                     * character tokens list. */
-                    $this->pendingTableCharacters .= $token['data'];
-                    $this->pendingTableCharactersDirty = true;
-                } elseif ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    $this->pendingTableCharacters .= $token['data'];
-                /* Anything else */
-                } else {
-                    if ($this->pendingTableCharacters !== '' && is_string($this->pendingTableCharacters)) {
-                        /* If any of the tokens in the pending table character tokens list
-                         * are character tokens that are not one of U+0009 CHARACTER
-                         * TABULATION, U+000A LINE FEED (LF), U+000C FORM FEED (FF), or
-                         * U+0020 SPACE, then reprocess those character tokens using the
-                         * rules given in the "anything else" entry in the in table"
-                         * insertion mode.*/
-                        if ($this->pendingTableCharactersDirty) {
-                            /* Parse error. Process the token using the rules for the
-                             * "in body" insertion mode, except that if the current
-                             * node is a table, tbody, tfoot, thead, or tr element,
-                             * then, whenever a node would be inserted into the current
-                             * node, it must instead be foster parented. */
-                            // XERROR
-                            $old = $this->foster_parent;
-                            $this->foster_parent = true;
-                            $text_token = [
-                                'type' => HTML5_Tokenizer::CHARACTER,
-                                'data' => $this->pendingTableCharacters,
-                            ];
-                            $this->processWithRulesFor($text_token, self::IN_BODY);
-                            $this->foster_parent = $old;
-
-                        /* Otherwise, insert the characters given by the pending table
-                         * character tokens list into the current node. */
-                        } else {
-                            $this->insertText($this->pendingTableCharacters);
-                        }
-                        $this->pendingTableCharacters = null;
-                        $this->pendingTableCharactersNull = null;
-                    }
-
-                    /* Switch the insertion mode to the original insertion mode and
-                     * reprocess the token.
-                     */
-                    $this->mode = $this->original_mode;
-                    $this->emitToken($token);
-                }
-            break;
-
-            case self::IN_CAPTION:
-                /* An end tag whose tag name is "caption" */
-                if ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'caption') {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as the token, this is a parse error.
-                    Ignore the token. (fragment case) */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        $this->ignored = true;
-                        // Ignore
-
-                    /* Otherwise: */
-                    } else {
-                        /* Generate implied end tags. */
-                        $this->generateImpliedEndTags();
-
-                        /* Now, if the current node is not a caption element, then this
-                        is a parse error. */
-                        // XERROR: implement
-
-                        /* Pop elements from this stack until a caption element has
-                        been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== 'caption');
-
-                        /* Clear the list of active formatting elements up to the last
-                        marker. */
-                        $this->clearTheActiveFormattingElementsUpToTheLastMarker();
-
-                        /* Switch the insertion mode to "in table". */
-                        $this->mode = self::IN_TABLE;
-                    }
-
-                /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-                "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
-                name is "table" */
-                } elseif (($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-                ['caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
-                'thead', 'tr'])) || ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'table')) {
-                    /* Parse error. Act as if an end tag with the tag name "caption"
-                    had been seen, then, if that token wasn't ignored, reprocess the
-                    current token. */
-                    $this->emitToken([
-                        'name' => 'caption',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ]);
-
-                    if (!$this->ignored) {
-                        $this->emitToken($token);
-                    }
-
-                /* An end tag whose tag name is one of: "body", "col", "colgroup",
-                "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-                ['body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th',
-                'thead', 'tr'])) {
-                    // Parse error. Ignore the token.
-                    $this->ignored = true;
-                } else {
-                    /* Process the token as if the insertion mode was "in body". */
-                    $this->processWithRulesFor($token, self::IN_BODY);
-                }
-            break;
-
-            case self::IN_COLUMN_GROUP:
-                /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-                U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-                or U+0020 SPACE */
-                if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    /* Append the character to the current node. */
-                    $this->insertText($token['data']);
-
-                /* A comment token */
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the current node with the data
-                    attribute set to the data given in the comment token. */
-                    $this->insertComment($token['data']);
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // parse error
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* A start tag whose tag name is "col" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'col') {
-                    /* Insert a col element for the token. Immediately pop the current
-                    node off the stack of open elements. */
-                    $this->insertElement($token);
-                    array_pop($this->stack);
-                    // XERROR: Acknowledge the token's self-closing flag, if it is set.
-
-                /* An end tag whose tag name is "colgroup" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'colgroup') {
-                    /* If the current node is the root html element, then this is a
-                    parse error, ignore the token. (fragment case) */
-                    if (end($this->stack)->tagName === 'html') {
-                        $this->ignored = true;
-
-                    /* Otherwise, pop the current node (which will be a colgroup
-                    element) from the stack of open elements. Switch the insertion
-                    mode to "in table". */
-                    } else {
-                        array_pop($this->stack);
-                        $this->mode = self::IN_TABLE;
-                    }
-
-                /* An end tag whose tag name is "col" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'col') {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-
-                /* An end-of-file token */
-                /* If the current node is the root html  element */
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF && end($this->stack)->tagName === 'html') {
-                    /* Stop parsing */
-
-                /* Anything else */
-                } else {
-                    /* Act as if an end tag with the tag name "colgroup" had been seen,
-                    and then, if that token wasn't ignored, reprocess the current token. */
-                    $this->emitToken([
-                        'name' => 'colgroup',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ]);
-
-                    if (!$this->ignored) {
-                        $this->emitToken($token);
-                    }
-                }
-            break;
-
-            case self::IN_TABLE_BODY:
-                $clear = ['tbody', 'tfoot', 'thead', 'html'];
-
-                /* A start tag whose tag name is "tr" */
-                if ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'tr') {
-                    /* Clear the stack back to a table body context. */
-                    $this->clearStackToTableContext($clear);
-
-                    /* Insert a tr element for the token, then switch the insertion
-                    mode to "in row". */
-                    $this->insertElement($token);
-                    $this->mode = self::IN_ROW;
-
-                /* A start tag whose tag name is one of: "th", "td" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                ($token['name'] === 'th' ||    $token['name'] === 'td')) {
-                    /* Parse error. Act as if a start tag with the tag name "tr" had
-                    been seen, then reprocess the current token. */
-                    $this->emitToken([
-                        'name' => 'tr',
-                        'type' => HTML5_Tokenizer::STARTTAG,
-                        'attr' => []
-                    ]);
-
-                    $this->emitToken($token);
-
-                /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                in_array($token['name'], ['tbody', 'tfoot', 'thead'])) {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as the token, this is a parse error.
-                    Ignore the token. */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        // Parse error
-                        $this->ignored = true;
-
-                    /* Otherwise: */
-                    } else {
-                        /* Clear the stack back to a table body context. */
-                        $this->clearStackToTableContext($clear);
-
-                        /* Pop the current node from the stack of open elements. Switch
-                        the insertion mode to "in table". */
-                        array_pop($this->stack);
-                        $this->mode = self::IN_TABLE;
-                    }
-
-                /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-                "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
-                } elseif (($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-                ['caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead'])) ||
-                ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'table')) {
-                    /* If the stack of open elements does not have a tbody, thead, or
-                    tfoot element in table scope, this is a parse error. Ignore the
-                    token. (fragment case) */
-                    if (!$this->elementInScope(['tbody', 'thead', 'tfoot'], self::SCOPE_TABLE)) {
-                        // parse error
-                        $this->ignored = true;
-
-                    /* Otherwise: */
-                    } else {
-                        /* Clear the stack back to a table body context. */
-                        $this->clearStackToTableContext($clear);
-
-                        /* Act as if an end tag with the same tag name as the current
-                        node ("tbody", "tfoot", or "thead") had been seen, then
-                        reprocess the current token. */
-                        $this->emitToken([
-                            'name' => end($this->stack)->tagName,
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-
-                        $this->emitToken($token);
-                    }
-
-                /* An end tag whose tag name is one of: "body", "caption", "col",
-                "colgroup", "html", "td", "th", "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-                ['body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'])) {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-
-                /* Anything else */
-                } else {
-                    /* Process the token as if the insertion mode was "in table". */
-                    $this->processWithRulesFor($token, self::IN_TABLE);
-                }
-            break;
-
-            case self::IN_ROW:
-                $clear = ['tr', 'html'];
-
-                /* A start tag whose tag name is one of: "th", "td" */
-                if ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                ($token['name'] === 'th' || $token['name'] === 'td')) {
-                    /* Clear the stack back to a table row context. */
-                    $this->clearStackToTableContext($clear);
-
-                    /* Insert an HTML element for the token, then switch the insertion
-                    mode to "in cell". */
-                    $this->insertElement($token);
-                    $this->mode = self::IN_CELL;
-
-                    /* Insert a marker at the end of the list of active formatting
-                    elements. */
-                    $this->a_formatting[] = self::MARKER;
-
-                /* An end tag whose tag name is "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'tr') {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as the token, this is a parse error.
-                    Ignore the token. (fragment case) */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        // Ignore.
-                        $this->ignored = true;
-                    } else {
-                        /* Clear the stack back to a table row context. */
-                        $this->clearStackToTableContext($clear);
-
-                        /* Pop the current node (which will be a tr element) from the
-                        stack of open elements. Switch the insertion mode to "in table
-                        body". */
-                        array_pop($this->stack);
-                        $this->mode = self::IN_TABLE_BODY;
-                    }
-
-                /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-                "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
-                } elseif (($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-                ['caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'])) ||
-                ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'table')) {
-                    /* Act as if an end tag with the tag name "tr" had been seen, then,
-                    if that token wasn't ignored, reprocess the current token. */
-                    $this->emitToken([
-                        'name' => 'tr',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ]);
-                    if (!$this->ignored) {
-                        $this->emitToken($token);
-                    }
-
-                /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                in_array($token['name'], ['tbody', 'tfoot', 'thead'])) {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as the token, this is a parse error.
-                    Ignore the token. */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        $this->ignored = true;
-
-                    /* Otherwise: */
-                    } else {
-                        /* Otherwise, act as if an end tag with the tag name "tr" had
-                        been seen, then reprocess the current token. */
-                        $this->emitToken([
-                            'name' => 'tr',
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-
-                        $this->emitToken($token);
-                    }
-
-                /* An end tag whose tag name is one of: "body", "caption", "col",
-                "colgroup", "html", "td", "th" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-                ['body', 'caption', 'col', 'colgroup', 'html', 'td', 'th'])) {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-
-                /* Anything else */
-                } else {
-                    /* Process the token as if the insertion mode was "in table". */
-                    $this->processWithRulesFor($token, self::IN_TABLE);
-                }
-            break;
-
-            case self::IN_CELL:
-                /* An end tag whose tag name is one of: "td", "th" */
-                if ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                ($token['name'] === 'td' || $token['name'] === 'th')) {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as that of the token, then this is a
-                    parse error and the token must be ignored. */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        $this->ignored = true;
-
-                    /* Otherwise: */
-                    } else {
-                        /* Generate implied end tags, except for elements with the same
-                        tag name as the token. */
-                        $this->generateImpliedEndTags([$token['name']]);
-
-                        /* Now, if the current node is not an element with the same tag
-                        name as the token, then this is a parse error. */
-                        // XERROR: Implement parse error code
-
-                        /* Pop elements from this stack until an element with the same
-                        tag name as the token has been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== $token['name']);
-
-                        /* Clear the list of active formatting elements up to the last
-                        marker. */
-                        $this->clearTheActiveFormattingElementsUpToTheLastMarker();
-
-                        /* Switch the insertion mode to "in row". (The current node
-                        will be a tr element at this point.) */
-                        $this->mode = self::IN_ROW;
-                    }
-
-                /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-                "tbody", "td", "tfoot", "th", "thead", "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-                ['caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
-                'thead', 'tr'])) {
-                    /* If the stack of open elements does not have a td or th element
-                    in table scope, then this is a parse error; ignore the token.
-                    (fragment case) */
-                    if (!$this->elementInScope(['td', 'th'], self::SCOPE_TABLE)) {
-                        // parse error
-                        $this->ignored = true;
-
-                    /* Otherwise, close the cell (see below) and reprocess the current
-                    token. */
-                    } else {
-                        $this->closeCell();
-                        $this->emitToken($token);
-                    }
-
-                /* An end tag whose tag name is one of: "body", "caption", "col",
-                "colgroup", "html" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-                ['body', 'caption', 'col', 'colgroup', 'html'])) {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-
-                /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
-                "thead", "tr" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-                ['table', 'tbody', 'tfoot', 'thead', 'tr'])) {
-                    /* If the stack of open elements does not have a td or th element
-                    in table scope, then this is a parse error; ignore the token.
-                    (innerHTML case) */
-                    if (!$this->elementInScope(['td', 'th'], self::SCOPE_TABLE)) {
-                        // Parse error
-                        $this->ignored = true;
-
-                    /* Otherwise, close the cell (see below) and reprocess the current
-                    token. */
-                    } else {
-                        $this->closeCell();
-                        $this->emitToken($token);
-                    }
-
-                /* Anything else */
-                } else {
-                    /* Process the token as if the insertion mode was "in body". */
-                    $this->processWithRulesFor($token, self::IN_BODY);
-                }
-            break;
-
-            case self::IN_SELECT:
-                /* Handle the token as follows: */
-
-                /* A character token */
-                if (
-                    $token['type'] === HTML5_Tokenizer::CHARACTER ||
-                    $token['type'] === HTML5_Tokenizer::SPACECHARACTER
-                ) {
-                    /* Append the token's character to the current node. */
-                    $this->insertText($token['data']);
-
-                /* A comment token */
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the current node with the data
-                    attribute set to the data given in the comment token. */
-                    $this->insertComment($token['data']);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // parse error
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* A start tag token whose tag name is "option" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'option') {
-                    /* If the current node is an option element, act as if an end tag
-                    with the tag name "option" had been seen. */
-                    if (end($this->stack)->tagName === 'option') {
-                        $this->emitToken([
-                            'name' => 'option',
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-                    }
-
-                    /* Insert an HTML element for the token. */
-                    $this->insertElement($token);
-
-                /* A start tag token whose tag name is "optgroup" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'optgroup') {
-                    /* If the current node is an option element, act as if an end tag
-                    with the tag name "option" had been seen. */
-                    if (end($this->stack)->tagName === 'option') {
-                        $this->emitToken([
-                            'name' => 'option',
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-                    }
-
-                    /* If the current node is an optgroup element, act as if an end tag
-                    with the tag name "optgroup" had been seen. */
-                    if (end($this->stack)->tagName === 'optgroup') {
-                        $this->emitToken([
-                            'name' => 'optgroup',
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-                    }
-
-                    /* Insert an HTML element for the token. */
-                    $this->insertElement($token);
-
-                /* An end tag token whose tag name is "optgroup" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'optgroup') {
-                    /* First, if the current node is an option element, and the node
-                    immediately before it in the stack of open elements is an optgroup
-                    element, then act as if an end tag with the tag name "option" had
-                    been seen. */
-                    $elements_in_stack = count($this->stack);
-
-                    if ($this->stack[$elements_in_stack - 1]->tagName === 'option' &&
-                    $this->stack[$elements_in_stack - 2]->tagName === 'optgroup') {
-                        $this->emitToken([
-                            'name' => 'option',
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-                    }
-
-                    /* If the current node is an optgroup element, then pop that node
-                    from the stack of open elements. Otherwise, this is a parse error,
-                    ignore the token. */
-                    if (end($this->stack)->tagName === 'optgroup') {
-                        array_pop($this->stack);
-                    } else {
-                        // parse error
-                        $this->ignored = true;
-                    }
-
-                /* An end tag token whose tag name is "option" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'option') {
-                    /* If the current node is an option element, then pop that node
-                    from the stack of open elements. Otherwise, this is a parse error,
-                    ignore the token. */
-                    if (end($this->stack)->tagName === 'option') {
-                        array_pop($this->stack);
-                    } else {
-                        // parse error
-                        $this->ignored = true;
-                    }
-
-                /* An end tag whose tag name is "select" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'select') {
-                    /* If the stack of open elements does not have an element in table
-                    scope with the same tag name as the token, this is a parse error.
-                    Ignore the token. (fragment case) */
-                    if (!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        $this->ignored = true;
-                        // parse error
-
-                    /* Otherwise: */
-                    } else {
-                        /* Pop elements from the stack of open elements until a select
-                        element has been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== 'select');
-
-                        /* Reset the insertion mode appropriately. */
-                        $this->resetInsertionMode();
-                    }
-
-                /* A start tag whose tag name is "select" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'select') {
-                    /* Parse error. Act as if the token had been an end tag with the
-                    tag name "select" instead. */
-                    $this->emitToken([
-                        'name' => 'select',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ]);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                ($token['name'] === 'input' || $token['name'] === 'keygen' ||  $token['name'] === 'textarea')) {
-                    // parse error
-                    $this->emitToken([
-                        'name' => 'select',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ]);
-                    $this->emitToken($token);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'script') {
-                    $this->processWithRulesFor($token, self::IN_HEAD);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    // XERROR: If the current node is not the root html element, then this is a parse error.
-                    /* Stop parsing */
-
-                /* Anything else */
-                } else {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-                }
-            break;
-
-            case self::IN_SELECT_IN_TABLE:
-
-                if ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                in_array($token['name'], ['caption', 'table', 'tbody',
-                'tfoot', 'thead', 'tr', 'td', 'th'])) {
-                    // parse error
-                    $this->emitToken([
-                        'name' => 'select',
-                        'type' => HTML5_Tokenizer::ENDTAG,
-                    ]);
-                    $this->emitToken($token);
-
-                /* An end tag whose tag name is one of: "caption", "table", "tbody",
-                "tfoot", "thead", "tr", "td", "th" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                in_array($token['name'], ['caption', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'td', 'th']))  {
-                    /* Parse error. */
-                    // parse error
-
-                    /* If the stack of open elements has an element in table scope with
-                    the same tag name as that of the token, then act as if an end tag
-                    with the tag name "select" had been seen, and reprocess the token.
-                    Otherwise, ignore the token. */
-                    if ($this->elementInScope($token['name'], self::SCOPE_TABLE)) {
-                        $this->emitToken([
-                            'name' => 'select',
-                            'type' => HTML5_Tokenizer::ENDTAG
-                        ]);
-
-                        $this->emitToken($token);
-                    } else {
-                        $this->ignored = true;
-                    }
-                } else {
-                    $this->processWithRulesFor($token, self::IN_SELECT);
-                }
-            break;
-
-            case self::IN_FOREIGN_CONTENT:
-                if ($token['type'] === HTML5_Tokenizer::CHARACTER ||
-                $token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    $this->insertText($token['data']);
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    $this->insertComment($token['data']);
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // XERROR: parse error
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'script' && end($this->stack)->tagName === 'script' &&
-                // XDOM
-                end($this->stack)->namespaceURI === self::NS_SVG) {
-                    array_pop($this->stack);
-                    // a bunch of script running mumbo jumbo
-                } elseif (
-                    ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                        ((
-                            $token['name'] !== 'mglyph' &&
-                            $token['name'] !== 'malignmark' &&
-                            // XDOM
-                            end($this->stack)->namespaceURI === self::NS_MATHML &&
-                            in_array(end($this->stack)->tagName, ['mi', 'mo', 'mn', 'ms', 'mtext'])
-                        ) ||
-                        (
-                            $token['name'] === 'svg' &&
-                            // XDOM
-                            end($this->stack)->namespaceURI === self::NS_MATHML &&
-                            end($this->stack)->tagName === 'annotation-xml'
-                        ) ||
-                        (
-                            // XDOM
-                            end($this->stack)->namespaceURI === self::NS_SVG &&
-                            in_array(end($this->stack)->tagName, ['foreignObject', 'desc', 'title'])
-                        ) ||
-                        (
-                            // XSKETCHY && XDOM
-                            end($this->stack)->namespaceURI === self::NS_HTML
-                        ))
-                    ) || $token['type'] === HTML5_Tokenizer::ENDTAG
-                ) {
-                    $this->processWithRulesFor($token, $this->secondary_mode);
-                    /* If, after doing so, the insertion mode is still "in foreign
-                     * content", but there is no element in scope that has a namespace
-                     * other than the HTML namespace, switch the insertion mode to the
-                     * secondary insertion mode. */
-                    if ($this->mode === self::IN_FOREIGN_CONTENT) {
-                        $found = false;
-                        // this basically duplicates elementInScope()
-                        for ($i = count($this->stack) - 1; $i >= 0; $i--) {
-                            // XDOM
-                            $node = $this->stack[$i];
-                            if ($node->namespaceURI !== self::NS_HTML) {
-                                $found = true;
-                                break;
-                            } elseif (in_array($node->tagName, ['table', 'html',
-                            'applet', 'caption', 'td', 'th', 'button', 'marquee',
-                            'object']) || ($node->tagName === 'foreignObject' &&
-                            $node->namespaceURI === self::NS_SVG)) {
-                                break;
-                            }
-                        }
-                        if (!$found) {
-                            $this->mode = $this->secondary_mode;
-                        }
-                    }
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF || (
-                $token['type'] === HTML5_Tokenizer::STARTTAG &&
-                (in_array($token['name'], ['b', "big", "blockquote", "body", "br",
-                "center", "code", "dc", "dd", "div", "dl", "ds", "dt", "em", "embed", "h1", "h2",
-                "h3", "h4", "h5", "h6", "head", "hr", "i", "img", "li", "listing",
-                "menu", "meta", "nobr", "ol", "p", "pre", "ruby", "s",  "small",
-                "span", "strong", "strike",  "sub", "sup", "table", "tt", "u", "ul",
-                "var"]) || ($token['name'] === 'font' && ($this->getAttr($token, 'color') ||
-                $this->getAttr($token, 'face') || $this->getAttr($token, 'size')))))) {
-                    // XERROR: parse error
-                    do {
-                        $node = array_pop($this->stack);
-                        // XDOM
-                    } while ($node->namespaceURI !== self::NS_HTML);
-                    $this->stack[] = $node;
-                    $this->mode = $this->secondary_mode;
-                    $this->emitToken($token);
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG) {
-                    static $svg_lookup = [
-                        'altglyph' => 'altGlyph',
-                        'altglyphdef' => 'altGlyphDef',
-                        'altglyphitem' => 'altGlyphItem',
-                        'animatecolor' => 'animateColor',
-                        'animatemotion' => 'animateMotion',
-                        'animatetransform' => 'animateTransform',
-                        'clippath' => 'clipPath',
-                        'feblend' => 'feBlend',
-                        'fecolormatrix' => 'feColorMatrix',
-                        'fecomponenttransfer' => 'feComponentTransfer',
-                        'fecomposite' => 'feComposite',
-                        'feconvolvematrix' => 'feConvolveMatrix',
-                        'fediffuselighting' => 'feDiffuseLighting',
-                        'fedisplacementmap' => 'feDisplacementMap',
-                        'fedistantlight' => 'feDistantLight',
-                        'feflood' => 'feFlood',
-                        'fefunca' => 'feFuncA',
-                        'fefuncb' => 'feFuncB',
-                        'fefuncg' => 'feFuncG',
-                        'fefuncr' => 'feFuncR',
-                        'fegaussianblur' => 'feGaussianBlur',
-                        'feimage' => 'feImage',
-                        'femerge' => 'feMerge',
-                        'femergenode' => 'feMergeNode',
-                        'femorphology' => 'feMorphology',
-                        'feoffset' => 'feOffset',
-                        'fepointlight' => 'fePointLight',
-                        'fespecularlighting' => 'feSpecularLighting',
-                        'fespotlight' => 'feSpotLight',
-                        'fetile' => 'feTile',
-                        'feturbulence' => 'feTurbulence',
-                        'foreignobject' => 'foreignObject',
-                        'glyphref' => 'glyphRef',
-                        'lineargradient' => 'linearGradient',
-                        'radialgradient' => 'radialGradient',
-                        'textpath' => 'textPath',
-                    ];
-                    // XDOM
-                    $current = end($this->stack);
-                    if ($current->namespaceURI === self::NS_MATHML) {
-                        $token = $this->adjustMathMLAttributes($token);
-                    }
-                    if ($current->namespaceURI === self::NS_SVG &&
-                    isset($svg_lookup[$token['name']])) {
-                        $token['name'] = $svg_lookup[$token['name']];
-                    }
-                    if ($current->namespaceURI === self::NS_SVG) {
-                        $token = $this->adjustSVGAttributes($token);
-                    }
-                    $token = $this->adjustForeignAttributes($token);
-                    $this->insertForeignElement($token, $current->namespaceURI);
-                    if (isset($token['self-closing'])) {
-                        array_pop($this->stack);
-                        // XERROR: acknowledge self-closing flag
-                    }
-                }
-            break;
-
-            case self::AFTER_BODY:
-                /* Handle the token as follows: */
-
-                /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-                U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-                or U+0020 SPACE */
-                if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    /* Process the token as it would be processed if the insertion mode
-                    was "in body". */
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* A comment token */
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the first element in the stack of open
-                    elements (the html element), with the data attribute set to the
-                    data given in the comment token. */
-                    // XDOM
-                    $comment = $this->dom->createComment($token['data']);
-                    $this->stack[0]->appendChild($comment);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // parse error
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* An end tag with the tag name "html" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'html') {
-                    /*     If the parser was originally created as part of the HTML
-                     *     fragment parsing algorithm, this is a parse error; ignore
-                     *     the token. (fragment case) */
-                    $this->ignored = true;
-                    // XERROR: implement this
-
-                    $this->mode = self::AFTER_AFTER_BODY;
-
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    /* Stop parsing */
-
-                /* Anything else */
-                } else {
-                    /* Parse error. Set the insertion mode to "in body" and reprocess
-                    the token. */
-                    $this->mode = self::IN_BODY;
-                    $this->emitToken($token);
-                }
-            break;
-
-            case self::IN_FRAMESET:
-                /* Handle the token as follows: */
-
-                /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-                U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-                U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
-                if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    /* Append the character to the current node. */
-                    $this->insertText($token['data']);
-
-                /* A comment token */
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the current node with the data
-                    attribute set to the data given in the comment token. */
-                    $this->insertComment($token['data']);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // parse error
-
-                /* A start tag with the tag name "frameset" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'frameset') {
-                    $this->insertElement($token);
-
-                /* An end tag with the tag name "frameset" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'frameset') {
-                    /* If the current node is the root html element, then this is a
-                    parse error; ignore the token. (fragment case) */
-                    if (end($this->stack)->tagName === 'html') {
-                        $this->ignored = true;
-                        // Parse error
-
-                    } else {
-                        /* Otherwise, pop the current node from the stack of open
-                        elements. */
-                        array_pop($this->stack);
-
-                        /* If the parser was not originally created as part of the HTML
-                         * fragment parsing algorithm  (fragment case), and the current
-                         * node is no longer a frameset element, then switch the
-                         * insertion mode to "after frameset". */
-                        $this->mode = self::AFTER_FRAMESET;
-                    }
-
-                /* A start tag with the tag name "frame" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'frame') {
-                    /* Insert an HTML element for the token. */
-                    $this->insertElement($token);
-
-                    /* Immediately pop the current node off the stack of open elements. */
-                    array_pop($this->stack);
-
-                    // XERROR: Acknowledge the token's self-closing flag, if it is set.
-
-                /* A start tag with the tag name "noframes" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'noframes') {
-                    /* Process the token using the rules for the "in head" insertion mode. */
-                    $this->processwithRulesFor($token, self::IN_HEAD);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    // XERROR: If the current node is not the root html element, then this is a parse error.
-                    /* Stop parsing */
-                /* Anything else */
-                } else {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-                }
-            break;
-
-            case self::AFTER_FRAMESET:
-                /* Handle the token as follows: */
-
-                /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-                U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-                U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
-                if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-                    /* Append the character to the current node. */
-                    $this->insertText($token['data']);
-
-                /* A comment token */
-                } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the current node with the data
-                    attribute set to the data given in the comment token. */
-                    $this->insertComment($token['data']);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-                    // parse error
-
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* An end tag with the tag name "html" */
-                } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-                $token['name'] === 'html') {
-                    $this->mode = self::AFTER_AFTER_FRAMESET;
-
-                /* A start tag with the tag name "noframes" */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                $token['name'] === 'noframes') {
-                    $this->processWithRulesFor($token, self::IN_HEAD);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    /* Stop parsing */
-
-                /* Anything else */
-                } else {
-                    /* Parse error. Ignore the token. */
-                    $this->ignored = true;
-                }
-            break;
-
-            case self::AFTER_AFTER_BODY:
-                /* A comment token */
-                if ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the Document object with the data
-                    attribute set to the data given in the comment token. */
-                    // XDOM
-                    $comment = $this->dom->createComment($token['data']);
-                    $this->dom->appendChild($comment);
-
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE ||
-                $token['type'] === HTML5_Tokenizer::SPACECHARACTER ||
-                ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html')) {
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* An end-of-file token */
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    /* OMG DONE!! */
-                } else {
-                    // parse error
-                    $this->mode = self::IN_BODY;
-                    $this->emitToken($token);
-                }
-            break;
-
-            case self::AFTER_AFTER_FRAMESET:
-                /* A comment token */
-                if ($token['type'] === HTML5_Tokenizer::COMMENT) {
-                    /* Append a Comment node to the Document object with the data
-                    attribute set to the data given in the comment token. */
-                    // XDOM
-                    $comment = $this->dom->createComment($token['data']);
-                    $this->dom->appendChild($comment);
-                } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE ||
-                $token['type'] === HTML5_Tokenizer::SPACECHARACTER ||
-                ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html')) {
-                    $this->processWithRulesFor($token, self::IN_BODY);
-
-                /* An end-of-file token */
-                } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-                    /* OMG DONE!! */
-                } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'nofrmaes') {
-                    $this->processWithRulesFor($token, self::IN_HEAD);
-                } else {
-                    // parse error
-                }
-            break;
-        }
-    }
-
-    private function insertElement($token, $append = true) {
-        $el = $this->dom->createElementNS(self::NS_HTML, $token['name']);
-
-        if (!empty($token['attr'])) {
-            foreach ($token['attr'] as $attr) {
-                if (!$el->hasAttribute($attr['name']) && preg_match("/^[a-zA-Z_:]/", $attr['name'])) {
-                    $el->setAttribute($attr['name'], $attr['value']);
-                }
-            }
-        }
-        if ($append) {
-            $this->appendToRealParent($el);
-            $this->stack[] = $el;
-        }
-
-        return $el;
-    }
-
-    /**
-     * @param $data
-     */
-    private function insertText($data) {
-        if ($data === '') {
-            return;
-        }
-        if ($this->ignore_lf_token) {
-            if ($data[0] === "\n") {
-                $data = substr($data, 1);
-                if ($data === false) {
-                    return;
-                }
-            }
-        }
-        $text = $this->dom->createTextNode($data);
-        $this->appendToRealParent($text);
-    }
-
-    /**
-     * @param $data
-     */
-    private function insertComment($data) {
-        $comment = $this->dom->createComment($data);
-        $this->appendToRealParent($comment);
-    }
-
-    /**
-     * @param $node
-     */
-    private function appendToRealParent($node) {
-        // this is only for the foster_parent case
-        /* If the current node is a table, tbody, tfoot, thead, or tr
-        element, then, whenever a node would be inserted into the current
-        node, it must instead be inserted into the foster parent element. */
-        if (
-            !$this->foster_parent ||
-            !in_array(
-                end($this->stack)->tagName,
-                ['table', 'tbody', 'tfoot', 'thead', 'tr']
-            )
-        ) {
-            end($this->stack)->appendChild($node);
-        } else {
-            $this->fosterParent($node);
-        }
-    }
-
-    /**
-     * @param $el
-     * @param int $scope
-     * @return bool|null
-     */
-    private function elementInScope($el, $scope = self::SCOPE) {
-        if (is_array($el)) {
-            foreach($el as $element) {
-                if ($this->elementInScope($element, $scope)) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        $leng = count($this->stack);
-
-        for ($n = 0; $n < $leng; $n++) {
-            /* 1. Initialise node to be the current node (the bottommost node of
-            the stack). */
-            $node = $this->stack[$leng - 1 - $n];
-
-            if ($node->tagName === $el) {
-                /* 2. If node is the target node, terminate in a match state. */
-                return true;
-
-                // We've expanded the logic for these states a little differently;
-                // Hixie's refactoring into "specific scope" is more general, but
-                // this "gets the job done"
-
-            // these are the common states for all scopes
-            } elseif ($node->tagName === 'table' || $node->tagName === 'html') {
-                return false;
-
-            // these are valid for "in scope" and "in list item scope"
-            } elseif ($scope !== self::SCOPE_TABLE &&
-            (in_array($node->tagName, ['applet', 'caption', 'td',
-                'th', 'button', 'marquee', 'object']) ||
-                $node->tagName === 'foreignObject' && $node->namespaceURI === self::NS_SVG)) {
-                return false;
-
-
-            // these are valid for "in list item scope"
-            } elseif ($scope === self::SCOPE_LISTITEM && in_array($node->tagName, ['ol', 'ul'])) {
-                return false;
-            }
-
-            /* Otherwise, set node to the previous entry in the stack of open
-            elements and return to step 2. (This will never fail, since the loop
-            will always terminate in the previous step if the top of the stack
-            is reached.) */
-        }
-
-        // To fix warning. This never happens or should return true/false
-        return null;
-    }
-
-    /**
-     * @return bool
-     */
-    private function reconstructActiveFormattingElements() {
-        /* 1. If there are no entries in the list of active formatting elements,
-        then there is nothing to reconstruct; stop this algorithm. */
-        $formatting_elements = count($this->a_formatting);
-
-        if ($formatting_elements === 0) {
-            return false;
-        }
-
-        /* 3. Let entry be the last (most recently added) element in the list
-        of active formatting elements. */
-        $entry = end($this->a_formatting);
-
-        /* 2. If the last (most recently added) entry in the list of active
-        formatting elements is a marker, or if it is an element that is in the
-        stack of open elements, then there is nothing to reconstruct; stop this
-        algorithm. */
-        if ($entry === self::MARKER || in_array($entry, $this->stack, true)) {
-            return false;
-        }
-
-        for ($a = $formatting_elements - 1; $a >= 0; true) {
-            /* 4. If there are no entries before entry in the list of active
-            formatting elements, then jump to step 8. */
-            if ($a === 0) {
-                $step_seven = false;
-                break;
-            }
-
-            /* 5. Let entry be the entry one earlier than entry in the list of
-            active formatting elements. */
-            $a--;
-            $entry = $this->a_formatting[$a];
-
-            /* 6. If entry is neither a marker nor an element that is also in
-            thetack of open elements, go to step 4. */
-            if ($entry === self::MARKER || in_array($entry, $this->stack, true)) {
-                break;
-            }
-        }
-
-        while (true) {
-            /* 7. Let entry be the element one later than entry in the list of
-            active formatting elements. */
-            if (isset($step_seven) && $step_seven === true) {
-                $a++;
-                $entry = $this->a_formatting[$a];
-            }
-
-            /* 8. Perform a shallow clone of the element entry to obtain clone. */
-            $clone = $entry->cloneNode();
-
-            /* 9. Append clone to the current node and push it onto the stack
-            of open elements  so that it is the new current node. */
-            $this->appendToRealParent($clone);
-            $this->stack[] = $clone;
-
-            /* 10. Replace the entry for entry in the list with an entry for
-            clone. */
-            $this->a_formatting[$a] = $clone;
-
-            /* 11. If the entry for clone in the list of active formatting
-            elements is not the last entry in the list, return to step 7. */
-            if (end($this->a_formatting) !== $clone) {
-                $step_seven = true;
-            } else {
-                break;
-            }
-        }
-
-        // Return value not in use ATM. Would just make sense to also return true here.
-        return true;
-    }
-
-    /**
-     *
-     */
-    private function clearTheActiveFormattingElementsUpToTheLastMarker() {
-        /* When the steps below require the UA to clear the list of active
-        formatting elements up to the last marker, the UA must perform the
-        following steps: */
-
-        while (true) {
-            /* 1. Let entry be the last (most recently added) entry in the list
-            of active formatting elements. */
-            $entry = end($this->a_formatting);
-
-            /* 2. Remove entry from the list of active formatting elements. */
-            array_pop($this->a_formatting);
-
-            /* 3. If entry was a marker, then stop the algorithm at this point.
-            The list has been cleared up to the last marker. */
-            if ($entry === self::MARKER) {
-                break;
-            }
-        }
-    }
-
-    /**
-     * @param array $exclude
-     */
-    private function generateImpliedEndTags($exclude = []) {
-        /* When the steps below require the UA to generate implied end tags,
-         * then, while the current node is a dc element, a dd element, a ds
-         * element, a dt element, an li element, an option element, an optgroup
-         * element, a p element, an rp element, or an rt element, the UA must
-         * pop the current node off the stack of open elements. */
-        $node = end($this->stack);
-        $elements = array_diff(['dc', 'dd', 'ds', 'dt', 'li', 'p', 'td', 'th', 'tr'], $exclude);
-
-        while (in_array(end($this->stack)->tagName, $elements)) {
-            array_pop($this->stack);
-        }
-    }
-
-    /**
-     * @param $node
-     * @return int
-     */
-    private function getElementCategory($node) {
-        if (!is_object($node)) {
-            debug_print_backtrace();
-        }
-        $name = $node->tagName;
-        if (in_array($name, $this->special)) {
-            return self::SPECIAL;
-        } elseif (in_array($name, $this->scoping)) {
-            return self::SCOPING;
-        } elseif (in_array($name, $this->formatting)) {
-            return self::FORMATTING;
-        } else {
-            return self::PHRASING;
-        }
-    }
-
-    /**
-     * @param $elements
-     */
-    private function clearStackToTableContext($elements) {
-        /* When the steps above require the UA to clear the stack back to a
-        table context, it means that the UA must, while the current node is not
-        a table element or an html element, pop elements from the stack of open
-        elements. */
-        while (true) {
-            $name = end($this->stack)->tagName;
-
-            if (in_array($name, $elements)) {
-                break;
-            } else {
-                array_pop($this->stack);
-            }
-        }
-    }
-
-    /**
-     * @param null $context
-     */
-    private function resetInsertionMode($context = null) {
-        /* 1. Let last be false. */
-        $last = false;
-        $leng = count($this->stack);
-
-        for ($n = $leng - 1; $n >= 0; $n--) {
-            /* 2. Let node be the last node in the stack of open elements. */
-            $node = $this->stack[$n];
-
-            /* 3. If node is the first node in the stack of open elements, then
-             * set last to true and set node to the context  element. (fragment
-             * case) */
-            if ($this->stack[0]->isSameNode($node)) {
-                $last = true;
-                $node = $context;
-            }
-
-            /* 4. If node is a select element, then switch the insertion mode to
-            "in select" and abort these steps. (fragment case) */
-            if ($node->tagName === 'select') {
-                $this->mode = self::IN_SELECT;
-                break;
-
-            /* 5. If node is a td or th element, then switch the insertion mode
-            to "in cell" and abort these steps. */
-            } elseif ($node->tagName === 'td' || $node->nodeName === 'th') {
-                $this->mode = self::IN_CELL;
-                break;
-
-            /* 6. If node is a tr element, then switch the insertion mode to
-            "in    row" and abort these steps. */
-            } elseif ($node->tagName === 'tr') {
-                $this->mode = self::IN_ROW;
-                break;
-
-            /* 7. If node is a tbody, thead, or tfoot element, then switch the
-            insertion mode to "in table body" and abort these steps. */
-            } elseif (in_array($node->tagName, ['tbody', 'thead', 'tfoot'])) {
-                $this->mode = self::IN_TABLE_BODY;
-                break;
-
-            /* 8. If node is a caption element, then switch the insertion mode
-            to "in caption" and abort these steps. */
-            } elseif ($node->tagName === 'caption') {
-                $this->mode = self::IN_CAPTION;
-                break;
-
-            /* 9. If node is a colgroup element, then switch the insertion mode
-            to "in column group" and abort these steps. (innerHTML case) */
-            } elseif ($node->tagName === 'colgroup') {
-                $this->mode = self::IN_COLUMN_GROUP;
-                break;
-
-            /* 10. If node is a table element, then switch the insertion mode
-            to "in table" and abort these steps. */
-            } elseif ($node->tagName === 'table') {
-                $this->mode = self::IN_TABLE;
-                break;
-
-            /* 11. If node is an element from the MathML namespace or the SVG
-             * namespace, then switch the insertion mode to "in foreign
-             * content", let the secondary insertion mode be "in body", and
-             * abort these steps. */
-            } elseif ($node->namespaceURI === self::NS_SVG ||
-            $node->namespaceURI === self::NS_MATHML) {
-                $this->mode = self::IN_FOREIGN_CONTENT;
-                $this->secondary_mode = self::IN_BODY;
-                break;
-
-            /* 12. If node is a head element, then switch the insertion mode
-            to "in body" ("in body"! not "in head"!) and abort these steps.
-            (fragment case) */
-            } elseif ($node->tagName === 'head') {
-                $this->mode = self::IN_BODY;
-                break;
-
-            /* 13. If node is a body element, then switch the insertion mode to
-            "in body" and abort these steps. */
-            } elseif ($node->tagName === 'body') {
-                $this->mode = self::IN_BODY;
-                break;
-
-            /* 14. If node is a frameset element, then switch the insertion
-            mode to "in frameset" and abort these steps. (fragment case) */
-            } elseif ($node->tagName === 'frameset') {
-                $this->mode = self::IN_FRAMESET;
-                break;
-
-            /* 15. If node is an html element, then: if the head element
-            pointer is null, switch the insertion mode to "before head",
-            otherwise, switch the insertion mode to "after head". In either
-            case, abort these steps. (fragment case) */
-            } elseif ($node->tagName === 'html') {
-                $this->mode = ($this->head_pointer === null)
-                    ? self::BEFORE_HEAD
-                    : self::AFTER_HEAD;
-
-                break;
-
-            /* 16. If last is true, then set the insertion mode to "in body"
-            and    abort these steps. (fragment case) */
-            } elseif ($last) {
-                $this->mode = self::IN_BODY;
-                break;
-            }
-        }
-    }
-
-    /**
-     *
-     */
-    private function closeCell() {
-        /* If the stack of open elements has a td or th element in table scope,
-        then act as if an end tag token with that tag name had been seen. */
-        foreach (['td', 'th'] as $cell) {
-            if ($this->elementInScope($cell, self::SCOPE_TABLE)) {
-                $this->emitToken([
-                    'name' => $cell,
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ]);
-
-                break;
-            }
-        }
-    }
-
-    /**
-     * @param $token
-     * @param $mode
-     */
-    private function processWithRulesFor($token, $mode) {
-        /* "using the rules for the m insertion mode", where m is one of these
-         * modes, the user agent must use the rules described under the m
-         * insertion mode's section, but must leave the insertion mode
-         * unchanged unless the rules in m themselves switch the insertion mode
-         * to a new value. */
-        $this->emitToken($token, $mode);
-    }
-
-    /**
-     * @param $token
-     */
-    private function insertCDATAElement($token) {
-        $this->insertElement($token);
-        $this->original_mode = $this->mode;
-        $this->mode = self::IN_CDATA_RCDATA;
-        $this->content_model = HTML5_Tokenizer::CDATA;
-    }
-
-    /**
-     * @param $token
-     */
-    private function insertRCDATAElement($token) {
-        $this->insertElement($token);
-        $this->original_mode = $this->mode;
-        $this->mode = self::IN_CDATA_RCDATA;
-        $this->content_model = HTML5_Tokenizer::RCDATA;
-    }
-
-    /**
-     * @param $token
-     * @param $key
-     * @return bool
-     */
-    private function getAttr($token, $key) {
-        if (!isset($token['attr'])) {
-            return false;
-        }
-        $ret = false;
-        foreach ($token['attr'] as $keypair) {
-            if ($keypair['name'] === $key) {
-                $ret = $keypair['value'];
-            }
-        }
-        return $ret;
-    }
-
-    /**
-     * @return mixed
-     */
-    private function getCurrentTable() {
-        /* The current table is the last table  element in the stack of open
-         * elements, if there is one. If there is no table element in the stack
-         * of open elements (fragment case), then the current table is the
-         * first element in the stack of open elements (the html element). */
-        for ($i = count($this->stack) - 1; $i >= 0; $i--) {
-            if ($this->stack[$i]->tagName === 'table') {
-                return $this->stack[$i];
-            }
-        }
-        return $this->stack[0];
-    }
-
-    /**
-     * @return mixed
-     */
-    private function getFosterParent() {
-        /* The foster parent element is the parent element of the last
-        table element in the stack of open elements, if there is a
-        table element and it has such a parent element. If there is no
-        table element in the stack of open elements (innerHTML case),
-        then the foster parent element is the first element in the
-        stack of open elements (the html  element). Otherwise, if there
-        is a table element in the stack of open elements, but the last
-        table element in the stack of open elements has no parent, or
-        its parent node is not an element, then the foster parent
-        element is the element before the last table element in the
-        stack of open elements. */
-        for ($n = count($this->stack) - 1; $n >= 0; $n--) {
-            if ($this->stack[$n]->tagName === 'table') {
-                $table = $this->stack[$n];
-                break;
-            }
-        }
-
-        if (isset($table) && $table->parentNode !== null) {
-            return $table->parentNode;
-
-        } elseif (!isset($table)) {
-            return $this->stack[0];
-
-        } elseif (isset($table) && ($table->parentNode === null ||
-        $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
-            return $this->stack[$n - 1];
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $node
-     */
-    public function fosterParent($node) {
-        $foster_parent = $this->getFosterParent();
-        $table = $this->getCurrentTable(); // almost equivalent to last table element, except it can be html
-        /* When a node node is to be foster parented, the node node must be
-         * be inserted into the foster parent element. */
-        /* If the foster parent element is the parent element of the last table
-         * element in the stack of open elements, then node must be inserted
-         * immediately before the last table element in the stack of open
-         * elements in the foster parent element; otherwise, node must be
-         * appended to the foster parent element. */
-        if ($table->tagName === 'table' && $table->parentNode->isSameNode($foster_parent)) {
-            $foster_parent->insertBefore($node, $table);
-        } else {
-            $foster_parent->appendChild($node);
-        }
-    }
-
-    /**
-     * For debugging, prints the stack
-     */
-    private function printStack() {
-        $names = [];
-        foreach ($this->stack as $i => $element) {
-            $names[] = $element->tagName;
-        }
-        echo "  -> stack [" . implode(', ', $names) . "]\n";
-    }
-
-    /**
-     * For debugging, prints active formatting elements
-     */
-    private function printActiveFormattingElements() {
-        if (!$this->a_formatting) {
-            return;
-        }
-        $names = [];
-        foreach ($this->a_formatting as $node) {
-            if ($node === self::MARKER) {
-                $names[] = 'MARKER';
-            } else {
-                $names[] = $node->tagName;
-            }
-        }
-        echo "  -> active formatting [" . implode(', ', $names) . "]\n";
-    }
-
-    /**
-     * @return bool
-     */
-    public function currentTableIsTainted() {
-        return !empty($this->getCurrentTable()->tainted);
-    }
-
-    /**
-     * Sets up the tree constructor for building a fragment.
-     *
-     * @param null $context
-     */
-    public function setupContext($context = null) {
-        $this->fragment = true;
-        if ($context) {
-            $context = $this->dom->createElementNS(self::NS_HTML, $context);
-            /* 4.1. Set the HTML parser's tokenization  stage's content model
-             * flag according to the context element, as follows: */
-            switch ($context->tagName) {
-                case 'title': case 'textarea':
-                    $this->content_model = HTML5_Tokenizer::RCDATA;
-                    break;
-                case 'style': case 'script': case 'xmp': case 'iframe':
-                case 'noembed': case 'noframes':
-                    $this->content_model = HTML5_Tokenizer::CDATA;
-                    break;
-                case 'noscript':
-                    // XSCRIPT: assuming scripting is enabled
-                    $this->content_model = HTML5_Tokenizer::CDATA;
-                    break;
-                case 'plaintext':
-                    $this->content_model = HTML5_Tokenizer::PLAINTEXT;
-                    break;
-            }
-            /* 4.2. Let root be a new html element with no attributes. */
-            $root = $this->dom->createElementNS(self::NS_HTML, 'html');
-            $this->root = $root;
-            /* 4.3 Append the element root to the Document node created above. */
-            $this->dom->appendChild($root);
-            /* 4.4 Set up the parser's stack of open elements so that it
-             * contains just the single element root. */
-            $this->stack = [$root];
-            /* 4.5 Reset the parser's insertion mode appropriately. */
-            $this->resetInsertionMode($context);
-            /* 4.6 Set the parser's form element pointer  to the nearest node
-             * to the context element that is a form element (going straight up
-             * the ancestor chain, and including the element itself, if it is a
-             * form element), or, if there is no such form element, to null. */
-            $node = $context;
-            do {
-                if ($node->tagName === 'form') {
-                    $this->form_pointer = $node;
-                    break;
-                }
-            } while ($node = $node->parentNode);
-        }
-    }
-
-    /**
-     * @param $token
-     * @return mixed
-     */
-    public function adjustMathMLAttributes($token) {
-        foreach ($token['attr'] as &$kp) {
-            if ($kp['name'] === 'definitionurl') {
-                $kp['name'] = 'definitionURL';
-            }
-        }
-        return $token;
-    }
-
-    /**
-     * @param $token
-     * @return mixed
-     */
-    public function adjustSVGAttributes($token) {
-        static $lookup = [
-            'attributename' => 'attributeName',
-            'attributetype' => 'attributeType',
-            'basefrequency' => 'baseFrequency',
-            'baseprofile' => 'baseProfile',
-            'calcmode' => 'calcMode',
-            'clippathunits' => 'clipPathUnits',
-            'contentscripttype' => 'contentScriptType',
-            'contentstyletype' => 'contentStyleType',
-            'diffuseconstant' => 'diffuseConstant',
-            'edgemode' => 'edgeMode',
-            'externalresourcesrequired' => 'externalResourcesRequired',
-            'filterres' => 'filterRes',
-            'filterunits' => 'filterUnits',
-            'glyphref' => 'glyphRef',
-            'gradienttransform' => 'gradientTransform',
-            'gradientunits' => 'gradientUnits',
-            'kernelmatrix' => 'kernelMatrix',
-            'kernelunitlength' => 'kernelUnitLength',
-            'keypoints' => 'keyPoints',
-            'keysplines' => 'keySplines',
-            'keytimes' => 'keyTimes',
-            'lengthadjust' => 'lengthAdjust',
-            'limitingconeangle' => 'limitingConeAngle',
-            'markerheight' => 'markerHeight',
-            'markerunits' => 'markerUnits',
-            'markerwidth' => 'markerWidth',
-            'maskcontentunits' => 'maskContentUnits',
-            'maskunits' => 'maskUnits',
-            'numoctaves' => 'numOctaves',
-            'pathlength' => 'pathLength',
-            'patterncontentunits' => 'patternContentUnits',
-            'patterntransform' => 'patternTransform',
-            'patternunits' => 'patternUnits',
-            'pointsatx' => 'pointsAtX',
-            'pointsaty' => 'pointsAtY',
-            'pointsatz' => 'pointsAtZ',
-            'preservealpha' => 'preserveAlpha',
-            'preserveaspectratio' => 'preserveAspectRatio',
-            'primitiveunits' => 'primitiveUnits',
-            'refx' => 'refX',
-            'refy' => 'refY',
-            'repeatcount' => 'repeatCount',
-            'repeatdur' => 'repeatDur',
-            'requiredextensions' => 'requiredExtensions',
-            'requiredfeatures' => 'requiredFeatures',
-            'specularconstant' => 'specularConstant',
-            'specularexponent' => 'specularExponent',
-            'spreadmethod' => 'spreadMethod',
-            'startoffset' => 'startOffset',
-            'stddeviation' => 'stdDeviation',
-            'stitchtiles' => 'stitchTiles',
-            'surfacescale' => 'surfaceScale',
-            'systemlanguage' => 'systemLanguage',
-            'tablevalues' => 'tableValues',
-            'targetx' => 'targetX',
-            'targety' => 'targetY',
-            'textlength' => 'textLength',
-            'viewbox' => 'viewBox',
-            'viewtarget' => 'viewTarget',
-            'xchannelselector' => 'xChannelSelector',
-            'ychannelselector' => 'yChannelSelector',
-            'zoomandpan' => 'zoomAndPan',
-        ];
-        foreach ($token['attr'] as &$kp) {
-            if (isset($lookup[$kp['name']])) {
-                $kp['name'] = $lookup[$kp['name']];
-            }
-        }
-        return $token;
-    }
-
-    /**
-     * @param $token
-     * @return mixed
-     */
-    public function adjustForeignAttributes($token) {
-        static $lookup = [
-            'xlink:actuate' => ['xlink', 'actuate', self::NS_XLINK],
-            'xlink:arcrole' => ['xlink', 'arcrole', self::NS_XLINK],
-            'xlink:href' => ['xlink', 'href', self::NS_XLINK],
-            'xlink:role' => ['xlink', 'role', self::NS_XLINK],
-            'xlink:show' => ['xlink', 'show', self::NS_XLINK],
-            'xlink:title' => ['xlink', 'title', self::NS_XLINK],
-            'xlink:type' => ['xlink', 'type', self::NS_XLINK],
-            'xml:base' => ['xml', 'base', self::NS_XML],
-            'xml:lang' => ['xml', 'lang', self::NS_XML],
-            'xml:space' => ['xml', 'space', self::NS_XML],
-            'xmlns' => [null, 'xmlns', self::NS_XMLNS],
-            'xmlns:xlink' => ['xmlns', 'xlink', self::NS_XMLNS],
-        ];
-        foreach ($token['attr'] as &$kp) {
-            if (isset($lookup[$kp['name']])) {
-                $kp['name'] = $lookup[$kp['name']];
-            }
-        }
-        return $token;
-    }
-
-    /**
-     * @param $token
-     * @param $namespaceURI
-     */
-    public function insertForeignElement($token, $namespaceURI) {
-        $el = $this->dom->createElementNS($namespaceURI, $token['name']);
-
-        if (!empty($token['attr'])) {
-            foreach ($token['attr'] as $kp) {
-                $attr = $kp['name'];
-                if (is_array($attr)) {
-                    $ns = $attr[2];
-                    $attr = $attr[1];
-                } else {
-                    $ns = self::NS_HTML;
-                }
-                if (!$el->hasAttributeNS($ns, $attr)) {
-                    // XSKETCHY: work around godawful libxml bug
-                    if ($ns === self::NS_XLINK) {
-                        $el->setAttribute('xlink:'.$attr, $kp['value']);
-                    } elseif ($ns === self::NS_HTML) {
-                        // Another godawful libxml bug
-                        $el->setAttribute($attr, $kp['value']);
-                    } else {
-                        $el->setAttributeNS($ns, $attr, $kp['value']);
-                    }
-                }
-            }
-        }
-        $this->appendToRealParent($el);
-        $this->stack[] = $el;
-        // XERROR: see below
-        /* If the newly created element has an xmlns attribute in the XMLNS
-         * namespace  whose value is not exactly the same as the element's
-         * namespace, that is a parse error. Similarly, if the newly created
-         * element has an xmlns:xlink attribute in the XMLNS namespace whose
-         * value is not the XLink Namespace, that is a parse error. */
-    }
-
-    /**
-     * @return DOMDocument|DOMNodeList
-     */
-    public function save() {
-        $this->dom->normalize();
-        if (!$this->fragment) {
-            return $this->dom;
-        } else {
-            if ($this->root) {
-                return $this->root->childNodes;
-            } else {
-                return $this->dom->childNodes;
-            }
-        }
-    }
-}
-
diff --git a/library/vendor/dompdf/lib/html5lib/named-character-references.ser b/library/vendor/dompdf/lib/html5lib/named-character-references.ser
deleted file mode 100644
index e3ae05020..000000000
--- a/library/vendor/dompdf/lib/html5lib/named-character-references.ser
+++ /dev/null
@@ -1 +0,0 @@
-a:52:{s:1:"A";a:16:{s:1:"E";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:198;}s:9:"codepoint";i:198;}}}}s:1:"M";a:1:{s:1:"P";a:2:{s:1:";";a:1:{s:9:"codepoint";i:38;}s:9:"codepoint";i:38;}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:193;}s:9:"codepoint";i:193;}}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:258;}}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:194;}s:9:"codepoint";i:194;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1040;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120068;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:192;}s:9:"codepoint";i:192;}}}}}s:1:"l";a:1:{s:1:"p";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:913;}}}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:256;}}}}}s:1:"n";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10835;}}}s:1:"o";a:2:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:260;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120120;}}}}s:1:"p";a:1:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"y";a:1:{s:1:"F";a:1:{s:1:"u";a:1:{s:1:"n";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8289;}}}}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:197;}s:9:"codepoint";i:197;}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119964;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8788;}}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:195;}s:9:"codepoint";i:195;}}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:196;}s:9:"codepoint";i:196;}}}}s:1:"B";a:8:{s:1:"a";a:2:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"s";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8726;}}}}}}}}s:1:"r";a:2:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10983;}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8966;}}}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1041;}}}s:1:"e";a:3:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8757;}}}}}}s:1:"r";a:1:{s:1:"n";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8492;}}}}}}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:914;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120069;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120121;}}}}s:1:"r";a:1:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:728;}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8492;}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"p";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8782;}}}}}}}s:1:"C";a:14:{s:1:"H";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1063;}}}}s:1:"O";a:1:{s:1:"P";a:1:{s:1:"Y";a:2:{s:1:";";a:1:{s:9:"codepoint";i:169;}s:9:"codepoint";i:169;}}}s:1:"a";a:3:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:262;}}}}}s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8914;}s:1:"i";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"D";a:1:{s:1:"i";a:1:{s:1:"f";a:1:{s:1:"f";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"D";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8517;}}}}}}}}}}}}}}}}}}}s:1:"y";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"y";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8493;}}}}}}}s:1:"c";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:268;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:199;}s:9:"codepoint";i:199;}}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:264;}}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8752;}}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:266;}}}}s:1:"e";a:2:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:184;}}}}}}s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:183;}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8493;}}}s:1:"h";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:935;}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:"l";a:1:{s:1:"e";a:4:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8857;}}}}s:1:"M";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8854;}}}}}}s:1:"P";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8853;}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8855;}}}}}}}}}}}s:1:"l";a:1:{s:1:"o";a:2:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"w";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"C";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"I";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8754;}}}}}}}}}}}}}}}}}}}}}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"C";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"l";a:1:{s:1:"y";a:2:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"Q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8221;}}}}}}}}}}}}s:1:"Q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8217;}}}}}}}}}}}}}}}s:1:"o";a:4:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8759;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10868;}}}}}s:1:"n";a:3:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8801;}}}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8751;}}}}s:1:"t";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"I";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8750;}}}}}}}}}}}}}}s:1:"p";a:2:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8450;}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"d";a:1:{s:1:"u";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8720;}}}}}}}}s:1:"u";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"C";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"w";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"C";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"I";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8755;}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10799;}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119966;}}}}s:1:"u";a:1:{s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8915;}s:1:"C";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8781;}}}}}}}s:1:"D";a:11:{s:1:"D";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8517;}s:1:"o";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"h";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10513;}}}}}}}}s:1:"J";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1026;}}}}s:1:"S";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1029;}}}}s:1:"Z";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1039;}}}}s:1:"a";a:3:{s:1:"g";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8225;}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8609;}}}s:1:"s";a:1:{s:1:"h";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10980;}}}}}s:1:"c";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:270;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1044;}}}s:1:"e";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8711;}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:916;}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120071;}}}s:1:"i";a:2:{s:1:"a";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:4:{s:1:"A";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:180;}}}}}}s:1:"D";a:1:{s:1:"o";a:2:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:729;}}s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"A";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:733;}}}}}}}}}}}}s:1:"G";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:96;}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:732;}}}}}}}}}}}}}}s:1:"m";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8900;}}}}}}s:1:"f";a:1:{s:1:"f";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"D";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8518;}}}}}}}}}}}}}s:1:"o";a:4:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120123;}}}s:1:"t";a:3:{s:1:";";a:1:{s:9:"codepoint";i:168;}s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8412;}}}}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8784;}}}}}}}s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:6:{s:1:"C";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"I";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8751;}}}}}}}}}}}}}}}}s:1:"D";a:1:{s:1:"o";a:2:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:168;}}s:1:"w";a:1:{s:1:"n";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8659;}}}}}}}}}}s:1:"L";a:2:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:3:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8656;}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8660;}}}}}}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10980;}}}}}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"g";a:2:{s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10232;}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10234;}}}}}}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10233;}}}}}}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8658;}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8872;}}}}}}}}}s:1:"U";a:1:{s:1:"p";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8657;}}}}}}s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8661;}}}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8741;}}}}}}}}}}}}}}}}s:1:"w";a:1:{s:1:"n";a:6:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8595;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10515;}}}}s:1:"U";a:1:{s:1:"p";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8693;}}}}}}}}}}}}}s:1:"B";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:785;}}}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:3:{s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10576;}}}}}}}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10590;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8637;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10582;}}}}}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:2:{s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10591;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8641;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10583;}}}}}}}}}}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8868;}s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8615;}}}}}}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8659;}}}}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119967;}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:272;}}}}}}}s:1:"E";a:16:{s:1:"N";a:1:{s:1:"G";a:1:{s:1:";";a:1:{s:9:"codepoint";i:330;}}}s:1:"T";a:1:{s:1:"H";a:2:{s:1:";";a:1:{s:9:"codepoint";i:208;}s:9:"codepoint";i:208;}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:201;}s:9:"codepoint";i:201;}}}}}s:1:"c";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:282;}}}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:202;}s:9:"codepoint";i:202;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1069;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:278;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120072;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:200;}s:9:"codepoint";i:200;}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8712;}}}}}}}s:1:"m";a:2:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:274;}}}}s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:2:{s:1:"S";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"S";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9723;}}}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"y";a:1:{s:1:"S";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"S";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9643;}}}}}}}}}}}}}}}}}}}}s:1:"o";a:2:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:280;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120124;}}}}s:1:"p";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:917;}}}}}}}s:1:"q";a:1:{s:1:"u";a:2:{s:1:"a";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10869;}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8770;}}}}}}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"b";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8652;}}}}}}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8496;}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10867;}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:919;}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:203;}s:9:"codepoint";i:203;}}}s:1:"x";a:2:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8707;}}}}}s:1:"p";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8519;}}}}}}}}}}}}}s:1:"F";a:5:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1060;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120073;}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"d";a:2:{s:1:"S";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"S";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9724;}}}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"y";a:1:{s:1:"S";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"S";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9642;}}}}}}}}}}}}}}}}}}}}}s:1:"o";a:3:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120125;}}}s:1:"r";a:1:{s:1:"A";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8704;}}}}}s:1:"u";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8497;}}}}}}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8497;}}}}}s:1:"G";a:12:{s:1:"J";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1027;}}}}s:1:"T";a:2:{s:1:";";a:1:{s:9:"codepoint";i:62;}s:9:"codepoint";i:62;}s:1:"a";a:1:{s:1:"m";a:1:{s:1:"m";a:1:{s:1:"a";a:2:{s:1:";";a:1:{s:9:"codepoint";i:915;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:988;}}}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:286;}}}}}}s:1:"c";a:3:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:290;}}}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:284;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1043;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:288;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120074;}}}s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8921;}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120126;}}}}s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:6:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8805;}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8923;}}}}}}}}}}s:1:"F";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8807;}}}}}}}}}}s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10914;}}}}}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8823;}}}}}s:1:"S";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10878;}}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8819;}}}}}}}}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119970;}}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8811;}}}s:1:"H";a:8:{s:1:"A";a:1:{s:1:"R";a:1:{s:1:"D";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1066;}}}}}}s:1:"a";a:2:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:711;}}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:94;}}}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:292;}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8460;}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"b";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8459;}}}}}}}}}}}}s:1:"o";a:2:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8461;}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"z";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"L";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9472;}}}}}}}}}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8459;}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:294;}}}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"p";a:2:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"H";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8782;}}}}}}}}}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8783;}}}}}}}}}}s:1:"I";a:14:{s:1:"E";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1045;}}}}s:1:"J";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:306;}}}}}s:1:"O";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1025;}}}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:205;}s:9:"codepoint";i:205;}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:206;}s:9:"codepoint";i:206;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1048;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:304;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8465;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:204;}s:9:"codepoint";i:204;}}}}}s:1:"m";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8465;}s:1:"a";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:298;}}}s:1:"g";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"y";a:1:{s:1:"I";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8520;}}}}}}}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8658;}}}}}}}s:1:"n";a:2:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8748;}s:1:"e";a:2:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8747;}}}}}s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8898;}}}}}}}}}}}s:1:"v";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:2:{s:1:"C";a:1:{s:1:"o";a:1:{s:1:"m";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8291;}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8290;}}}}}}}}}}}}}}s:1:"o";a:3:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:302;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120128;}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:921;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8464;}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:296;}}}}}}s:1:"u";a:2:{s:1:"k";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1030;}}}}s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:207;}s:9:"codepoint";i:207;}}}}s:1:"J";a:5:{s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:308;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1049;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120077;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120129;}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119973;}}}s:1:"e";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1032;}}}}}}s:1:"u";a:1:{s:1:"k";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1028;}}}}}}s:1:"K";a:7:{s:1:"H";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1061;}}}}s:1:"J";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1036;}}}}s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:922;}}}}}s:1:"c";a:2:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:310;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1050;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120078;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120130;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119974;}}}}}s:1:"L";a:11:{s:1:"J";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1033;}}}}s:1:"T";a:2:{s:1:";";a:1:{s:9:"codepoint";i:60;}s:9:"codepoint";i:60;}s:1:"a";a:5:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:313;}}}}}s:1:"m";a:1:{s:1:"b";a:1:{s:1:"d";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:923;}}}}}s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10218;}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8466;}}}}}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8606;}}}}s:1:"c";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:317;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:315;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1051;}}}s:1:"e";a:2:{s:1:"f";a:1:{s:1:"t";a:10:{s:1:"A";a:2:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"B";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10216;}}}}}}}}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8592;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8676;}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8646;}}}}}}}}}}}}}}}}s:1:"C";a:1:{s:1:"e";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8968;}}}}}}}}s:1:"D";a:1:{s:1:"o";a:2:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"B";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10214;}}}}}}}}}}}}s:1:"w";a:1:{s:1:"n";a:2:{s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10593;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8643;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10585;}}}}}}}}}}}}}}s:1:"F";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8970;}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8596;}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10574;}}}}}}}}}}}}s:1:"T";a:2:{s:1:"e";a:1:{s:1:"e";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8867;}s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8612;}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10586;}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8882;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10703;}}}}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8884;}}}}}}}}}}}}}}s:1:"U";a:1:{s:1:"p";a:3:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10577;}}}}}}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10592;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8639;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10584;}}}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8636;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10578;}}}}}}}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8656;}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8660;}}}}}}}}}}}}}s:1:"s";a:1:{s:1:"s";a:6:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8922;}}}}}}}}}}}}}s:1:"F";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8806;}}}}}}}}}}s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8822;}}}}}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10913;}}}}}s:1:"S";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10877;}}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8818;}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120079;}}}s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8920;}s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8666;}}}}}}}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:319;}}}}}}s:1:"o";a:3:{s:1:"n";a:1:{s:1:"g";a:4:{s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10229;}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10231;}}}}}}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10230;}}}}}}}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10232;}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10234;}}}}}}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10233;}}}}}}}}}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120131;}}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"r";a:2:{s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8601;}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8600;}}}}}}}}}}}}}}}s:1:"s";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8466;}}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8624;}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:321;}}}}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8810;}}}s:1:"M";a:8:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10501;}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1052;}}}s:1:"e";a:2:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8287;}}}}}}}}}}s:1:"l";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8499;}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120080;}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:"P";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8723;}}}}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120132;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8499;}}}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:924;}}}s:1:"N";a:9:{s:1:"J";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1034;}}}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:323;}}}}}}s:1:"c";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:327;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:325;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1053;}}}s:1:"e";a:3:{s:1:"g";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"v";a:1:{s:1:"e";a:3:{s:1:"M";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8203;}}}}}}}}}}}}s:1:"T";a:1:{s:1:"h";a:1:{s:1:"i";a:2:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8203;}}}}}}}}s:1:"n";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8203;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"y";a:1:{s:1:"T";a:1:{s:1:"h";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8203;}}}}}}}}}}}}}}}}}}}}s:1:"s";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"d";a:2:{s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8811;}}}}}}}}}}}}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:"L";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8810;}}}}}}}}}}}}}s:1:"w";a:1:{s:1:"L";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10;}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120081;}}}s:1:"o";a:4:{s:1:"B";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8288;}}}}}}s:1:"n";a:1:{s:1:"B";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"k";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:160;}}}}}}}}}}}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8469;}}}s:1:"t";a:11:{s:1:";";a:1:{s:9:"codepoint";i:10988;}s:1:"C";a:2:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8802;}}}}}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:"C";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8813;}}}}}}}s:1:"D";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8742;}}}}}}}}}}}}}}}}}}s:1:"E";a:3:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8713;}}}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8800;}}}}}s:1:"x";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8708;}}}}}}}s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8815;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8817;}}}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8825;}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8821;}}}}}}}}}}}}}s:1:"L";a:1:{s:1:"e";a:2:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"T";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8938;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8940;}}}}}}}}}}}}}}}}s:1:"s";a:1:{s:1:"s";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8814;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8816;}}}}}}s:1:"G";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8824;}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8820;}}}}}}}}}}s:1:"P";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8832;}s:1:"S";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8928;}}}}}}}}}}}}}}}}}}}s:1:"R";a:2:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"E";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8716;}}}}}}}}}}}}}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"T";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8939;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8941;}}}}}}}}}}}}}}}}}}}s:1:"S";a:2:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"S";a:1:{s:1:"u";a:2:{s:1:"b";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8930;}}}}}}}}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8931;}}}}}}}}}}}}}}}}}}}s:1:"u";a:3:{s:1:"b";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8840;}}}}}}}}}}s:1:"c";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8833;}s:1:"S";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8929;}}}}}}}}}}}}}}}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8841;}}}}}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8769;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8772;}}}}}}s:1:"F";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8775;}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8777;}}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8740;}}}}}}}}}}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119977;}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:209;}s:9:"codepoint";i:209;}}}}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:925;}}}s:1:"O";a:14:{s:1:"E";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:338;}}}}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:211;}s:9:"codepoint";i:211;}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:212;}s:9:"codepoint";i:212;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1054;}}}s:1:"d";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:336;}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120082;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:210;}s:9:"codepoint";i:210;}}}}}s:1:"m";a:3:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:332;}}}}s:1:"e";a:1:{s:1:"g";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:937;}}}}s:1:"i";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:927;}}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120134;}}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"C";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"l";a:1:{s:1:"y";a:2:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"Q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8220;}}}}}}}}}}}}s:1:"Q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8216;}}}}}}}}}}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10836;}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119978;}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:2:{s:1:";";a:1:{s:9:"codepoint";i:216;}s:9:"codepoint";i:216;}}}}}s:1:"t";a:1:{s:1:"i";a:2:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:213;}s:9:"codepoint";i:213;}}}s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10807;}}}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:214;}s:9:"codepoint";i:214;}}}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"r";a:2:{s:1:"B";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:175;}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"c";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9182;}}s:1:"k";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9140;}}}}}}}}s:1:"P";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9180;}}}}}}}}}}}}}}}}s:1:"P";a:9:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"D";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8706;}}}}}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1055;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120083;}}}s:1:"h";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:934;}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:928;}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:"M";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:177;}}}}}}}}}s:1:"o";a:2:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8460;}}}}}}}}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8473;}}}}s:1:"r";a:4:{s:1:";";a:1:{s:9:"codepoint";i:10939;}s:1:"e";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:"s";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8826;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10927;}}}}}}s:1:"S";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8828;}}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8830;}}}}}}}}}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8243;}}}}s:1:"o";a:2:{s:1:"d";a:1:{s:1:"u";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8719;}}}}}s:1:"p";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8759;}s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8733;}}}}}}}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119979;}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:936;}}}}s:1:"Q";a:4:{s:1:"U";a:1:{s:1:"O";a:1:{s:1:"T";a:2:{s:1:";";a:1:{s:9:"codepoint";i:34;}s:9:"codepoint";i:34;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120084;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8474;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119980;}}}}}s:1:"R";a:12:{s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10512;}}}}}s:1:"E";a:1:{s:1:"G";a:2:{s:1:";";a:1:{s:9:"codepoint";i:174;}s:9:"codepoint";i:174;}}s:1:"a";a:3:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:340;}}}}}s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10219;}}}s:1:"r";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8608;}s:1:"t";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10518;}}}}}}s:1:"c";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:344;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:342;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1056;}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8476;}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:2:{s:1:"E";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8715;}}}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"b";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8651;}}}}}}}}}}}}s:1:"U";a:1:{s:1:"p";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"b";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10607;}}}}}}}}}}}}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8476;}}}s:1:"h";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:929;}}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:8:{s:1:"A";a:2:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"B";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10217;}}}}}}}}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8594;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8677;}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8644;}}}}}}}}}}}}}}}s:1:"C";a:1:{s:1:"e";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8969;}}}}}}}}s:1:"D";a:1:{s:1:"o";a:2:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"B";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10215;}}}}}}}}}}}}s:1:"w";a:1:{s:1:"n";a:2:{s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10589;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8642;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10581;}}}}}}}}}}}}}}s:1:"F";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8971;}}}}}}s:1:"T";a:2:{s:1:"e";a:1:{s:1:"e";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8866;}s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8614;}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10587;}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8883;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10704;}}}}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8885;}}}}}}}}}}}}}}s:1:"U";a:1:{s:1:"p";a:3:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10575;}}}}}}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10588;}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8638;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10580;}}}}}}}}}}}}s:1:"V";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8640;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10579;}}}}}}}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8658;}}}}}}}}}}s:1:"o";a:2:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8477;}}}s:1:"u";a:1:{s:1:"n";a:1:{s:1:"d";a:1:{s:1:"I";a:1:{s:1:"m";a:1:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10608;}}}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8667;}}}}}}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8475;}}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8625;}}}s:1:"u";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"D";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"y";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10740;}}}}}}}}}}}}s:1:"S";a:13:{s:1:"H";a:2:{s:1:"C";a:1:{s:1:"H";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1065;}}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1064;}}}}s:1:"O";a:1:{s:1:"F";a:1:{s:1:"T";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1068;}}}}}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:346;}}}}}}s:1:"c";a:5:{s:1:";";a:1:{s:9:"codepoint";i:10940;}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:352;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:350;}}}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:348;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1057;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120086;}}}s:1:"h";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"t";a:4:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8595;}}}}}}}}}}s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8592;}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8594;}}}}}}}}}}}s:1:"U";a:1:{s:1:"p";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8593;}}}}}}}}}}}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:931;}}}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"C";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8728;}}}}}}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120138;}}}}s:1:"q";a:2:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8730;}}}s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:4:{s:1:";";a:1:{s:9:"codepoint";i:9633;}s:1:"I";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8851;}}}}}}}}}}}}}s:1:"S";a:1:{s:1:"u";a:2:{s:1:"b";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8847;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8849;}}}}}}}}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8848;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8850;}}}}}}}}}}}}}}s:1:"U";a:1:{s:1:"n";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8852;}}}}}}}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119982;}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8902;}}}}s:1:"u";a:4:{s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8912;}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8912;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8838;}}}}}}}}}}s:1:"c";a:2:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"s";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8827;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10928;}}}}}}s:1:"S";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8829;}}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8831;}}}}}}}}}}}s:1:"h";a:1:{s:1:"T";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8715;}}}}}}}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8721;}}s:1:"p";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8913;}s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8835;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8839;}}}}}}}}}}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8913;}}}}}}}s:1:"T";a:11:{s:1:"H";a:1:{s:1:"O";a:1:{s:1:"R";a:1:{s:1:"N";a:2:{s:1:";";a:1:{s:9:"codepoint";i:222;}s:9:"codepoint";i:222;}}}}s:1:"R";a:1:{s:1:"A";a:1:{s:1:"D";a:1:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8482;}}}}}s:1:"S";a:2:{s:1:"H";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1035;}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1062;}}}}s:1:"a";a:2:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9;}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:932;}}}s:1:"c";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:356;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:354;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1058;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120087;}}}s:1:"h";a:2:{s:1:"e";a:2:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8756;}}}}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:920;}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8201;}}}}}}}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8764;}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8771;}}}}}}s:1:"F";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8773;}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8776;}}}}}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120139;}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8411;}}}}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119983;}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:358;}}}}}}}s:1:"U";a:14:{s:1:"a";a:2:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:218;}s:9:"codepoint";i:218;}}}}s:1:"r";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8607;}s:1:"o";a:1:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10569;}}}}}}}}s:1:"b";a:1:{s:1:"r";a:2:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1038;}}}s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:364;}}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:219;}s:9:"codepoint";i:219;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1059;}}}s:1:"d";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:368;}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120088;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:217;}s:9:"codepoint";i:217;}}}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:362;}}}}}s:1:"n";a:2:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:"r";a:2:{s:1:"B";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:818;}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"c";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9183;}}s:1:"k";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9141;}}}}}}}}s:1:"P";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9181;}}}}}}}}}}}}}}}s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8899;}s:1:"P";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8846;}}}}}}}}}s:1:"o";a:2:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:370;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120140;}}}}s:1:"p";a:8:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8593;}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10514;}}}}s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8645;}}}}}}}}}}}}}}}s:1:"D";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8597;}}}}}}}}}}s:1:"E";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"b";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10606;}}}}}}}}}}}}s:1:"T";a:1:{s:1:"e";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8869;}s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8613;}}}}}}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8657;}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8661;}}}}}}}}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"r";a:2:{s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8598;}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8599;}}}}}}}}}}}}}}s:1:"s";a:1:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:978;}s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:933;}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:366;}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119984;}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:360;}}}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:220;}s:9:"codepoint";i:220;}}}}s:1:"V";a:9:{s:1:"D";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8875;}}}}}s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10987;}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1042;}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8873;}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10982;}}}}}}s:1:"e";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8897;}}s:1:"r";a:3:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8214;}}}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8214;}s:1:"i";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:4:{s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8739;}}}}s:1:"L";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:124;}}}}}s:1:"S";a:1:{s:1:"e";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10072;}}}}}}}}}}s:1:"T";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8768;}}}}}}}}}}}s:1:"y";a:1:{s:1:"T";a:1:{s:1:"h";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8202;}}}}}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120089;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120141;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119985;}}}}s:1:"v";a:1:{s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8874;}}}}}}}s:1:"W";a:5:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:372;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8896;}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120090;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120142;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119986;}}}}}s:1:"X";a:4:{s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120091;}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:926;}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120143;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119987;}}}}}s:1:"Y";a:9:{s:1:"A";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1071;}}}}s:1:"I";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1031;}}}}s:1:"U";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1070;}}}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:221;}s:9:"codepoint";i:221;}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:374;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1067;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120092;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120144;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119988;}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:376;}}}}}s:1:"Z";a:8:{s:1:"H";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1046;}}}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:377;}}}}}}s:1:"c";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:381;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1047;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:379;}}}}s:1:"e";a:2:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"W";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:"S";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8203;}}}}}}}}}}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:918;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8488;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8484;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119989;}}}}}s:1:"a";a:16:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:225;}s:9:"codepoint";i:225;}}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:259;}}}}}}s:1:"c";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8766;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8767;}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:226;}s:9:"codepoint";i:226;}}}s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:180;}s:9:"codepoint";i:180;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1072;}}}s:1:"e";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:230;}s:9:"codepoint";i:230;}}}}s:1:"f";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8289;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120094;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:224;}s:9:"codepoint";i:224;}}}}}s:1:"l";a:2:{s:1:"e";a:2:{s:1:"f";a:1:{s:1:"s";a:1:{s:1:"y";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8501;}}}}}s:1:"p";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8501;}}}}s:1:"p";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:945;}}}}}s:1:"m";a:2:{s:1:"a";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:257;}}}s:1:"l";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10815;}}}}s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:38;}s:9:"codepoint";i:38;}}s:1:"n";a:2:{s:1:"d";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8743;}s:1:"a";a:1:{s:1:"n";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10837;}}}}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10844;}}s:1:"s";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10840;}}}}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10842;}}}s:1:"g";a:7:{s:1:";";a:1:{s:9:"codepoint";i:8736;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10660;}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8736;}}}s:1:"m";a:1:{s:1:"s";a:1:{s:1:"d";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8737;}s:1:"a";a:8:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10664;}}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10665;}}s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10666;}}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10667;}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10668;}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10669;}}s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10670;}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10671;}}}}}}s:1:"r";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8735;}s:1:"v";a:1:{s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8894;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10653;}}}}}}s:1:"s";a:2:{s:1:"p";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8738;}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8491;}}}s:1:"z";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9084;}}}}}}}s:1:"o";a:2:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:261;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120146;}}}}s:1:"p";a:7:{s:1:";";a:1:{s:9:"codepoint";i:8776;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10864;}}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10863;}}}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8778;}}s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8779;}}}s:1:"o";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:39;}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8776;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8778;}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:229;}s:9:"codepoint";i:229;}}}}s:1:"s";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119990;}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:42;}}s:1:"y";a:1:{s:1:"m";a:1:{s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8776;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8781;}}}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:227;}s:9:"codepoint";i:227;}}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:228;}s:9:"codepoint";i:228;}}}s:1:"w";a:2:{s:1:"c";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8755;}}}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10769;}}}}}}s:1:"b";a:16:{s:1:"N";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10989;}}}}s:1:"a";a:2:{s:1:"c";a:1:{s:1:"k";a:4:{s:1:"c";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8780;}}}}}s:1:"e";a:1:{s:1:"p";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1014;}}}}}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8245;}}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8765;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8909;}}}}}}}}s:1:"r";a:2:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8893;}}}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8965;}s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8965;}}}}}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9141;}s:1:"t";a:1:{s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9142;}}}}}}}}s:1:"c";a:2:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8780;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1073;}}}s:1:"d";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8222;}}}}}s:1:"e";a:5:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"u";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8757;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8757;}}}}}}s:1:"m";a:1:{s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10672;}}}}}}s:1:"p";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1014;}}}}s:1:"r";a:1:{s:1:"n";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8492;}}}}}s:1:"t";a:3:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:946;}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8502;}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8812;}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120095;}}}s:1:"i";a:1:{s:1:"g";a:7:{s:1:"c";a:3:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8898;}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9711;}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8899;}}}}s:1:"o";a:3:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10752;}}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10753;}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10754;}}}}}}}s:1:"s";a:2:{s:1:"q";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10758;}}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9733;}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:2:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9661;}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9651;}}}}}}}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10756;}}}}}}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8897;}}}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8896;}}}}}}}}s:1:"k";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10509;}}}}}}s:1:"l";a:3:{s:1:"a";a:2:{s:1:"c";a:1:{s:1:"k";a:3:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"z";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10731;}}}}}}}}s:1:"s";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9642;}}}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:4:{s:1:";";a:1:{s:9:"codepoint";i:9652;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9662;}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9666;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9656;}}}}}}}}}}}}}}}}s:1:"n";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9251;}}}}s:1:"k";a:2:{i:1;a:2:{i:2;a:1:{s:1:";";a:1:{s:9:"codepoint";i:9618;}}i:4;a:1:{s:1:";";a:1:{s:9:"codepoint";i:9617;}}}i:3;a:1:{i:4;a:1:{s:1:";";a:1:{s:9:"codepoint";i:9619;}}}}s:1:"o";a:1:{s:1:"c";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9608;}}}}}s:1:"n";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8976;}}}}s:1:"o";a:4:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120147;}}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8869;}s:1:"t";a:1:{s:1:"o";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8869;}}}}}s:1:"w";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8904;}}}}}s:1:"x";a:12:{s:1:"D";a:4:{s:1:"L";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9559;}}s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9556;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9558;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9555;}}}s:1:"H";a:5:{s:1:";";a:1:{s:9:"codepoint";i:9552;}s:1:"D";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9574;}}s:1:"U";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9577;}}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9572;}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9575;}}}s:1:"U";a:4:{s:1:"L";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9565;}}s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9562;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9564;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9561;}}}s:1:"V";a:7:{s:1:";";a:1:{s:9:"codepoint";i:9553;}s:1:"H";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9580;}}s:1:"L";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9571;}}s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9568;}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9579;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9570;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9567;}}}s:1:"b";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10697;}}}}s:1:"d";a:4:{s:1:"L";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9557;}}s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9554;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9488;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9484;}}}s:1:"h";a:5:{s:1:";";a:1:{s:9:"codepoint";i:9472;}s:1:"D";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9573;}}s:1:"U";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9576;}}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9516;}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9524;}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8863;}}}}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8862;}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8864;}}}}}}s:1:"u";a:4:{s:1:"L";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9563;}}s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9560;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9496;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9492;}}}s:1:"v";a:7:{s:1:";";a:1:{s:9:"codepoint";i:9474;}s:1:"H";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9578;}}s:1:"L";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9569;}}s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9566;}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9532;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9508;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9500;}}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8245;}}}}}}s:1:"r";a:2:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:728;}}}}s:1:"v";a:1:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:166;}s:9:"codepoint";i:166;}}}}}s:1:"s";a:4:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119991;}}}s:1:"e";a:1:{s:1:"m";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8271;}}}}s:1:"i";a:1:{s:1:"m";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8765;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8909;}}}}s:1:"o";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:92;}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10693;}}}}}s:1:"u";a:2:{s:1:"l";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8226;}s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8226;}}}}}s:1:"m";a:1:{s:1:"p";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8782;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10926;}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8783;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8783;}}}}}}}s:1:"c";a:15:{s:1:"a";a:3:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:263;}}}}}s:1:"p";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8745;}s:1:"a";a:1:{s:1:"n";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10820;}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10825;}}}}}}s:1:"c";a:2:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10827;}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10823;}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10816;}}}}}s:1:"r";a:2:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8257;}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:711;}}}}}s:1:"c";a:4:{s:1:"a";a:2:{s:1:"p";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10829;}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:269;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:231;}s:9:"codepoint";i:231;}}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:265;}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10828;}s:1:"s";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10832;}}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:267;}}}}s:1:"e";a:3:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:184;}s:9:"codepoint";i:184;}}}s:1:"m";a:1:{s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10674;}}}}}}s:1:"n";a:1:{s:1:"t";a:3:{s:1:";";a:1:{s:9:"codepoint";i:162;}s:9:"codepoint";i:162;s:1:"e";a:1:{s:1:"r";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:183;}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120096;}}}s:1:"h";a:3:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1095;}}}s:1:"e";a:1:{s:1:"c";a:1:{s:1:"k";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10003;}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10003;}}}}}}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:967;}}}s:1:"i";a:1:{s:1:"r";a:7:{s:1:";";a:1:{s:9:"codepoint";i:9675;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10691;}}s:1:"c";a:3:{s:1:";";a:1:{s:9:"codepoint";i:710;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8791;}}}s:1:"l";a:1:{s:1:"e";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8634;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8635;}}}}}}}}}}}s:1:"d";a:5:{s:1:"R";a:1:{s:1:";";a:1:{s:9:"codepoint";i:174;}}s:1:"S";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9416;}}s:1:"a";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8859;}}}}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8858;}}}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8861;}}}}}}}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8791;}}s:1:"f";a:1:{s:1:"n";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10768;}}}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10991;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10690;}}}}}}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9827;}s:1:"u";a:1:{s:1:"i";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9827;}}}}}}}}s:1:"o";a:4:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:58;}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8788;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8788;}}}}}}s:1:"m";a:2:{s:1:"m";a:1:{s:1:"a";a:2:{s:1:";";a:1:{s:9:"codepoint";i:44;}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:64;}}}}s:1:"p";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8705;}s:1:"f";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8728;}}}s:1:"l";a:1:{s:1:"e";a:2:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8705;}}}}}s:1:"x";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8450;}}}}}}}}s:1:"n";a:2:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8773;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10861;}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8750;}}}}}s:1:"p";a:3:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120148;}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8720;}}}}s:1:"y";a:3:{s:1:";";a:1:{s:9:"codepoint";i:169;}s:9:"codepoint";i:169;s:1:"s";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8471;}}}}}}s:1:"r";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8629;}}}}s:1:"o";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10007;}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119992;}}}s:1:"u";a:2:{s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10959;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10961;}}}s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10960;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10962;}}}}}s:1:"t";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8943;}}}}}s:1:"u";a:7:{s:1:"d";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:2:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10552;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10549;}}}}}}s:1:"e";a:2:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8926;}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8927;}}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8630;}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10557;}}}}}}s:1:"p";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8746;}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10824;}}}}}}s:1:"c";a:2:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10822;}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10826;}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8845;}}}}s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10821;}}}}s:1:"r";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8631;}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10556;}}}}}s:1:"l";a:1:{s:1:"y";a:3:{s:1:"e";a:1:{s:1:"q";a:2:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8926;}}}}}s:1:"s";a:1:{s:1:"u";a:1:{s:1:"c";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8927;}}}}}}}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8910;}}}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8911;}}}}}}}}s:1:"r";a:1:{s:1:"e";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:164;}s:9:"codepoint";i:164;}}}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8630;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8631;}}}}}}}}}}}}}}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8910;}}}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8911;}}}}}s:1:"w";a:2:{s:1:"c";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8754;}}}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8753;}}}}}s:1:"y";a:1:{s:1:"l";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9005;}}}}}}}s:1:"d";a:19:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8659;}}}}s:1:"H";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10597;}}}}s:1:"a";a:4:{s:1:"g";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8224;}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8504;}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8595;}}}s:1:"s";a:1:{s:1:"h";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8208;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8867;}}}}}s:1:"b";a:2:{s:1:"k";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10511;}}}}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:733;}}}}}s:1:"c";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:271;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1076;}}}s:1:"d";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8518;}s:1:"a";a:2:{s:1:"g";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8225;}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8650;}}}}s:1:"o";a:1:{s:1:"t";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10871;}}}}}}}s:1:"e";a:3:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:176;}s:9:"codepoint";i:176;}s:1:"l";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:948;}}}}s:1:"m";a:1:{s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10673;}}}}}}}s:1:"f";a:2:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10623;}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120097;}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8643;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8642;}}}}}s:1:"i";a:5:{s:1:"a";a:1:{s:1:"m";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8900;}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"d";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8900;}s:1:"s";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9830;}}}}}}}}s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9830;}}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:168;}}s:1:"g";a:1:{s:1:"a";a:1:{s:1:"m";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:989;}}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8946;}}}}s:1:"v";a:3:{s:1:";";a:1:{s:9:"codepoint";i:247;}s:1:"i";a:1:{s:1:"d";a:1:{s:1:"e";a:3:{s:1:";";a:1:{s:9:"codepoint";i:247;}s:9:"codepoint";i:247;s:1:"o";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8903;}}}}}}}}}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8903;}}}}}}s:1:"j";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1106;}}}}s:1:"l";a:1:{s:1:"c";a:2:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8990;}}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8973;}}}}}}s:1:"o";a:5:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:36;}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120149;}}}s:1:"t";a:5:{s:1:";";a:1:{s:9:"codepoint";i:729;}s:1:"e";a:1:{s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8784;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8785;}}}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8760;}}}}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8724;}}}}}s:1:"s";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8865;}}}}}}}}s:1:"u";a:1:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8966;}}}}}}}}}}}}}s:1:"w";a:1:{s:1:"n";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8595;}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8650;}}}}}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8643;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8642;}}}}}}}}}}}}}}}}s:1:"r";a:2:{s:1:"b";a:1:{s:1:"k";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10512;}}}}}}}s:1:"c";a:2:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8991;}}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8972;}}}}}}s:1:"s";a:3:{s:1:"c";a:2:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119993;}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1109;}}}s:1:"o";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10742;}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:273;}}}}}}s:1:"t";a:2:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8945;}}}}s:1:"r";a:1:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9663;}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9662;}}}}}s:1:"u";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8693;}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10607;}}}}}s:1:"w";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10662;}}}}}}}s:1:"z";a:2:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1119;}}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10239;}}}}}}}}}s:1:"e";a:18:{s:1:"D";a:2:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10871;}}}}s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8785;}}}}s:1:"a";a:2:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:233;}s:9:"codepoint";i:233;}}}}s:1:"s";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10862;}}}}}}s:1:"c";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:283;}}}}}s:1:"i";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8790;}s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:234;}s:9:"codepoint";i:234;}}}s:1:"o";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8789;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1101;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:279;}}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8519;}}s:1:"f";a:2:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8786;}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120098;}}}s:1:"g";a:3:{s:1:";";a:1:{s:9:"codepoint";i:10906;}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:232;}s:9:"codepoint";i:232;}}}}s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10902;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10904;}}}}}}s:1:"l";a:4:{s:1:";";a:1:{s:9:"codepoint";i:10905;}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9191;}}}}}}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8467;}}s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10901;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10903;}}}}}}s:1:"m";a:3:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:275;}}}}s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8709;}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8709;}}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8709;}}}}}s:1:"s";a:1:{s:1:"p";a:2:{i:1;a:2:{i:3;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8196;}}i:4;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8197;}}}s:1:";";a:1:{s:9:"codepoint";i:8195;}}}}s:1:"n";a:2:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:331;}}s:1:"s";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8194;}}}}s:1:"o";a:2:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:281;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120150;}}}}s:1:"p";a:3:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8917;}s:1:"s";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10723;}}}}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10865;}}}}s:1:"s";a:1:{s:1:"i";a:3:{s:1:";";a:1:{s:9:"codepoint";i:1013;}s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:949;}}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:949;}}}}}s:1:"q";a:4:{s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8790;}}}}s:1:"o";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8789;}}}}}}s:1:"s";a:2:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8770;}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:2:{s:1:"g";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10902;}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10901;}}}}}}}}}}s:1:"u";a:3:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:61;}}}}s:1:"e";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8799;}}}}s:1:"i";a:1:{s:1:"v";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8801;}s:1:"D";a:1:{s:1:"D";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10872;}}}}}}s:1:"v";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10725;}}}}}}}}s:1:"r";a:2:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8787;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10609;}}}}}s:1:"s";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8495;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8784;}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8770;}}}}s:1:"t";a:2:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:951;}}s:1:"h";a:2:{s:1:";";a:1:{s:9:"codepoint";i:240;}s:9:"codepoint";i:240;}}s:1:"u";a:2:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:235;}s:9:"codepoint";i:235;}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8364;}}}}s:1:"x";a:3:{s:1:"c";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:33;}}}s:1:"i";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8707;}}}}s:1:"p";a:2:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8496;}}}}}}}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8519;}}}}}}}}}}}}}s:1:"f";a:11:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8786;}}}}}}}}}}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1092;}}}s:1:"e";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9792;}}}}}}s:1:"f";a:3:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:64259;}}}}}s:1:"l";a:2:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:64256;}}}s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:64260;}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120099;}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:64257;}}}}}s:1:"l";a:3:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9837;}}}s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:64258;}}}}s:1:"t";a:1:{s:1:"n";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9649;}}}}}s:1:"n";a:1:{s:1:"o";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:402;}}}}s:1:"o";a:2:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120151;}}}s:1:"r";a:2:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8704;}}}}s:1:"k";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8916;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10969;}}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10765;}}}}}}}}s:1:"r";a:2:{s:1:"a";a:2:{s:1:"c";a:6:{i:1;a:6:{i:2;a:2:{s:1:";";a:1:{s:9:"codepoint";i:189;}s:9:"codepoint";i:189;}i:3;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8531;}}i:4;a:2:{s:1:";";a:1:{s:9:"codepoint";i:188;}s:9:"codepoint";i:188;}i:5;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8533;}}i:6;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8537;}}i:8;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8539;}}}i:2;a:2:{i:3;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8532;}}i:5;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8534;}}}i:3;a:3:{i:4;a:2:{s:1:";";a:1:{s:9:"codepoint";i:190;}s:9:"codepoint";i:190;}i:5;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8535;}}i:8;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8540;}}}i:4;a:1:{i:5;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8536;}}}i:5;a:2:{i:6;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8538;}}i:8;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8541;}}}i:7;a:1:{i:8;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8542;}}}}s:1:"s";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8260;}}}}s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8994;}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119995;}}}}}s:1:"g";a:16:{s:1:"E";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8807;}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10892;}}}s:1:"a";a:3:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:501;}}}}}s:1:"m";a:1:{s:1:"m";a:1:{s:1:"a";a:2:{s:1:";";a:1:{s:9:"codepoint";i:947;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:989;}}}}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10886;}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:287;}}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:285;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1075;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:289;}}}}s:1:"e";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8805;}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8923;}}s:1:"q";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8805;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8807;}}s:1:"s";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10878;}}}}}}}s:1:"s";a:4:{s:1:";";a:1:{s:9:"codepoint";i:10878;}s:1:"c";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10921;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10880;}s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10882;}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10884;}}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10900;}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120100;}}}s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8811;}s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8921;}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8503;}}}}}s:1:"j";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1107;}}}}s:1:"l";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8823;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10898;}}s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10917;}}s:1:"j";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10916;}}}s:1:"n";a:4:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8809;}}s:1:"a";a:1:{s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10890;}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10890;}}}}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10888;}s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10888;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8809;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8935;}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120152;}}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:96;}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8458;}}}s:1:"i";a:1:{s:1:"m";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8819;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10894;}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10896;}}}}}s:1:"t";a:7:{s:1:";";a:1:{s:9:"codepoint";i:62;}s:9:"codepoint";i:62;s:1:"c";a:2:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10919;}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10874;}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8919;}}}}s:1:"l";a:1:{s:1:"P";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10645;}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10876;}}}}}}s:1:"r";a:5:{s:1:"a";a:2:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10886;}}}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10616;}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8919;}}}}s:1:"e";a:1:{s:1:"q";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8923;}}}}}s:1:"q";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10892;}}}}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8823;}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8819;}}}}}}}s:1:"h";a:10:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8660;}}}}s:1:"a";a:4:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8202;}}}}}s:1:"l";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:189;}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8459;}}}}}s:1:"r";a:2:{s:1:"d";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1098;}}}}s:1:"r";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8596;}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10568;}}}}s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8621;}}}}}s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8463;}}}}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:293;}}}}}s:1:"e";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9829;}s:1:"u";a:1:{s:1:"i";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9829;}}}}}}}}s:1:"l";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8230;}}}}}s:1:"r";a:1:{s:1:"c";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8889;}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120101;}}}s:1:"k";a:1:{s:1:"s";a:2:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10533;}}}}}}s:1:"w";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10534;}}}}}}}}s:1:"o";a:5:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8703;}}}}s:1:"m";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8763;}}}}}s:1:"o";a:1:{s:1:"k";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8617;}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8618;}}}}}}}}}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120153;}}}s:1:"r";a:1:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8213;}}}}}}s:1:"s";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119997;}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8463;}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:295;}}}}}}s:1:"y";a:2:{s:1:"b";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8259;}}}}}s:1:"p";a:1:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8208;}}}}}}}s:1:"i";a:15:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:237;}s:9:"codepoint";i:237;}}}}}s:1:"c";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8291;}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:238;}s:9:"codepoint";i:238;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1080;}}}s:1:"e";a:2:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1077;}}}s:1:"x";a:1:{s:1:"c";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:161;}s:9:"codepoint";i:161;}}}}s:1:"f";a:2:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8660;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120102;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:236;}s:9:"codepoint";i:236;}}}}}s:1:"i";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8520;}s:1:"i";a:2:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10764;}}}}s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8749;}}}}s:1:"n";a:1:{s:1:"f";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10716;}}}}}s:1:"o";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8489;}}}}}s:1:"j";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:307;}}}}}s:1:"m";a:3:{s:1:"a";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:299;}}}s:1:"g";a:3:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8465;}}s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8464;}}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8465;}}}}}}s:1:"t";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:305;}}}}s:1:"o";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8887;}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:437;}}}}}s:1:"n";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8712;}s:1:"c";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8453;}}}}}s:1:"f";a:1:{s:1:"i";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8734;}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10717;}}}}}}}s:1:"o";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:305;}}}}}s:1:"t";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8747;}s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8890;}}}}s:1:"e";a:2:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8484;}}}}}s:1:"r";a:1:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8890;}}}}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10775;}}}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10812;}}}}}}}s:1:"o";a:4:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1105;}}}s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:303;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120154;}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:953;}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10812;}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:191;}s:9:"codepoint";i:191;}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119998;}}}s:1:"i";a:1:{s:1:"n";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8712;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8953;}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8949;}}}}s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8948;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8947;}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8712;}}}}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8290;}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:297;}}}}}}s:1:"u";a:2:{s:1:"k";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1110;}}}}s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:239;}s:9:"codepoint";i:239;}}}}s:1:"j";a:6:{s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:309;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1081;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120103;}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:567;}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120155;}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:119999;}}}s:1:"e";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1112;}}}}}}s:1:"u";a:1:{s:1:"k";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1108;}}}}}}s:1:"k";a:8:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"a";a:2:{s:1:";";a:1:{s:9:"codepoint";i:954;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1008;}}}}}}s:1:"c";a:2:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:311;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1082;}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120104;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:312;}}}}}}s:1:"h";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1093;}}}}s:1:"j";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1116;}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120156;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120000;}}}}}s:1:"l";a:22:{s:1:"A";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8666;}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8656;}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10523;}}}}}}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10510;}}}}}s:1:"E";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8806;}s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10891;}}}s:1:"H";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10594;}}}}s:1:"a";a:9:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:314;}}}}}s:1:"e";a:1:{s:1:"m";a:1:{s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10676;}}}}}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8466;}}}}}s:1:"m";a:1:{s:1:"b";a:1:{s:1:"d";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:955;}}}}}s:1:"n";a:1:{s:1:"g";a:3:{s:1:";";a:1:{s:9:"codepoint";i:10216;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10641;}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10216;}}}}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10885;}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:171;}s:9:"codepoint";i:171;}}}s:1:"r";a:1:{s:1:"r";a:8:{s:1:";";a:1:{s:9:"codepoint";i:8592;}s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8676;}s:1:"f";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10527;}}}}s:1:"f";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10525;}}}s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8617;}}}s:1:"l";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8619;}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10553;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10611;}}}}s:1:"t";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8610;}}}}}s:1:"t";a:3:{s:1:";";a:1:{s:9:"codepoint";i:10923;}s:1:"a";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10521;}}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10925;}}}}s:1:"b";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10508;}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10098;}}}}s:1:"r";a:2:{s:1:"a";a:1:{s:1:"c";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:123;}}s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:91;}}}}s:1:"k";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10635;}}s:1:"s";a:1:{s:1:"l";a:2:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10639;}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10637;}}}}}}}s:1:"c";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:318;}}}}}s:1:"e";a:2:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:316;}}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8968;}}}}s:1:"u";a:1:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:123;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1083;}}}s:1:"d";a:4:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10550;}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8220;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8222;}}}}}s:1:"r";a:2:{s:1:"d";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10599;}}}}}s:1:"u";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10571;}}}}}}}s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8626;}}}}s:1:"e";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8804;}s:1:"f";a:1:{s:1:"t";a:5:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8592;}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8610;}}}}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8637;}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8636;}}}}}}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8647;}}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8596;}s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8646;}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8651;}}}}}}}}}s:1:"s";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8621;}}}}}}}}}}}}}}}}s:1:"t";a:1:{s:1:"h";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8907;}}}}}}}}}}}}}s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8922;}}s:1:"q";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8804;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8806;}}s:1:"s";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10877;}}}}}}}s:1:"s";a:5:{s:1:";";a:1:{s:9:"codepoint";i:10877;}s:1:"c";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10920;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10879;}s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10881;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10883;}}}}}}s:1:"g";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10899;}}}}s:1:"s";a:5:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10885;}}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8918;}}}}s:1:"e";a:1:{s:1:"q";a:2:{s:1:"g";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8922;}}}}s:1:"q";a:1:{s:1:"g";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10891;}}}}}}}s:1:"g";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8822;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8818;}}}}}}}s:1:"f";a:3:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10620;}}}}}s:1:"l";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8970;}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120105;}}}s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8822;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10897;}}}s:1:"h";a:2:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8637;}}s:1:"u";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8636;}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10602;}}}}}s:1:"b";a:1:{s:1:"l";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9604;}}}}}s:1:"j";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1113;}}}}s:1:"l";a:5:{s:1:";";a:1:{s:9:"codepoint";i:8810;}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8647;}}}}s:1:"c";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8990;}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10603;}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9722;}}}}}s:1:"m";a:2:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:320;}}}}}s:1:"o";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9136;}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9136;}}}}}}}}}}s:1:"n";a:4:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8808;}}s:1:"a";a:1:{s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10889;}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10889;}}}}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10887;}s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10887;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8808;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8934;}}}}}s:1:"o";a:8:{s:1:"a";a:2:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10220;}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8701;}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10214;}}}}s:1:"n";a:1:{s:1:"g";a:3:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10229;}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10231;}}}}}}}}}}}}}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10236;}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10230;}}}}}}}}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8619;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8620;}}}}}}}}}}}}}s:1:"p";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10629;}}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120157;}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10797;}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10804;}}}}}}s:1:"w";a:2:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8727;}}}}s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:95;}}}}}s:1:"z";a:3:{s:1:";";a:1:{s:9:"codepoint";i:9674;}s:1:"e";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9674;}}}}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10731;}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:40;}s:1:"l";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10643;}}}}}}s:1:"r";a:5:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8646;}}}}s:1:"c";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8991;}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8651;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10605;}}}}}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8206;}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8895;}}}}}s:1:"s";a:6:{s:1:"a";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8249;}}}}}s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120001;}}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8624;}}s:1:"i";a:1:{s:1:"m";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8818;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10893;}}s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10895;}}}}s:1:"q";a:2:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:91;}}s:1:"u";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8216;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8218;}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:322;}}}}}}s:1:"t";a:9:{s:1:";";a:1:{s:9:"codepoint";i:60;}s:9:"codepoint";i:60;s:1:"c";a:2:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10918;}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10873;}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8918;}}}}s:1:"h";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8907;}}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8905;}}}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10614;}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10875;}}}}}}s:1:"r";a:2:{s:1:"P";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10646;}}}}s:1:"i";a:3:{s:1:";";a:1:{s:9:"codepoint";i:9667;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8884;}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9666;}}}}}s:1:"u";a:1:{s:1:"r";a:2:{s:1:"d";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10570;}}}}}}s:1:"u";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10598;}}}}}}}}s:1:"m";a:14:{s:1:"D";a:1:{s:1:"D";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8762;}}}}}s:1:"a";a:4:{s:1:"c";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:175;}s:9:"codepoint";i:175;}}s:1:"l";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9794;}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10016;}s:1:"e";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10016;}}}}}}s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8614;}s:1:"s";a:1:{s:1:"t";a:1:{s:1:"o";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8614;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8615;}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8612;}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8613;}}}}}}}s:1:"r";a:1:{s:1:"k";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9646;}}}}}}s:1:"c";a:2:{s:1:"o";a:1:{s:1:"m";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10793;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1084;}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8212;}}}}}s:1:"e";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8737;}}}}}}}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120106;}}}s:1:"h";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8487;}}}s:1:"i";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:181;}s:9:"codepoint";i:181;}}}s:1:"d";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8739;}s:1:"a";a:1:{s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:42;}}}}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10992;}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:183;}s:9:"codepoint";i:183;}}}}s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8722;}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8863;}}s:1:"d";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8760;}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10794;}}}}}}}s:1:"l";a:2:{s:1:"c";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10971;}}}s:1:"d";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8230;}}}}s:1:"n";a:1:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8723;}}}}}}s:1:"o";a:2:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8871;}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120158;}}}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8723;}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120002;}}}s:1:"t";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8766;}}}}}}s:1:"u";a:3:{s:1:";";a:1:{s:9:"codepoint";i:956;}s:1:"l";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8888;}}}}}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8888;}}}}}}s:1:"n";a:23:{s:1:"L";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8653;}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8654;}}}}}}}}}}}}}}}s:1:"R";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8655;}}}}}}}}}}}s:1:"V";a:2:{s:1:"D";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8879;}}}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8878;}}}}}}s:1:"a";a:4:{s:1:"b";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8711;}}}}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:324;}}}}}s:1:"p";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8777;}s:1:"o";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:329;}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8777;}}}}}}s:1:"t";a:1:{s:1:"u";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9838;}s:1:"a";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9838;}s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8469;}}}}}}}}s:1:"b";a:1:{s:1:"s";a:1:{s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:160;}s:9:"codepoint";i:160;}}}s:1:"c";a:5:{s:1:"a";a:2:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10819;}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:328;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:326;}}}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8775;}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10818;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1085;}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8211;}}}}}s:1:"e";a:6:{s:1:";";a:1:{s:9:"codepoint";i:8800;}s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8663;}}}}s:1:"a";a:1:{s:1:"r";a:2:{s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10532;}}}s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8599;}s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8599;}}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8802;}}}}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10536;}}}}}s:1:"x";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8708;}s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8708;}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120107;}}}s:1:"g";a:3:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8817;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8817;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8821;}}}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8815;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8815;}}}}s:1:"h";a:3:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8654;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8622;}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10994;}}}}}s:1:"i";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8715;}s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8956;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8954;}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8715;}}}s:1:"j";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1114;}}}}s:1:"l";a:6:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8653;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8602;}}}}s:1:"d";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8229;}}}s:1:"e";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8816;}s:1:"f";a:1:{s:1:"t";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8602;}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8622;}}}}}}}}}}}}}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8816;}}s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8814;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8820;}}}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8814;}s:1:"r";a:1:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8938;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8940;}}}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8740;}}}}s:1:"o";a:2:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120159;}}}s:1:"t";a:4:{s:1:";";a:1:{s:9:"codepoint";i:172;}s:9:"codepoint";i:172;s:1:"i";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8713;}s:1:"v";a:3:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8713;}}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8951;}}s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8950;}}}}}s:1:"n";a:1:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8716;}s:1:"v";a:3:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8716;}}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8958;}}s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8957;}}}}}}}s:1:"p";a:3:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8742;}s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8742;}}}}}}}}s:1:"o";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10772;}}}}}}s:1:"r";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8832;}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8928;}}}}s:1:"e";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8832;}}}}}s:1:"r";a:4:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8655;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8603;}}}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8603;}}}}}}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8939;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8941;}}}}}}s:1:"s";a:7:{s:1:"c";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8833;}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8929;}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120003;}}}s:1:"h";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"t";a:2:{s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8740;}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8742;}}}}}}}}}}}}}s:1:"i";a:1:{s:1:"m";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8769;}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8772;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8772;}}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8740;}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8742;}}}}s:1:"q";a:1:{s:1:"s";a:1:{s:1:"u";a:2:{s:1:"b";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8930;}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8931;}}}}}}s:1:"u";a:3:{s:1:"b";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8836;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8840;}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8840;}}}}}}}s:1:"c";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8833;}}}s:1:"p";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8837;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8841;}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8841;}}}}}}}}}s:1:"t";a:4:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8825;}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:241;}s:9:"codepoint";i:241;}}}}s:1:"l";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8824;}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8938;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8940;}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8939;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8941;}}}}}}}}}}}}}}}}s:1:"u";a:2:{s:1:";";a:1:{s:9:"codepoint";i:957;}s:1:"m";a:3:{s:1:";";a:1:{s:9:"codepoint";i:35;}s:1:"e";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8470;}}}}s:1:"s";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8199;}}}}}s:1:"v";a:6:{s:1:"D";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8877;}}}}}s:1:"H";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10500;}}}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8876;}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"f";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10718;}}}}}}s:1:"l";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10498;}}}}}s:1:"r";a:1:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10499;}}}}}}s:1:"w";a:3:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8662;}}}}s:1:"a";a:1:{s:1:"r";a:2:{s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10531;}}}s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8598;}s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8598;}}}}}}s:1:"n";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10535;}}}}}}}s:1:"o";a:18:{s:1:"S";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9416;}}s:1:"a";a:2:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:243;}s:9:"codepoint";i:243;}}}}s:1:"s";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8859;}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8858;}s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:244;}s:9:"codepoint";i:244;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1086;}}}s:1:"d";a:5:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8861;}}}}s:1:"b";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:337;}}}}}s:1:"i";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10808;}}}s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8857;}}}s:1:"s";a:1:{s:1:"o";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10684;}}}}}}s:1:"e";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:339;}}}}}s:1:"f";a:2:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10687;}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120108;}}}s:1:"g";a:3:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:731;}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:242;}s:9:"codepoint";i:242;}}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10689;}}}s:1:"h";a:2:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10677;}}}}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8486;}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8750;}}}}s:1:"l";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8634;}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10686;}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"s";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10683;}}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8254;}}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10688;}}}s:1:"m";a:3:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:333;}}}}s:1:"e";a:1:{s:1:"g";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:969;}}}}s:1:"i";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:959;}}}}}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10678;}}s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8854;}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120160;}}}}s:1:"p";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10679;}}}s:1:"e";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10681;}}}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8853;}}}}}s:1:"r";a:7:{s:1:";";a:1:{s:9:"codepoint";i:8744;}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8635;}}}}s:1:"d";a:4:{s:1:";";a:1:{s:9:"codepoint";i:10845;}s:1:"e";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8500;}s:1:"o";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8500;}}}}}s:1:"f";a:2:{s:1:";";a:1:{s:9:"codepoint";i:170;}s:9:"codepoint";i:170;}s:1:"m";a:2:{s:1:";";a:1:{s:9:"codepoint";i:186;}s:9:"codepoint";i:186;}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8886;}}}}}s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10838;}}}s:1:"s";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10839;}}}}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10843;}}}s:1:"s";a:3:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8500;}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:2:{s:1:";";a:1:{s:9:"codepoint";i:248;}s:9:"codepoint";i:248;}}}}s:1:"o";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8856;}}}}s:1:"t";a:1:{s:1:"i";a:2:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:245;}s:9:"codepoint";i:245;}}}s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8855;}s:1:"a";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10806;}}}}}}}}s:1:"u";a:1:{s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:246;}s:9:"codepoint";i:246;}}}s:1:"v";a:1:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9021;}}}}}}s:1:"p";a:12:{s:1:"a";a:1:{s:1:"r";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8741;}s:1:"a";a:3:{s:1:";";a:1:{s:9:"codepoint";i:182;}s:9:"codepoint";i:182;s:1:"l";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8741;}}}}}}s:1:"s";a:2:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10995;}}}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:11005;}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8706;}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1087;}}}s:1:"e";a:1:{s:1:"r";a:5:{s:1:"c";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:37;}}}}s:1:"i";a:1:{s:1:"o";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:46;}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8240;}}}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8869;}}s:1:"t";a:1:{s:1:"e";a:1:{s:1:"n";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8241;}}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120109;}}}s:1:"h";a:3:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:966;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:966;}}}s:1:"m";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8499;}}}}}s:1:"o";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9742;}}}}}s:1:"i";a:3:{s:1:";";a:1:{s:9:"codepoint";i:960;}s:1:"t";a:1:{s:1:"c";a:1:{s:1:"h";a:1:{s:1:"f";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8916;}}}}}}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:982;}}}s:1:"l";a:2:{s:1:"a";a:1:{s:1:"n";a:2:{s:1:"c";a:1:{s:1:"k";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8463;}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8462;}}}}s:1:"k";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8463;}}}}}s:1:"u";a:1:{s:1:"s";a:9:{s:1:";";a:1:{s:9:"codepoint";i:43;}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10787;}}}}}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8862;}}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10786;}}}}s:1:"d";a:2:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8724;}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10789;}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10866;}}s:1:"m";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:177;}s:9:"codepoint";i:177;}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10790;}}}}s:1:"t";a:1:{s:1:"w";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10791;}}}}}}}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:177;}}s:1:"o";a:3:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10773;}}}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120161;}}}s:1:"u";a:1:{s:1:"n";a:1:{s:1:"d";a:2:{s:1:";";a:1:{s:9:"codepoint";i:163;}s:9:"codepoint";i:163;}}}}s:1:"r";a:10:{s:1:";";a:1:{s:9:"codepoint";i:8826;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10931;}}s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10935;}}}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8828;}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10927;}s:1:"c";a:6:{s:1:";";a:1:{s:9:"codepoint";i:8826;}s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10935;}}}}}}}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"l";a:1:{s:1:"y";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8828;}}}}}}}}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10927;}}}s:1:"n";a:3:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10937;}}}}}}}s:1:"e";a:1:{s:1:"q";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10933;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8936;}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8830;}}}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8242;}s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8473;}}}}}s:1:"n";a:3:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10933;}}s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10937;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8936;}}}}}s:1:"o";a:3:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8719;}}s:1:"f";a:3:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9006;}}}}}s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8978;}}}}}s:1:"s";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8979;}}}}}}s:1:"p";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8733;}s:1:"t";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8733;}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8830;}}}}s:1:"u";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8880;}}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120005;}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:968;}}}s:1:"u";a:1:{s:1:"n";a:1:{s:1:"c";a:1:{s:1:"s";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8200;}}}}}}}s:1:"q";a:6:{s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120110;}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10764;}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120162;}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8279;}}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120006;}}}}s:1:"u";a:3:{s:1:"a";a:1:{s:1:"t";a:2:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"n";a:1:{s:1:"i";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8461;}}}}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10774;}}}}}}s:1:"e";a:1:{s:1:"s";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:63;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8799;}}}}}}s:1:"o";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:34;}s:9:"codepoint";i:34;}}}}s:1:"r";a:21:{s:1:"A";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8667;}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8658;}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10524;}}}}}}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10511;}}}}}s:1:"H";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10596;}}}}s:1:"a";a:7:{s:1:"c";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10714;}}s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:341;}}}}}s:1:"d";a:1:{s:1:"i";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8730;}}}}s:1:"e";a:1:{s:1:"m";a:1:{s:1:"p";a:1:{s:1:"t";a:1:{s:1:"y";a:1:{s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10675;}}}}}}}s:1:"n";a:1:{s:1:"g";a:4:{s:1:";";a:1:{s:9:"codepoint";i:10217;}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10642;}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10661;}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10217;}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:187;}s:9:"codepoint";i:187;}}}s:1:"r";a:1:{s:1:"r";a:11:{s:1:";";a:1:{s:9:"codepoint";i:8594;}s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10613;}}}s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8677;}s:1:"f";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10528;}}}}s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10547;}}s:1:"f";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10526;}}}s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8618;}}}s:1:"l";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8620;}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10565;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10612;}}}}s:1:"t";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8611;}}}s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8605;}}}}s:1:"t";a:2:{s:1:"a";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10522;}}}}s:1:"i";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8758;}s:1:"n";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8474;}}}}}}}}}s:1:"b";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10509;}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10099;}}}}s:1:"r";a:2:{s:1:"a";a:1:{s:1:"c";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:125;}}s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:93;}}}}s:1:"k";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10636;}}s:1:"s";a:1:{s:1:"l";a:2:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10638;}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10640;}}}}}}}s:1:"c";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:345;}}}}}s:1:"e";a:2:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:343;}}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8969;}}}}s:1:"u";a:1:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:125;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1088;}}}s:1:"d";a:4:{s:1:"c";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10551;}}}s:1:"l";a:1:{s:1:"d";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10601;}}}}}}s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8221;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8221;}}}}}s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8627;}}}}s:1:"e";a:3:{s:1:"a";a:1:{s:1:"l";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8476;}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8475;}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8476;}}}}}s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8477;}}}}s:1:"c";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9645;}}}s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:174;}s:9:"codepoint";i:174;}}s:1:"f";a:3:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10621;}}}}}s:1:"l";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8971;}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120111;}}}s:1:"h";a:2:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8641;}}s:1:"u";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8640;}s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10604;}}}}}s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:961;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1009;}}}}s:1:"i";a:3:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:6:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8594;}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8611;}}}}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8641;}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8640;}}}}}}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8644;}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8652;}}}}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8649;}}}}}}}}}}}}s:1:"s";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8605;}}}}}}}}}}}s:1:"t";a:1:{s:1:"h";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8908;}}}}}}}}}}}}}}s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:730;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8787;}}}}}}}}}}}}s:1:"l";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8644;}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8652;}}}}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8207;}}}s:1:"m";a:1:{s:1:"o";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9137;}s:1:"a";a:1:{s:1:"c";a:1:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9137;}}}}}}}}}}s:1:"n";a:1:{s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10990;}}}}}s:1:"o";a:4:{s:1:"a";a:2:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10221;}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8702;}}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10215;}}}}s:1:"p";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10630;}}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120163;}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10798;}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10805;}}}}}}}s:1:"p";a:2:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:41;}s:1:"g";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10644;}}}}}s:1:"p";a:1:{s:1:"o";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10770;}}}}}}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8649;}}}}}s:1:"s";a:4:{s:1:"a";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8250;}}}}}s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120007;}}}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8625;}}s:1:"q";a:2:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:93;}}s:1:"u";a:1:{s:1:"o";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8217;}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8217;}}}}}}s:1:"t";a:3:{s:1:"h";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8908;}}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8906;}}}}}s:1:"r";a:1:{s:1:"i";a:4:{s:1:";";a:1:{s:9:"codepoint";i:9657;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8885;}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9656;}}s:1:"l";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10702;}}}}}}}}s:1:"u";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10600;}}}}}}}s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8478;}}}s:1:"s";a:19:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:347;}}}}}}s:1:"b";a:1:{s:1:"q";a:1:{s:1:"u";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8218;}}}}}s:1:"c";a:10:{s:1:";";a:1:{s:9:"codepoint";i:8827;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10932;}}s:1:"a";a:2:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10936;}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:353;}}}}}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8829;}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10928;}s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:351;}}}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:349;}}}}s:1:"n";a:3:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10934;}}s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10938;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8937;}}}}}s:1:"p";a:1:{s:1:"o";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10771;}}}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8831;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1089;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8901;}s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8865;}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10854;}}}}}s:1:"e";a:7:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8664;}}}}s:1:"a";a:1:{s:1:"r";a:2:{s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10533;}}}s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8600;}s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8600;}}}}}}s:1:"c";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:167;}s:9:"codepoint";i:167;}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:59;}}}s:1:"s";a:1:{s:1:"w";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10537;}}}}}s:1:"t";a:1:{s:1:"m";a:2:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8726;}}}}}s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8726;}}}}s:1:"x";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10038;}}}}s:1:"f";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:120112;}s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8994;}}}}}}s:1:"h";a:4:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9839;}}}}s:1:"c";a:2:{s:1:"h";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1097;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1096;}}}s:1:"o";a:1:{s:1:"r";a:1:{s:1:"t";a:2:{s:1:"m";a:1:{s:1:"i";a:1:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8739;}}}}s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8741;}}}}}}}}}}}}s:1:"y";a:2:{s:1:";";a:1:{s:9:"codepoint";i:173;}s:9:"codepoint";i:173;}}s:1:"i";a:2:{s:1:"g";a:1:{s:1:"m";a:1:{s:1:"a";a:3:{s:1:";";a:1:{s:9:"codepoint";i:963;}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:962;}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:962;}}}}}s:1:"m";a:8:{s:1:";";a:1:{s:9:"codepoint";i:8764;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10858;}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8771;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8771;}}}s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10910;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10912;}}}s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10909;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10911;}}}s:1:"n";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8774;}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10788;}}}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10610;}}}}}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8592;}}}}}s:1:"m";a:4:{s:1:"a";a:2:{s:1:"l";a:1:{s:1:"l";a:1:{s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"m";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8726;}}}}}}}}}}}s:1:"s";a:1:{s:1:"h";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10803;}}}}}s:1:"e";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"s";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10724;}}}}}}}s:1:"i";a:2:{s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8739;}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8995;}}}}s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10922;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10924;}}}}s:1:"o";a:3:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1100;}}}}}s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:47;}s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10692;}s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9023;}}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120164;}}}}s:1:"p";a:1:{s:1:"a";a:2:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:"s";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9824;}s:1:"u";a:1:{s:1:"i";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9824;}}}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8741;}}}}s:1:"q";a:3:{s:1:"c";a:2:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8851;}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8852;}}}}s:1:"s";a:1:{s:1:"u";a:2:{s:1:"b";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8847;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8849;}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8847;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8849;}}}}}}}s:1:"p";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8848;}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8850;}}s:1:"s";a:1:{s:1:"e";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8848;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8850;}}}}}}}}}s:1:"u";a:3:{s:1:";";a:1:{s:9:"codepoint";i:9633;}s:1:"a";a:1:{s:1:"r";a:2:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9633;}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9642;}}}}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9642;}}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8594;}}}}}s:1:"s";a:4:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120008;}}}s:1:"e";a:1:{s:1:"t";a:1:{s:1:"m";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8726;}}}}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8995;}}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8902;}}}}}}s:1:"t";a:2:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9734;}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9733;}}}}s:1:"r";a:2:{s:1:"a";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:2:{s:1:"e";a:1:{s:1:"p";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1013;}}}}}}}}s:1:"p";a:1:{s:1:"h";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:981;}}}}}}}}}s:1:"n";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:175;}}}}}s:1:"u";a:5:{s:1:"b";a:9:{s:1:";";a:1:{s:9:"codepoint";i:8834;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10949;}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10941;}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8838;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10947;}}}}}s:1:"m";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10945;}}}}}s:1:"n";a:2:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10955;}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8842;}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10943;}}}}}s:1:"r";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10617;}}}}}s:1:"s";a:3:{s:1:"e";a:1:{s:1:"t";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8834;}s:1:"e";a:1:{s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8838;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10949;}}}}s:1:"n";a:1:{s:1:"e";a:1:{s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8842;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10955;}}}}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10951;}}}s:1:"u";a:2:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10965;}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10963;}}}}}s:1:"c";a:1:{s:1:"c";a:6:{s:1:";";a:1:{s:9:"codepoint";i:8827;}s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10936;}}}}}}}s:1:"c";a:1:{s:1:"u";a:1:{s:1:"r";a:1:{s:1:"l";a:1:{s:1:"y";a:1:{s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8829;}}}}}}}}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10928;}}}s:1:"n";a:3:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10938;}}}}}}}s:1:"e";a:1:{s:1:"q";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10934;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8937;}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8831;}}}}}}s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8721;}}s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9834;}}}s:1:"p";a:13:{i:1;a:2:{s:1:";";a:1:{s:9:"codepoint";i:185;}s:9:"codepoint";i:185;}i:2;a:2:{s:1:";";a:1:{s:9:"codepoint";i:178;}s:9:"codepoint";i:178;}i:3;a:2:{s:1:";";a:1:{s:9:"codepoint";i:179;}s:9:"codepoint";i:179;}s:1:";";a:1:{s:9:"codepoint";i:8835;}s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10950;}}s:1:"d";a:2:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10942;}}}s:1:"s";a:1:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10968;}}}}}s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8839;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10948;}}}}}s:1:"h";a:1:{s:1:"s";a:1:{s:1:"u";a:1:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10967;}}}}}s:1:"l";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10619;}}}}}s:1:"m";a:1:{s:1:"u";a:1:{s:1:"l";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10946;}}}}}s:1:"n";a:2:{s:1:"E";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10956;}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8843;}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10944;}}}}}s:1:"s";a:3:{s:1:"e";a:1:{s:1:"t";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8835;}s:1:"e";a:1:{s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8839;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10950;}}}}s:1:"n";a:1:{s:1:"e";a:1:{s:1:"q";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8843;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10956;}}}}}}}s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10952;}}}s:1:"u";a:2:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10964;}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10966;}}}}}}s:1:"w";a:3:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8665;}}}}s:1:"a";a:1:{s:1:"r";a:2:{s:1:"h";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10534;}}}s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8601;}s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8601;}}}}}}s:1:"n";a:1:{s:1:"w";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10538;}}}}}}s:1:"z";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"g";a:2:{s:1:";";a:1:{s:9:"codepoint";i:223;}s:9:"codepoint";i:223;}}}}}s:1:"t";a:13:{s:1:"a";a:2:{s:1:"r";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8982;}}}}}s:1:"u";a:1:{s:1:";";a:1:{s:9:"codepoint";i:964;}}}s:1:"b";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9140;}}}}s:1:"c";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:357;}}}}}s:1:"e";a:1:{s:1:"d";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:355;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1090;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8411;}}}}s:1:"e";a:1:{s:1:"l";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8981;}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120113;}}}s:1:"h";a:4:{s:1:"e";a:2:{s:1:"r";a:1:{s:1:"e";a:2:{i:4;a:1:{s:1:";";a:1:{s:9:"codepoint";i:8756;}}s:1:"f";a:1:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8756;}}}}}}}s:1:"t";a:1:{s:1:"a";a:3:{s:1:";";a:1:{s:9:"codepoint";i:952;}s:1:"s";a:1:{s:1:"y";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:977;}}}}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:977;}}}}}s:1:"i";a:2:{s:1:"c";a:1:{s:1:"k";a:2:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"x";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8776;}}}}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8764;}}}}}}s:1:"n";a:1:{s:1:"s";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8201;}}}}}s:1:"k";a:2:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8776;}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8764;}}}}}s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:254;}s:9:"codepoint";i:254;}}}}s:1:"i";a:3:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:732;}}}}s:1:"m";a:1:{s:1:"e";a:1:{s:1:"s";a:4:{s:1:";";a:1:{s:9:"codepoint";i:215;}s:9:"codepoint";i:215;s:1:"b";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8864;}s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10801;}}}}s:1:"d";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10800;}}}}}s:1:"n";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8749;}}}}s:1:"o";a:3:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10536;}}}s:1:"p";a:4:{s:1:";";a:1:{s:9:"codepoint";i:8868;}s:1:"b";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9014;}}}}s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10993;}}}}s:1:"f";a:2:{s:1:";";a:1:{s:9:"codepoint";i:120165;}s:1:"o";a:1:{s:1:"r";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10970;}}}}}}s:1:"s";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10537;}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8244;}}}}}}s:1:"r";a:3:{s:1:"a";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8482;}}}}s:1:"i";a:7:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:5:{s:1:";";a:1:{s:9:"codepoint";i:9653;}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9663;}}}}}s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9667;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8884;}}}}}}}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8796;}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9657;}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8885;}}}}}}}}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9708;}}}}s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8796;}}s:1:"m";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10810;}}}}}}s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10809;}}}}}s:1:"s";a:1:{s:1:"b";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10701;}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10811;}}}}}}s:1:"p";a:1:{s:1:"e";a:1:{s:1:"z";a:1:{s:1:"i";a:1:{s:1:"u";a:1:{s:1:"m";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9186;}}}}}}}}s:1:"s";a:3:{s:1:"c";a:2:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120009;}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1094;}}}s:1:"h";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1115;}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:359;}}}}}}s:1:"w";a:2:{s:1:"i";a:1:{s:1:"x";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8812;}}}}s:1:"o";a:1:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:"a";a:1:{s:1:"d";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8606;}}}}}}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8608;}}}}}}}}}}}}}}}}}}s:1:"u";a:18:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8657;}}}}s:1:"H";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10595;}}}}s:1:"a";a:2:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:250;}s:9:"codepoint";i:250;}}}}s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8593;}}}}s:1:"b";a:1:{s:1:"r";a:2:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1118;}}}s:1:"e";a:1:{s:1:"v";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:365;}}}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:2:{s:1:";";a:1:{s:9:"codepoint";i:251;}s:9:"codepoint";i:251;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1091;}}}s:1:"d";a:3:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8645;}}}}s:1:"b";a:1:{s:1:"l";a:1:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:369;}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10606;}}}}}s:1:"f";a:2:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10622;}}}}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120114;}}}s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"v";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:249;}s:9:"codepoint";i:249;}}}}}s:1:"h";a:2:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:"l";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8639;}}s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8638;}}}}s:1:"b";a:1:{s:1:"l";a:1:{s:1:"k";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9600;}}}}}s:1:"l";a:2:{s:1:"c";a:2:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8988;}s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8988;}}}}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8975;}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9720;}}}}}s:1:"m";a:2:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:363;}}}}s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:168;}s:9:"codepoint";i:168;}}s:1:"o";a:2:{s:1:"g";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:371;}}}}s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120166;}}}}s:1:"p";a:6:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8593;}}}}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"n";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8597;}}}}}}}}}}s:1:"h";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:"o";a:1:{s:1:"o";a:1:{s:1:"n";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8639;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8638;}}}}}}}}}}}}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8846;}}}}s:1:"s";a:1:{s:1:"i";a:3:{s:1:";";a:1:{s:9:"codepoint";i:965;}s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:978;}}s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:965;}}}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"w";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8648;}}}}}}}}}}s:1:"r";a:3:{s:1:"c";a:2:{s:1:"o";a:1:{s:1:"r";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8989;}s:1:"e";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8989;}}}}}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8974;}}}}}s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:367;}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9721;}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120010;}}}}s:1:"t";a:3:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8944;}}}}s:1:"i";a:1:{s:1:"l";a:1:{s:1:"d";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:361;}}}}}s:1:"r";a:1:{s:1:"i";a:2:{s:1:";";a:1:{s:9:"codepoint";i:9653;}s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9652;}}}}}s:1:"u";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8648;}}}}s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:252;}s:9:"codepoint";i:252;}}}s:1:"w";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10663;}}}}}}}}s:1:"v";a:14:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8661;}}}}s:1:"B";a:1:{s:1:"a";a:1:{s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:10984;}s:1:"v";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10985;}}}}}s:1:"D";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8872;}}}}}s:1:"a";a:2:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10652;}}}}}s:1:"r";a:7:{s:1:"e";a:1:{s:1:"p";a:1:{s:1:"s";a:1:{s:1:"i";a:1:{s:1:"l";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:949;}}}}}}}}s:1:"k";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:"p";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1008;}}}}}}s:1:"n";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:"i";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8709;}}}}}}}}s:1:"p";a:3:{s:1:"h";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:966;}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:982;}}s:1:"r";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:"t";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8733;}}}}}}}s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8597;}s:1:"h";a:1:{s:1:"o";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1009;}}}}s:1:"s";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"m";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:962;}}}}}}s:1:"t";a:2:{s:1:"h";a:1:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:977;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"a";a:1:{s:1:"n";a:1:{s:1:"g";a:1:{s:1:"l";a:1:{s:1:"e";a:2:{s:1:"l";a:1:{s:1:"e";a:1:{s:1:"f";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8882;}}}}}s:1:"r";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"h";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8883;}}}}}}}}}}}}}}}}s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1074;}}}s:1:"d";a:1:{s:1:"a";a:1:{s:1:"s";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8866;}}}}}s:1:"e";a:3:{s:1:"e";a:3:{s:1:";";a:1:{s:9:"codepoint";i:8744;}s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8891;}}}}s:1:"e";a:1:{s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8794;}}}}s:1:"l";a:1:{s:1:"l";a:1:{s:1:"i";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8942;}}}}}s:1:"r";a:2:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:124;}}}}s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:124;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120115;}}}s:1:"l";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8882;}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120167;}}}}s:1:"p";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8733;}}}}}s:1:"r";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8883;}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120011;}}}}s:1:"z";a:1:{s:1:"i";a:1:{s:1:"g";a:1:{s:1:"z";a:1:{s:1:"a";a:1:{s:1:"g";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10650;}}}}}}}}s:1:"w";a:7:{s:1:"c";a:1:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:373;}}}}}s:1:"e";a:2:{s:1:"d";a:2:{s:1:"b";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10847;}}}}s:1:"g";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8743;}s:1:"q";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8793;}}}}}s:1:"i";a:1:{s:1:"e";a:1:{s:1:"r";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8472;}}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120116;}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120168;}}}}s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8472;}}s:1:"r";a:2:{s:1:";";a:1:{s:9:"codepoint";i:8768;}s:1:"e";a:1:{s:1:"a";a:1:{s:1:"t";a:1:{s:1:"h";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8768;}}}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120012;}}}}}s:1:"x";a:14:{s:1:"c";a:3:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8898;}}}s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9711;}}}}s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8899;}}}}s:1:"d";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9661;}}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120117;}}}s:1:"h";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10234;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10231;}}}}}s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:958;}}s:1:"l";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10232;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10229;}}}}}s:1:"m";a:1:{s:1:"a";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10236;}}}}s:1:"n";a:1:{s:1:"i";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8955;}}}}s:1:"o";a:3:{s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10752;}}}}s:1:"p";a:2:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120169;}}s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10753;}}}}}s:1:"t";a:1:{s:1:"i";a:1:{s:1:"m";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10754;}}}}}}s:1:"r";a:2:{s:1:"A";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10233;}}}}s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10230;}}}}}s:1:"s";a:2:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120013;}}}s:1:"q";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"p";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10758;}}}}}}s:1:"u";a:2:{s:1:"p";a:1:{s:1:"l";a:1:{s:1:"u";a:1:{s:1:"s";a:1:{s:1:";";a:1:{s:9:"codepoint";i:10756;}}}}}s:1:"t";a:1:{s:1:"r";a:1:{s:1:"i";a:1:{s:1:";";a:1:{s:9:"codepoint";i:9651;}}}}}s:1:"v";a:1:{s:1:"e";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8897;}}}}s:1:"w";a:1:{s:1:"e";a:1:{s:1:"d";a:1:{s:1:"g";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8896;}}}}}}}s:1:"y";a:8:{s:1:"a";a:1:{s:1:"c";a:2:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:2:{s:1:";";a:1:{s:9:"codepoint";i:253;}s:9:"codepoint";i:253;}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1103;}}}}s:1:"c";a:2:{s:1:"i";a:1:{s:1:"r";a:1:{s:1:"c";a:1:{s:1:";";a:1:{s:9:"codepoint";i:375;}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1099;}}}s:1:"e";a:1:{s:1:"n";a:2:{s:1:";";a:1:{s:9:"codepoint";i:165;}s:9:"codepoint";i:165;}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120118;}}}s:1:"i";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1111;}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120170;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120014;}}}}s:1:"u";a:2:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1102;}}}s:1:"m";a:1:{s:1:"l";a:2:{s:1:";";a:1:{s:9:"codepoint";i:255;}s:9:"codepoint";i:255;}}}}s:1:"z";a:10:{s:1:"a";a:1:{s:1:"c";a:1:{s:1:"u";a:1:{s:1:"t";a:1:{s:1:"e";a:1:{s:1:";";a:1:{s:9:"codepoint";i:378;}}}}}}s:1:"c";a:2:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"o";a:1:{s:1:"n";a:1:{s:1:";";a:1:{s:9:"codepoint";i:382;}}}}}s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1079;}}}s:1:"d";a:1:{s:1:"o";a:1:{s:1:"t";a:1:{s:1:";";a:1:{s:9:"codepoint";i:380;}}}}s:1:"e";a:2:{s:1:"e";a:1:{s:1:"t";a:1:{s:1:"r";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8488;}}}}}s:1:"t";a:1:{s:1:"a";a:1:{s:1:";";a:1:{s:9:"codepoint";i:950;}}}}s:1:"f";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120119;}}}s:1:"h";a:1:{s:1:"c";a:1:{s:1:"y";a:1:{s:1:";";a:1:{s:9:"codepoint";i:1078;}}}}s:1:"i";a:1:{s:1:"g";a:1:{s:1:"r";a:1:{s:1:"a";a:1:{s:1:"r";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8669;}}}}}}}s:1:"o";a:1:{s:1:"p";a:1:{s:1:"f";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120171;}}}}s:1:"s";a:1:{s:1:"c";a:1:{s:1:"r";a:1:{s:1:";";a:1:{s:9:"codepoint";i:120015;}}}}s:1:"w";a:2:{s:1:"j";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8205;}}s:1:"n";a:1:{s:1:"j";a:1:{s:1:";";a:1:{s:9:"codepoint";i:8204;}}}}}}
\ No newline at end of file
diff --git a/library/vendor/dompdf/lib/php-svg-lib/LICENSE b/library/vendor/dompdf/lib/php-svg-lib/LICENSE
deleted file mode 100644
index f288702d2..000000000
--- a/library/vendor/dompdf/lib/php-svg-lib/LICENSE
+++ /dev/null
@@ -1,674 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. 
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  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
-them 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 prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  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.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey 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;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If 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 convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU 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 that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  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.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-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.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     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
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    
-    Copyright (C)   
-
-    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 3 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, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-      Copyright (C)   
-    This program 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, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
-  The GNU 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.  But first, please read
-.
diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/autoload.php b/library/vendor/dompdf/lib/php-svg-lib/src/autoload.php
deleted file mode 100644
index b0e2b9cc4..000000000
--- a/library/vendor/dompdf/lib/php-svg-lib/src/autoload.php
+++ /dev/null
@@ -1,17 +0,0 @@
-
- * @license GNU LGPLv3+ http://www.gnu.org/copyleft/lesser.html
- */
-
-spl_autoload_register(function($class) {
-  if (0 === strpos($class, "Svg")) {
-    $file = str_replace('\\', DIRECTORY_SEPARATOR, $class);
-    $file = realpath(__DIR__ . DIRECTORY_SEPARATOR . $file . '.php');
-    if (file_exists($file)) {
-      include_once $file;
-    }
-  }
-});
\ No newline at end of file
diff --git a/library/vendor/dompdf/src/Autoloader.php b/library/vendor/dompdf/src/Autoloader.php
deleted file mode 100644
index d6598d31e..000000000
--- a/library/vendor/dompdf/src/Autoloader.php
+++ /dev/null
@@ -1,42 +0,0 @@
-_frame = $frame;
-    }
-
-    /**
-     * @return FrameListIterator
-     */
-    function getIterator(): FrameListIterator
-    {
-        return new FrameListIterator($this->_frame);
-    }
-}
diff --git a/library/vendor/dompdf/src/Frame/FrameTreeList.php b/library/vendor/dompdf/src/Frame/FrameTreeList.php
deleted file mode 100644
index bd97b66f6..000000000
--- a/library/vendor/dompdf/src/Frame/FrameTreeList.php
+++ /dev/null
@@ -1,35 +0,0 @@
-_root = $root;
-    }
-
-    /**
-     * @return FrameTreeIterator
-     */
-    public function getIterator(): FrameTreeIterator
-    {
-        return new FrameTreeIterator($this->_root);
-    }
-}
diff --git a/library/vendor/dompdf/src/FrameDecorator/TableRow.php b/library/vendor/dompdf/src/FrameDecorator/TableRow.php
deleted file mode 100644
index b4d4958d2..000000000
--- a/library/vendor/dompdf/src/FrameDecorator/TableRow.php
+++ /dev/null
@@ -1,58 +0,0 @@
-
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-namespace Dompdf\FrameDecorator;
-
-use Dompdf\Dompdf;
-use Dompdf\Frame;
-use Dompdf\FrameDecorator\Table as TableFrameDecorator;
-
-/**
- * Decorates Frames for table row layout
- *
- * @package dompdf
- */
-class TableRow extends AbstractFrameDecorator
-{
-    /**
-     * TableRow constructor.
-     * @param Frame $frame
-     * @param Dompdf $dompdf
-     */
-    function __construct(Frame $frame, Dompdf $dompdf)
-    {
-        parent::__construct($frame, $dompdf);
-    }
-
-    //........................................................................
-
-    /**
-     * Remove all non table-cell frames from this row and move them after
-     * the table.
-     *
-     * @deprecated
-     */
-    function normalise()
-    {
-        // Find our table parent
-        $p = TableFrameDecorator::find_parent_table($this);
-
-        $erroneous_frames = [];
-        foreach ($this->get_children() as $child) {
-            $display = $child->get_style()->display;
-
-            if ($display !== "table-cell") {
-                $erroneous_frames[] = $child;
-            }
-        }
-
-        //  dump the extra nodes after the table.
-        foreach ($erroneous_frames as $frame) {
-            $p->move_after($frame);
-        }
-    }
-}
diff --git a/library/vendor/dompdf/src/Image/Cache.php b/library/vendor/dompdf/src/Image/Cache.php
deleted file mode 100644
index a6ef0fe5d..000000000
--- a/library/vendor/dompdf/src/Image/Cache.php
+++ /dev/null
@@ -1,268 +0,0 @@
-
- * @author  Helmut Tischer 
- * @author  Fabien Ménager 
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-namespace Dompdf\Image;
-
-use Dompdf\Dompdf;
-use Dompdf\Helpers;
-use Dompdf\Exception\ImageException;
-
-/**
- * Static class that resolves image urls and downloads and caches
- * remote images if required.
- *
- * @package dompdf
- */
-class Cache
-{
-    /**
-     * Array of downloaded images.  Cached so that identical images are
-     * not needlessly downloaded.
-     *
-     * @var array
-     */
-    protected static $_cache = [];
-
-    /**
-     * @var array
-     */
-    protected static $tempImages = [];
-
-    /**
-     * The url to the "broken image" used when images can't be loaded
-     *
-     * @var string
-     */
-    public static $broken_image = "data:image/svg+xml;charset=utf8,%3C?xml version='1.0'?%3E%3Csvg width='64' height='64' xmlns='http://www.w3.org/2000/svg'%3E%3Cg%3E%3Crect stroke='%23666666' id='svg_1' height='60.499994' width='60.166667' y='1.666669' x='1.999998' stroke-width='1.5' fill='none'/%3E%3Cline stroke-linecap='null' stroke-linejoin='null' id='svg_3' y2='59.333253' x2='59.749916' y1='4.333415' x1='4.250079' stroke-width='1.5' stroke='%23999999' fill='none'/%3E%3Cline stroke-linecap='null' stroke-linejoin='null' id='svg_4' y2='59.999665' x2='4.062838' y1='3.750342' x1='60.062164' stroke-width='1.5' stroke='%23999999' fill='none'/%3E%3C/g%3E%3C/svg%3E";
-
-    public static $error_message = "Image not found or type unknown";
-    
-    /**
-     * Current dompdf instance
-     *
-     * @var Dompdf
-     */
-    protected static $_dompdf;
-
-    /**
-     * Resolve and fetch an image for use.
-     *
-     * @param string $url       The url of the image
-     * @param string $protocol  Default protocol if none specified in $url
-     * @param string $host      Default host if none specified in $url
-     * @param string $base_path Default path if none specified in $url
-     * @param Dompdf $dompdf    The Dompdf instance
-     *
-     * @throws ImageException
-     * @return array             An array with two elements: The local path to the image and the image extension
-     */
-    static function resolve_url($url, $protocol, $host, $base_path, Dompdf $dompdf)
-    {
-        self::$_dompdf = $dompdf;
-        
-        $protocol = mb_strtolower($protocol);
-        $parsed_url = Helpers::explode_url($url);
-        $message = null;
-
-        $remote = ($protocol && $protocol !== "file://") || ($parsed_url['protocol'] !== "");
-
-        $data_uri = strpos($parsed_url['protocol'], "data:") === 0;
-        $full_url = null;
-        $enable_remote = $dompdf->getOptions()->getIsRemoteEnabled();
-        $tempfile = false;
-
-        try {
-
-            // Remote not allowed and is not DataURI
-            if (!$enable_remote && $remote && !$data_uri) {
-                throw new ImageException("Remote file access is disabled.", E_WARNING);
-            }
-            
-            // remote allowed or DataURI
-            if (($enable_remote && $remote) || $data_uri) {
-                // Download remote files to a temporary directory
-                $full_url = Helpers::build_url($protocol, $host, $base_path, $url);
-
-                // From cache
-                if (isset(self::$_cache[$full_url])) {
-                    $resolved_url = self::$_cache[$full_url];
-                } // From remote
-                else {
-                    $tmp_dir = $dompdf->getOptions()->getTempDir();
-                    if (($resolved_url = @tempnam($tmp_dir, "ca_dompdf_img_")) === false) {
-                        throw new ImageException("Unable to create temporary image in " . $tmp_dir, E_WARNING);
-                    }
-                    $tempfile = $resolved_url;
-                    $image = null;
-
-                    if ($data_uri) {
-                        if ($parsed_data_uri = Helpers::parse_data_uri($url)) {
-                            $image = $parsed_data_uri['data'];
-                        }
-                    } else {
-                        list($image, $http_response_header) = Helpers::getFileContent($full_url, $dompdf->getHttpContext());
-                    }
-
-                    // Image not found or invalid
-                    if ($image === null) {
-                        $msg = ($data_uri ? "Data-URI could not be parsed" : "Image not found");
-                        throw new ImageException($msg, E_WARNING);
-                    } // Image found, put in cache and process
-                    else {
-                        //e.g. fetch.php?media=url.jpg&cache=1
-                        //- Image file name might be one of the dynamic parts of the url, don't strip off!
-                        //- a remote url does not need to have a file extension at all
-                        //- local cached file does not have a matching file extension
-                        //Therefore get image type from the content
-                        if (@file_put_contents($resolved_url, $image) === false) {
-                            throw new ImageException("Unable to create temporary image in " . $tmp_dir, E_WARNING);
-                        }
-                    }
-                }
-            } // Not remote, local image
-            else {
-                $resolved_url = Helpers::build_url($protocol, $host, $base_path, $url);
-
-                if ($protocol === "" || $protocol === "file://") {
-                    $realfile = realpath($resolved_url);
-        
-                    $rootDir = realpath($dompdf->getOptions()->getRootDir());
-                    if (strpos($realfile, $rootDir) !== 0) {
-                        $chroot = $dompdf->getOptions()->getChroot();
-                        $chrootValid = false;
-                        foreach ($chroot as $chrootPath) {
-                            $chrootPath = realpath($chrootPath);
-                            if ($chrootPath !== false && strpos($realfile, $chrootPath) === 0) {
-                                $chrootValid = true;
-                                break;
-                            }
-                        }
-                        if ($chrootValid !== true) {
-                            throw new ImageException("Permission denied on $resolved_url. The file could not be found under the paths specified by Options::chroot.", E_WARNING);
-                        }
-                    }
-        
-                    if (!$realfile) {
-                        throw new ImageException("File '$realfile' not found.", E_WARNING);
-                    }
-        
-                    $resolved_url = $realfile;
-                }
-            }
-
-            // Check if the local file is readable
-            if (!is_readable($resolved_url) || !filesize($resolved_url)) {
-                throw new ImageException("Image not readable or empty", E_WARNING);
-            } // Check is the file is an image
-            else {
-                list($width, $height, $type) = Helpers::dompdf_getimagesize($resolved_url, $dompdf->getHttpContext());
-
-                // Known image type
-                if ($width && $height && in_array($type, ["gif", "png", "jpeg", "bmp", "svg","webp"], true)) {
-                    //Don't put replacement image into cache - otherwise it will be deleted on cache cleanup.
-                    //Only execute on successful caching of remote image.
-                    if ($enable_remote && $remote || $data_uri) {
-                        self::$_cache[$full_url] = $resolved_url;
-                    }
-                } // Unknown image type
-                else {
-                    throw new ImageException("Image type unknown", E_WARNING);
-                }
-            }
-        } catch (ImageException $e) {
-            if ($tempfile) {
-                unlink($tempfile);
-            }
-            $resolved_url = self::$broken_image;
-            $type = "png";
-            $message = self::$error_message;
-            Helpers::record_warnings($e->getCode(), $e->getMessage() . " \n $url", $e->getFile(), $e->getLine());
-            self::$_cache[$full_url] = $resolved_url;
-        }
-
-        return [$resolved_url, $type, $message];
-    }
-
-    /**
-     * Register a temp file for the given original image file.
-     *
-     * @param string $filePath The path of the original image.
-     * @param string $tempPath The path of the temp file to register.
-     * @param string $key      An optional key to register the temp file at.
-     */
-    static function addTempImage(string $filePath, string $tempPath, string $key = "default"): void
-    {
-        if (!isset(self::$tempImages[$filePath])) {
-            self::$tempImages[$filePath] = [];
-        }
-
-        self::$tempImages[$filePath][$key] = $tempPath;
-    }
-
-    /**
-     * Get the path of a temp file registered for the given original image file.
-     *
-     * @param string $filePath The path of the original image.
-     * @param string $key      The key the temp file is registered at.
-     */
-    static function getTempImage(string $filePath, string $key = "default"): ?string
-    {
-        return self::$tempImages[$filePath][$key] ?? null;
-    }
-
-    /**
-     * Unlink all cached images (i.e. temporary images either downloaded
-     * or converted) except for the bundled "broken image"
-     */
-    static function clear(bool $debugPng = false)
-    {
-        foreach (self::$_cache as $file) {
-            if ($file === self::$broken_image) {
-                continue;
-            }
-            if ($debugPng) {
-                print "[clear unlink $file]";
-            }
-            unlink($file);
-        }
-
-        foreach (self::$tempImages as $versions) {
-            foreach ($versions as $file) {
-                if ($file === self::$broken_image) {
-                    continue;
-                }
-                if ($debugPng) {
-                    print "[unlink temp image $file]";
-                }
-                if (file_exists($file)) {
-                    unlink($file);
-                }
-            }
-        }
-
-        self::$_cache = [];
-        self::$tempImages = [];
-    }
-
-    static function detect_type($file, $context = null)
-    {
-        list(, , $type) = Helpers::dompdf_getimagesize($file, $context);
-
-        return $type;
-    }
-
-    static function is_broken($url)
-    {
-        return $url === self::$broken_image;
-    }
-}
-
-if (file_exists(realpath(__DIR__ . "/../../lib/res/broken_image.svg"))) {
-    Cache::$broken_image = realpath(__DIR__ . "/../../lib/res/broken_image.svg");
-}
diff --git a/library/vendor/dompdf/src/Renderer/Block.php b/library/vendor/dompdf/src/Renderer/Block.php
deleted file mode 100644
index 0e4dffb60..000000000
--- a/library/vendor/dompdf/src/Renderer/Block.php
+++ /dev/null
@@ -1,301 +0,0 @@
-
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-namespace Dompdf\Renderer;
-
-use Dompdf\Frame;
-use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
-use Dompdf\Helpers;
-
-/**
- * Renders block frames
- *
- * @package dompdf
- */
-class Block extends AbstractRenderer
-{
-
-    /**
-     * @param Frame $frame
-     */
-    function render(Frame $frame)
-    {
-        $style = $frame->get_style();
-        $node = $frame->get_node();
-        $dompdf = $this->_dompdf;
-
-        $this->_set_opacity($frame->get_opacity($style->opacity));
-
-        [$x, $y, $w, $h] = $frame->get_border_box();
-
-        if ($node->nodeName === "body") {
-            $h = $frame->get_containing_block("h") - (float)$style->length_in_pt([
-                        $style->margin_top,
-                        $style->border_top_width,
-                        $style->border_bottom_width,
-                        $style->margin_bottom],
-                    (float)$style->length_in_pt($style->width));
-        }
-
-        $border_box = [$x, $y, $w, $h];
-
-        // Draw our background, border and content
-        $this->_render_background($frame, $border_box);
-        $this->_render_border($frame, $border_box);
-        $this->_render_outline($frame, $border_box);
-
-        // Handle anchors & links
-        if ($node->nodeName === "a" && $href = $node->getAttribute("href")) {
-            $href = Helpers::build_url($dompdf->getProtocol(), $dompdf->getBaseHost(), $dompdf->getBasePath(), $href);
-            $this->_canvas->add_link($href, $x, $y, $w, $h);
-        }
-
-        $id = $frame->get_node()->getAttribute("id");
-        if (strlen($id) > 0) {
-            $this->_canvas->add_named_dest($id);
-        }
-
-        $this->debugBlockLayout($frame, "red", false);
-    }
-
-    /**
-     * @param Frame $frame
-     * @param float[] $border_box
-     */
-    protected function _render_background(Frame $frame, array $border_box): void
-    {
-        $style = $frame->get_style();
-        [$x, $y, $w, $h] = $border_box;
-
-        if ($style->has_border_radius()) {
-            [$tl, $tr, $br, $bl] = $style->resolve_border_radius($border_box);
-            $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl);
-        }
-
-        if (($bg = $style->background_color) !== "transparent") {
-            $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
-        }
-
-        if (($url = $style->background_image) && $url !== "none") {
-            $this->_background_image($url, $x, $y, $w, $h, $style);
-        }
-
-        if ($style->has_border_radius()) {
-            $this->_canvas->clipping_end();
-        }
-    }
-
-    /**
-     * @param Frame $frame
-     * @param float[] $border_box
-     * @param string $corner_style
-     */
-    protected function _render_border(Frame $frame, array $border_box, string $corner_style = "bevel"): void
-    {
-        $style = $frame->get_style();
-        $bp = $style->get_border_properties();
-        [$x, $y, $w, $h] = $border_box;
-        [$tl, $tr, $br, $bl] = $style->resolve_border_radius($border_box);
-
-        // Short-cut: If all the borders are "solid" with the same color and style, and no radius, we'd better draw a rectangle
-        if (
-            in_array($bp["top"]["style"], ["solid", "dashed", "dotted"]) &&
-            $bp["top"] == $bp["right"] &&
-            $bp["right"] == $bp["bottom"] &&
-            $bp["bottom"] == $bp["left"] &&
-            !$style->has_border_radius()
-        ) {
-            $props = $bp["top"];
-            if ($props["color"] === "transparent" || $props["width"] <= 0) {
-                return;
-            }
-
-            $width = (float)$style->length_in_pt($props["width"]);
-            $pattern = $this->_get_dash_pattern($props["style"], $width);
-            $this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width, $pattern);
-            return;
-        }
-
-        // Do it the long way
-        $widths = [
-            (float)$style->length_in_pt($bp["top"]["width"]),
-            (float)$style->length_in_pt($bp["right"]["width"]),
-            (float)$style->length_in_pt($bp["bottom"]["width"]),
-            (float)$style->length_in_pt($bp["left"]["width"])
-        ];
-
-        foreach ($bp as $side => $props) {
-            list($x, $y, $w, $h) = $border_box;
-            $length = 0;
-            $r1 = 0;
-            $r2 = 0;
-
-            if (!$props["style"] ||
-                $props["style"] === "none" ||
-                $props["width"] <= 0 ||
-                $props["color"] == "transparent"
-            ) {
-                continue;
-            }
-
-            switch ($side) {
-                case "top":
-                    $length = $w;
-                    $r1 = $tl;
-                    $r2 = $tr;
-                    break;
-
-                case "bottom":
-                    $length = $w;
-                    $y += $h;
-                    $r1 = $bl;
-                    $r2 = $br;
-                    break;
-
-                case "left":
-                    $length = $h;
-                    $r1 = $tl;
-                    $r2 = $bl;
-                    break;
-
-                case "right":
-                    $length = $h;
-                    $x += $w;
-                    $r1 = $tr;
-                    $r2 = $br;
-                    break;
-                default:
-                    break;
-            }
-            $method = "_border_" . $props["style"];
-
-            // draw rounded corners
-            $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style, $r1, $r2);
-        }
-    }
-
-    /**
-     * @param Frame $frame
-     * @param float[] $border_box
-     * @param string $corner_style
-     */
-    protected function _render_outline(Frame $frame, array $border_box, string $corner_style = "bevel"): void
-    {
-        $style = $frame->get_style();
-
-        $width = (float) $style->length_in_pt($style->outline_width);
-        $outline_style = $style->outline_style;
-        $color = $style->outline_color;
-
-        if (!$outline_style || $outline_style === "none" || $color === "transparent" || $width <= 0) {
-            return;
-        }
-
-        $offset = (float) $style->length_in_pt($style->outline_offset);
-
-        [$x, $y, $w, $h] = $border_box;
-        $d = $width + $offset;
-        $outline_box = [$x - $d, $y - $d, $w + $d * 2, $h + $d * 2];
-        [$tl, $tr, $br, $bl] = $style->resolve_border_radius($border_box, $outline_box);
-
-        $x -= $offset;
-        $y -= $offset;
-        $w += $offset * 2;
-        $h += $offset * 2;
-
-        // For a simple outline, we can draw a rectangle
-        if (in_array($outline_style, ["solid", "dashed", "dotted"], true)
-            && !$style->has_border_radius()
-        ) {
-            $x -= $width / 2;
-            $y -= $width / 2;
-            $w += $width;
-            $h += $width;
-
-            $pattern = $this->_get_dash_pattern($outline_style, $width);
-            $this->_canvas->rectangle($x, $y, $w, $h, $color, $width, $pattern);
-            return;
-        }
-
-        $x -= $width;
-        $y -= $width;
-        $w += $width * 2;
-        $h += $width * 2;
-
-        $method = "_border_" . $outline_style;
-        $widths = array_fill(0, 4, $width);
-        $sides = ["top", "right", "left", "bottom"];
-
-        foreach ($sides as $side) {
-            switch ($side) {
-                case "top":
-                    $length = $w;
-                    $side_x = $x;
-                    $side_y = $y;
-                    $r1 = $tl;
-                    $r2 = $tr;
-                    break;
-
-                case "bottom":
-                    $length = $w;
-                    $side_x = $x;
-                    $side_y = $y + $h;
-                    $r1 = $bl;
-                    $r2 = $br;
-                    break;
-
-                case "left":
-                    $length = $h;
-                    $side_x = $x;
-                    $side_y = $y;
-                    $r1 = $tl;
-                    $r2 = $bl;
-                    break;
-
-                case "right":
-                    $length = $h;
-                    $side_x = $x + $w;
-                    $side_y = $y;
-                    $r1 = $tr;
-                    $r2 = $br;
-                    break;
-
-                default:
-                    break;
-            }
-
-            $this->$method($side_x, $side_y, $length, $color, $widths, $side, $corner_style, $r1, $r2);
-        }
-    }
-
-    protected function debugBlockLayout(Frame $frame, ?string $color, bool $lines = false): void
-    {
-        $options = $this->_dompdf->getOptions();
-        $debugLayout = $options->getDebugLayout();
-
-        if (!$debugLayout) {
-            return;
-        }
-
-        if ($color && $options->getDebugLayoutBlocks()) {
-            $this->_debug_layout($frame->get_border_box(), $color);
-
-            if ($options->getDebugLayoutPaddingBox()) {
-                $this->_debug_layout($frame->get_padding_box(), $color, [0.5, 0.5]);
-            }
-        }
-
-        if ($lines && $options->getDebugLayoutLines() && $frame instanceof BlockFrameDecorator) {
-            [$cx, , $cw] = $frame->get_content_box();
-
-            foreach ($frame->get_line_boxes() as $line) {
-                $lw = $cw - $line->left - $line->right;
-                $this->_debug_layout([$cx + $line->left, $line->y, $lw, $line->h], "orange");
-            }
-        }
-    }
-}
diff --git a/library/vendor/dompdf/src/Renderer/Inline.php b/library/vendor/dompdf/src/Renderer/Inline.php
deleted file mode 100644
index c91bd9b23..000000000
--- a/library/vendor/dompdf/src/Renderer/Inline.php
+++ /dev/null
@@ -1,164 +0,0 @@
-
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-namespace Dompdf\Renderer;
-
-use Dompdf\Frame;
-use Dompdf\Helpers;
-
-/**
- * Renders inline frames
- *
- * @access  private
- * @package dompdf
- */
-class Inline extends AbstractRenderer
-{
-    function render(Frame $frame)
-    {
-        if (!$frame->get_first_child()) {
-            return; // No children, no service
-        }
-
-        $style = $frame->get_style();
-        $dompdf = $this->_dompdf;
-
-        // Draw the left border if applicable
-        $bp = $style->get_border_properties();
-        $widths = [
-            (float)$style->length_in_pt($bp["top"]["width"]),
-            (float)$style->length_in_pt($bp["right"]["width"]),
-            (float)$style->length_in_pt($bp["bottom"]["width"]),
-            (float)$style->length_in_pt($bp["left"]["width"])
-        ];
-
-        // Draw the background & border behind each child.  To do this we need
-        // to figure out just how much space each child takes:
-        list($x, $y) = $frame->get_first_child()->get_position();
-
-        $this->_set_opacity($frame->get_opacity($style->opacity));
-
-        $do_debug_layout_line = $dompdf->getOptions()->getDebugLayout()
-            && $dompdf->getOptions()->getDebugLayoutInline();
-
-        list($w, $h) = $this->get_child_size($frame, $do_debug_layout_line);
-
-        // make sure the border and background start inside the left margin
-        $left_margin = (float)$style->length_in_pt($style->margin_left);
-        $x += $left_margin;
-
-        // Handle the last child
-        if (($bg = $style->background_color) !== "transparent") {
-            $this->_canvas->filled_rectangle($x + $widths[3], $y + $widths[0], $w, $h, $bg);
-        }
-
-        //On continuation lines (after line break) of inline elements, the style got copied.
-        //But a non repeatable background image should not be repeated on the next line.
-        //But removing the background image above has never an effect, and removing it below
-        //removes it always, even on the initial line.
-        //Need to handle it elsewhere, e.g. on certain ...clone()... usages.
-        // Repeat not given: default is Style::__construct
-        // ... && (!($repeat = $style->background_repeat) || $repeat === "repeat" ...
-        //different position? $this->_background_image($url, $x, $y, $w, $h, $style);
-        if (($url = $style->background_image) && $url !== "none") {
-            $this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style);
-        }
-
-        // Add the border widths
-        $w += (float)$widths[1] + (float)$widths[3];
-        $h += (float)$widths[0] + (float)$widths[2];
-
-        // If this is the first row, draw the left border too
-        if ($bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $widths[3] > 0) {
-            $method = "_border_" . $bp["left"]["style"];
-            $this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left");
-        }
-
-        // Draw the top & bottom borders
-        if ($bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $widths[0] > 0) {
-            $method = "_border_" . $bp["top"]["style"];
-            $this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top");
-        }
-
-        if ($bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $widths[2] > 0) {
-            $method = "_border_" . $bp["bottom"]["style"];
-            $this->$method($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
-        }
-
-        // Helpers::var_dump(get_class($frame->get_next_sibling()));
-        // $last_row = get_class($frame->get_next_sibling()) !== 'Inline';
-        // Draw the right border if this is the last row
-        if ($bp["right"]["style"] !== "none" && $bp["right"]["color"] !== "transparent" && $widths[1] > 0) {
-            $method = "_border_" . $bp["right"]["style"];
-            $this->$method($x + $w, $y, $h, $bp["right"]["color"], $widths, "right");
-        }
-
-        $node = $frame->get_node();
-        $id = $node->getAttribute("id");
-        if (strlen($id) > 0) {
-            $this->_canvas->add_named_dest($id);
-        }
-
-        // Only two levels of links frames
-        $is_link_node = $node->nodeName === "a";
-        if ($is_link_node) {
-            if (($name = $node->getAttribute("name"))) {
-                $this->_canvas->add_named_dest($name);
-            }
-        }
-
-        if ($frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a") {
-            $link_node = $frame->get_parent()->get_node();
-        }
-
-        // Handle anchors & links
-        if ($is_link_node) {
-            if ($href = $node->getAttribute("href")) {
-                $href = Helpers::build_url($dompdf->getProtocol(), $dompdf->getBaseHost(), $dompdf->getBasePath(), $href);
-                $this->_canvas->add_link($href, $x, $y, $w, $h);
-            }
-        }
-    }
-
-    protected function get_child_size(Frame $frame, bool $do_debug_layout_line): array
-    {
-        $w = 0.0;
-        $h = 0.0;
-
-        foreach ($frame->get_children() as $child) {
-            if ($child->get_node()->nodeValue === " " && $child->get_prev_sibling() && !$child->get_next_sibling()) {
-                break;
-            }
-
-            $style = $child->get_style();
-            list(, , $child_w, $child_h) = $child->get_padding_box();
-
-            $child_h2 = 0.0;
-
-            if ($style->width === "auto") {
-                list($child_w, $child_h2) = $this->get_child_size($child, $do_debug_layout_line);
-            }
-
-            if ($style->height === "auto") {
-                list(, $child_h2) = $this->get_child_size($child, $do_debug_layout_line);
-            }
-
-            $w += $child_w;
-            $h = max($h, $child_h, $child_h2);
-
-            if ($do_debug_layout_line) {
-                $this->_debug_layout($child->get_border_box(), "blue");
-
-                if ($this->_dompdf->getOptions()->getDebugLayoutPaddingBox()) {
-                    $this->_debug_layout($child->get_padding_box(), "blue", [0.5, 0.5]);
-                }
-            }
-        }
-
-        return [$w, $h];
-    }
-}
diff --git a/library/vendor/dompdf/vendor/autoload.php b/library/vendor/dompdf/vendor/autoload.php
new file mode 100644
index 000000000..77629e9bf
--- /dev/null
+++ b/library/vendor/dompdf/vendor/autoload.php
@@ -0,0 +1,7 @@
+
+ *     Jordi Boggiano 
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ *     $loader = new \Composer\Autoload\ClassLoader();
+ *
+ *     // register classes with namespaces
+ *     $loader->add('Symfony\Component', __DIR__.'/component');
+ *     $loader->add('Symfony',           __DIR__.'/framework');
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ *     // to enable searching the include path (eg. for PEAR packages)
+ *     $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier 
+ * @author Jordi Boggiano 
+ * @see    https://www.php-fig.org/psr/psr-0/
+ * @see    https://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+    /** @var ?string */
+    private $vendorDir;
+
+    // PSR-4
+    /**
+     * @var array[]
+     * @psalm-var array>
+     */
+    private $prefixLengthsPsr4 = array();
+    /**
+     * @var array[]
+     * @psalm-var array>
+     */
+    private $prefixDirsPsr4 = array();
+    /**
+     * @var array[]
+     * @psalm-var array
+     */
+    private $fallbackDirsPsr4 = array();
+
+    // PSR-0
+    /**
+     * @var array[]
+     * @psalm-var array>
+     */
+    private $prefixesPsr0 = array();
+    /**
+     * @var array[]
+     * @psalm-var array
+     */
+    private $fallbackDirsPsr0 = array();
+
+    /** @var bool */
+    private $useIncludePath = false;
+
+    /**
+     * @var string[]
+     * @psalm-var array
+     */
+    private $classMap = array();
+
+    /** @var bool */
+    private $classMapAuthoritative = false;
+
+    /**
+     * @var bool[]
+     * @psalm-var array
+     */
+    private $missingClasses = array();
+
+    /** @var ?string */
+    private $apcuPrefix;
+
+    /**
+     * @var self[]
+     */
+    private static $registeredLoaders = array();
+
+    /**
+     * @param ?string $vendorDir
+     */
+    public function __construct($vendorDir = null)
+    {
+        $this->vendorDir = $vendorDir;
+    }
+
+    /**
+     * @return string[]
+     */
+    public function getPrefixes()
+    {
+        if (!empty($this->prefixesPsr0)) {
+            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
+        }
+
+        return array();
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return array>
+     */
+    public function getPrefixesPsr4()
+    {
+        return $this->prefixDirsPsr4;
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return array
+     */
+    public function getFallbackDirs()
+    {
+        return $this->fallbackDirsPsr0;
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return array
+     */
+    public function getFallbackDirsPsr4()
+    {
+        return $this->fallbackDirsPsr4;
+    }
+
+    /**
+     * @return string[] Array of classname => path
+     * @psalm-return array
+     */
+    public function getClassMap()
+    {
+        return $this->classMap;
+    }
+
+    /**
+     * @param string[] $classMap Class to filename map
+     * @psalm-param array $classMap
+     *
+     * @return void
+     */
+    public function addClassMap(array $classMap)
+    {
+        if ($this->classMap) {
+            $this->classMap = array_merge($this->classMap, $classMap);
+        } else {
+            $this->classMap = $classMap;
+        }
+    }
+
+    /**
+     * Registers a set of PSR-0 directories for a given prefix, either
+     * appending or prepending to the ones previously set for this prefix.
+     *
+     * @param string          $prefix  The prefix
+     * @param string[]|string $paths   The PSR-0 root directories
+     * @param bool            $prepend Whether to prepend the directories
+     *
+     * @return void
+     */
+    public function add($prefix, $paths, $prepend = false)
+    {
+        if (!$prefix) {
+            if ($prepend) {
+                $this->fallbackDirsPsr0 = array_merge(
+                    (array) $paths,
+                    $this->fallbackDirsPsr0
+                );
+            } else {
+                $this->fallbackDirsPsr0 = array_merge(
+                    $this->fallbackDirsPsr0,
+                    (array) $paths
+                );
+            }
+
+            return;
+        }
+
+        $first = $prefix[0];
+        if (!isset($this->prefixesPsr0[$first][$prefix])) {
+            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+            return;
+        }
+        if ($prepend) {
+            $this->prefixesPsr0[$first][$prefix] = array_merge(
+                (array) $paths,
+                $this->prefixesPsr0[$first][$prefix]
+            );
+        } else {
+            $this->prefixesPsr0[$first][$prefix] = array_merge(
+                $this->prefixesPsr0[$first][$prefix],
+                (array) $paths
+            );
+        }
+    }
+
+    /**
+     * Registers a set of PSR-4 directories for a given namespace, either
+     * appending or prepending to the ones previously set for this namespace.
+     *
+     * @param string          $prefix  The prefix/namespace, with trailing '\\'
+     * @param string[]|string $paths   The PSR-4 base directories
+     * @param bool            $prepend Whether to prepend the directories
+     *
+     * @throws \InvalidArgumentException
+     *
+     * @return void
+     */
+    public function addPsr4($prefix, $paths, $prepend = false)
+    {
+        if (!$prefix) {
+            // Register directories for the root namespace.
+            if ($prepend) {
+                $this->fallbackDirsPsr4 = array_merge(
+                    (array) $paths,
+                    $this->fallbackDirsPsr4
+                );
+            } else {
+                $this->fallbackDirsPsr4 = array_merge(
+                    $this->fallbackDirsPsr4,
+                    (array) $paths
+                );
+            }
+        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+            // Register directories for a new namespace.
+            $length = strlen($prefix);
+            if ('\\' !== $prefix[$length - 1]) {
+                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+            }
+            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+            $this->prefixDirsPsr4[$prefix] = (array) $paths;
+        } elseif ($prepend) {
+            // Prepend directories for an already registered namespace.
+            $this->prefixDirsPsr4[$prefix] = array_merge(
+                (array) $paths,
+                $this->prefixDirsPsr4[$prefix]
+            );
+        } else {
+            // Append directories for an already registered namespace.
+            $this->prefixDirsPsr4[$prefix] = array_merge(
+                $this->prefixDirsPsr4[$prefix],
+                (array) $paths
+            );
+        }
+    }
+
+    /**
+     * Registers a set of PSR-0 directories for a given prefix,
+     * replacing any others previously set for this prefix.
+     *
+     * @param string          $prefix The prefix
+     * @param string[]|string $paths  The PSR-0 base directories
+     *
+     * @return void
+     */
+    public function set($prefix, $paths)
+    {
+        if (!$prefix) {
+            $this->fallbackDirsPsr0 = (array) $paths;
+        } else {
+            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+        }
+    }
+
+    /**
+     * Registers a set of PSR-4 directories for a given namespace,
+     * replacing any others previously set for this namespace.
+     *
+     * @param string          $prefix The prefix/namespace, with trailing '\\'
+     * @param string[]|string $paths  The PSR-4 base directories
+     *
+     * @throws \InvalidArgumentException
+     *
+     * @return void
+     */
+    public function setPsr4($prefix, $paths)
+    {
+        if (!$prefix) {
+            $this->fallbackDirsPsr4 = (array) $paths;
+        } else {
+            $length = strlen($prefix);
+            if ('\\' !== $prefix[$length - 1]) {
+                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+            }
+            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+            $this->prefixDirsPsr4[$prefix] = (array) $paths;
+        }
+    }
+
+    /**
+     * Turns on searching the include path for class files.
+     *
+     * @param bool $useIncludePath
+     *
+     * @return void
+     */
+    public function setUseIncludePath($useIncludePath)
+    {
+        $this->useIncludePath = $useIncludePath;
+    }
+
+    /**
+     * Can be used to check if the autoloader uses the include path to check
+     * for classes.
+     *
+     * @return bool
+     */
+    public function getUseIncludePath()
+    {
+        return $this->useIncludePath;
+    }
+
+    /**
+     * Turns off searching the prefix and fallback directories for classes
+     * that have not been registered with the class map.
+     *
+     * @param bool $classMapAuthoritative
+     *
+     * @return void
+     */
+    public function setClassMapAuthoritative($classMapAuthoritative)
+    {
+        $this->classMapAuthoritative = $classMapAuthoritative;
+    }
+
+    /**
+     * Should class lookup fail if not found in the current class map?
+     *
+     * @return bool
+     */
+    public function isClassMapAuthoritative()
+    {
+        return $this->classMapAuthoritative;
+    }
+
+    /**
+     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+     *
+     * @param string|null $apcuPrefix
+     *
+     * @return void
+     */
+    public function setApcuPrefix($apcuPrefix)
+    {
+        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
+    }
+
+    /**
+     * The APCu prefix in use, or null if APCu caching is not enabled.
+     *
+     * @return string|null
+     */
+    public function getApcuPrefix()
+    {
+        return $this->apcuPrefix;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not
+     *
+     * @return void
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+
+        if (null === $this->vendorDir) {
+            return;
+        }
+
+        if ($prepend) {
+            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
+        } else {
+            unset(self::$registeredLoaders[$this->vendorDir]);
+            self::$registeredLoaders[$this->vendorDir] = $this;
+        }
+    }
+
+    /**
+     * Unregisters this instance as an autoloader.
+     *
+     * @return void
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister(array($this, 'loadClass'));
+
+        if (null !== $this->vendorDir) {
+            unset(self::$registeredLoaders[$this->vendorDir]);
+        }
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param  string    $class The name of the class
+     * @return true|null True if loaded, null otherwise
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            includeFile($file);
+
+            return true;
+        }
+
+        return null;
+    }
+
+    /**
+     * Finds the path to the file where the class is defined.
+     *
+     * @param string $class The name of the class
+     *
+     * @return string|false The path if found, false otherwise
+     */
+    public function findFile($class)
+    {
+        // class map lookup
+        if (isset($this->classMap[$class])) {
+            return $this->classMap[$class];
+        }
+        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+            return false;
+        }
+        if (null !== $this->apcuPrefix) {
+            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+            if ($hit) {
+                return $file;
+            }
+        }
+
+        $file = $this->findFileWithExtension($class, '.php');
+
+        // Search for Hack files if we are running on HHVM
+        if (false === $file && defined('HHVM_VERSION')) {
+            $file = $this->findFileWithExtension($class, '.hh');
+        }
+
+        if (null !== $this->apcuPrefix) {
+            apcu_add($this->apcuPrefix.$class, $file);
+        }
+
+        if (false === $file) {
+            // Remember that this class does not exist.
+            $this->missingClasses[$class] = true;
+        }
+
+        return $file;
+    }
+
+    /**
+     * Returns the currently registered loaders indexed by their corresponding vendor directories.
+     *
+     * @return self[]
+     */
+    public static function getRegisteredLoaders()
+    {
+        return self::$registeredLoaders;
+    }
+
+    /**
+     * @param  string       $class
+     * @param  string       $ext
+     * @return string|false
+     */
+    private function findFileWithExtension($class, $ext)
+    {
+        // PSR-4 lookup
+        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+        $first = $class[0];
+        if (isset($this->prefixLengthsPsr4[$first])) {
+            $subPath = $class;
+            while (false !== $lastPos = strrpos($subPath, '\\')) {
+                $subPath = substr($subPath, 0, $lastPos);
+                $search = $subPath . '\\';
+                if (isset($this->prefixDirsPsr4[$search])) {
+                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
+                        if (file_exists($file = $dir . $pathEnd)) {
+                            return $file;
+                        }
+                    }
+                }
+            }
+        }
+
+        // PSR-4 fallback dirs
+        foreach ($this->fallbackDirsPsr4 as $dir) {
+            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+                return $file;
+            }
+        }
+
+        // PSR-0 lookup
+        if (false !== $pos = strrpos($class, '\\')) {
+            // namespaced class name
+            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+        } else {
+            // PEAR-like class name
+            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+        }
+
+        if (isset($this->prefixesPsr0[$first])) {
+            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+                if (0 === strpos($class, $prefix)) {
+                    foreach ($dirs as $dir) {
+                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+                            return $file;
+                        }
+                    }
+                }
+            }
+        }
+
+        // PSR-0 fallback dirs
+        foreach ($this->fallbackDirsPsr0 as $dir) {
+            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+                return $file;
+            }
+        }
+
+        // PSR-0 include paths.
+        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+            return $file;
+        }
+
+        return false;
+    }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ *
+ * @param  string $file
+ * @return void
+ * @private
+ */
+function includeFile($file)
+{
+    include $file;
+}
diff --git a/library/vendor/dompdf/vendor/composer/InstalledVersions.php b/library/vendor/dompdf/vendor/composer/InstalledVersions.php
new file mode 100644
index 000000000..d50e0c9fc
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/InstalledVersions.php
@@ -0,0 +1,350 @@
+
+ *     Jordi Boggiano 
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer;
+
+use Composer\Autoload\ClassLoader;
+use Composer\Semver\VersionParser;
+
+/**
+ * This class is copied in every Composer installed project and available to all
+ *
+ * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
+ *
+ * To require its presence, you can require `composer-runtime-api ^2.0`
+ */
+class InstalledVersions
+{
+    /**
+     * @var mixed[]|null
+     * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}|array{}|null
+     */
+    private static $installed;
+
+    /**
+     * @var bool|null
+     */
+    private static $canGetVendors;
+
+    /**
+     * @var array[]
+     * @psalm-var array}>
+     */
+    private static $installedByVendor = array();
+
+    /**
+     * Returns a list of all package names which are present, either by being installed, replaced or provided
+     *
+     * @return string[]
+     * @psalm-return list
+     */
+    public static function getInstalledPackages()
+    {
+        $packages = array();
+        foreach (self::getInstalled() as $installed) {
+            $packages[] = array_keys($installed['versions']);
+        }
+
+        if (1 === \count($packages)) {
+            return $packages[0];
+        }
+
+        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
+    }
+
+    /**
+     * Returns a list of all package names with a specific type e.g. 'library'
+     *
+     * @param  string   $type
+     * @return string[]
+     * @psalm-return list
+     */
+    public static function getInstalledPackagesByType($type)
+    {
+        $packagesByType = array();
+
+        foreach (self::getInstalled() as $installed) {
+            foreach ($installed['versions'] as $name => $package) {
+                if (isset($package['type']) && $package['type'] === $type) {
+                    $packagesByType[] = $name;
+                }
+            }
+        }
+
+        return $packagesByType;
+    }
+
+    /**
+     * Checks whether the given package is installed
+     *
+     * This also returns true if the package name is provided or replaced by another package
+     *
+     * @param  string $packageName
+     * @param  bool   $includeDevRequirements
+     * @return bool
+     */
+    public static function isInstalled($packageName, $includeDevRequirements = true)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (isset($installed['versions'][$packageName])) {
+                return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks whether the given package satisfies a version constraint
+     *
+     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
+     *
+     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
+     *
+     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
+     * @param  string        $packageName
+     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
+     * @return bool
+     */
+    public static function satisfies(VersionParser $parser, $packageName, $constraint)
+    {
+        $constraint = $parser->parseConstraints($constraint);
+        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
+
+        return $provided->matches($constraint);
+    }
+
+    /**
+     * Returns a version constraint representing all the range(s) which are installed for a given package
+     *
+     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
+     * whether a given version of a package is installed, and not just whether it exists
+     *
+     * @param  string $packageName
+     * @return string Version constraint usable with composer/semver
+     */
+    public static function getVersionRanges($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            $ranges = array();
+            if (isset($installed['versions'][$packageName]['pretty_version'])) {
+                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
+            }
+            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
+            }
+            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
+            }
+            if (array_key_exists('provided', $installed['versions'][$packageName])) {
+                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
+            }
+
+            return implode(' || ', $ranges);
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+     */
+    public static function getVersion($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['version'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['version'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
+     */
+    public static function getPrettyVersion($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['pretty_version'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
+     */
+    public static function getReference($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            if (!isset($installed['versions'][$packageName]['reference'])) {
+                return null;
+            }
+
+            return $installed['versions'][$packageName]['reference'];
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @param  string      $packageName
+     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
+     */
+    public static function getInstallPath($packageName)
+    {
+        foreach (self::getInstalled() as $installed) {
+            if (!isset($installed['versions'][$packageName])) {
+                continue;
+            }
+
+            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
+        }
+
+        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
+    }
+
+    /**
+     * @return array
+     * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
+     */
+    public static function getRootPackage()
+    {
+        $installed = self::getInstalled();
+
+        return $installed[0]['root'];
+    }
+
+    /**
+     * Returns the raw installed.php data for custom implementations
+     *
+     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
+     * @return array[]
+     * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array}
+     */
+    public static function getRawData()
+    {
+        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
+
+        if (null === self::$installed) {
+            // only require the installed.php file if this file is loaded from its dumped location,
+            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+            if (substr(__DIR__, -8, 1) !== 'C') {
+                self::$installed = include __DIR__ . '/installed.php';
+            } else {
+                self::$installed = array();
+            }
+        }
+
+        return self::$installed;
+    }
+
+    /**
+     * Returns the raw data of all installed.php which are currently loaded for custom implementations
+     *
+     * @return array[]
+     * @psalm-return list}>
+     */
+    public static function getAllRawData()
+    {
+        return self::getInstalled();
+    }
+
+    /**
+     * Lets you reload the static array from another file
+     *
+     * This is only useful for complex integrations in which a project needs to use
+     * this class but then also needs to execute another project's autoloader in process,
+     * and wants to ensure both projects have access to their version of installed.php.
+     *
+     * A typical case would be PHPUnit, where it would need to make sure it reads all
+     * the data it needs from this class, then call reload() with
+     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
+     * the project in which it runs can then also use this class safely, without
+     * interference between PHPUnit's dependencies and the project's dependencies.
+     *
+     * @param  array[] $data A vendor/composer/installed.php data set
+     * @return void
+     *
+     * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array} $data
+     */
+    public static function reload($data)
+    {
+        self::$installed = $data;
+        self::$installedByVendor = array();
+    }
+
+    /**
+     * @return array[]
+     * @psalm-return list}>
+     */
+    private static function getInstalled()
+    {
+        if (null === self::$canGetVendors) {
+            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
+        }
+
+        $installed = array();
+
+        if (self::$canGetVendors) {
+            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
+                if (isset(self::$installedByVendor[$vendorDir])) {
+                    $installed[] = self::$installedByVendor[$vendorDir];
+                } elseif (is_file($vendorDir.'/composer/installed.php')) {
+                    $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
+                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
+                        self::$installed = $installed[count($installed) - 1];
+                    }
+                }
+            }
+        }
+
+        if (null === self::$installed) {
+            // only require the installed.php file if this file is loaded from its dumped location,
+            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
+            if (substr(__DIR__, -8, 1) !== 'C') {
+                self::$installed = require __DIR__ . '/installed.php';
+            } else {
+                self::$installed = array();
+            }
+        }
+        $installed[] = self::$installed;
+
+        return $installed;
+    }
+}
diff --git a/library/vendor/dompdf/vendor/composer/LICENSE b/library/vendor/dompdf/vendor/composer/LICENSE
new file mode 100644
index 000000000..f27399a04
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/library/vendor/dompdf/vendor/composer/autoload_classmap.php b/library/vendor/dompdf/vendor/composer/autoload_classmap.php
new file mode 100644
index 000000000..b708d77ba
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/autoload_classmap.php
@@ -0,0 +1,11 @@
+ $vendorDir . '/composer/InstalledVersions.php',
+    'Dompdf\\Cpdf' => $vendorDir . '/dompdf/dompdf/lib/Cpdf.php',
+);
diff --git a/library/vendor/dompdf/vendor/composer/autoload_namespaces.php b/library/vendor/dompdf/vendor/composer/autoload_namespaces.php
new file mode 100644
index 000000000..b7fc0125d
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/autoload_namespaces.php
@@ -0,0 +1,9 @@
+ array($vendorDir . '/phenx/php-svg-lib/src/Svg'),
+    'Sabberworm\\CSS\\' => array($vendorDir . '/sabberworm/php-css-parser/src'),
+    'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'),
+    'FontLib\\' => array($vendorDir . '/phenx/php-font-lib/src/FontLib'),
+    'Dompdf\\' => array($vendorDir . '/dompdf/dompdf/src'),
+);
diff --git a/library/vendor/dompdf/vendor/composer/autoload_real.php b/library/vendor/dompdf/vendor/composer/autoload_real.php
new file mode 100644
index 000000000..49d5ac331
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/autoload_real.php
@@ -0,0 +1,57 @@
+= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
+        if ($useStaticLoader) {
+            require __DIR__ . '/autoload_static.php';
+
+            call_user_func(\Composer\Autoload\ComposerStaticInit47dfdbccdbe2c66869f4658d0723ed1a::getInitializer($loader));
+        } else {
+            $map = require __DIR__ . '/autoload_namespaces.php';
+            foreach ($map as $namespace => $path) {
+                $loader->set($namespace, $path);
+            }
+
+            $map = require __DIR__ . '/autoload_psr4.php';
+            foreach ($map as $namespace => $path) {
+                $loader->setPsr4($namespace, $path);
+            }
+
+            $classMap = require __DIR__ . '/autoload_classmap.php';
+            if ($classMap) {
+                $loader->addClassMap($classMap);
+            }
+        }
+
+        $loader->register(true);
+
+        return $loader;
+    }
+}
diff --git a/library/vendor/dompdf/vendor/composer/autoload_static.php b/library/vendor/dompdf/vendor/composer/autoload_static.php
new file mode 100644
index 000000000..2c05e6cb1
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/autoload_static.php
@@ -0,0 +1,66 @@
+ 
+        array (
+            'Svg\\' => 4,
+            'Sabberworm\\CSS\\' => 15,
+        ),
+        'M' => 
+        array (
+            'Masterminds\\' => 12,
+        ),
+        'F' => 
+        array (
+            'FontLib\\' => 8,
+        ),
+        'D' => 
+        array (
+            'Dompdf\\' => 7,
+        ),
+    );
+
+    public static $prefixDirsPsr4 = array (
+        'Svg\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/phenx/php-svg-lib/src/Svg',
+        ),
+        'Sabberworm\\CSS\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/sabberworm/php-css-parser/src',
+        ),
+        'Masterminds\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/masterminds/html5/src',
+        ),
+        'FontLib\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/phenx/php-font-lib/src/FontLib',
+        ),
+        'Dompdf\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/dompdf/dompdf/src',
+        ),
+    );
+
+    public static $classMap = array (
+        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
+        'Dompdf\\Cpdf' => __DIR__ . '/..' . '/dompdf/dompdf/lib/Cpdf.php',
+    );
+
+    public static function getInitializer(ClassLoader $loader)
+    {
+        return \Closure::bind(function () use ($loader) {
+            $loader->prefixLengthsPsr4 = ComposerStaticInit47dfdbccdbe2c66869f4658d0723ed1a::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInit47dfdbccdbe2c66869f4658d0723ed1a::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInit47dfdbccdbe2c66869f4658d0723ed1a::$classMap;
+
+        }, null, ClassLoader::class);
+    }
+}
diff --git a/library/vendor/dompdf/vendor/composer/installed.json b/library/vendor/dompdf/vendor/composer/installed.json
new file mode 100644
index 000000000..0acb559d3
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/installed.json
@@ -0,0 +1,295 @@
+{
+    "packages": [
+        {
+            "name": "dompdf/dompdf",
+            "version": "v2.0.1",
+            "version_normalized": "2.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/dompdf/dompdf.git",
+                "reference": "c5310df0e22c758c85ea5288175fc6cd777bc085"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/dompdf/dompdf/zipball/c5310df0e22c758c85ea5288175fc6cd777bc085",
+                "reference": "c5310df0e22c758c85ea5288175fc6cd777bc085",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-mbstring": "*",
+                "masterminds/html5": "^2.0",
+                "phenx/php-font-lib": ">=0.5.4 <1.0.0",
+                "phenx/php-svg-lib": ">=0.3.3 <1.0.0",
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "ext-json": "*",
+                "ext-zip": "*",
+                "mockery/mockery": "^1.3",
+                "phpunit/phpunit": "^7.5 || ^8 || ^9",
+                "squizlabs/php_codesniffer": "^3.5"
+            },
+            "suggest": {
+                "ext-gd": "Needed to process images",
+                "ext-gmagick": "Improves image processing performance",
+                "ext-imagick": "Improves image processing performance",
+                "ext-zlib": "Needed for pdf stream compression"
+            },
+            "time": "2022-09-22T13:43:41+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Dompdf\\": "src/"
+                },
+                "classmap": [
+                    "lib/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1"
+            ],
+            "authors": [
+                {
+                    "name": "The Dompdf Community",
+                    "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
+                }
+            ],
+            "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
+            "homepage": "https://github.com/dompdf/dompdf",
+            "support": {
+                "issues": "https://github.com/dompdf/dompdf/issues",
+                "source": "https://github.com/dompdf/dompdf/tree/v2.0.1"
+            },
+            "install-path": "../dompdf/dompdf"
+        },
+        {
+            "name": "masterminds/html5",
+            "version": "2.7.6",
+            "version_normalized": "2.7.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Masterminds/html5-php.git",
+                "reference": "897eb517a343a2281f11bc5556d6548db7d93947"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/897eb517a343a2281f11bc5556d6548db7d93947",
+                "reference": "897eb517a343a2281f11bc5556d6548db7d93947",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-dom": "*",
+                "ext-libxml": "*",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7"
+            },
+            "time": "2022-08-18T16:18:26+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.7-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Masterminds\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Matt Butcher",
+                    "email": "technosophos@gmail.com"
+                },
+                {
+                    "name": "Matt Farina",
+                    "email": "matt@mattfarina.com"
+                },
+                {
+                    "name": "Asmir Mustafic",
+                    "email": "goetas@gmail.com"
+                }
+            ],
+            "description": "An HTML5 parser and serializer.",
+            "homepage": "http://masterminds.github.io/html5-php",
+            "keywords": [
+                "HTML5",
+                "dom",
+                "html",
+                "parser",
+                "querypath",
+                "serializer",
+                "xml"
+            ],
+            "support": {
+                "issues": "https://github.com/Masterminds/html5-php/issues",
+                "source": "https://github.com/Masterminds/html5-php/tree/2.7.6"
+            },
+            "install-path": "../masterminds/html5"
+        },
+        {
+            "name": "phenx/php-font-lib",
+            "version": "0.5.4",
+            "version_normalized": "0.5.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/dompdf/php-font-lib.git",
+                "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/dd448ad1ce34c63d09baccd05415e361300c35b4",
+                "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*"
+            },
+            "require-dev": {
+                "symfony/phpunit-bridge": "^3 || ^4 || ^5"
+            },
+            "time": "2021-12-17T19:44:54+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "FontLib\\": "src/FontLib"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Ménager",
+                    "email": "fabien.menager@gmail.com"
+                }
+            ],
+            "description": "A library to read, parse, export and make subsets of different types of font files.",
+            "homepage": "https://github.com/PhenX/php-font-lib",
+            "support": {
+                "issues": "https://github.com/dompdf/php-font-lib/issues",
+                "source": "https://github.com/dompdf/php-font-lib/tree/0.5.4"
+            },
+            "install-path": "../phenx/php-font-lib"
+        },
+        {
+            "name": "phenx/php-svg-lib",
+            "version": "0.5.0",
+            "version_normalized": "0.5.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/dompdf/php-svg-lib.git",
+                "reference": "76876c6cf3080bcb6f249d7d59705108166a6685"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685",
+                "reference": "76876c6cf3080bcb6f249d7d59705108166a6685",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": "^7.1 || ^8.0",
+                "sabberworm/php-css-parser": "^8.4"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
+            },
+            "time": "2022-09-06T12:16:56+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Svg\\": "src/Svg"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Ménager",
+                    "email": "fabien.menager@gmail.com"
+                }
+            ],
+            "description": "A library to read, parse and export to PDF SVG files.",
+            "homepage": "https://github.com/PhenX/php-svg-lib",
+            "support": {
+                "issues": "https://github.com/dompdf/php-svg-lib/issues",
+                "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0"
+            },
+            "install-path": "../phenx/php-svg-lib"
+        },
+        {
+            "name": "sabberworm/php-css-parser",
+            "version": "8.4.0",
+            "version_normalized": "8.4.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sabberworm/PHP-CSS-Parser.git",
+                "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/e41d2140031d533348b2192a83f02d8dd8a71d30",
+                "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30",
+                "shasum": ""
+            },
+            "require": {
+                "ext-iconv": "*",
+                "php": ">=5.6.20"
+            },
+            "require-dev": {
+                "codacy/coverage": "^1.4",
+                "phpunit/phpunit": "^4.8.36"
+            },
+            "suggest": {
+                "ext-mbstring": "for parsing UTF-8 CSS"
+            },
+            "time": "2021-12-11T13:40:54+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Sabberworm\\CSS\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Raphael Schweikert"
+                }
+            ],
+            "description": "Parser for CSS Files written in PHP",
+            "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
+            "keywords": [
+                "css",
+                "parser",
+                "stylesheet"
+            ],
+            "support": {
+                "issues": "https://github.com/sabberworm/PHP-CSS-Parser/issues",
+                "source": "https://github.com/sabberworm/PHP-CSS-Parser/tree/8.4.0"
+            },
+            "install-path": "../sabberworm/php-css-parser"
+        }
+    ],
+    "dev": true,
+    "dev-package-names": []
+}
diff --git a/library/vendor/dompdf/vendor/composer/installed.php b/library/vendor/dompdf/vendor/composer/installed.php
new file mode 100644
index 000000000..cdf63de96
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/installed.php
@@ -0,0 +1,68 @@
+ array(
+        'pretty_version' => '1.0.0+no-version-set',
+        'version' => '1.0.0.0',
+        'type' => 'project',
+        'install_path' => __DIR__ . '/../../',
+        'aliases' => array(),
+        'reference' => NULL,
+        'name' => '__root__',
+        'dev' => true,
+    ),
+    'versions' => array(
+        '__root__' => array(
+            'pretty_version' => '1.0.0+no-version-set',
+            'version' => '1.0.0.0',
+            'type' => 'project',
+            'install_path' => __DIR__ . '/../../',
+            'aliases' => array(),
+            'reference' => NULL,
+            'dev_requirement' => false,
+        ),
+        'dompdf/dompdf' => array(
+            'pretty_version' => 'v2.0.1',
+            'version' => '2.0.1.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../dompdf/dompdf',
+            'aliases' => array(),
+            'reference' => 'c5310df0e22c758c85ea5288175fc6cd777bc085',
+            'dev_requirement' => false,
+        ),
+        'masterminds/html5' => array(
+            'pretty_version' => '2.7.6',
+            'version' => '2.7.6.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../masterminds/html5',
+            'aliases' => array(),
+            'reference' => '897eb517a343a2281f11bc5556d6548db7d93947',
+            'dev_requirement' => false,
+        ),
+        'phenx/php-font-lib' => array(
+            'pretty_version' => '0.5.4',
+            'version' => '0.5.4.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phenx/php-font-lib',
+            'aliases' => array(),
+            'reference' => 'dd448ad1ce34c63d09baccd05415e361300c35b4',
+            'dev_requirement' => false,
+        ),
+        'phenx/php-svg-lib' => array(
+            'pretty_version' => '0.5.0',
+            'version' => '0.5.0.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phenx/php-svg-lib',
+            'aliases' => array(),
+            'reference' => '76876c6cf3080bcb6f249d7d59705108166a6685',
+            'dev_requirement' => false,
+        ),
+        'sabberworm/php-css-parser' => array(
+            'pretty_version' => '8.4.0',
+            'version' => '8.4.0.0',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../sabberworm/php-css-parser',
+            'aliases' => array(),
+            'reference' => 'e41d2140031d533348b2192a83f02d8dd8a71d30',
+            'dev_requirement' => false,
+        ),
+    ),
+);
diff --git a/library/vendor/dompdf/vendor/composer/platform_check.php b/library/vendor/dompdf/vendor/composer/platform_check.php
new file mode 100644
index 000000000..6d3407dbb
--- /dev/null
+++ b/library/vendor/dompdf/vendor/composer/platform_check.php
@@ -0,0 +1,26 @@
+= 70100)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.';
+}
+
+if ($issues) {
+    if (!headers_sent()) {
+        header('HTTP/1.1 500 Internal Server Error');
+    }
+    if (!ini_get('display_errors')) {
+        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
+            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
+        } elseif (!headers_sent()) {
+            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
+        }
+    }
+    trigger_error(
+        'Composer detected issues in your platform: ' . implode(' ', $issues),
+        E_USER_ERROR
+    );
+}
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/AUTHORS.md b/library/vendor/dompdf/vendor/dompdf/dompdf/AUTHORS.md
new file mode 100644
index 000000000..686147928
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/AUTHORS.md
@@ -0,0 +1,24 @@
+Dompdf was designed and developed by Benj Carson.
+
+### Current Team
+
+* **Brian Sweeney** (maintainer)
+* **Till Berger**
+
+### Alumni
+
+* **Benj Carson** (creator)
+* **Fabien Ménager**
+* **Simon Berger**
+* **Orion Richardson**
+
+### Contributors
+* **Gabriel Bull**
+* **Barry vd. Heuvel**
+* **Ryan H. Masten**
+* **Helmut Tischer**
+* [and many more...](https://github.com/dompdf/dompdf/graphs/contributors)
+
+### Thanks
+
+Dompdf would not have been possible without strong community support.
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/LICENSE.LGPL b/library/vendor/dompdf/vendor/dompdf/dompdf/LICENSE.LGPL
new file mode 100644
index 000000000..6ef5de82a
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/LICENSE.LGPL
@@ -0,0 +1,456 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be 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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
\ No newline at end of file
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/README.md b/library/vendor/dompdf/vendor/dompdf/dompdf/README.md
new file mode 100644
index 000000000..7546e807e
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/README.md
@@ -0,0 +1,232 @@
+Dompdf
+======
+
+[![Build Status](https://github.com/dompdf/dompdf/actions/workflows/test.yml/badge.svg)](https://github.com/dompdf/dompdf/actions/workflows/test.yml)
+[![Latest Release](https://poser.pugx.org/dompdf/dompdf/v/stable.png)](https://packagist.org/packages/dompdf/dompdf)
+[![Total Downloads](https://poser.pugx.org/dompdf/dompdf/downloads.png)](https://packagist.org/packages/dompdf/dompdf)
+[![License](https://poser.pugx.org/dompdf/dompdf/license.png)](https://packagist.org/packages/dompdf/dompdf)
+ 
+**Dompdf is an HTML to PDF converter**
+
+At its heart, dompdf is (mostly) a [CSS 2.1](http://www.w3.org/TR/CSS2/) compliant
+HTML layout and rendering engine written in PHP. It is a style-driven renderer:
+it will download and read external stylesheets, inline style tags, and the style
+attributes of individual HTML elements. It also supports most presentational
+HTML attributes.
+
+*This document applies to the latest stable code which may not reflect the current 
+release. For released code please
+[navigate to the appropriate tag](https://github.com/dompdf/dompdf/tags).*
+
+----
+
+**Check out the [demo](http://eclecticgeek.com/dompdf/debug.php) and ask any
+question on [StackOverflow](https://stackoverflow.com/questions/tagged/dompdf) or
+in [Discussions](https://github.com/dompdf/dompdf/discussions).**
+
+Follow us on [![Twitter](http://twitter-badges.s3.amazonaws.com/twitter-a.png)](http://www.twitter.com/dompdf).
+
+---
+
+
+
+## Features
+
+ * Handles most CSS 2.1 and a few CSS3 properties, including @import, @media &
+   @page rules
+ * Supports most presentational HTML 4.0 attributes
+ * Supports external stylesheets, either local or through http/ftp (via
+   fopen-wrappers)
+ * Supports complex tables, including row & column spans, separate & collapsed
+   border models, individual cell styling
+ * Image support (gif, png (8, 24 and 32 bit with alpha channel), bmp & jpeg)
+ * No dependencies on external PDF libraries, thanks to the R&OS PDF class
+ * Inline PHP support
+ * Basic SVG support (see "Limitations" below)
+ 
+## Requirements
+
+ * PHP version 7.1 or higher
+ * DOM extension
+ * MBString extension
+ * php-font-lib
+ * php-svg-lib
+ 
+Note that some required dependencies may have further dependencies 
+(notably php-svg-lib requires sabberworm/php-css-parser).
+
+### Recommendations
+
+ * OPcache (OPcache, XCache, APC, etc.): improves performance
+ * GD (for image processing)
+ * IMagick or GMagick extension: improves image processing performance
+
+Visit the wiki for more information:
+https://github.com/dompdf/dompdf/wiki/Requirements
+
+## About Fonts & Character Encoding
+
+PDF documents internally support the following fonts: Helvetica, Times-Roman,
+Courier, Zapf-Dingbats, & Symbol. These fonts only support Windows ANSI
+encoding. In order for a PDF to display characters that are not available in
+Windows ANSI, you must supply an external font. Dompdf will embed any referenced
+font in the PDF so long as it has been pre-loaded or is accessible to dompdf and
+reference in CSS @font-face rules. See the
+[font overview](https://github.com/dompdf/dompdf/wiki/About-Fonts-and-Character-Encoding)
+for more information on how to use fonts.
+
+The [DejaVu TrueType fonts](https://dejavu-fonts.github.io/) have been pre-installed
+to give dompdf decent Unicode character coverage by default. To use the DejaVu
+fonts reference the font in your stylesheet, e.g. `body { font-family: DejaVu
+Sans; }` (for DejaVu Sans). The following DejaVu 2.34 fonts are available:
+DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono.
+
+## Easy Installation
+
+### Install with composer
+
+To install with [Composer](https://getcomposer.org/), simply require the
+latest version of this package.
+
+```bash
+composer require dompdf/dompdf
+```
+
+Make sure that the autoload file from Composer is loaded.
+
+```php
+// somewhere early in your project's loading, require the Composer autoloader
+// see: http://getcomposer.org/doc/00-intro.md
+require 'vendor/autoload.php';
+
+```
+
+### Download and install
+
+Download a packaged archive of dompdf and extract it into the 
+directory where dompdf will reside
+
+ * You can download stable copies of dompdf from
+   https://github.com/dompdf/dompdf/releases
+ * Or download a nightly (the latest, unreleased code) from
+   http://eclecticgeek.com/dompdf
+
+Use the packaged release autoloader to load dompdf, libraries,
+and helper functions in your PHP:
+
+```php
+// include autoloader
+require_once 'dompdf/autoload.inc.php';
+```
+
+Note: packaged releases are named according using semantic
+versioning (_dompdf_MAJOR-MINOR-PATCH.zip_). So the 1.0.0 
+release would be dompdf_1-0-0.zip. This is the only download
+that includes the autoloader for Dompdf and all its dependencies.
+
+### Install with git
+
+From the command line, switch to the directory where dompdf will
+reside and run the following commands:
+
+```sh
+git clone https://github.com/dompdf/dompdf.git
+cd dompdf/lib
+
+git clone https://github.com/PhenX/php-font-lib.git php-font-lib
+cd php-font-lib
+git checkout 0.5.1
+cd ..
+
+git clone https://github.com/PhenX/php-svg-lib.git php-svg-lib
+cd php-svg-lib
+git checkout v0.3.2
+cd ..
+
+git clone https://github.com/sabberworm/PHP-CSS-Parser.git php-css-parser
+cd php-css-parser
+git checkout 8.1.0
+```
+
+Require dompdf and it's dependencies in your PHP.
+For details see the [autoloader in the utils project](https://github.com/dompdf/utils/blob/master/autoload.inc.php).
+
+## Quick Start
+
+Just pass your HTML in to dompdf and stream the output:
+
+```php
+// reference the Dompdf namespace
+use Dompdf\Dompdf;
+
+// instantiate and use the dompdf class
+$dompdf = new Dompdf();
+$dompdf->loadHtml('hello world');
+
+// (Optional) Setup the paper size and orientation
+$dompdf->setPaper('A4', 'landscape');
+
+// Render the HTML as PDF
+$dompdf->render();
+
+// Output the generated PDF to Browser
+$dompdf->stream();
+```
+
+### Setting Options
+
+Set options during dompdf instantiation:
+
+```php
+use Dompdf\Dompdf;
+use Dompdf\Options;
+
+$options = new Options();
+$options->set('defaultFont', 'Courier');
+$dompdf = new Dompdf($options);
+```
+
+or at run time
+
+```php
+use Dompdf\Dompdf;
+
+$dompdf = new Dompdf();
+$options = $dompdf->getOptions();
+$options->setDefaultFont('Courier');
+$dompdf->setOptions($options);
+```
+
+See [Dompdf\Options](src/Options.php) for a list of available options.
+
+### Resource Reference Requirements
+
+In order to protect potentially sensitive information Dompdf imposes 
+restrictions on files referenced from the local file system or the web. 
+
+Files accessed through web-based protocols have the following requirements:
+ * The Dompdf option "isRemoteEnabled" must be set to "true"
+ * PHP must either have the curl extension enabled or the 
+   allow_url_fopen setting set to true
+   
+Files accessed through the local file system have the following requirement:
+ * The file must fall within the path(s) specified for the Dompdf "chroot" option
+
+## Limitations (Known Issues)
+
+ * Table cells are not pageable, meaning a table row must fit on a single page.
+ * Elements are rendered on the active page when they are parsed.
+ * Embedding "raw" SVG's (``) isn't working yet, you need to
+   either link to an external SVG file, or use a DataURI like this:
+     ```php
+     $html = '';
+     ```
+     Watch https://github.com/dompdf/dompdf/issues/320 for progress
+ * Does not support CSS flexbox.
+ * Does not support CSS Grid.
+---
+
+[![Donate button](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](http://goo.gl/DSvWf)
+
+*If you find this project useful, please consider making a donation.
+Any funds donated will be used to help further development on this project.)*
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/VERSION b/library/vendor/dompdf/vendor/dompdf/dompdf/VERSION
new file mode 100644
index 000000000..38f77a65b
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/VERSION
@@ -0,0 +1 @@
+2.0.1
diff --git a/library/vendor/dompdf/composer.json b/library/vendor/dompdf/vendor/dompdf/dompdf/composer.json
similarity index 72%
rename from library/vendor/dompdf/composer.json
rename to library/vendor/dompdf/vendor/dompdf/dompdf/composer.json
index a16ad58fb..268a81e7b 100644
--- a/library/vendor/dompdf/composer.json
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/composer.json
@@ -6,16 +6,8 @@
     "license": "LGPL-2.1",
     "authors": [
         {
-            "name": "Fabien Ménager",
-            "email": "fabien.menager@gmail.com"
-        },
-        {
-            "name": "Brian Sweeney",
-            "email": "eclecticgeek@gmail.com"
-        },
-        {
-            "name": "Gabriel Bull",
-            "email": "me@gabrielbull.com"
+            "name": "The Dompdf Community",
+            "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
         }
     ],
     "autoload": {
@@ -35,10 +27,13 @@
         "php": "^7.1 || ^8.0",
         "ext-dom": "*",
         "ext-mbstring": "*",
-        "phenx/php-font-lib": "^0.5.4",
-        "phenx/php-svg-lib": "^0.3.3 || ^0.4.0"
+        "masterminds/html5": "^2.0",
+        "phenx/php-font-lib": ">=0.5.4 <1.0.0",
+        "phenx/php-svg-lib": ">=0.3.3 <1.0.0"
     },
     "require-dev": {
+        "ext-json": "*",
+        "ext-zip": "*",
         "phpunit/phpunit": "^7.5 || ^8 || ^9",
         "squizlabs/php_codesniffer": "^3.5",
         "mockery/mockery": "^1.3"
diff --git a/library/vendor/dompdf/lib/Cpdf.php b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/Cpdf.php
similarity index 97%
rename from library/vendor/dompdf/lib/Cpdf.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/Cpdf.php
index 8c4098900..27bfa2981 100644
--- a/library/vendor/dompdf/lib/Cpdf.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/Cpdf.php
@@ -3,19 +3,10 @@
  * A PHP class to provide the basic functionality to create a pdf document without
  * any requirement for additional modules.
  *
- * Extended by Orion Richardson to support Unicode / UTF-8 characters using
- * TCPDF and others as a guide.
- *
- * @author  Wayne Munro 
- * @author  Orion Richardson 
- * @author  Helmut Tischer 
- * @author  Ryan H. Masten 
- * @author  Brian Sweeney 
- * @author  Fabien Ménager 
- * @license Public Domain http://creativecommons.org/licenses/publicdomain/
+ * @author  Wayne Munro
+ * @license http://creativecommons.org/licenses/publicdomain/ Public Domain
  * @package Cpdf
  */
-
 namespace Dompdf;
 
 use FontLib\Exception\FontNotFoundException;
@@ -1048,7 +1039,7 @@ class Cpdf
             }
         }
 
-        return 'SUB' . str_pad($base_26, 3 , 'A', STR_PAD_LEFT);
+        return 'SUB' . str_pad($base_26, 3, 'A', STR_PAD_LEFT);
     }
 
     /**
@@ -1381,7 +1372,7 @@ EOT;
 
                 $res = "\n$id 0 obj\n";
                 $res .= "<>\n";
-                $res .= "stream\n" . $stream . "\nendstream" . "\nendobj";;
+                $res .= "stream\n" . $stream . "\nendstream" . "\nendobj";
 
                 return $res;
         }
@@ -2423,8 +2414,7 @@ EOT;
                 $res = "\n$id 0 obj\n<< /Type /XObject\n";
 
                 foreach ($o["info"] as $k => $v) {
-                    switch($k)
-                    {
+                    switch ($k) {
                         case 'Subtype':
                             $res .= "/Subtype /$v\n";
                             break;
@@ -2477,7 +2467,7 @@ EOT;
                 }
 
                 $res .= "/Length " . mb_strlen($tmp, '8bit') . " >>\n";
-                $res .= "stream\n" . $tmp . "\nendstream" . "\nendobj";;
+                $res .= "stream\n" . $tmp . "\nendstream" . "\nendobj";
 
                 return $res;
         }
@@ -2515,7 +2505,7 @@ EOT;
                 $res = "\n$id 0 obj\n<<";
 
                 foreach ($o["info"] as $k => $v) {
-                    switch($k) {
+                    switch ($k) {
                         case 'Fields':
                             $res .= " /Fields [";
                             foreach ($v as $i) {
@@ -2619,7 +2609,7 @@ EOT;
                             $res .= ">>\n";
                             break;
                         case 'T':
-                            if($encrypted) {
+                            if ($encrypted) {
                                 $v = $this->filterText($this->ARC4($v), false, false);
                             }
                             $res .= "/T ($v)\n";
@@ -2662,7 +2652,7 @@ EOT;
                 $pos = strpos($content, sprintf("/ByteRange [ %'.010d", $id));
                 $len = strlen('/ByteRange [ ********** ********** ********** ********** ]');
                 $rangeStartPos = $pos + $len + 1 + 10; // before '<'
-                $content = substr_replace($content, str_pad(sprintf('/ByteRange [ 0 %u %u %u ]', $rangeStartPos, $rangeStartPos + $sign_maxlen + 2, $content_len - 2 - $sign_maxlen - $rangeStartPos ), $len, ' ', STR_PAD_RIGHT), $pos, $len);
+                $content = substr_replace($content, str_pad(sprintf('/ByteRange [ 0 %u %u %u ]', $rangeStartPos, $rangeStartPos + $sign_maxlen + 2, $content_len - 2 - $sign_maxlen - $rangeStartPos), $len, ' ', STR_PAD_RIGHT), $pos, $len);
 
                 $fuid = uniqid();
                 $tmpInput = $this->tmp . "/pkcs7.tmp." . $fuid . '.in';
@@ -2726,7 +2716,7 @@ EOT;
 
                 $o = &$this->objects[$id];
                 foreach ($o['info'] as $k => $v) {
-                    switch($k) {
+                    switch ($k) {
                         case 'Name':
                         case 'Location':
                         case 'Reason':
@@ -2852,7 +2842,7 @@ EOT;
             case 'out':
                 $res = "\n$id 0 obj << ";
 
-                foreach($this->objects[$id]['info'] as $referenceObjName => $referenceObjId) {
+                foreach ($this->objects[$id]['info'] as $referenceObjName => $referenceObjId) {
                     $res .= "/$referenceObjName $referenceObjId 0 R ";
                 }
 
@@ -3310,11 +3300,11 @@ EOT;
     {
         // assume that $font contains the path and file but not the extension
         $name = basename($font);
-        $dir = dirname($font) . '/';
+        $dir = dirname($font);
 
         $fontcache = $this->fontcache;
         if ($fontcache == '') {
-            $fontcache = rtrim($dir, DIRECTORY_SEPARATOR."/\\");
+            $fontcache = $dir;
         }
 
         //$name       filename without folder and extension of font metrics
@@ -3331,36 +3321,22 @@ EOT;
             $metrics_name = "$name.ufm";
         }
 
-        $cache_name = "$metrics_name.php";
+        $cache_name = "$metrics_name.json";
         $this->addMessage("metrics: $metrics_name, cache: $cache_name");
-
+        
         if (file_exists($fontcache . '/' . $cache_name)) {
-            $this->addMessage("openFont: php file exists $fontcache/$cache_name");
-            $this->fonts[$font] = require($fontcache . '/' . $cache_name);
-
-            if (!isset($this->fonts[$font]['_version_']) || $this->fonts[$font]['_version_'] != $this->fontcacheVersion) {
-                // if the font file is old, then clear it out and prepare for re-creation
-                $this->addMessage('openFont: clear out, make way for new version.');
-                $this->fonts[$font] = null;
-                unset($this->fonts[$font]);
-            }
-        } else {
-            $old_cache_name = "php_$metrics_name";
-            if (file_exists($fontcache . '/' . $old_cache_name)) {
-                $this->addMessage(
-                    "openFont: php file doesn't exist $fontcache/$cache_name, creating it from the old format"
-                );
-                $old_cache = file_get_contents($fontcache . '/' . $old_cache_name);
-                file_put_contents($fontcache . '/' . $cache_name, 'openFont($font);
-                return;
+            $this->addMessage("openFont: json metrics file exists $fontcache/$cache_name");
+            $cached_font_info = json_decode(file_get_contents($fontcache . '/' . $cache_name), true);
+            if (!isset($cached_font_info['_version_']) || $cached_font_info['_version_'] != $this->fontcacheVersion) {
+                $this->addMessage('openFont: font cache is out of date, regenerating');
+            } else {
+                $this->fonts[$font] = $cached_font_info;
             }
         }
 
-        if (!isset($this->fonts[$font]) && file_exists($dir . $metrics_name)) {
+        if (!isset($this->fonts[$font]) && file_exists("$dir/$metrics_name")) {
             // then rebuild the php_.afm file from the .afm file
-            $this->addMessage("openFont: build php file from $dir$metrics_name");
+            $this->addMessage("openFont: build php file from $dir/$metrics_name");
             $data = [];
 
             // 20 => 'space'
@@ -3375,7 +3351,7 @@ EOT;
                 $cidtogid = str_pad('', 256 * 256 * 2, "\x00");
             }
 
-            $file = file($dir . $metrics_name);
+            $file = file("$dir/$metrics_name");
 
             foreach ($file as $rowA) {
                 $row = trim($rowA);
@@ -3529,7 +3505,7 @@ EOT;
             //Because of potential trouble with php safe mode, expect that the folder already exists.
             //If not existing, this will hit performance because of missing cached results.
             if (is_dir($fontcache) && is_writable($fontcache)) {
-                file_put_contents($fontcache . '/' . $cache_name, 'fonts[$font])) {
             $this->addMessage("openFont: no font file found for $font. Do you need to run load_font.php?");
         }
-
-        //pre_r($this->messages);
     }
 
     /**
@@ -3548,7 +3522,7 @@ EOT;
      * note that encoding='none' will need to be used for symbolic fonts
      * and 'differences' => an array of mappings between numbers 0->255 and character names.
      *
-     * @param $fontName
+     * @param string $fontName
      * @param string $encoding
      * @param bool $set
      * @param bool $isSubsetting
@@ -3696,8 +3670,8 @@ EOT;
     /**
      * sets the color for fill operations
      *
-     * @param $color
-     * @param bool $force
+     * @param array $color
+     * @param bool  $force
      */
     function setColor($color, $force = false)
     {
@@ -3719,9 +3693,7 @@ EOT;
     }
 
     /**
-     * sets the color for fill operations
-     *
-     * @param $fillRule
+     * @param string $fillRule
      */
     function setFillRule($fillRule)
     {
@@ -3735,8 +3707,8 @@ EOT;
     /**
      * sets the color for stroke operations
      *
-     * @param $color
-     * @param bool $force
+     * @param array $color
+     * @param bool  $force
      */
     function setStrokeColor($color, $force = false)
     {
@@ -3887,11 +3859,11 @@ EOT;
     /**
      * draw a line from one set of coordinates to another
      *
-     * @param $x1
-     * @param $y1
-     * @param $x2
-     * @param $y2
-     * @param bool $stroke
+     * @param float $x1
+     * @param float $y1
+     * @param float $x2
+     * @param float $y2
+     * @param bool  $stroke
      */
     function line($x1, $y1, $x2, $y2, $stroke = true)
     {
@@ -3905,14 +3877,14 @@ EOT;
     /**
      * draw a bezier curve based on 4 control points
      *
-     * @param $x0
-     * @param $y0
-     * @param $x1
-     * @param $y1
-     * @param $x2
-     * @param $y2
-     * @param $x3
-     * @param $y3
+     * @param float $x0
+     * @param float $y0
+     * @param float $x1
+     * @param float $y1
+     * @param float $x2
+     * @param float $y2
+     * @param float $x3
+     * @param float $y3
      */
     function curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
     {
@@ -3926,13 +3898,13 @@ EOT;
     /**
      * draw a part of an ellipse
      *
-     * @param $x0
-     * @param $y0
-     * @param $astart
-     * @param $afinish
-     * @param $r1
-     * @param int $r2
-     * @param int $angle
+     * @param float $x0
+     * @param float $y0
+     * @param float $astart
+     * @param float $afinish
+     * @param float $r1
+     * @param float $r2
+     * @param float $angle
      * @param int $nSeg
      */
     function partEllipse($x0, $y0, $astart, $afinish, $r1, $r2 = 0, $angle = 0, $nSeg = 8)
@@ -3943,14 +3915,14 @@ EOT;
     /**
      * draw a filled ellipse
      *
-     * @param $x0
-     * @param $y0
-     * @param $r1
-     * @param int $r2
-     * @param int $angle
+     * @param float $x0
+     * @param float $y0
+     * @param float $r1
+     * @param float $r2
+     * @param float $angle
      * @param int $nSeg
-     * @param int $astart
-     * @param int $afinish
+     * @param float $astart
+     * @param float $afinish
      */
     function filledEllipse($x0, $y0, $r1, $r2 = 0, $angle = 0, $nSeg = 8, $astart = 0, $afinish = 360)
     {
@@ -3958,8 +3930,8 @@ EOT;
     }
 
     /**
-     * @param $x
-     * @param $y
+     * @param float $x
+     * @param float $y
      */
     function lineTo($x, $y)
     {
@@ -3967,8 +3939,8 @@ EOT;
     }
 
     /**
-     * @param $x
-     * @param $y
+     * @param float $x
+     * @param float $y
      */
     function moveTo($x, $y)
     {
@@ -3978,12 +3950,12 @@ EOT;
     /**
      * draw a bezier curve based on 4 control points
      *
-     * @param $x1
-     * @param $y1
-     * @param $x2
-     * @param $y2
-     * @param $x3
-     * @param $y3
+     * @param float $x1
+     * @param float $y1
+     * @param float $x2
+     * @param float $y2
+     * @param float $x3
+     * @param float $y3
      */
     function curveTo($x1, $y1, $x2, $y2, $x3, $y3)
     {
@@ -3992,6 +3964,11 @@ EOT;
 
     /**
      * draw a bezier curve based on 4 control points
+     *
+     * @param float $cpx
+     * @param float $cpy
+     * @param float $x
+     * @param float $y
      */
     function quadTo($cpx, $cpy, $x, $y)
     {
@@ -4019,18 +3996,18 @@ EOT;
      * nSeg is not allowed to be less than 2, as this will simply draw a line (and will even draw a
      * pretty crappy shape at 2, as we are approximating with bezier curves.
      *
-     * @param $x0
-     * @param $y0
-     * @param $r1
-     * @param int $r2
-     * @param int $angle
-     * @param int $nSeg
-     * @param int $astart
-     * @param int $afinish
-     * @param bool $close
-     * @param bool $fill
-     * @param bool $stroke
-     * @param bool $incomplete
+     * @param float $x0
+     * @param float $y0
+     * @param float $r1
+     * @param float $r2
+     * @param float $angle
+     * @param int   $nSeg
+     * @param float $astart
+     * @param float $afinish
+     * @param bool  $close
+     * @param bool  $fill
+     * @param bool  $stroke
+     * @param bool  $incomplete
      */
     function ellipse(
         $x0,
@@ -4144,11 +4121,11 @@ EOT;
      *   (2,1) is 2 on, 1 off, 2 on, 1 off.. etc
      * phase is a modifier on the dash pattern which is used to shift the point at which the pattern starts.
      *
-     * @param int $width
+     * @param float  $width
      * @param string $cap
      * @param string $join
-     * @param string $dash
-     * @param int $phase
+     * @param array  $dash
+     * @param int    $phase
      */
     function setLineStyle($width = 1, $cap = '', $join = '', $dash = '', $phase = 0)
     {
@@ -4182,19 +4159,19 @@ EOT;
     /**
      * draw a polygon, the syntax for this is similar to the GD polygon command
      *
-     * @param $p
-     * @param $np
-     * @param bool $f
+     * @param float[] $p
+     * @param bool    $fill
      */
-    function polygon($p, $np, $f = false)
+    public function polygon(array $p, bool $fill = false): void
     {
         $this->addContent(sprintf("\n%.3F %.3F m ", $p[0], $p[1]));
 
-        for ($i = 2; $i < $np * 2; $i = $i + 2) {
+        $n = count($p);
+        for ($i = 2; $i < $n; $i = $i + 2) {
             $this->addContent(sprintf("%.3F %.3F l ", $p[$i], $p[$i + 1]));
         }
 
-        if ($f) {
+        if ($fill) {
             $this->addContent(' f');
         } else {
             $this->addContent(' S');
@@ -4205,10 +4182,10 @@ EOT;
      * a filled rectangle, note that it is the width and height of the rectangle which are the secondary parameters, not
      * the coordinates of the upper-right corner
      *
-     * @param $x1
-     * @param $y1
-     * @param $width
-     * @param $height
+     * @param float $x1
+     * @param float $y1
+     * @param float $width
+     * @param float $height
      */
     function filledRectangle($x1, $y1, $width, $height)
     {
@@ -4219,10 +4196,10 @@ EOT;
      * draw a rectangle, note that it is the width and height of the rectangle which are the secondary parameters, not
      * the coordinates of the upper-right corner
      *
-     * @param $x1
-     * @param $y1
-     * @param $width
-     * @param $height
+     * @param float $x1
+     * @param float $y1
+     * @param float $width
+     * @param float $height
      */
     function rectangle($x1, $y1, $width, $height)
     {
@@ -4233,10 +4210,10 @@ EOT;
      * draw a rectangle, note that it is the width and height of the rectangle which are the secondary parameters, not
      * the coordinates of the upper-right corner
      *
-     * @param $x1
-     * @param $y1
-     * @param $width
-     * @param $height
+     * @param float $x1
+     * @param float $y1
+     * @param float $width
+     * @param float $height
      */
     function rect($x1, $y1, $width, $height)
     {
@@ -4348,8 +4325,10 @@ EOT;
         $color = implode(' ', $color) . ' rg';
 
         $currentFontNum = $this->currentFontNum;
-        $font = array_filter($this->objects[$this->currentNode]['info']['fonts'],
-          function($item) use ($currentFontNum) { return $item['fontNum'] == $currentFontNum; });
+        $font = array_filter(
+            $this->objects[$this->currentNode]['info']['fonts'],
+            function ($item) use ($currentFontNum) { return $item['fontNum'] == $currentFontNum; }
+        );
 
         $this->o_acroform($this->acroFormId, 'font',
           ['objNum' => $font[0]['objNum'], 'fontNum' => $font[0]['fontNum']]);
@@ -4464,10 +4443,10 @@ EOT;
     /**
      * draw a clipping rectangle, all the elements added after this will be clipped
      *
-     * @param $x1
-     * @param $y1
-     * @param $width
-     * @param $height
+     * @param float $x1
+     * @param float $y1
+     * @param float $width
+     * @param float $height
      */
     function clippingRectangle($x1, $y1, $width, $height)
     {
@@ -4478,14 +4457,14 @@ EOT;
     /**
      * draw a clipping rounded rectangle, all the elements added after this will be clipped
      *
-     * @param $x1
-     * @param $y1
-     * @param $w
-     * @param $h
-     * @param $rTL
-     * @param $rTR
-     * @param $rBR
-     * @param $rBL
+     * @param float $x1
+     * @param float $y1
+     * @param float $w
+     * @param float $h
+     * @param float $rTL
+     * @param float $rTR
+     * @param float $rBR
+     * @param float $rBL
      */
     function clippingRectangleRounded($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
     {
@@ -4525,6 +4504,25 @@ EOT;
         $this->addContent(" W n");
     }
 
+    /**
+     * draw a clipping polygon, the syntax for this is similar to the GD polygon command
+     *
+     * @param float[] $p
+     */
+    public function clippingPolygon(array $p): void
+    {
+        $this->save();
+
+        $this->addContent(sprintf("\n%.3F %.3F m ", $p[0], $p[1]));
+
+        $n = count($p);
+        for ($i = 2; $i < $n; $i = $i + 2) {
+            $this->addContent(sprintf("%.3F %.3F l ", $p[$i], $p[$i + 1]));
+        }
+
+        $this->addContent("W n");
+    }
+
     /**
      * ends the last clipping shape
      */
@@ -4741,10 +4739,11 @@ EOT;
     /**
      * return the height in units of the current font in the given size
      *
-     * @param $size
-     * @return float|int
+     * @param float $size
+     *
+     * @return float
      */
-    function getFontHeight($size)
+    public function getFontHeight(float $size): float
     {
         if (!$this->numFonts) {
             $this->selectFont($this->defaultFont);
@@ -4776,10 +4775,11 @@ EOT;
     }
 
     /**
-     * @param $size
-     * @return float|int
+     * @param float $size
+     *
+     * @return float
      */
-    function getFontXHeight($size)
+    public function getFontXHeight(float $size): float
     {
         if (!$this->numFonts) {
             $this->selectFont($this->defaultFont);
@@ -4802,10 +4802,11 @@ EOT;
      * if you add this number to the baseline, you get the level of the bottom of the font
      * it is in the pdf user units
      *
-     * @param $size
-     * @return float|int
+     * @param float $size
+     *
+     * @return float
      */
-    function getFontDescender($size)
+    public function getFontDescender(float $size): float
     {
         // note that this will most likely return a negative value
         if (!$this->numFonts) {
@@ -4822,8 +4823,6 @@ EOT;
      * filter the text, this is applied to all text just before being inserted into the pdf document
      * it escapes the various things that need to be escaped, and so on
      *
-     * @access private
-     *
      * @param $text
      * @param bool $bom
      * @param bool $convert_encoding
@@ -4843,7 +4842,7 @@ EOT;
                 //$text = html_entity_decode($text, ENT_QUOTES);
                 $text = mb_convert_encoding($text, self::$targetEncoding, 'UTF-8');
             }
-        } else if ($bom) {
+        } elseif ($bom) {
             $text = $this->utf8toUtf16BE($text, $bom);
         }
 
@@ -4858,12 +4857,7 @@ EOT;
      * based on the excellent TCPDF code by Nicola Asuni and the
      * RFC for UTF-8 at http://www.faqs.org/rfcs/rfc3629.html
      *
-     * @access private
-     * @author Orion Richardson
-     * @since  January 5, 2008
-     *
      * @param string $text UTF-8 string to process
-     *
      * @return array UTF-8 codepoints array for the string
      */
     function utf8toCodePointsArray(&$text)
@@ -4933,13 +4927,8 @@ EOT;
      * based on the excellent TCPDF code by Nicola Asuni and the
      * RFC for UTF-8 at http://www.faqs.org/rfcs/rfc3629.html
      *
-     * @access private
-     * @author Orion Richardson
-     * @since  January 5, 2008
-     *
      * @param string  $text UTF-8 string to process
      * @param boolean $bom  whether to add the byte order marker
-     *
      * @return string UTF-16 result string
      */
     function utf8toUtf16BE(&$text, $bom = true)
@@ -5014,8 +5003,8 @@ EOT;
     /**
      * register text for font subsetting
      *
-     * @param $font
-     * @param $text
+     * @param string $font
+     * @param string $text
      */
     function registerText($font, $text)
     {
@@ -5024,7 +5013,8 @@ EOT;
         }
 
         if (!isset($this->stringSubsets[$font])) {
-            $this->stringSubsets[$font] = [];
+            $base_subset = "\u{fffd}\u{fffe}\u{ffff}";
+            $this->stringSubsets[$font] = $this->utf8toCodePointsArray($base_subset);
         }
 
         $this->stringSubsets[$font] = array_unique(
@@ -5035,14 +5025,14 @@ EOT;
     /**
      * add text to the document, at a specified location, size and angle on the page
      *
-     * @param $x
-     * @param $y
-     * @param $size
-     * @param $text
-     * @param int $angle
-     * @param int $wordSpaceAdjust
-     * @param int $charSpaceAdjust
-     * @param bool $smallCaps
+     * @param float  $x
+     * @param float  $y
+     * @param float  $size
+     * @param string $text
+     * @param float  $angle
+     * @param float  $wordSpaceAdjust
+     * @param float  $charSpaceAdjust
+     * @param bool   $smallCaps
      */
     function addText($x, $y, $size, $text, $angle = 0, $wordSpaceAdjust = 0, $charSpaceAdjust = 0, $smallCaps = false)
     {
@@ -5155,13 +5145,14 @@ EOT;
      * calculate how wide a given text string will be on a page, at a given size.
      * this can be called externally, but is also used by the other class functions
      *
-     * @param float $size
+     * @param float  $size
      * @param string $text
-     * @param float $word_spacing
-     * @param float $char_spacing
+     * @param float  $wordSpacing
+     * @param float  $charSpacing
+     *
      * @return float
      */
-    function getTextWidth($size, $text, $word_spacing = 0, $char_spacing = 0)
+    public function getTextWidth(float $size, string $text, float $wordSpacing = 0.0, float $charSpacing = 0.0): float
     {
         static $ord_cache = [];
 
@@ -5176,9 +5167,6 @@ EOT;
 
         $text = str_replace(["\r", "\n"], "", $text);
 
-        // converts a number or a float to a string so it can get the width
-        $text = "$text";
-
         // hmm, this is where it all starts to get tricky - use the font information to
         // calculate the width of each character, add them up and convert to user units
         $w = 0;
@@ -5205,14 +5193,14 @@ EOT;
 
                     // add additional padding for space
                     if (isset($current_font['codeToName'][$char]) && $current_font['codeToName'][$char] === 'space') {  // Space
-                        $w += $word_spacing * $space_scale;
+                        $w += $wordSpacing * $space_scale;
                     }
                 }
             }
 
             // add additional char spacing
-            if ($char_spacing != 0) {
-                $w += $char_spacing * $space_scale * count($unicode);
+            if ($charSpacing != 0) {
+                $w += $charSpacing * $space_scale * count($unicode);
             }
 
         } else {
@@ -5240,14 +5228,14 @@ EOT;
 
                     // add additional padding for space
                     if (isset($current_font['codeToName'][$char]) && $current_font['codeToName'][$char] === 'space') {  // Space
-                        $w += $word_spacing * $space_scale;
+                        $w += $wordSpacing * $space_scale;
                     }
                 }
             }
 
             // add additional char spacing
-            if ($char_spacing != 0) {
-                $w += $char_spacing * $space_scale * $len;
+            if ($charSpacing != 0) {
+                $w += $charSpacing * $space_scale * $len;
             }
         }
 
@@ -5487,12 +5475,12 @@ EOT;
     }
 
     /**
-     * add content to the documents info object
+     * Add content to the documents info object
      *
-     * @param $label
-     * @param int $value
+     * @param string|array $label
+     * @param string       $value
      */
-    function addInfo($label, $value = 0)
+    public function addInfo($label, string $value = ""): void
     {
         // this will only work if the label is one of the valid ones.
         // modify this so that arrays can be passed as well.
@@ -5500,7 +5488,7 @@ EOT;
         // else assume that they are both scalar, anything else will probably error
         if (is_array($label)) {
             foreach ($label as $l => $v) {
-                $this->o_info($this->infoObject, $l, $v);
+                $this->o_info($this->infoObject, $l, (string) $v);
             }
         } else {
             $this->o_info($this->infoObject, $label, $value);
diff --git a/library/vendor/dompdf/lib/fonts/Courier-Bold.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier-Bold.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Courier-Bold.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier-Bold.afm
diff --git a/library/vendor/dompdf/lib/fonts/Courier-BoldOblique.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier-BoldOblique.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Courier-BoldOblique.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier-BoldOblique.afm
diff --git a/library/vendor/dompdf/lib/fonts/Courier-Oblique.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier-Oblique.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Courier-Oblique.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier-Oblique.afm
diff --git a/library/vendor/dompdf/lib/fonts/Courier.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Courier.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Courier.afm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Bold.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Bold.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Bold.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Bold.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans-BoldOblique.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-BoldOblique.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans-BoldOblique.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-BoldOblique.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans-BoldOblique.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-BoldOblique.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans-BoldOblique.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-BoldOblique.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans-Oblique.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Oblique.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans-Oblique.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Oblique.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans-Oblique.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Oblique.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans-Oblique.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Oblique.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSans.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSans.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono-Bold.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Bold.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono-Bold.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Bold.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono-Oblique.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Oblique.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono-Oblique.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Oblique.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono-Oblique.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Oblique.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono-Oblique.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Oblique.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSansMono.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSansMono.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Bold.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Bold.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Bold.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Bold.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif-Italic.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Italic.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif-Italic.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Italic.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif-Italic.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Italic.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif-Italic.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Italic.ufm
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif.ttf b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif.ttf
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif.ttf
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif.ttf
diff --git a/library/vendor/dompdf/lib/fonts/DejaVuSerif.ufm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif.ufm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/DejaVuSerif.ufm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/DejaVuSerif.ufm
diff --git a/library/vendor/dompdf/lib/fonts/Helvetica-Bold.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica-Bold.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Helvetica-Bold.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica-Bold.afm
diff --git a/library/vendor/dompdf/lib/fonts/Helvetica-BoldOblique.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica-BoldOblique.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Helvetica-BoldOblique.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica-BoldOblique.afm
diff --git a/library/vendor/dompdf/lib/fonts/Helvetica-Oblique.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica-Oblique.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Helvetica-Oblique.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica-Oblique.afm
diff --git a/library/vendor/dompdf/lib/fonts/Helvetica.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Helvetica.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Helvetica.afm
diff --git a/library/vendor/dompdf/lib/fonts/Symbol.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Symbol.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Symbol.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Symbol.afm
diff --git a/library/vendor/dompdf/lib/fonts/Times-Bold.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-Bold.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Times-Bold.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-Bold.afm
diff --git a/library/vendor/dompdf/lib/fonts/Times-BoldItalic.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-BoldItalic.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Times-BoldItalic.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-BoldItalic.afm
diff --git a/library/vendor/dompdf/lib/fonts/Times-Italic.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-Italic.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Times-Italic.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-Italic.afm
diff --git a/library/vendor/dompdf/lib/fonts/Times-Roman.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-Roman.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/Times-Roman.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/Times-Roman.afm
diff --git a/library/vendor/dompdf/lib/fonts/ZapfDingbats.afm b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/ZapfDingbats.afm
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/ZapfDingbats.afm
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/ZapfDingbats.afm
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/installed-fonts.dist.json b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/installed-fonts.dist.json
new file mode 100644
index 000000000..c6abf158b
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/installed-fonts.dist.json
@@ -0,0 +1,80 @@
+{
+    "sans-serif": {
+        "normal": "Helvetica",
+        "bold": "Helvetica-Bold",
+        "italic": "Helvetica-Oblique",
+        "bold_italic": "Helvetica-BoldOblique"
+    },
+    "times": {
+        "normal": "Times-Roman",
+        "bold": "Times-Bold",
+        "italic": "Times-Italic",
+        "bold_italic": "Times-BoldItalic"
+    },
+    "times-roman": {
+        "normal": "Times-Roman",
+        "bold": "Times-Bold",
+        "italic": "Times-Italic",
+        "bold_italic": "Times-BoldItalic"
+    },
+    "courier": {
+        "normal": "Courier",
+        "bold": "Courier-Bold",
+        "italic": "Courier-Oblique",
+        "bold_italic": "Courier-BoldOblique"
+    },
+    "helvetica": {
+        "normal": "Helvetica",
+        "bold": "Helvetica-Bold",
+        "italic": "Helvetica-Oblique",
+        "bold_italic": "Helvetica-BoldOblique"
+    },
+    "zapfdingbats": {
+        "normal": "ZapfDingbats",
+        "bold": "ZapfDingbats",
+        "italic": "ZapfDingbats",
+        "bold_italic": "ZapfDingbats"
+    },
+    "symbol": {
+        "normal": "Symbol",
+        "bold": "Symbol",
+        "italic": "Symbol",
+        "bold_italic": "Symbol"
+    },
+    "serif": {
+        "normal": "Times-Roman",
+        "bold": "Times-Bold",
+        "italic": "Times-Italic",
+        "bold_italic": "Times-BoldItalic"
+    },
+    "monospace": {
+        "normal": "Courier",
+        "bold": "Courier-Bold",
+        "italic": "Courier-Oblique",
+        "bold_italic": "Courier-BoldOblique"
+    },
+    "fixed": {
+        "normal": "Courier",
+        "bold": "Courier-Bold",
+        "italic": "Courier-Oblique",
+        "bold_italic": "Courier-BoldOblique"
+    },
+    "dejavu sans": {
+        "bold": "DejaVuSans-Bold",
+        "bold_italic": "DejaVuSans-BoldOblique",
+        "italic": "DejaVuSans-Oblique",
+        "normal": "DejaVuSans"
+    },
+    "dejavu sans mono": {
+        "bold": "DejaVuSansMono-Bold",
+        "bold_italic": "DejaVuSansMono-BoldOblique",
+        "italic": "DejaVuSansMono-Oblique",
+        "normal": "DejaVuSansMono"
+    },
+    "dejavu serif": {
+        "bold": "DejaVuSerif-Bold",
+        "bold_italic": "DejaVuSerif-BoldItalic",
+        "italic": "DejaVuSerif-Italic",
+        "normal": "DejaVuSerif"
+    }
+}
\ No newline at end of file
diff --git a/library/vendor/dompdf/lib/fonts/mustRead.html b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/mustRead.html
similarity index 100%
rename from library/vendor/dompdf/lib/fonts/mustRead.html
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/fonts/mustRead.html
diff --git a/library/vendor/dompdf/lib/res/broken_image.png b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/broken_image.png
similarity index 100%
rename from library/vendor/dompdf/lib/res/broken_image.png
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/broken_image.png
diff --git a/library/vendor/dompdf/lib/res/broken_image.svg b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/broken_image.svg
similarity index 100%
rename from library/vendor/dompdf/lib/res/broken_image.svg
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/broken_image.svg
diff --git a/library/vendor/dompdf/lib/res/html.css b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/html.css
similarity index 97%
rename from library/vendor/dompdf/lib/res/html.css
rename to library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/html.css
index 379fb1372..89dcde633 100644
--- a/library/vendor/dompdf/lib/res/html.css
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/lib/res/html.css
@@ -2,15 +2,12 @@
  * dompdf default stylesheet.
  *
  * @package dompdf
- * @link    http://dompdf.github.com/
- * @author  Benj Carson 
- * @author  Blake Ross 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  *
  * Portions from Mozilla
  * @link https://dxr.mozilla.org/mozilla-central/source/layout/style/res/html.css
- * @license http://mozilla.org/MPL/2.0/ Mozilla Public License, v. 2.0 
+ * @license http://mozilla.org/MPL/2.0/ Mozilla Public License, v. 2.0
  *
  * Portions from W3C
  * @link https://drafts.csswg.org/css-ui-3/#default-style-sheet
diff --git a/library/vendor/dompdf/src/Adapter/CPDF.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/CPDF.php
similarity index 62%
rename from library/vendor/dompdf/src/Adapter/CPDF.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/CPDF.php
index a7e6bec08..e8fc6ae4d 100644
--- a/library/vendor/dompdf/src/Adapter/CPDF.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/CPDF.php
@@ -1,11 +1,7 @@
 
- * @author  Orion Richardson 
- * @author  Helmut Tischer 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 
@@ -14,10 +10,10 @@ namespace Dompdf\Adapter;
 
 use Dompdf\Canvas;
 use Dompdf\Dompdf;
-use Dompdf\Helpers;
 use Dompdf\Exception;
+use Dompdf\FontMetrics;
+use Dompdf\Helpers;
 use Dompdf\Image\Cache;
-use Dompdf\PhpEvaluator;
 use FontLib\Exception\FontNotFoundException;
 
 /**
@@ -41,66 +37,66 @@ class CPDF implements Canvas
     /**
      * Dimensions of paper sizes in points
      *
-     * @var array;
+     * @var array
      */
     static $PAPER_SIZES = [
-        "4a0" => [0, 0, 4767.87, 6740.79],
-        "2a0" => [0, 0, 3370.39, 4767.87],
-        "a0" => [0, 0, 2383.94, 3370.39],
-        "a1" => [0, 0, 1683.78, 2383.94],
-        "a2" => [0, 0, 1190.55, 1683.78],
-        "a3" => [0, 0, 841.89, 1190.55],
-        "a4" => [0, 0, 595.28, 841.89],
-        "a5" => [0, 0, 419.53, 595.28],
-        "a6" => [0, 0, 297.64, 419.53],
-        "a7" => [0, 0, 209.76, 297.64],
-        "a8" => [0, 0, 147.40, 209.76],
-        "a9" => [0, 0, 104.88, 147.40],
-        "a10" => [0, 0, 73.70, 104.88],
-        "b0" => [0, 0, 2834.65, 4008.19],
-        "b1" => [0, 0, 2004.09, 2834.65],
-        "b2" => [0, 0, 1417.32, 2004.09],
-        "b3" => [0, 0, 1000.63, 1417.32],
-        "b4" => [0, 0, 708.66, 1000.63],
-        "b5" => [0, 0, 498.90, 708.66],
-        "b6" => [0, 0, 354.33, 498.90],
-        "b7" => [0, 0, 249.45, 354.33],
-        "b8" => [0, 0, 175.75, 249.45],
-        "b9" => [0, 0, 124.72, 175.75],
-        "b10" => [0, 0, 87.87, 124.72],
-        "c0" => [0, 0, 2599.37, 3676.54],
-        "c1" => [0, 0, 1836.85, 2599.37],
-        "c2" => [0, 0, 1298.27, 1836.85],
-        "c3" => [0, 0, 918.43, 1298.27],
-        "c4" => [0, 0, 649.13, 918.43],
-        "c5" => [0, 0, 459.21, 649.13],
-        "c6" => [0, 0, 323.15, 459.21],
-        "c7" => [0, 0, 229.61, 323.15],
-        "c8" => [0, 0, 161.57, 229.61],
-        "c9" => [0, 0, 113.39, 161.57],
-        "c10" => [0, 0, 79.37, 113.39],
-        "ra0" => [0, 0, 2437.80, 3458.27],
-        "ra1" => [0, 0, 1729.13, 2437.80],
-        "ra2" => [0, 0, 1218.90, 1729.13],
-        "ra3" => [0, 0, 864.57, 1218.90],
-        "ra4" => [0, 0, 609.45, 864.57],
-        "sra0" => [0, 0, 2551.18, 3628.35],
-        "sra1" => [0, 0, 1814.17, 2551.18],
-        "sra2" => [0, 0, 1275.59, 1814.17],
-        "sra3" => [0, 0, 907.09, 1275.59],
-        "sra4" => [0, 0, 637.80, 907.09],
-        "letter" => [0, 0, 612.00, 792.00],
-        "half-letter" => [0, 0, 396.00, 612.00],
-        "legal" => [0, 0, 612.00, 1008.00],
-        "ledger" => [0, 0, 1224.00, 792.00],
-        "tabloid" => [0, 0, 792.00, 1224.00],
-        "executive" => [0, 0, 521.86, 756.00],
-        "folio" => [0, 0, 612.00, 936.00],
-        "commercial #10 envelope" => [0, 0, 684, 297],
-        "catalog #10 1/2 envelope" => [0, 0, 648, 864],
-        "8.5x11" => [0, 0, 612.00, 792.00],
-        "8.5x14" => [0, 0, 612.00, 1008.0],
-        "11x17" => [0, 0, 792.00, 1224.00],
+        "4a0" => [0.0, 0.0, 4767.87, 6740.79],
+        "2a0" => [0.0, 0.0, 3370.39, 4767.87],
+        "a0" => [0.0, 0.0, 2383.94, 3370.39],
+        "a1" => [0.0, 0.0, 1683.78, 2383.94],
+        "a2" => [0.0, 0.0, 1190.55, 1683.78],
+        "a3" => [0.0, 0.0, 841.89, 1190.55],
+        "a4" => [0.0, 0.0, 595.28, 841.89],
+        "a5" => [0.0, 0.0, 419.53, 595.28],
+        "a6" => [0.0, 0.0, 297.64, 419.53],
+        "a7" => [0.0, 0.0, 209.76, 297.64],
+        "a8" => [0.0, 0.0, 147.40, 209.76],
+        "a9" => [0.0, 0.0, 104.88, 147.40],
+        "a10" => [0.0, 0.0, 73.70, 104.88],
+        "b0" => [0.0, 0.0, 2834.65, 4008.19],
+        "b1" => [0.0, 0.0, 2004.09, 2834.65],
+        "b2" => [0.0, 0.0, 1417.32, 2004.09],
+        "b3" => [0.0, 0.0, 1000.63, 1417.32],
+        "b4" => [0.0, 0.0, 708.66, 1000.63],
+        "b5" => [0.0, 0.0, 498.90, 708.66],
+        "b6" => [0.0, 0.0, 354.33, 498.90],
+        "b7" => [0.0, 0.0, 249.45, 354.33],
+        "b8" => [0.0, 0.0, 175.75, 249.45],
+        "b9" => [0.0, 0.0, 124.72, 175.75],
+        "b10" => [0.0, 0.0, 87.87, 124.72],
+        "c0" => [0.0, 0.0, 2599.37, 3676.54],
+        "c1" => [0.0, 0.0, 1836.85, 2599.37],
+        "c2" => [0.0, 0.0, 1298.27, 1836.85],
+        "c3" => [0.0, 0.0, 918.43, 1298.27],
+        "c4" => [0.0, 0.0, 649.13, 918.43],
+        "c5" => [0.0, 0.0, 459.21, 649.13],
+        "c6" => [0.0, 0.0, 323.15, 459.21],
+        "c7" => [0.0, 0.0, 229.61, 323.15],
+        "c8" => [0.0, 0.0, 161.57, 229.61],
+        "c9" => [0.0, 0.0, 113.39, 161.57],
+        "c10" => [0.0, 0.0, 79.37, 113.39],
+        "ra0" => [0.0, 0.0, 2437.80, 3458.27],
+        "ra1" => [0.0, 0.0, 1729.13, 2437.80],
+        "ra2" => [0.0, 0.0, 1218.90, 1729.13],
+        "ra3" => [0.0, 0.0, 864.57, 1218.90],
+        "ra4" => [0.0, 0.0, 609.45, 864.57],
+        "sra0" => [0.0, 0.0, 2551.18, 3628.35],
+        "sra1" => [0.0, 0.0, 1814.17, 2551.18],
+        "sra2" => [0.0, 0.0, 1275.59, 1814.17],
+        "sra3" => [0.0, 0.0, 907.09, 1275.59],
+        "sra4" => [0.0, 0.0, 637.80, 907.09],
+        "letter" => [0.0, 0.0, 612.00, 792.00],
+        "half-letter" => [0.0, 0.0, 396.00, 612.00],
+        "legal" => [0.0, 0.0, 612.00, 1008.00],
+        "ledger" => [0.0, 0.0, 1224.00, 792.00],
+        "tabloid" => [0.0, 0.0, 792.00, 1224.00],
+        "executive" => [0.0, 0.0, 521.86, 756.00],
+        "folio" => [0.0, 0.0, 612.00, 936.00],
+        "commercial #10 envelope" => [0.0, 0.0, 684.00, 297.00],
+        "catalog #10 1/2 envelope" => [0.0, 0.0, 648.00, 864.00],
+        "8.5x11" => [0.0, 0.0, 612.00, 792.00],
+        "8.5x14" => [0.0, 0.0, 612.00, 1008.00],
+        "11x17" => [0.0, 0.0, 792.00, 1224.00],
     ];
 
     /**
@@ -145,13 +141,6 @@ class CPDF implements Canvas
      */
     protected $_page_count;
 
-    /**
-     * Text to display on every page
-     *
-     * @var array
-     */
-    protected $_page_text;
-
     /**
      * Array of pages for accessing after rendering is initially complete
      *
@@ -166,24 +155,16 @@ class CPDF implements Canvas
      */
     protected $_current_opacity = 1;
 
-    /**
-     * Class constructor
-     *
-     * @param mixed $paper The size of paper to use in this PDF ({@link CPDF::$PAPER_SIZES})
-     * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
-     * @param Dompdf $dompdf The Dompdf instance
-     */
-    public function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf = null)
+    public function __construct($paper = "letter", $orientation = "portrait", ?Dompdf $dompdf = null)
     {
         if (is_array($paper)) {
-            $size = $paper;
-        } else if (isset(self::$PAPER_SIZES[mb_strtolower($paper)])) {
-            $size = self::$PAPER_SIZES[mb_strtolower($paper)];
+            $size = array_map("floatval", $paper);
         } else {
-            $size = self::$PAPER_SIZES["letter"];
+            $paper = strtolower($paper);
+            $size = self::$PAPER_SIZES[$paper] ?? self::$PAPER_SIZES["letter"];
         }
 
-        if (mb_strtolower($orientation) === "landscape") {
+        if (strtolower($orientation) === "landscape") {
             [$size[2], $size[3]] = [$size[3], $size[2]];
         }
 
@@ -209,14 +190,10 @@ class CPDF implements Canvas
         $this->_height = $size[3] - $size[1];
 
         $this->_page_number = $this->_page_count = 1;
-        $this->_page_text = [];
 
         $this->_pages = [$this->_pdf->getFirstPageId()];
     }
 
-    /**
-     * @return Dompdf
-     */
     public function get_dompdf()
     {
         return $this->_dompdf;
@@ -232,13 +209,7 @@ class CPDF implements Canvas
         return $this->_pdf;
     }
 
-    /**
-     * Add meta information to the PDF
-     *
-     * @param string $label label of the value (Creator, Producer, etc.)
-     * @param string $value the text to set
-     */
-    public function add_info($label, $value)
+    public function add_info(string $label, string $value): void
     {
         $this->_pdf->addInfo($label, $value);
     }
@@ -324,17 +295,13 @@ class CPDF implements Canvas
     }
 
     /**
-     * @access private
+     * Serialize the pdf object's current state for retrieval later
      */
     public function serialize_object($id)
     {
-        // Serialize the pdf object's current state for retrieval later
         return $this->_pdf->serializeObject($id);
     }
 
-    /**
-     * @access private
-     */
     public function reopen_serialized_object($obj)
     {
         return $this->_pdf->restoreSerializedObject($obj);
@@ -342,37 +309,21 @@ class CPDF implements Canvas
 
     //........................................................................
 
-    /**
-     * Returns the PDF's width in points
-     * @return float
-     */
     public function get_width()
     {
         return $this->_width;
     }
 
-    /**
-     * Returns the PDF's height in points
-     * @return float
-     */
     public function get_height()
     {
         return $this->_height;
     }
 
-    /**
-     * Returns the current page number
-     * @return int
-     */
     public function get_page_number()
     {
         return $this->_page_number;
     }
 
-    /**
-     * Returns the total number of pages in the document
-     * @return int
-     */
     public function get_page_count()
     {
         return $this->_page_count;
@@ -388,11 +339,6 @@ class CPDF implements Canvas
         $this->_page_number = $num;
     }
 
-    /**
-     * Sets the page count
-     *
-     * @param int $count
-     */
     public function set_page_count($count)
     {
         $this->_page_count = $count;
@@ -402,15 +348,14 @@ class CPDF implements Canvas
      * Sets the stroke color
      *
      * See {@link Style::set_color()} for the format of the color array.
+     *
      * @param array $color
      */
     protected function _set_stroke_color($color)
     {
         $this->_pdf->setStrokeColor($color);
         $alpha = isset($color["alpha"]) ? $color["alpha"] : 1;
-        if ($this->_current_opacity != 1) {
-            $alpha *= $this->_current_opacity;
-        }
+        $alpha *= $this->_current_opacity;
         $this->_set_line_transparency("Normal", $alpha);
     }
 
@@ -418,15 +363,14 @@ class CPDF implements Canvas
      * Sets the fill colour
      *
      * See {@link Style::set_color()} for the format of the colour array.
+     *
      * @param array $color
      */
     protected function _set_fill_color($color)
     {
         $this->_pdf->setColor($color);
         $alpha = isset($color["alpha"]) ? $color["alpha"] : 1;
-        if ($this->_current_opacity) {
-            $alpha *= $this->_current_opacity;
-        }
+        $alpha *= $this->_current_opacity;
         $this->_set_fill_transparency("Normal", $alpha);
     }
 
@@ -440,8 +384,8 @@ class CPDF implements Canvas
      * ColorDodge, ColorBurn, HardLight, SoftLight, Difference,
      * Exclusion
      *
-     * @param string $mode the blending mode to use
-     * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
+     * @param string $mode    the blending mode to use
+     * @param float  $opacity 0.0 fully transparent, 1.0 fully opaque
      */
     protected function _set_line_transparency($mode, $opacity)
     {
@@ -458,8 +402,8 @@ class CPDF implements Canvas
      * ColorDogde, ColorBurn, HardLight, SoftLight, Difference,
      * Exclusion
      *
-     * @param string $mode the blending mode to use
-     * @param float $opacity 0.0 fully transparent, 1.0 fully opaque
+     * @param string $mode    the blending mode to use
+     * @param float  $opacity 0.0 fully transparent, 1.0 fully opaque
      */
     protected function _set_fill_transparency($mode, $opacity)
     {
@@ -471,23 +415,17 @@ class CPDF implements Canvas
      *
      * @see Cpdf::setLineStyle()
      *
-     * @param float $width
+     * @param float  $width
      * @param string $cap
      * @param string $join
-     * @param array $dash
+     * @param array  $dash
      */
     protected function _set_line_style($width, $cap, $join, $dash)
     {
         $this->_pdf->setLineStyle($width, $cap, $join, $dash);
     }
 
-    /**
-     * Sets the opacity
-     *
-     * @param $opacity
-     * @param $mode
-     */
-    public function set_opacity($opacity, $mode = "Normal")
+    public function set_opacity(float $opacity, string $mode = "Normal"): void
     {
         $this->_set_line_transparency($mode, $opacity);
         $this->_set_fill_transparency($mode, $opacity);
@@ -511,90 +449,33 @@ class CPDF implements Canvas
         return $this->_height - $y;
     }
 
-    /**
-     * Canvas implementation
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $x2
-     * @param float $y2
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function line($x1, $y1, $x2, $y2, $color, $width, $style = [])
+    public function line($x1, $y1, $x2, $y2, $color, $width, $style = [], $cap = "butt")
     {
         $this->_set_stroke_color($color);
-        $this->_set_line_style($width, "butt", "", $style);
+        $this->_set_line_style($width, $cap, "", $style);
 
         $this->_pdf->line($x1, $this->y($y1),
             $x2, $this->y($y2));
         $this->_set_line_transparency("Normal", $this->_current_opacity);
     }
 
-    /**
-     * Draw line at the specified coordinates on every page.
-     *
-     * See {@link Style::munge_color()} for the format of the colour array.
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $x2
-     * @param float $y2
-     * @param array $color
-     * @param float $width
-     * @param array $style optional
-     */
-    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = [])
-    {
-        $_t = 'line';
-        $this->_page_text[] = compact('_t', 'x1', 'y1', 'x2', 'y2', 'color', 'width', 'style');
-    }
-
-    /**
-     * @param float $x
-     * @param float $y
-     * @param float $r1
-     * @param float $r2
-     * @param float $astart
-     * @param float $aend
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = [])
+    public function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = [], $cap = "butt")
     {
         $this->_set_stroke_color($color);
-        $this->_set_line_style($width, "butt", "", $style);
+        $this->_set_line_style($width, $cap, "", $style);
 
         $this->_pdf->ellipse($x, $this->y($y), $r1, $r2, 0, 8, $astart, $aend, false, false, true, false);
         $this->_set_line_transparency("Normal", $this->_current_opacity);
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = [])
+    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = [], $cap = "butt")
     {
         $this->_set_stroke_color($color);
-        $this->_set_line_style($width, "butt", "", $style);
+        $this->_set_line_style($width, $cap, "", $style);
         $this->_pdf->rectangle($x1, $this->y($y1) - $h, $w, $h);
         $this->_set_line_transparency("Normal", $this->_current_opacity);
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     */
     public function filled_rectangle($x1, $y1, $w, $h, $color)
     {
         $this->_set_fill_color($color);
@@ -602,143 +483,87 @@ class CPDF implements Canvas
         $this->_set_fill_transparency("Normal", $this->_current_opacity);
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     */
     public function clipping_rectangle($x1, $y1, $w, $h)
     {
         $this->_pdf->clippingRectangle($x1, $this->y($y1) - $h, $w, $h);
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param float $rTL
-     * @param float $rTR
-     * @param float $rBR
-     * @param float $rBL
-     */
     public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
     {
         $this->_pdf->clippingRectangleRounded($x1, $this->y($y1) - $h, $w, $h, $rTL, $rTR, $rBR, $rBL);
     }
 
-    /**
-     *
-     */
+    public function clipping_polygon(array $points): void
+    {
+        // Adjust y values
+        for ($i = 1; $i < count($points); $i += 2) {
+            $points[$i] = $this->y($points[$i]);
+        }
+
+        $this->_pdf->clippingPolygon($points);
+    }
+
     public function clipping_end()
     {
         $this->_pdf->clippingEnd();
     }
 
-    /**
-     *
-     */
     public function save()
     {
         $this->_pdf->saveState();
     }
 
-    /**
-     *
-     */
     public function restore()
     {
         $this->_pdf->restoreState();
     }
 
-    /**
-     * @param $angle
-     * @param $x
-     * @param $y
-     */
     public function rotate($angle, $x, $y)
     {
         $this->_pdf->rotate($angle, $x, $y);
     }
 
-    /**
-     * @param $angle_x
-     * @param $angle_y
-     * @param $x
-     * @param $y
-     */
     public function skew($angle_x, $angle_y, $x, $y)
     {
         $this->_pdf->skew($angle_x, $angle_y, $x, $y);
     }
 
-    /**
-     * @param $s_x
-     * @param $s_y
-     * @param $x
-     * @param $y
-     */
     public function scale($s_x, $s_y, $x, $y)
     {
         $this->_pdf->scale($s_x, $s_y, $x, $y);
     }
 
-    /**
-     * @param $t_x
-     * @param $t_y
-     */
     public function translate($t_x, $t_y)
     {
         $this->_pdf->translate($t_x, $t_y);
     }
 
-    /**
-     * @param $a
-     * @param $b
-     * @param $c
-     * @param $d
-     * @param $e
-     * @param $f
-     */
     public function transform($a, $b, $c, $d, $e, $f)
     {
         $this->_pdf->transform([$a, $b, $c, $d, $e, $f]);
     }
 
-    /**
-     * @param array $points
-     * @param array $color
-     * @param null $width
-     * @param array $style
-     * @param bool $fill
-     */
     public function polygon($points, $color, $width = null, $style = [], $fill = false)
     {
         $this->_set_fill_color($color);
         $this->_set_stroke_color($color);
 
+        if (!$fill && isset($width)) {
+            $this->_set_line_style($width, "square", "miter", $style);
+        }
+
         // Adjust y values
         for ($i = 1; $i < count($points); $i += 2) {
             $points[$i] = $this->y($points[$i]);
         }
 
-        $this->_pdf->polygon($points, count($points) / 2, $fill);
+        $this->_pdf->polygon($points, $fill);
 
         $this->_set_fill_transparency("Normal", $this->_current_opacity);
         $this->_set_line_transparency("Normal", $this->_current_opacity);
     }
 
-    /**
-     * @param float $x
-     * @param float $y
-     * @param float $r1
-     * @param array $color
-     * @param null $width
-     * @param null $style
-     * @param bool $fill
-     */
-    public function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false)
+    public function circle($x, $y, $r, $color, $width = null, $style = [], $fill = false)
     {
         $this->_set_fill_color($color);
         $this->_set_stroke_color($color);
@@ -747,7 +572,7 @@ class CPDF implements Canvas
             $this->_set_line_style($width, "round", "round", $style);
         }
 
-        $this->_pdf->ellipse($x, $this->y($y), $r1, 0, 0, 8, 0, 360, 1, $fill);
+        $this->_pdf->ellipse($x, $this->y($y), $r, 0, 0, 8, 0, 360, 1, $fill);
 
         $this->_set_fill_transparency("Normal", $this->_current_opacity);
         $this->_set_line_transparency("Normal", $this->_current_opacity);
@@ -759,8 +584,7 @@ class CPDF implements Canvas
      * @param string $image_url
      * @param string $type
      *
-     * @throws Exception
-     * @return string The url of the newly converted image
+     * @return string|null The url of the newly converted image
      */
     protected function _convert_to_png($image_url, $type)
     {
@@ -772,6 +596,8 @@ class CPDF implements Canvas
  
         $func_name = "imagecreatefrom$type";
 
+        set_error_handler([Helpers::class, "record_warnings"]);
+
         if (!function_exists($func_name)) {
             if (!method_exists(Helpers::class, $func_name)) {
                 throw new Exception("Function $func_name() not found.  Cannot convert $type image: $image_url.  Please install the image PHP extension.");
@@ -779,8 +605,6 @@ class CPDF implements Canvas
             $func_name = [Helpers::class, $func_name];
         }
 
-        set_error_handler([Helpers::class, "record_warnings"]);
-
         try {
             $im = call_user_func($func_name, $image_url);
 
@@ -795,25 +619,19 @@ class CPDF implements Canvas
                 imagepng($im, $filename);
                 imagedestroy($im);
             } else {
-                $filename = Cache::$broken_image;
+                $filename = null;
             }
         } finally {
             restore_error_handler();
         }
 
-        Cache::addTempImage($image_url, $filename);
+        if ($filename !== null) {
+            Cache::addTempImage($image_url, $filename);
+        }
 
         return $filename;
     }
 
-    /**
-     * @param string $img
-     * @param float $x
-     * @param float $y
-     * @param int $w
-     * @param int $h
-     * @param string $resolution
-     */
     public function image($img, $x, $y, $w, $h, $resolution = "normal")
     {
         [$width, $height, $type] = Helpers::dompdf_getimagesize($img, $this->get_dompdf()->getHttpContext());
@@ -839,6 +657,11 @@ class CPDF implements Canvas
             case "bmp":
                 if ($debug_png) print "!!!{$type}!!!";
                 $img = $this->_convert_to_png($img, $type);
+                if ($img === null) {
+                    if ($debug_png) print '!!!conversion to PDF failed!!!';
+                    $this->image(Cache::$broken_image, $x, $y, $w, $h, $resolution);
+                    break;
+                }
 
             case "png":
                 if ($debug_png) print '!!!png!!!';
@@ -922,17 +745,6 @@ class CPDF implements Canvas
         $pdf->addFormField($ft, rand(), $x, $this->y($y) - $h, $x + $w, $this->y($y), $ff, $size, $color);
     }
 
-    /**
-     * @param float $x
-     * @param float $y
-     * @param string $text
-     * @param string $font
-     * @param float $size
-     * @param array $color
-     * @param float $word_space
-     * @param float $char_space
-     * @param float $angle
-     */
     public function text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
     {
         $pdf = $this->_pdf;
@@ -947,9 +759,6 @@ class CPDF implements Canvas
         $this->_set_fill_transparency("Normal", $this->_current_opacity);
     }
 
-    /**
-     * @param string $code
-     */
     public function javascript($code)
     {
         $this->_pdf->addJavascript($code);
@@ -957,25 +766,11 @@ class CPDF implements Canvas
 
     //........................................................................
 
-    /**
-     * Add a named destination (similar to ... in html)
-     *
-     * @param string $anchorname The name of the named destination
-     */
     public function add_named_dest($anchorname)
     {
         $this->_pdf->addDestination($anchorname, "Fit");
     }
 
-    /**
-     * Add a link to the pdf
-     *
-     * @param string $url The url to link to
-     * @param float $x The x position of the link
-     * @param float $y The y position of the link
-     * @param float $width The width of the link
-     * @param float $height The height of the link
-     */
     public function add_link($url, $x, $y, $width, $height)
     {
         $y = $this->y($y) - $height;
@@ -987,28 +782,20 @@ class CPDF implements Canvas
                 $this->_pdf->addInternalLink($name, $x, $y, $x + $width, $y + $height);
             }
         } else {
-            $this->_pdf->addLink(rawurldecode($url), $x, $y, $x + $width, $y + $height);
+            $this->_pdf->addLink($url, $x, $y, $x + $width, $y + $height);
         }
     }
 
     /**
-     * @param string $text
-     * @param string $font
-     * @param float $size
-     * @param float $word_spacing
-     * @param float $char_spacing
-     * @return float
+     * @throws FontNotFoundException
      */
-    public function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0)
+    public function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0)
     {
         $this->_pdf->selectFont($font, '', true, $this->_dompdf->getOptions()->getIsFontSubsettingEnabled());
         return $this->_pdf->getTextWidth($size, $text, $word_spacing, $char_spacing);
     }
 
     /**
-     * @param string $font
-     * @param float $size
-     * @return float|int
      * @throws FontNotFoundException
      */
     public function get_font_height($font, $size)
@@ -1026,9 +813,7 @@ class CPDF implements Canvas
     }*/
 
     /**
-     * @param string $font
-     * @param float $size
-     * @return float
+     * @throws FontNotFoundException
      */
     public function get_font_baseline($font, $size)
     {
@@ -1037,53 +822,53 @@ class CPDF implements Canvas
     }
 
     /**
-     * Writes text at the specified x and y coordinates on every page
+     * Processes a callback or script on every page.
      *
-     * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
-     * with their current values.
-     *
-     * See {@link Style::munge_color()} for the format of the colour array.
-     *
-     * @param float $x
-     * @param float $y
-     * @param string $text the text to write
-     * @param string $font the font file to use
-     * @param float $size the font size, in points
-     * @param array $color
-     * @param float $word_space word spacing adjustment
-     * @param float $char_space char spacing adjustment
-     * @param float $angle angle to write the text at, measured CW starting from the x-axis
-     */
-    public function page_text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
-    {
-        $_t = "text";
-        $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle");
-    }
-
-    /**
-     * Processes a callback or script on every page
-     *
-     * The callback function receives the four parameters `$pageNumber`,
-     * `$pageCount`, `$pdf`, and `$fontMetrics`, in that order. If a script is
-     * passed as string, the variables `$PAGE_NUM`, `$PAGE_COUNT`, `$pdf`, and
-     * `$fontMetrics` are available instead.
+     * The callback function receives the four parameters `int $pageNumber`,
+     * `int $pageCount`, `Canvas $canvas`, and `FontMetrics $fontMetrics`, in
+     * that order. If a script is passed as string, the variables `$PAGE_NUM`,
+     * `$PAGE_COUNT`, `$pdf`, and `$fontMetrics` are available instead. Passing
+     * a script as string is deprecated and will be removed in a future version.
      *
      * This function can be used to add page numbers to all pages after the
      * first one, for example.
      *
-     * @param callable|string $code The callback function or PHP script to process on every page
+     * @param callable|string $callback The callback function or PHP script to process on every page
      */
-    public function page_script($code)
+    public function page_script($callback): void
     {
-        if (is_callable($code)) {
-            $this->_page_text[] = [
-                "_t"       => "callback",
-                "callback" => $code
-            ];
-        } else {
-            $_t = "script";
-            $this->_page_text[] = compact("_t", "code");
+        if (is_string($callback)) {
+            $this->processPageScript(function (
+                int $PAGE_NUM,
+                int $PAGE_COUNT,
+                self $pdf,
+                FontMetrics $fontMetrics
+            ) use ($callback) {
+                eval($callback);
+            });
+            return;
         }
+
+        $this->processPageScript($callback);
+    }
+
+    public function page_text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
+    {
+        $this->processPageScript(function (int $pageNumber, int $pageCount) use ($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle) {
+            $text = str_replace(
+                ["{PAGE_NUM}", "{PAGE_COUNT}"],
+                [$pageNumber, $pageCount],
+                $text
+            );
+            $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
+        });
+    }
+
+    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = [])
+    {
+        $this->processPageScript(function () use ($x1, $y1, $x2, $y2, $color, $width, $style) {
+            $this->line($x1, $y1, $x2, $y2, $color, $width, $style);
+        });
     }
 
     /**
@@ -1099,60 +884,21 @@ class CPDF implements Canvas
         return $ret;
     }
 
-    /**
-     * Add text to each page after rendering is complete
-     */
-    protected function _add_page_text()
+    protected function processPageScript(callable $callback): void
     {
-        if (!count($this->_page_text)) {
-            return;
-        }
-
-        $page_number = 1;
-        $eval = null;
+        $pageNumber = 1;
 
         foreach ($this->_pages as $pid) {
             $this->reopen_object($pid);
 
-            foreach ($this->_page_text as $pt) {
-                extract($pt);
-
-                switch ($_t) {
-                    case "text":
-                        $text = str_replace(["{PAGE_NUM}", "{PAGE_COUNT}"],
-                            [$page_number, $this->_page_count], $text);
-                        $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
-                        break;
-
-                    case "callback":
-                        $fontMetrics = $this->get_dompdf()->getFontMetrics();
-                        $callback($page_number, $this->_page_count, $this, $fontMetrics);
-                        break;
-
-                    case "script":
-                        if (!$eval) {
-                            $eval = new PhpEvaluator($this);
-                        }
-                        $eval->evaluate($code, ["PAGE_NUM" => $page_number, "PAGE_COUNT" => $this->_page_count]);
-                        break;
-
-                    case "line":
-                        $this->line($x1, $y1, $x2, $y2, $color, $width, $style);
-                        break;
-                }
-            }
+            $fontMetrics = $this->_dompdf->getFontMetrics();
+            $callback($pageNumber, $this->_page_count, $this, $fontMetrics);
 
             $this->close_object();
-            $page_number++;
+            $pageNumber++;
         }
     }
 
-    /**
-     * Streams the PDF to the client.
-     *
-     * @param string $filename The filename to present to the client.
-     * @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
-     */
     public function stream($filename = "document.pdf", $options = [])
     {
         if (headers_sent()) {
@@ -1162,8 +908,6 @@ class CPDF implements Canvas
         if (!isset($options["compress"])) $options["compress"] = true;
         if (!isset($options["Attachment"])) $options["Attachment"] = true;
 
-        $this->_add_page_text();
-
         $debug = !$options['compress'];
         $tmp = ltrim($this->_pdf->output($debug));
 
@@ -1179,18 +923,10 @@ class CPDF implements Canvas
         flush();
     }
 
-    /**
-     * Returns the PDF as a string.
-     *
-     * @param array $options Associative array: 'compress' => 1 or 0 (default 1).
-     * @return string
-     */
     public function output($options = [])
     {
         if (!isset($options["compress"])) $options["compress"] = true;
 
-        $this->_add_page_text();
-
         $debug = !$options['compress'];
 
         return $this->_pdf->output($debug);
diff --git a/library/vendor/dompdf/src/Adapter/GD.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/GD.php
similarity index 66%
rename from library/vendor/dompdf/src/Adapter/GD.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/GD.php
index de5edc7f2..8c10e4766 100644
--- a/library/vendor/dompdf/src/Adapter/GD.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/GD.php
@@ -1,17 +1,15 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Adapter;
 
 use Dompdf\Canvas;
 use Dompdf\Dompdf;
-use Dompdf\Image\Cache;
 use Dompdf\Helpers;
+use Dompdf\Image\Cache;
 
 /**
  * Image rendering interface
@@ -130,29 +128,24 @@ class GD implements Canvas
     const FONT_SCALE = 0.75;
 
     /**
-     * Class constructor
-     *
-     * @param mixed $size The size of image to create: array(x1,y1,x2,y2) or "letter", "legal", etc.
-     * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
-     * @param Dompdf $dompdf
-     * @param float $aa_factor Anti-aliasing factor, 1 for no AA
-     * @param array $bg_color Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1
+     * @param string|float[] $paper       The paper size to use as either a standard paper size (see {@link CPDF::$PAPER_SIZES}) or
+     *                                    an array of the form `[x1, y1, x2, y2]` (typically `[0, 0, width, height]`).
+     * @param string         $orientation The paper orientation, either `portrait` or `landscape`.
+     * @param Dompdf         $dompdf      The Dompdf instance.
+     * @param float          $aa_factor   Anti-aliasing factor, 1 for no AA
+     * @param array          $bg_color    Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1
      */
-    public function __construct($size = 'letter', $orientation = "portrait", Dompdf $dompdf = null, $aa_factor = 1.0, $bg_color = [1, 1, 1, 0])
+    public function __construct($paper = "letter", $orientation = "portrait", ?Dompdf $dompdf = null, $aa_factor = 1.0, $bg_color = [1, 1, 1, 0])
     {
-
-        if (!is_array($size)) {
-            $size = strtolower($size);
-
-            if (isset(CPDF::$PAPER_SIZES[$size])) {
-                $size = CPDF::$PAPER_SIZES[$size];
-            } else {
-                $size = CPDF::$PAPER_SIZES["letter"];
-            }
+        if (is_array($paper)) {
+            $size = array_map("floatval", $paper);
+        } else {
+            $paper = strtolower($paper);
+            $size = CPDF::$PAPER_SIZES[$paper] ?? CPDF::$PAPER_SIZES["letter"];
         }
 
         if (strtolower($orientation) === "landscape") {
-            list($size[2], $size[3]) = [$size[3], $size[2]];
+            [$size[2], $size[3]] = [$size[3], $size[2]];
         }
 
         if ($dompdf === null) {
@@ -190,9 +183,6 @@ class GD implements Canvas
         $this->new_page();
     }
 
-    /**
-     * @return Dompdf
-     */
     public function get_dompdf()
     {
         return $this->_dompdf;
@@ -228,21 +218,11 @@ class GD implements Canvas
         return round($this->_height / $this->_aa_factor);
     }
 
-    /**
-     * Returns the current page number
-     *
-     * @return int
-     */
     public function get_page_number()
     {
         return $this->_page_number;
     }
 
-    /**
-     * Returns the total number of pages in the document
-     *
-     * @return int
-     */
     public function get_page_count()
     {
         return $this->_page_count;
@@ -258,23 +238,12 @@ class GD implements Canvas
         $this->_page_number = $num;
     }
 
-    /**
-     * Sets the page count
-     *
-     * @param int $count
-     */
     public function set_page_count($count)
     {
         $this->_page_count = $count;
     }
 
-    /**
-     * Sets the opacity
-     *
-     * @param $opacity
-     * @param $mode
-     */
-    public function set_opacity($opacity, $mode = "Normal")
+    public function set_opacity(float $opacity, string $mode = "Normal"): void
     {
         // FIXME
     }
@@ -284,7 +253,7 @@ class GD implements Canvas
      * previously allocated colors in $this->_colors.
      *
      * @param array $color The new current color
-     * @return int           The allocated color
+     * @return int The allocated color
      */
     protected function _allocate_color($color)
     {
@@ -342,30 +311,61 @@ class GD implements Canvas
      * Scales value down from the current canvas DPI to 72 DPI
      *
      * @param float $length
-     * @return int
+     * @return float
      */
     protected function _downscale($length)
     {
         return round(($length / $this->dpi * 72) / $this->_aa_factor);
     }
 
-    /**
-     * Draws a line from x1,y1 to x2,y2
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the format of the
-     * $style parameter (aka dash).
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $x2
-     * @param float $y2
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function line($x1, $y1, $x2, $y2, $color, $width, $style = null)
+    protected function convertStyle(array $style, int $color, int $width): array
     {
+        $gdStyle = [];
+
+        if (count($style) === 1) {
+            $style[] = $style[0];
+        }
+
+        foreach ($style as $index => $s) {
+            $d = $this->_upscale($s);
+
+            for ($i = 0; $i < $d; $i++) {
+                for ($j = 0; $j < $width; $j++) {
+                    $gdStyle[] = $index % 2 === 0
+                        ? $color
+                        : IMG_COLOR_TRANSPARENT;
+                }
+            }
+        }
+
+        return $gdStyle;
+    }
+
+    public function line($x1, $y1, $x2, $y2, $color, $width, $style = [], $cap = "butt")
+    {
+        // Account for the fact that round and square caps are expected to
+        // extend outwards
+        if ($cap === "round" || $cap === "square") {
+            // Shift line by half width
+            $w = $width / 2;
+            $a = $x2 - $x1;
+            $b = $y2 - $y1;
+            $c = sqrt($a ** 2 + $b ** 2);
+            $dx = $a * $w / $c;
+            $dy = $b * $w / $c;
+
+            $x1 -= $dx;
+            $x2 -= $dx;
+            $y1 -= $dy;
+            $y2 -= $dy;
+
+            // Adapt dash pattern
+            if (is_array($style)) {
+                foreach ($style as $index => &$s) {
+                    $s = $index % 2 === 0 ? $s + $width : $s - $width;
+                }
+            }
+        }
 
         // Scale by the AA factor and DPI
         $x1 = $this->_upscale($x1);
@@ -378,34 +378,7 @@ class GD implements Canvas
 
         // Convert the style array if required
         if (is_array($style) && count($style) > 0) {
-            $gd_style = [];
-
-            if (count($style) == 1) {
-                for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
-                    $gd_style[] = $c;
-                }
-
-                for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
-                    $gd_style[] = $this->_bg_color;
-                }
-            } else {
-                $i = 0;
-                foreach ($style as $length) {
-                    if ($i % 2 == 0) {
-                        // 'On' pattern
-                        for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
-                            $gd_style[] = $c;
-                        }
-
-                    } else {
-                        // Off pattern
-                        for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
-                            $gd_style[] = $this->_bg_color;
-                        }
-                    }
-                    $i++;
-                }
-            }
+            $gd_style = $this->convertStyle($style, $c, $width);
 
             if (!empty($gd_style)) {
                 imagesetstyle($this->get_image(), $gd_style);
@@ -418,39 +391,59 @@ class GD implements Canvas
         imageline($this->get_image(), $x1, $y1, $x2, $y2, $c);
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $r1
-     * @param float $r2
-     * @param float $astart
-     * @param float $aend
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = [])
+    public function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = [], $cap = "butt")
     {
-        // @todo
+        // Account for the fact that round and square caps are expected to
+        // extend outwards
+        if ($cap === "round" || $cap === "square") {
+            // Adapt dash pattern
+            if (is_array($style)) {
+                foreach ($style as $index => &$s) {
+                    $s = $index % 2 === 0 ? $s + $width : $s - $width;
+                }
+            }
+        }
+
+        // Scale by the AA factor and DPI
+        $x = $this->_upscale($x);
+        $y = $this->_upscale($y);
+        $w = $this->_upscale($r1 * 2);
+        $h = $this->_upscale($r2 * 2);
+        $width = $this->_upscale($width);
+
+        // Adapt angles as imagearc counts clockwise
+        $start = 360 - $aend;
+        $end = 360 - $astart;
+
+        $c = $this->_allocate_color($color);
+
+        // Convert the style array if required
+        if (is_array($style) && count($style) > 0) {
+            $gd_style = $this->convertStyle($style, $c, $width);
+
+            if (!empty($gd_style)) {
+                imagesetstyle($this->get_image(), $gd_style);
+                $c = IMG_COLOR_STYLED;
+            }
+        }
+
+        imagesetthickness($this->get_image(), $width);
+
+        imagearc($this->get_image(), $x, $y, $w, $h, $start, $end, $c);
     }
 
-    /**
-     * Draws a rectangle at x1,y1 with width w and height h
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the $style
-     * parameter (aka dash)
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
+    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = [], $cap = "butt")
     {
+        // Account for the fact that round and square caps are expected to
+        // extend outwards
+        if ($cap === "round" || $cap === "square") {
+            // Adapt dash pattern
+            if (is_array($style)) {
+                foreach ($style as $index => &$s) {
+                    $s = $index % 2 === 0 ? $s + $width : $s - $width;
+                }
+            }
+        }
 
         // Scale by the AA factor and DPI
         $x1 = $this->_upscale($x1);
@@ -463,13 +456,7 @@ class GD implements Canvas
 
         // Convert the style array if required
         if (is_array($style) && count($style) > 0) {
-            $gd_style = [];
-
-            foreach ($style as $length) {
-                for ($i = 0; $i < $length; $i++) {
-                    $gd_style[] = $c;
-                }
-            }
+            $gd_style = $this->convertStyle($style, $c, $width);
 
             if (!empty($gd_style)) {
                 imagesetstyle($this->get_image(), $gd_style);
@@ -479,20 +466,18 @@ class GD implements Canvas
 
         imagesetthickness($this->get_image(), $width);
 
-        imagerectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
+        if ($c === IMG_COLOR_STYLED) {
+            imagepolygon($this->get_image(), [
+                $x1, $y1,
+                $x1 + $w, $y1,
+                $x1 + $w, $y1 + $h,
+                $x1, $y1 + $h
+            ], $c);
+        } else {
+            imagerectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
+        }
     }
 
-    /**
-     * Draws a filled rectangle at x1,y1 with width w and height h
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     */
     public function filled_rectangle($x1, $y1, $w, $h, $color)
     {
         // Scale by the AA factor and DPI
@@ -506,14 +491,6 @@ class GD implements Canvas
         imagefilledrectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
     }
 
-    /**
-     * Starts a clipping rectangle at x1,y1 with width w and height h
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     */
     public function clipping_rectangle($x1, $y1, $w, $h)
     {
         // @todo
@@ -524,127 +501,65 @@ class GD implements Canvas
         // @todo
     }
 
-    /**
-     * Ends the last clipping shape
-     */
+    public function clipping_polygon(array $points): void
+    {
+        // @todo
+    }
+
     public function clipping_end()
     {
         // @todo
     }
 
-    /**
-     *
-     */
     public function save()
     {
         $this->get_dompdf()->getOptions()->setDpi(72);
     }
 
-    /**
-     *
-     */
     public function restore()
     {
         $this->get_dompdf()->getOptions()->setDpi($this->dpi);
     }
 
-    /**
-     * @param $angle
-     * @param $x
-     * @param $y
-     */
     public function rotate($angle, $x, $y)
     {
         // @todo
     }
 
-    /**
-     * @param $angle_x
-     * @param $angle_y
-     * @param $x
-     * @param $y
-     */
     public function skew($angle_x, $angle_y, $x, $y)
     {
         // @todo
     }
 
-    /**
-     * @param $s_x
-     * @param $s_y
-     * @param $x
-     * @param $y
-     */
     public function scale($s_x, $s_y, $x, $y)
     {
         // @todo
     }
 
-    /**
-     * @param $t_x
-     * @param $t_y
-     */
     public function translate($t_x, $t_y)
     {
         // @todo
     }
 
-    /**
-     * @param $a
-     * @param $b
-     * @param $c
-     * @param $d
-     * @param $e
-     * @param $f
-     */
     public function transform($a, $b, $c, $d, $e, $f)
     {
         // @todo
     }
 
-    /**
-     * Draws a polygon
-     *
-     * The polygon is formed by joining all the points stored in the $points
-     * array.  $points has the following structure:
-     * 
-     * array(0 => x1,
-     *       1 => y1,
-     *       2 => x2,
-     *       3 => y2,
-     *       ...
-     *       );
-     * 
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the $style
-     * parameter (aka dash)
-     *
-     * @param array $points
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     * @param bool $fill Fills the polygon if true
-     */
-    public function polygon($points, $color, $width = null, $style = null, $fill = false)
+    public function polygon($points, $color, $width = null, $style = [], $fill = false)
     {
-
         // Scale each point by the AA factor and DPI
         foreach (array_keys($points) as $i) {
             $points[$i] = $this->_upscale($points[$i]);
         }
 
+        $width = isset($width) ? $this->_upscale($width) : null;
+
         $c = $this->_allocate_color($color);
 
         // Convert the style array if required
-        if (is_array($style) && count($style) > 0 && !$fill) {
-            $gd_style = [];
-
-            foreach ($style as $length) {
-                for ($i = 0; $i < $length; $i++) {
-                    $gd_style[] = $c;
-                }
-            }
+        if (is_array($style) && count($style) > 0 && isset($width) && !$fill) {
+            $gd_style = $this->convertStyle($style, $c, $width);
 
             if (!empty($gd_style)) {
                 imagesetstyle($this->get_image(), $gd_style);
@@ -652,7 +567,7 @@ class GD implements Canvas
             }
         }
 
-        imagesetthickness($this->get_image(), isset($width) ? round($width) : 0);
+        imagesetthickness($this->get_image(), isset($width) ? $width : 0);
 
         if ($fill) {
             imagefilledpolygon($this->get_image(), $points, $c);
@@ -661,39 +576,19 @@ class GD implements Canvas
         }
     }
 
-    /**
-     * Draws a circle at $x,$y with radius $r
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the $style
-     * parameter (aka dash)
-     *
-     * @param float $x
-     * @param float $y
-     * @param float $r
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     * @param bool $fill Fills the circle if true
-     */
-    public function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
+    public function circle($x, $y, $r, $color, $width = null, $style = [], $fill = false)
     {
         // Scale by the AA factor and DPI
         $x = $this->_upscale($x);
         $y = $this->_upscale($y);
         $d = $this->_upscale(2 * $r);
+        $width = isset($width) ? $this->_upscale($width) : null;
 
         $c = $this->_allocate_color($color);
 
         // Convert the style array if required
-        if (is_array($style) && count($style) > 0 && !$fill) {
-            $gd_style = [];
-
-            foreach ($style as $length) {
-                for ($i = 0; $i < $length; $i++) {
-                    $gd_style[] = $c;
-                }
-            }
+        if (is_array($style) && count($style) > 0 && isset($width) && !$fill) {
+            $gd_style = $this->convertStyle($style, $c, $width);
 
             if (!empty($gd_style)) {
                 imagesetstyle($this->get_image(), $gd_style);
@@ -701,7 +596,7 @@ class GD implements Canvas
             }
         }
 
-        imagesetthickness($this->get_image(), isset($width) ? round($width) : 0);
+        imagesetthickness($this->get_image(), isset($width) ? $width : 0);
 
         if ($fill) {
             imagefilledellipse($this->get_image(), $x, $y, $d, $d, $c);
@@ -711,24 +606,11 @@ class GD implements Canvas
     }
 
     /**
-     * Add an image to the pdf.
-     * The image is placed at the specified x and y coordinates with the
-     * given width and height.
-     *
-     * @param string $img_url the path to the image
-     * @param float $x x position
-     * @param float $y y position
-     * @param int $w width (in pixels)
-     * @param int $h height (in pixels)
-     * @param string $resolution
-     * @return void
-     *
      * @throws \Exception
-     * @internal param string $img_type the type (e.g. extension) of the image
      */
-    public function image($img_url, $x, $y, $w, $h, $resolution = "normal")
+    public function image($img, $x, $y, $w, $h, $resolution = "normal")
     {
-        $img_type = Cache::detect_type($img_url, $this->get_dompdf()->getHttpContext());
+        $img_type = Cache::detect_type($img, $this->get_dompdf()->getHttpContext());
 
         if (!$img_type) {
             return;
@@ -737,11 +619,11 @@ class GD implements Canvas
         $func_name = "imagecreatefrom$img_type";
         if (!function_exists($func_name)) {
             if (!method_exists(Helpers::class, $func_name)) {
-                throw new \Exception("Function $func_name() not found.  Cannot convert $img_type image: $img_url.  Please install the image PHP extension.");
+                throw new \Exception("Function $func_name() not found.  Cannot convert $img_type image: $img.  Please install the image PHP extension.");
             }
             $func_name = [Helpers::class, $func_name];
         }
-        $src = @call_user_func($func_name, $img_url);
+        $src = @call_user_func($func_name, $img);
 
         if (!$src) {
             return; // Probably should add to $_dompdf_errors or whatever here
@@ -760,22 +642,6 @@ class GD implements Canvas
         imagecopyresampled($this->get_image(), $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h);
     }
 
-    /**
-     * Writes text at the specified x and y coordinates
-     * See {@link Style::munge_color()} for the format of the color array.
-     *
-     * @param float $x
-     * @param float $y
-     * @param string $text the text to write
-     * @param string $font the font file to use
-     * @param float $size the font size, in points
-     * @param array $color
-     * @param float $word_spacing word spacing adjustment
-     * @param float $char_spacing
-     * @param float $angle Text angle
-     *
-     * @return void
-     */
     public function text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_spacing = 0.0, $char_spacing = 0.0, $angle = 0.0)
     {
         // Scale by the AA factor and DPI
@@ -805,61 +671,26 @@ class GD implements Canvas
         // Not implemented
     }
 
-    /**
-     * Add a named destination (similar to ... in html)
-     *
-     * @param string $anchorname The name of the named destination
-     */
     public function add_named_dest($anchorname)
     {
         // Not implemented
     }
 
-    /**
-     * Add a link to the pdf
-     *
-     * @param string $url The url to link to
-     * @param float $x The x position of the link
-     * @param float $y The y position of the link
-     * @param float $width The width of the link
-     * @param float $height The height of the link
-     */
     public function add_link($url, $x, $y, $width, $height)
     {
         // Not implemented
     }
 
-    /**
-     * Add meta information to the PDF
-     *
-     * @param string $label label of the value (Creator, Producer, etc.)
-     * @param string $value the text to set
-     */
-    public function add_info($label, $value)
+    public function add_info(string $label, string $value): void
     {
         // N/A
     }
 
-    /**
-     * @param string $view
-     * @param array $options
-     */
     public function set_default_view($view, $options = [])
     {
         // N/A
     }
 
-    /**
-     * Calculates text size, in points
-     *
-     * @param string $text the text to be sized
-     * @param string $font the desired font
-     * @param float $size the desired font size
-     * @param float $word_spacing word spacing, if any
-     * @param float $char_spacing char spacing, if any
-     *
-     * @return float
-     */
     public function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0)
     {
         $font = $this->get_ttf_file($font);
@@ -913,13 +744,6 @@ class GD implements Canvas
         return $font;
     }
 
-    /**
-     * Calculates font height, in points
-     *
-     * @param string $font
-     * @param float $size
-     * @return int
-     */
     public function get_font_height($font, $size)
     {
         $size = $this->_upscale($size) * self::FONT_SCALE;
@@ -929,6 +753,12 @@ class GD implements Canvas
         return $this->_downscale($height);
     }
 
+    /**
+     * @param string $font
+     * @param float  $size
+     *
+     * @return float
+     */
     protected function get_font_height_actual($font, $size)
     {
         $font = $this->get_ttf_file($font);
@@ -939,22 +769,12 @@ class GD implements Canvas
         return ($y2 - $y1) * $ratio;
     }
 
-    /**
-     * @param string $font
-     * @param float $size
-     * @return float
-     */
     public function get_font_baseline($font, $size)
     {
         $ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
         return $this->get_font_height($font, $size) / $ratio;
     }
 
-    /**
-     * Starts a new page
-     *
-     * Subsequent drawing operations will appear on the new page.
-     */
     public function new_page()
     {
         $this->_page_number++;
@@ -985,7 +805,7 @@ class GD implements Canvas
         // N/A
     }
 
-    public function page_script($callback)
+    public function page_script($callback): void
     {
         // N/A
     }
@@ -995,7 +815,7 @@ class GD implements Canvas
         // N/A
     }
 
-    public function page_line()
+    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = [])
     {
         // N/A
     }
@@ -1004,7 +824,7 @@ class GD implements Canvas
      * Streams the image to the client.
      *
      * @param string $filename The filename to present to the client.
-     * @param array $options Associative array: 'type' => jpeg|jpg|png; 'quality' => 0 - 100 (JPEG only);
+     * @param array  $options  Associative array: 'type' => jpeg|jpg|png; 'quality' => 0 - 100 (JPEG only);
      *     'page' => Number of the page to output (defaults to the first); 'Attachment': 1 or 0 (default 1).
      */
     public function stream($filename, $options = [])
diff --git a/library/vendor/dompdf/src/Adapter/PDFLib.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/PDFLib.php
similarity index 77%
rename from library/vendor/dompdf/src/Adapter/PDFLib.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/PDFLib.php
index eecba0d5b..ee5ae8dd2 100644
--- a/library/vendor/dompdf/src/Adapter/PDFLib.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Adapter/PDFLib.php
@@ -1,20 +1,17 @@
 
- * @author  Helmut Tischer 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Adapter;
 
 use Dompdf\Canvas;
 use Dompdf\Dompdf;
-use Dompdf\Helpers;
 use Dompdf\Exception;
+use Dompdf\FontMetrics;
+use Dompdf\Helpers;
 use Dompdf\Image\Cache;
-use Dompdf\PhpEvaluator;
 
 /**
  * PDF rendering interface
@@ -37,7 +34,7 @@ class PDFLib implements Canvas
     /**
      * Dimensions of paper sizes in points
      *
-     * @var array;
+     * @var array
      */
     public static $PAPER_SIZES = []; // Set to Dompdf\Adapter\CPDF::$PAPER_SIZES below.
 
@@ -130,7 +127,7 @@ class PDFLib implements Canvas
     /**
      * The current opacity level
      *
-     * @var array
+     * @var float|null
      */
     protected $_current_opacity;
 
@@ -184,39 +181,23 @@ class PDFLib implements Canvas
     protected $_page_count;
 
     /**
-     * Text to display on every page
-     *
-     * @var array
-     */
-    protected $_page_text;
-
-    /**
-     * Array of pages for accesing after rendering is initially complete
+     * Array of pages for accessing after rendering is initially complete
      *
      * @var array
      */
     protected $_pages;
 
-    /**
-     * Class constructor
-     *
-     * @param string|array $paper The size of paper to use either a string (see {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}) or
-     *                            an array(xmin,ymin,xmax,ymax)
-     * @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
-     * @param Dompdf $dompdf
-     */
-    public function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf = null)
+    public function __construct($paper = "letter", $orientation = "portrait", ?Dompdf $dompdf = null)
     {
         if (is_array($paper)) {
-            $size = $paper;
-        } elseif (isset(self::$PAPER_SIZES[mb_strtolower($paper)])) {
-            $size = self::$PAPER_SIZES[mb_strtolower($paper)];
+            $size = array_map("floatval", $paper);
         } else {
-            $size = self::$PAPER_SIZES["letter"];
+            $paper = strtolower($paper);
+            $size = self::$PAPER_SIZES[$paper] ?? self::$PAPER_SIZES["letter"];
         }
 
-        if (mb_strtolower($orientation) === "landscape") {
-            list($size[2], $size[3]) = [$size[3], $size[2]];
+        if (strtolower($orientation) === "landscape") {
+            [$size[2], $size[3]] = [$size[3], $size[2]];
         }
 
         $this->_width = $size[2] - $size[0];
@@ -235,7 +216,9 @@ class PDFLib implements Canvas
             $this->setPDFLibParameter("license", $license);
         }
 
-        $this->setPDFLibParameter("textformat", "utf8");
+        if ($this->getPDFLibMajorVersion() < 10) {
+            $this->setPDFLibParameter("textformat", "utf8");
+        }
         if ($this->getPDFLibMajorVersion() >= 7) {
             $this->setPDFLibParameter("errorpolicy", "return");
             //            $this->_pdf->set_option('logging={filename=' . \APP_PATH . '/logs/pdflib.log classes={api=1 warning=2}}');
@@ -271,16 +254,12 @@ class PDFLib implements Canvas
         $this->_pdf->begin_page_ext($this->_width, $this->_height, "");
 
         $this->_page_number = $this->_page_count = 1;
-        $this->_page_text = [];
 
         $this->_imgs = [];
         $this->_fonts = [];
         $this->_objs = [];
     }
 
-    /**
-     * @return Dompdf
-     */
     function get_dompdf()
     {
         return $this->_dompdf;
@@ -314,13 +293,7 @@ class PDFLib implements Canvas
         return $this->_pdf;
     }
 
-    /**
-     * Add meta information to the PDF
-     *
-     * @param string $label label of the value (Creator, Producter, etc.)
-     * @param string $value the text to set
-     */
-    public function add_info($label, $value)
+    public function add_info(string $label, string $value): void
     {
         $this->_pdf->set_info($label, $value);
     }
@@ -464,33 +437,21 @@ class PDFLib implements Canvas
         }
     }
 
-    /**
-     * @return float|mixed
-     */
     public function get_width()
     {
         return $this->_width;
     }
 
-    /**
-     * @return float|mixed
-     */
     public function get_height()
     {
         return $this->_height;
     }
 
-    /**
-     * @return int
-     */
     public function get_page_number()
     {
         return $this->_page_number;
     }
 
-    /**
-     * @return int
-     */
     public function get_page_count()
     {
         return $this->_page_count;
@@ -504,9 +465,6 @@ class PDFLib implements Canvas
         $this->_page_number = (int)$num;
     }
 
-    /**
-     * @param int $count
-     */
     public function set_page_count($count)
     {
         $this->_page_count = (int)$count;
@@ -516,19 +474,25 @@ class PDFLib implements Canvas
      * Sets the line style
      *
      * @param float  $width
-     * @param        $cap
+     * @param string $cap
      * @param string $join
      * @param array  $dash
-     *
-     * @return void
      */
     protected function _set_line_style($width, $cap, $join, $dash)
     {
         if (!is_array($dash)) {
-            $dash = array();
+            $dash = [];
         }
 
-        if (count($dash) == 1) {
+        // Work around PDFLib limitation with 0 dash length:
+        // Value 0 for option 'dasharray' is too small (minimum 1.5e-05)
+        foreach ($dash as &$d) {
+            if ($d == 0) {
+                $d = 1.5e-5;
+            }
+        }
+
+        if (count($dash) === 1) {
             $dash[] = $dash[0];
         }
 
@@ -684,12 +648,12 @@ class PDFLib implements Canvas
     /**
      * Sets the fill opacity
      *
-     * @param $opacity
-     * @param $mode
+     * @param float  $opacity
+     * @param string $mode
      */
     public function _set_fill_opacity($opacity, $mode = "Normal")
     {
-        if ($mode === "Normal" && is_null($opacity) === false) {
+        if ($mode === "Normal" && isset($opacity)) {
             $this->_set_gstate("opacityfill=$opacity");
         }
     }
@@ -697,25 +661,19 @@ class PDFLib implements Canvas
     /**
      * Sets the stroke opacity
      *
-     * @param $opacity
-     * @param $mode
+     * @param float  $opacity
+     * @param string $mode
      */
     public function _set_stroke_opacity($opacity, $mode = "Normal")
     {
-        if ($mode === "Normal" && is_null($opacity) === false) {
+        if ($mode === "Normal" && isset($opacity)) {
             $this->_set_gstate("opacitystroke=$opacity");
         }
     }
 
-    /**
-     * Sets the opacity
-     *
-     * @param $opacity
-     * @param $mode
-     */
-    public function set_opacity($opacity, $mode = "Normal")
+    public function set_opacity(float $opacity, string $mode = "Normal"): void
     {
-        if ($mode === "Normal" && is_null($opacity) === false) {
+        if ($mode === "Normal") {
             $this->_set_gstate("opacityfill=$opacity opacitystroke=$opacity");
             $this->_current_opacity = $opacity;
         }
@@ -874,18 +832,9 @@ class PDFLib implements Canvas
         return $this->_height - $y;
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $x2
-     * @param float $y2
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function line($x1, $y1, $x2, $y2, $color, $width, $style = null)
+    public function line($x1, $y1, $x2, $y2, $color, $width, $style = [], $cap = "butt")
     {
-        $this->_set_line_style($width, "butt", "", $style);
+        $this->_set_line_style($width, $cap, "", $style);
         $this->_set_stroke_color($color);
 
         $y1 = $this->y($y1);
@@ -898,62 +847,23 @@ class PDFLib implements Canvas
         $this->_set_stroke_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * Draw line at the specified coordinates on every page.
-     *
-     * See {@link Style::munge_color()} for the format of the colour array.
-     *
-     * @param float $x1
-     * @param float $y1
-     * @param float $x2
-     * @param float $y2
-     * @param array $color
-     * @param float $width
-     * @param array $style optional
-     */
-    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = [])
+    public function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = [], $cap = "butt")
     {
-        $_t = 'line';
-        $this->_page_text[] = compact('_t', 'x1', 'y1', 'x2', 'y2', 'color', 'width', 'style');
-    }
-
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $r1
-     * @param float $r2
-     * @param float $astart
-     * @param float $aend
-     * @param array $color
-     * @param float $width
-     * @param array $style
-     */
-    public function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = [])
-    {
-        $this->_set_line_style($width, "butt", "", $style);
+        $this->_set_line_style($width, $cap, "", $style);
         $this->_set_stroke_color($color);
 
-        $y1 = $this->y($y1);
+        $y = $this->y($y);
 
-        $this->_pdf->arc($x1, $y1, $r1, $astart, $aend);
+        $this->_pdf->arc($x, $y, $r1, $astart, $aend);
         $this->_pdf->stroke();
 
         $this->_set_stroke_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     * @param float $width
-     * @param null  $style
-     */
-    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
+    public function rectangle($x1, $y1, $w, $h, $color, $width, $style = [], $cap = "butt")
     {
         $this->_set_stroke_color($color);
-        $this->_set_line_style($width, "butt", "", $style);
+        $this->_set_line_style($width, $cap, "", $style);
 
         $y1 = $this->y($y1) - $h;
 
@@ -963,13 +873,6 @@ class PDFLib implements Canvas
         $this->_set_stroke_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     */
     public function filled_rectangle($x1, $y1, $w, $h, $color)
     {
         $this->_set_fill_color($color);
@@ -982,12 +885,6 @@ class PDFLib implements Canvas
         $this->_set_fill_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     */
     public function clipping_rectangle($x1, $y1, $w, $h)
     {
         $this->_pdf->save();
@@ -998,16 +895,6 @@ class PDFLib implements Canvas
         $this->_pdf->clip();
     }
 
-    /**
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param float $rTL
-     * @param float $rTR
-     * @param float $rBR
-     * @param float $rBL
-     */
     public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
     {
         if ($this->getPDFLibMajorVersion() < 9) {
@@ -1027,33 +914,53 @@ class PDFLib implements Canvas
         // line: left edge, bottom end
         $path = $this->_pdf->add_path_point($path, 0, 0 + $rBL, "line", "");
         // curve: bottom-left corner
-        $path = $this->_pdf->add_path_point($path, 0 + $rBL, 0, "elliptical", "radius=$rBL clockwise=false");
+        if ($rBL > 0) {
+            $path = $this->_pdf->add_path_point($path, 0 + $rBL, 0, "elliptical", "radius=$rBL clockwise=false");
+        }
         // line: bottom edge, left end
         $path = $this->_pdf->add_path_point($path, 0 - $rBR + $w, 0, "line", "");
         // curve: bottom-right corner
-        $path = $this->_pdf->add_path_point($path, 0 + $w, 0 + $rBR, "elliptical", "radius=$rBR clockwise=false");
+        if ($rBR > 0) {
+            $path = $this->_pdf->add_path_point($path, 0 + $w, 0 + $rBR, "elliptical", "radius=$rBR clockwise=false");
+        }
         // line: right edge, top end
         $path = $this->_pdf->add_path_point($path, 0 + $w, 0 - $rTR + $h, "line", "");
         // curve: top-right corner
-        $path = $this->_pdf->add_path_point($path, 0 - $rTR + $w, 0 +$h, "elliptical", "radius=$rTR clockwise=false");
+        if ($rTR > 0) {
+            $path = $this->_pdf->add_path_point($path, 0 - $rTR + $w, 0 + $h, "elliptical", "radius=$rTR clockwise=false");
+        }
         // line: top edge, left end
         $path = $this->_pdf->add_path_point($path, 0 + $rTL, 0 + $h, "line", "");
         // curve: top-left corner
-        $path = $this->_pdf->add_path_point($path, 0, 0 - $rTL + $h, "elliptical", "radius=$rTL clockwise=false");
+        if ($rTL > 0) {
+            $path = $this->_pdf->add_path_point($path, 0, 0 - $rTL + $h, "elliptical", "radius=$rTL clockwise=false");
+        }
         $this->_pdf->draw_path($path, $x1, $this->_height-$y1-$h, "clip=true");
     }
 
-    /**
-     *
-     */
+    public function clipping_polygon(array $points): void
+    {
+        $this->_pdf->save();
+
+        $y = $this->y(array_pop($points));
+        $x = array_pop($points);
+        $this->_pdf->moveto($x, $y);
+
+        while (count($points) > 1) {
+            $y = $this->y(array_pop($points));
+            $x = array_pop($points);
+            $this->_pdf->lineto($x, $y);
+        }
+
+        $this->_pdf->closepath();
+        $this->_pdf->clip();
+    }
+
     public function clipping_end()
     {
         $this->_pdf->restore();
     }
 
-    /**
-     *
-     */
     public function save()
     {
         $this->_pdf->save();
@@ -1064,11 +971,6 @@ class PDFLib implements Canvas
         $this->_pdf->restore();
     }
 
-    /**
-     * @param $angle
-     * @param $x
-     * @param $y
-     */
     public function rotate($angle, $x, $y)
     {
         $pdf = $this->_pdf;
@@ -1077,12 +979,6 @@ class PDFLib implements Canvas
         $pdf->translate(-$x, -$this->_height + $y);
     }
 
-    /**
-     * @param $angle_x
-     * @param $angle_y
-     * @param $x
-     * @param $y
-     */
     public function skew($angle_x, $angle_y, $x, $y)
     {
         $pdf = $this->_pdf;
@@ -1091,12 +987,6 @@ class PDFLib implements Canvas
         $pdf->translate(-$x, -$this->_height + $y);
     }
 
-    /**
-     * @param $s_x
-     * @param $s_y
-     * @param $x
-     * @param $y
-     */
     public function scale($s_x, $s_y, $x, $y)
     {
         $pdf = $this->_pdf;
@@ -1105,36 +995,17 @@ class PDFLib implements Canvas
         $pdf->translate(-$x, -$this->_height + $y);
     }
 
-    /**
-     * @param $t_x
-     * @param $t_y
-     */
     public function translate($t_x, $t_y)
     {
         $this->_pdf->translate($t_x, -$t_y);
     }
 
-    /**
-     * @param $a
-     * @param $b
-     * @param $c
-     * @param $d
-     * @param $e
-     * @param $f
-     */
     public function transform($a, $b, $c, $d, $e, $f)
     {
         $this->_pdf->concat($a, $b, $c, $d, $e, $f);
     }
 
-    /**
-     * @param array $points
-     * @param array $color
-     * @param null  $width
-     * @param null  $style
-     * @param bool  $fill
-     */
-    public function polygon($points, $color, $width = null, $style = null, $fill = false)
+    public function polygon($points, $color, $width = null, $style = [], $fill = false)
     {
         $this->_set_fill_color($color);
         $this->_set_stroke_color($color);
@@ -1163,16 +1034,7 @@ class PDFLib implements Canvas
         $this->_set_stroke_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * @param float $x
-     * @param float $y
-     * @param float $r
-     * @param array $color
-     * @param null  $width
-     * @param null  $style
-     * @param bool  $fill
-     */
-    public function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
+    public function circle($x, $y, $r, $color, $width = null, $style = [], $fill = false)
     {
         $this->_set_fill_color($color);
         $this->_set_stroke_color($color);
@@ -1195,37 +1057,34 @@ class PDFLib implements Canvas
         $this->_set_stroke_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * @param string $img_url
-     * @param float  $x
-     * @param float  $y
-     * @param int    $w
-     * @param int    $h
-     * @param string $resolution
-     */
-    public function image($img_url, $x, $y, $w, $h, $resolution = "normal")
+    public function image($img, $x, $y, $w, $h, $resolution = "normal")
     {
         $w = (int)$w;
         $h = (int)$h;
 
-        $img_type = Cache::detect_type($img_url, $this->get_dompdf()->getHttpContext());
+        $img_type = Cache::detect_type($img, $this->get_dompdf()->getHttpContext());
 
-        if (!isset($this->_imgs[$img_url])) {
+        // Strip file:// prefix
+        if (substr($img, 0, 7) === "file://") {
+            $img = substr($img, 7);
+        }
+
+        if (!isset($this->_imgs[$img])) {
             if (strtolower($img_type) === "svg") {
                 //FIXME: PDFLib loads SVG but returns error message "Function must not be called in 'page' scope"
-                $image_load_response = $this->_pdf->load_graphics($img_type, $img_url, "");
+                $image_load_response = $this->_pdf->load_graphics($img_type, $img, "");
             } else {
-                $image_load_response = $this->_pdf->load_image($img_type, $img_url, "");
+                $image_load_response = $this->_pdf->load_image($img_type, $img, "");
             }
             if ($image_load_response === 0) {
                 //TODO: should do something with the error message
                 $error = $this->_pdf->get_errmsg();
                 return;
             }
-            $this->_imgs[$img_url] = $image_load_response;
+            $this->_imgs[$img] = $image_load_response;
         }
 
-        $img = $this->_imgs[$img_url];
+        $img = $this->_imgs[$img];
 
         $y = $this->y($y) - $h;
         if (strtolower($img_type) === "svg") {
@@ -1235,19 +1094,12 @@ class PDFLib implements Canvas
         }
     }
 
-    /**
-     * @param float  $x
-     * @param float  $y
-     * @param string $text
-     * @param string $font
-     * @param float  $size
-     * @param array  $color
-     * @param int    $word_spacing
-     * @param int    $char_spacing
-     * @param int    $angle
-     */
     public function text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_spacing = 0, $char_spacing = 0, $angle = 0)
     {
+        if ($size == 0) {
+            return;
+        }
+
         $fh = $this->_load_font($font);
 
         $this->_pdf->setfont($fh, $size);
@@ -1264,9 +1116,6 @@ class PDFLib implements Canvas
         $this->_set_fill_opacity($this->_current_opacity, "Normal");
     }
 
-    /**
-     * @param string $code
-     */
     public function javascript($code)
     {
         if (strlen($this->_dompdf->getOptions()->getPdflibLicense()) > 0) {
@@ -1274,25 +1123,11 @@ class PDFLib implements Canvas
         }
     }
 
-    /**
-     * Add a named destination (similar to ... in html)
-     *
-     * @param string $anchorname The name of the named destination
-     */
     public function add_named_dest($anchorname)
     {
         $this->_pdf->add_nameddest($anchorname, "");
     }
 
-    /**
-     * Add a link to the pdf
-     *
-     * @param string $url    The url to link to
-     * @param float  $x      The x position of the link
-     * @param float  $y      The y position of the link
-     * @param float  $width  The width of the link
-     * @param float  $height The height of the link
-     */
     public function add_link($url, $x, $y, $width, $height)
     {
         $y = $this->y($y) - $height;
@@ -1304,29 +1139,21 @@ class PDFLib implements Canvas
                     "contents={$url} destname=" . substr($url, 1) . " linewidth=0");
             }
         } else {
-            list($proto, $host, $path, $file) = Helpers::explode_url($url);
-
-            if ($proto === "" || $proto === "file://") {
-                return; // Local links are not allowed
+            //TODO: PDFLib::create_action does not permit non-HTTP links for URI actions
+            $action = $this->_pdf->create_action("URI", "url={{$url}}");
+            // add the annotation only if the action was created
+            if ($action !== 0) {
+                $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={{$url}} action={activate=$action} linewidth=0");
             }
-            $url = Helpers::build_url($proto, $host, $path, $file);
-            $url = '{' . rawurldecode($url) . '}';
-
-            $action = $this->_pdf->create_action("URI", "url=" . $url);
-            $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={$url} action={activate=$action} linewidth=0");
         }
     }
 
-    /**
-     * @param string $text
-     * @param string $font
-     * @param float  $size
-     * @param float  $word_spacing
-     * @param float  $letter_spacing
-     * @return mixed
-     */
-    public function get_text_width($text, $font, $size, $word_spacing = 0, $letter_spacing = 0)
+    public function get_text_width($text, $font, $size, $word_spacing = 0.0, $letter_spacing = 0.0)
     {
+        if ($size == 0) {
+            return 0.0;
+        }
+
         $fh = $this->_load_font($font);
 
         // Determine the additional width due to extra spacing
@@ -1341,13 +1168,12 @@ class PDFLib implements Canvas
         return $this->_pdf->stringwidth($text, $fh, $size) + $delta;
     }
 
-    /**
-     * @param string $font
-     * @param float  $size
-     * @return float
-     */
     public function get_font_height($font, $size)
     {
+        if ($size == 0) {
+            return 0.0;
+        }
+
         $fh = $this->_load_font($font);
 
         $this->_pdf->setfont($fh, $size);
@@ -1361,11 +1187,6 @@ class PDFLib implements Canvas
         return (abs($asc) + abs($desc)) * $ratio;
     }
 
-    /**
-     * @param string $font
-     * @param float  $size
-     * @return float
-     */
     public function get_font_baseline($font, $size)
     {
         $ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
@@ -1374,60 +1195,55 @@ class PDFLib implements Canvas
     }
 
     /**
-     * Writes text at the specified x and y coordinates on every page
+     * Processes a callback or script on every page.
      *
-     * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
-     * with their current values.
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
-     *
-     * @param float  $x
-     * @param float  $y
-     * @param string $text       the text to write
-     * @param string $font       the font file to use
-     * @param float  $size       the font size, in points
-     * @param array  $color
-     * @param float  $word_space word spacing adjustment
-     * @param float  $char_space char spacing adjustment
-     * @param float  $angle      angle to write the text at, measured CW starting from the x-axis
-     */
-    public function page_text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
-    {
-        $_t = "text";
-        $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle");
-    }
-
-    //........................................................................
-
-    /**
-     * Processes a callback or script on every page
-     *
-     * The callback function receives the four parameters `$pageNumber`,
-     * `$pageCount`, `$pdf`, and `$fontMetrics`, in that order. If a script is
-     * passed as string, the variables `$PAGE_NUM`, `$PAGE_COUNT`, `$pdf`, and
-     * `$fontMetrics` are available instead.
+     * The callback function receives the four parameters `int $pageNumber`,
+     * `int $pageCount`, `Canvas $canvas`, and `FontMetrics $fontMetrics`, in
+     * that order. If a script is passed as string, the variables `$PAGE_NUM`,
+     * `$PAGE_COUNT`, `$pdf`, and `$fontMetrics` are available instead. Passing
+     * a script as string is deprecated and will be removed in a future version.
      *
      * This function can be used to add page numbers to all pages after the
      * first one, for example.
      *
-     * @param callable|string $code The callback function or PHP script to process on every page
+     * @param callable|string $callback The callback function or PHP script to process on every page
      */
-    public function page_script($code)
+    public function page_script($callback): void
     {
-        if (is_callable($code)) {
-            $this->_page_text[] = [
-                "_t"       => "callback",
-                "callback" => $code
-            ];
-        } else {
-            $_t = "script";
-            $this->_page_text[] = compact("_t", "code");
+        if (is_string($callback)) {
+            $this->processPageScript(function (
+                int $PAGE_NUM,
+                int $PAGE_COUNT,
+                self $pdf,
+                FontMetrics $fontMetrics
+            ) use ($callback) {
+                eval($callback);
+            });
+            return;
         }
+
+        $this->processPageScript($callback);
+    }
+
+    public function page_text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
+    {
+        $this->processPageScript(function (int $pageNumber, int $pageCount) use ($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle) {
+            $text = str_replace(
+                ["{PAGE_NUM}", "{PAGE_COUNT}"],
+                [$pageNumber, $pageCount],
+                $text
+            );
+            $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
+        });
+    }
+
+    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = [])
+    {
+        $this->processPageScript(function () use ($x1, $y1, $x2, $y2, $color, $width, $style) {
+            $this->line($x1, $y1, $x2, $y2, $color, $width, $style);
+        });
     }
 
-    /**
-     *
-     */
     public function new_page()
     {
         // Add objects to the current page
@@ -1438,49 +1254,15 @@ class PDFLib implements Canvas
         $this->_page_number = ++$this->_page_count;
     }
 
-    /**
-     * Add text to each page after rendering is complete
-     */
-    protected function _add_page_text()
+    protected function processPageScript(callable $callback): void
     {
-        if (count($this->_page_text) === 0) {
-            return;
-        }
-
-        $eval = null;
         $this->_pdf->suspend_page("");
 
         for ($p = 1; $p <= $this->_page_count; $p++) {
             $this->_pdf->resume_page("pagenumber=$p");
 
-            foreach ($this->_page_text as $pt) {
-                extract($pt);
-
-                switch ($_t) {
-                    case "text":
-                        $text = str_replace(["{PAGE_NUM}", "{PAGE_COUNT}"],
-                            [$p, $this->_page_count], $text);
-                        $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle);
-                        break;
-
-                    case "callback":
-                        $fontMetrics = $this->get_dompdf()->getFontMetrics();
-                        $callback($p, $this->_page_count, $this, $fontMetrics);
-                        break;
-
-                    case "script":
-                        if (!$eval) {
-                            $eval = new PHPEvaluator($this);
-                        }
-                        $eval->evaluate($code, ["PAGE_NUM" => $p, "PAGE_COUNT" => $this->_page_count]);
-                        break;
-
-                    case "line":
-                        $this->line($x1, $y1, $x2, $y2, $color, $width, $style);
-                        break;
-
-                }
-            }
+            $fontMetrics = $this->_dompdf->getFontMetrics();
+            $callback($p, $this->_page_count, $this, $fontMetrics);
 
             $this->_pdf->suspend_page("");
         }
@@ -1489,10 +1271,6 @@ class PDFLib implements Canvas
     }
 
     /**
-     * Streams the PDF to the client.
-     *
-     * @param string $filename The filename to present to the client.
-     * @param array  $options  Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
      * @throws Exception
      */
     public function stream($filename = "document.pdf", $options = [])
@@ -1508,8 +1286,6 @@ class PDFLib implements Canvas
             $options["Attachment"] = true;
         }
 
-        $this->_add_page_text();
-
         if ($options["compress"]) {
             $this->setPDFLibValue("compress", 6);
         } else {
@@ -1564,20 +1340,12 @@ class PDFLib implements Canvas
         flush();
     }
 
-    /**
-     * Returns the PDF as a string.
-     *
-     * @param array $options Associative array: 'compress' => 1 or 0 (default 1).
-     * @return string
-     */
     public function output($options = [])
     {
         if (!isset($options["compress"])) {
             $options["compress"] = true;
         }
 
-        $this->_add_page_text();
-
         if ($options["compress"]) {
             $this->setPDFLibValue("compress", 6);
         } else {
diff --git a/library/vendor/dompdf/src/Canvas.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Canvas.php
similarity index 51%
rename from library/vendor/dompdf/src/Canvas.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Canvas.php
index 8afeb67a1..1812def58 100644
--- a/library/vendor/dompdf/src/Canvas.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Canvas.php
@@ -1,12 +1,9 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf;
 
 /**
@@ -24,7 +21,13 @@ namespace Dompdf;
  */
 interface Canvas
 {
-    function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf = null);
+    /**
+     * @param string|float[] $paper       The paper size to use as either a standard paper size (see {@link Dompdf\Adapter\CPDF::$PAPER_SIZES})
+     *                                    or an array of the form `[x1, y1, x2, y2]` (typically `[0, 0, width, height]`).
+     * @param string         $orientation The paper orientation, either `portrait` or `landscape`.
+     * @param Dompdf         $dompdf      The Dompdf instance.
+     */
+    public function __construct($paper = "letter", $orientation = "portrait", ?Dompdf $dompdf = null);
 
     /**
      * @return Dompdf
@@ -39,7 +42,7 @@ interface Canvas
     function get_page_number();
 
     /**
-     * Returns the total number of pages
+     * Returns the total number of pages in the document
      *
      * @return int
      */
@@ -55,47 +58,68 @@ interface Canvas
     /**
      * Draws a line from x1,y1 to x2,y2
      *
-     * See {@link Style::munge_color()} for the format of the color array.
      * See {@link Cpdf::setLineStyle()} for a description of the format of the
-     * $style parameter (aka dash).
+     * $style and $cap parameters (aka dash and cap).
      *
-     * @param float $x1
-     * @param float $y1
-     * @param float $x2
-     * @param float $y2
-     * @param array $color
-     * @param float $width
-     * @param array $style
+     * @param float  $x1
+     * @param float  $y1
+     * @param float  $x2
+     * @param float  $y2
+     * @param array  $color Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                      where r, g, b, and alpha are float values between 0 and 1
+     * @param float  $width
+     * @param array  $style
+     * @param string $cap   `butt`, `round`, or `square`
      */
-    function line($x1, $y1, $x2, $y2, $color, $width, $style = null);
+    function line($x1, $y1, $x2, $y2, $color, $width, $style = [], $cap = "butt");
+
+    /**
+     * Draws an arc
+     *
+     * See {@link Cpdf::setLineStyle()} for a description of the format of the
+     * $style and $cap parameters (aka dash and cap).
+     *
+     * @param float  $x      X coordinate of the arc
+     * @param float  $y      Y coordinate of the arc
+     * @param float  $r1     Radius 1
+     * @param float  $r2     Radius 2
+     * @param float  $astart Start angle in degrees
+     * @param float  $aend   End angle in degrees
+     * @param array  $color  Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                       where r, g, b, and alpha are float values between 0 and 1
+     * @param float  $width
+     * @param array  $style
+     * @param string $cap   `butt`, `round`, or `square`
+     */
+    function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = [], $cap = "butt");
 
     /**
      * Draws a rectangle at x1,y1 with width w and height h
      *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the $style
-     * parameter (aka dash)
+     * See {@link Cpdf::setLineStyle()} for a description of the format of the
+     * $style and $cap parameters (aka dash and cap).
      *
-     * @param float $x1
-     * @param float $y1
-     * @param float $w
-     * @param float $h
-     * @param array $color
-     * @param float $width
-     * @param array $style
+     * @param float  $x1
+     * @param float  $y1
+     * @param float  $w
+     * @param float  $h
+     * @param array  $color  Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                       where r, g, b, and alpha are float values between 0 and 1
+     * @param float  $width
+     * @param array  $style
+     * @param string $cap   `butt`, `round`, or `square`
      */
-    function rectangle($x1, $y1, $w, $h, $color, $width, $style = null);
+    function rectangle($x1, $y1, $w, $h, $color, $width, $style = [], $cap = "butt");
 
     /**
      * Draws a filled rectangle at x1,y1 with width w and height h
      *
-     * See {@link Style::munge_color()} for the format of the color array.
-     *
      * @param float $x1
      * @param float $y1
      * @param float $w
      * @param float $h
-     * @param array $color
+     * @param array $color Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                     where r, g, b, and alpha are float values between 0 and 1
      */
     function filled_rectangle($x1, $y1, $w, $h, $color);
 
@@ -120,65 +144,67 @@ interface Canvas
      * @param float $tr
      * @param float $br
      * @param float $bl
-     *
-     * @return
      */
     function clipping_roundrectangle($x1, $y1, $w, $h, $tl, $tr, $br, $bl);
 
+    /**
+     * Starts a clipping polygon
+     *
+     * @param float[] $points
+     */
+    public function clipping_polygon(array $points): void;
+
     /**
      * Ends the last clipping shape
      */
     function clipping_end();
 
     /**
-     * Processes a callback on every page
+     * Processes a callback on every page.
      *
-     * The callback function receives the four parameters `$pageNumber`,
-     * `$pageCount`, `$pdf`, and `$fontMetrics`, in that order.
+     * The callback function receives the four parameters `int $pageNumber`,
+     * `int $pageCount`, `Canvas $canvas`, and `FontMetrics $fontMetrics`, in
+     * that order.
      *
      * This function can be used to add page numbers to all pages after the
      * first one, for example.
      *
      * @param callable $callback The callback function to process on every page
-     * @todo Enable with next major release
      */
-    //public function page_script(callable $callback): void;
+    public function page_script($callback): void;
 
     /**
-     * Writes text at the specified x and y coordinates on every page
+     * Writes text at the specified x and y coordinates on every page.
      *
      * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced
      * with their current values.
      *
-     * See {@link Style::munge_color()} for the format of the color array.
-     *
      * @param float  $x
      * @param float  $y
-     * @param string $text       the text to write
-     * @param string $font       the font file to use
-     * @param float  $size       the font size, in points
-     * @param array  $color
-     * @param float  $word_space word spacing adjustment
-     * @param float  $char_space char spacing adjustment
-     * @param float  $angle      angle to write the text at, measured CW starting from the x-axis
+     * @param string $text       The text to write
+     * @param string $font       The font file to use
+     * @param float  $size       The font size, in points
+     * @param array  $color      Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                           where r, g, b, and alpha are float values between 0 and 1
+     * @param float  $word_space Word spacing adjustment
+     * @param float  $char_space Char spacing adjustment
+     * @param float  $angle      Angle to write the text at, measured clockwise starting from the x-axis
      */
     public function page_text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0);
 
     /**
-     * Draw line at the specified coordinates on every page.
-     *
-     * See {@link Style::munge_color()} for the format of the color array.
+     * Draws a line at the specified coordinates on every page.
      *
      * @param float $x1
      * @param float $y1
      * @param float $x2
      * @param float $y2
-     * @param array $color
+     * @param array $color Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                     where r, g, b, and alpha are float values between 0 and 1
      * @param float $width
-     * @param array $style optional
-     * @todo Enable with next major release
+     * @param array $style
      */
-    //public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = []);
+    public function page_line($x1, $y1, $x2, $y2, $color, $width, $style = []);
 
     /**
      * Save current state
@@ -204,8 +230,8 @@ interface Canvas
      *
      * @param float $angle_x
      * @param float $angle_y
-     * @param float $x Origin abscissa
-     * @param float $y Origin ordinate
+     * @param float $x       Origin abscissa
+     * @param float $y       Origin ordinate
      */
     function skew($angle_x, $angle_y, $x, $y);
 
@@ -230,13 +256,12 @@ interface Canvas
     /**
      * Transform
      *
-     * @param $a
-     * @param $b
-     * @param $c
-     * @param $d
-     * @param $e
-     * @param $f
-     * @return
+     * @param float $a
+     * @param float $b
+     * @param float $c
+     * @param float $d
+     * @param float $e
+     * @param float $f
      */
     function transform($a, $b, $c, $d, $e, $f);
 
@@ -245,43 +270,43 @@ interface Canvas
      *
      * The polygon is formed by joining all the points stored in the $points
      * array.  $points has the following structure:
-     * 
+     * ```
      * array(0 => x1,
      *       1 => y1,
      *       2 => x2,
      *       3 => y2,
      *       ...
      *       );
-     * 
+     * ```
      *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the $style
-     * parameter (aka dash)
+     * See {@link Cpdf::setLineStyle()} for a description of the format of the
+     * $style parameter (aka dash).
      *
      * @param array $points
-     * @param array $color
+     * @param array $color  Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                      where r, g, b, and alpha are float values between 0 and 1
      * @param float $width
      * @param array $style
-     * @param bool $fill Fills the polygon if true
+     * @param bool  $fill   Fills the polygon if true
      */
-    function polygon($points, $color, $width = null, $style = null, $fill = false);
+    function polygon($points, $color, $width = null, $style = [], $fill = false);
 
     /**
      * Draws a circle at $x,$y with radius $r
      *
-     * See {@link Style::munge_color()} for the format of the color array.
-     * See {@link Cpdf::setLineStyle()} for a description of the $style
-     * parameter (aka dash)
+     * See {@link Cpdf::setLineStyle()} for a description of the format of the
+     * $style parameter (aka dash).
      *
      * @param float $x
      * @param float $y
      * @param float $r
-     * @param array $color
+     * @param array $color Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                     where r, g, b, and alpha are float values between 0 and 1
      * @param float $width
      * @param array $style
-     * @param bool $fill Fills the circle if true
+     * @param bool  $fill  Fills the circle if true
      */
-    function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false);
+    function circle($x, $y, $r, $color, $width = null, $style = [], $fill = false);
 
     /**
      * Add an image to the pdf.
@@ -289,44 +314,28 @@ interface Canvas
      * The image is placed at the specified x and y coordinates with the
      * given width and height.
      *
-     * @param string $img_url the path to the image
-     * @param float $x x position
-     * @param float $y y position
-     * @param int $w width (in pixels)
-     * @param int $h height (in pixels)
+     * @param string $img        The path to the image
+     * @param float  $x          X position
+     * @param float  $y          Y position
+     * @param float  $w          Width
+     * @param float  $h          Height
      * @param string $resolution The resolution of the image
      */
-    function image($img_url, $x, $y, $w, $h, $resolution = "normal");
-
-    /**
-     * Add an arc to the PDF
-     * See {@link Style::munge_color()} for the format of the color array.
-     *
-     * @param float $x X coordinate of the arc
-     * @param float $y Y coordinate of the arc
-     * @param float $r1 Radius 1
-     * @param float $r2 Radius 2
-     * @param float $astart Start angle in degrees
-     * @param float $aend End angle in degrees
-     * @param array $color Color
-     * @param float $width
-     * @param array $style
-     */
-    function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = []);
+    function image($img, $x, $y, $w, $h, $resolution = "normal");
 
     /**
      * Writes text at the specified x and y coordinates
-     * See {@link Style::munge_color()} for the format of the color array.
      *
-     * @param float $x
-     * @param float $y
-     * @param string $text the text to write
-     * @param string $font the font file to use
-     * @param float $size the font size, in points
-     * @param array $color
-     * @param float $word_space word spacing adjustment
-     * @param float $char_space char spacing adjustment
-     * @param float $angle angle
+     * @param float  $x
+     * @param float  $y
+     * @param string $text        The text to write
+     * @param string $font        The font file to use
+     * @param float  $size        The font size, in points
+     * @param array  $color       Color array in the format `[r, g, b, "alpha" => alpha]`
+     *                            where r, g, b, and alpha are float values between 0 and 1
+     * @param float  $word_space  Word spacing adjustment
+     * @param float  $char_space  Char spacing adjustment
+     * @param float  $angle       Angle to write the text at, measured clockwise starting from the x-axis
      */
     function text($x, $y, $text, $font, $size, $color = [0, 0, 0], $word_space = 0.0, $char_space = 0.0, $angle = 0.0);
 
@@ -340,30 +349,30 @@ interface Canvas
     /**
      * Add a link to the pdf
      *
-     * @param string $url The url to link to
-     * @param float $x The x position of the link
-     * @param float $y The y position of the link
-     * @param float $width The width of the link
-     * @param float $height The height of the link
+     * @param string $url    The url to link to
+     * @param float  $x      The x position of the link
+     * @param float  $y      The y position of the link
+     * @param float  $width  The width of the link
+     * @param float  $height The height of the link
      */
     function add_link($url, $x, $y, $width, $height);
 
     /**
-     * Add meta information to the pdf
+     * Add meta information to the PDF.
      *
-     * @param string $name Label of the value (Creator, Producer, etc.)
+     * @param string $label Label of the value (Creator, Producer, etc.)
      * @param string $value The text to set
      */
-    function add_info($name, $value);
+    public function add_info(string $label, string $value): void;
 
     /**
      * Calculates text size, in points
      *
-     * @param string $text the text to be sized
-     * @param string $font the desired font
-     * @param float $size the desired font size
-     * @param float $word_spacing word spacing, if any
-     * @param float $char_spacing char spacing, if any
+     * @param string $text         The text to be sized
+     * @param string $font         The font file to use
+     * @param float  $size         The font size, in points
+     * @param float  $word_spacing Word spacing, if any
+     * @param float  $char_spacing Char spacing, if any
      *
      * @return float
      */
@@ -372,18 +381,28 @@ interface Canvas
     /**
      * Calculates font height, in points
      *
-     * @param string $font
-     * @param float $size
+     * @param string $font The font file to use
+     * @param float  $size The font size, in points
      *
      * @return float
      */
     function get_font_height($font, $size);
 
+    /**
+     * Returns the font x-height, in points
+     *
+     * @param string $font The font file to use
+     * @param float  $size The font size, in points
+     *
+     * @return float
+     */
+    //function get_font_x_height($font, $size);
+
     /**
      * Calculates font baseline, in points
      *
-     * @param string $font
-     * @param float $size
+     * @param string $font The font file to use
+     * @param float  $size The font size, in points
      *
      * @return float
      */
@@ -396,31 +415,20 @@ interface Canvas
      */
     function get_width();
 
-
     /**
-     * Return the image's height in pixels
+     * Returns the PDF's height in points
      *
      * @return float
      */
     function get_height();
 
-    /**
-     * Returns the font x-height, in points
-     *
-     * @param string $font
-     * @param float $size
-     *
-     * @return float
-     */
-    //function get_font_x_height($font, $size);
-
     /**
      * Sets the opacity
      *
-     * @param float $opacity
+     * @param float  $opacity
      * @param string $mode
      */
-    function set_opacity($opacity, $mode = "Normal");
+    public function set_opacity(float $opacity, string $mode = "Normal"): void;
 
     /**
      * Sets the default view
@@ -435,17 +443,13 @@ interface Canvas
      * 'FitBH' top
      * 'FitBV' left
      * @param array $options
-     *
-     * @return void
      */
     function set_default_view($view, $options = []);
 
     /**
-     * @param string $script
-     *
-     * @return void
+     * @param string $code
      */
-    function javascript($script);
+    function javascript($code);
 
     /**
      * Starts a new page
@@ -455,10 +459,10 @@ interface Canvas
     function new_page();
 
     /**
-     * Streams the PDF directly to the browser.
+     * Streams the PDF to the client.
      *
-     * @param string $filename The filename to present to the browser.
-     * @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
+     * @param string $filename The filename to present to the client.
+     * @param array  $options  Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
      */
     function stream($filename, $options = []);
 
@@ -466,6 +470,7 @@ interface Canvas
      * Returns the PDF as a string.
      *
      * @param array $options Associative array: 'compress' => 1 or 0 (default 1).
+     *
      * @return string
      */
     function output($options = []);
diff --git a/library/vendor/dompdf/src/CanvasFactory.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/CanvasFactory.php
similarity index 93%
rename from library/vendor/dompdf/src/CanvasFactory.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/CanvasFactory.php
index b2bf1276a..86352e1dc 100644
--- a/library/vendor/dompdf/src/CanvasFactory.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/CanvasFactory.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
diff --git a/library/vendor/dompdf/src/Cellmap.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Cellmap.php
similarity index 91%
rename from library/vendor/dompdf/src/Cellmap.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Cellmap.php
index 40936a76a..e6c1c68e6 100644
--- a/library/vendor/dompdf/src/Cellmap.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Cellmap.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
@@ -23,10 +22,8 @@ class Cellmap
 {
     /**
      * Border style weight lookup for collapsed border resolution.
-     *
-     * @var array
      */
-    protected static $_BORDER_STYLE_SCORE = [
+    protected const BORDER_STYLE_SCORE = [
         "double" => 8,
         "solid"  => 7,
         "dashed" => 6,
@@ -131,10 +128,7 @@ class Cellmap
         $this->reset();
     }
 
-    /**
-     *
-     */
-    public function reset()
+    public function reset(): void
     {
         $this->_num_rows = 0;
         $this->_num_cols = 0;
@@ -153,10 +147,7 @@ class Cellmap
         $this->__col = $this->__row = 0;
     }
 
-    /**
-     *
-     */
-    public function lock_columns()
+    public function lock_columns(): void
     {
         $this->_columns_locked = true;
     }
@@ -170,9 +161,9 @@ class Cellmap
     }
 
     /**
-     * @param $fixed
+     * @param bool $fixed
      */
-    public function set_layout_fixed($fixed)
+    public function set_layout_fixed(bool $fixed)
     {
         $this->_fixed_layout = $fixed;
     }
@@ -456,12 +447,12 @@ class Cellmap
     /**
      * https://www.w3.org/TR/CSS21/tables.html#border-conflict-resolution
      *
-     * @param int $i
-     * @param int $j
-     * @param string $h_v
-     * @param array $border_spec
+     * @param int    $i
+     * @param int    $j
+     * @param string $h_v         `horizontal` or `vertical`
+     * @param array  $border_spec
      */
-    protected function _resolve_border($i, $j, $h_v, $border_spec)
+    protected function resolve_border(int $i, int $j, string $h_v, array $border_spec): void
     {
         if (!isset($this->_borders[$i][$j][$h_v])) {
             $this->_borders[$i][$j][$h_v] = $border_spec;
@@ -483,9 +474,9 @@ class Cellmap
         // width here, as its resolved width is always 0
         if ($n_style === "hidden" || $n_width > $o_width
             || ($o_width == $n_width
-                && isset(self::$_BORDER_STYLE_SCORE[$n_style])
-                && isset(self::$_BORDER_STYLE_SCORE[$o_style])
-                && self::$_BORDER_STYLE_SCORE[$n_style] > self::$_BORDER_STYLE_SCORE[$o_style])
+                && isset(self::BORDER_STYLE_SCORE[$n_style])
+                && isset(self::BORDER_STYLE_SCORE[$o_style])
+                && self::BORDER_STYLE_SCORE[$n_style] > self::BORDER_STYLE_SCORE[$o_style])
         ) {
             $this->_borders[$i][$j][$h_v] = $border_spec;
         }
@@ -554,7 +545,7 @@ class Cellmap
         // Recursively add the frames within the table, its row groups and rows
         if ($frame === $this->_table
             || $display === "table-row"
-            || in_array($display, TableFrameDecorator::$ROW_GROUPS, true)
+            || in_array($display, TableFrameDecorator::ROW_GROUPS, true)
         ) {
             $start_row = $this->__row;
 
@@ -579,14 +570,14 @@ class Cellmap
 
                 // Resolve vertical borders
                 for ($i = 0; $i < $num_rows + 1; $i++) {
-                    $this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
-                    $this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
+                    $this->resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
+                    $this->resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
                 }
 
                 // Resolve horizontal borders
                 for ($j = 0; $j < $this->_num_cols; $j++) {
-                    $this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
-                    $this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
+                    $this->resolve_border($start_row, $j, "horizontal", $bp["top"]);
+                    $this->resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
                 }
 
                 if ($frame === $this->_table) {
@@ -644,8 +635,8 @@ class Cellmap
 
             if ($collapse) {
                 // Resolve vertical borders
-                $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]);
-                $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]);
+                $this->resolve_border($row, $this->__col, "vertical", $bp["left"]);
+                $this->resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]);
             }
         }
 
@@ -656,8 +647,8 @@ class Cellmap
 
             if ($collapse) {
                 // Resolve horizontal borders
-                $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]);
-                $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]);
+                $this->resolve_border($this->__row, $col, "horizontal", $bp["top"]);
+                $this->resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]);
             }
         }
 
@@ -684,11 +675,8 @@ class Cellmap
         } else {
             // The additional 1/2 width gets added to the table proper
             [$h, $v] = $table_style->border_spacing;
-
-            $v = $table_style->length_in_pt($v);
-            $h = $table_style->length_in_pt($h);
-            $v_spacing = is_numeric($v) ? $v / 2 : $v;
-            $h_spacing = is_numeric($v) ? $h / 2 : $h;
+            $v_spacing = $v / 2;
+            $h_spacing = $h / 2;
         }
 
         foreach ($this->_frames as $frame_info) {
@@ -790,12 +778,19 @@ class Cellmap
                 }
             }
         }
+
+        // Adjust absolute columns so that the absolute (and max) width is the
+        // largest minimum width of all cells. This accounts for cells without
+        // absolute width within an absolute column
+        foreach ($this->_columns as &$col) {
+            if ($col["absolute"] > 0) {
+                $col["absolute"] = $col["min-width"];
+                $col["max-width"] = $col["min-width"];
+            }
+        }
     }
 
-    /**
-     *
-     */
-    public function add_row()
+    protected function add_row(): void
     {
         $this->__row++;
         $this->_num_rows++;
@@ -899,10 +894,7 @@ class Cellmap
         $this->_frames[$g_key]["rows"] = range($first_index, $last_index);
     }
 
-    /**
-     *
-     */
-    public function assign_x_positions()
+    public function assign_x_positions(): void
     {
         // Pre-condition: widths must be resolved and assigned to columns and
         // column[0]["x"] must be set.
@@ -918,17 +910,14 @@ class Cellmap
         }
     }
 
-    /**
-     *
-     */
-    public function assign_frame_heights()
+    public function assign_frame_heights(): void
     {
         // Pre-condition: widths and heights of each column & row must be
         // calcluated
         foreach ($this->_frames as $arr) {
             $frame = $arr["frame"];
 
-            $h = 0;
+            $h = 0.0;
             foreach ($arr["rows"] as $row) {
                 if (!isset($this->_rows[$row])) {
                     // The row has been removed because of a page split, so skip it.
@@ -941,7 +930,7 @@ class Cellmap
             if ($frame instanceof TableCellFrameDecorator) {
                 $frame->set_cell_height($h);
             } else {
-                $frame->get_style()->height = $h;
+                $frame->get_style()->set_used("height", $h);
             }
         }
     }
@@ -949,13 +938,13 @@ class Cellmap
     /**
      * Re-adjust frame height if the table height is larger than its content
      */
-    public function set_frame_heights($table_height, $content_height)
+    public function set_frame_heights(float $table_height, float $content_height): void
     {
         // Distribute the increased height proportionally amongst each row
         foreach ($this->_frames as $arr) {
             $frame = $arr["frame"];
 
-            $h = 0;
+            $h = 0.0;
             foreach ($arr["rows"] as $row) {
                 if (!isset($this->_rows[$row])) {
                     continue;
@@ -967,13 +956,13 @@ class Cellmap
             if ($content_height > 0) {
                 $new_height = ($h / $content_height) * $table_height;
             } else {
-                $new_height = 0;
+                $new_height = 0.0;
             }
 
             if ($frame instanceof TableCellFrameDecorator) {
                 $frame->set_cell_height($new_height);
             } else {
-                $frame->get_style()->height = $new_height;
+                $frame->get_style()->set_used("height", $new_height);
             }
         }
     }
@@ -983,7 +972,7 @@ class Cellmap
      *
      * @return string
      */
-    public function __toString()
+    public function __toString(): string
     {
         $str = "";
         $str .= "Columns:
"; diff --git a/library/vendor/dompdf/src/Css/AttributeTranslator.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/AttributeTranslator.php similarity index 99% rename from library/vendor/dompdf/src/Css/AttributeTranslator.php rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/AttributeTranslator.php index f012c9c8a..b2013e13c 100644 --- a/library/vendor/dompdf/src/Css/AttributeTranslator.php +++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/AttributeTranslator.php @@ -1,9 +1,7 @@ - * @author Fabien Ménager + * @link https://github.com/dompdf/dompdf * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License */ namespace Dompdf\Css; diff --git a/library/vendor/dompdf/src/Css/Color.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Color.php similarity index 97% rename from library/vendor/dompdf/src/Css/Color.php rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Color.php index 9f1f964a3..28a9f562c 100644 --- a/library/vendor/dompdf/src/Css/Color.php +++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Color.php @@ -2,12 +2,9 @@ /** * @package dompdf - * @link http://dompdf.github.com/ - * @author Benj Carson - * @author Fabien Ménager + * @link https://github.com/dompdf/dompdf * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License */ - namespace Dompdf\Css; use Dompdf\Helpers; @@ -165,7 +162,7 @@ class Color ]; /** - * @param $color + * @param array|string|null $color * @return array|string|null */ static function parse($color) @@ -261,7 +258,7 @@ class Color // Parse alpha value if (Helpers::is_percent($alpha)) { - $alpha = round((float) $alpha / 100, 2); + $alpha = (float) $alpha / 100; } else { $alpha = (float) $alpha; } @@ -294,7 +291,7 @@ class Color return null; } - $values = array_map(function($c) { + $values = array_map(function ($c) { return min(1.0, max(0.0, floatval(trim($c)))); }, $values); @@ -306,7 +303,7 @@ class Color } /** - * @param $color + * @param array|string $color * @param float $alpha * @return array */ diff --git a/library/vendor/dompdf/src/Css/Style.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Style.php similarity index 50% rename from library/vendor/dompdf/src/Css/Style.php rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Style.php index 341ae603a..2d4c9d798 100644 --- a/library/vendor/dompdf/src/Css/Style.php +++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Style.php @@ -1,13 +1,9 @@ - * @author Helmut Tischer - * @author Fabien Ménager + * @link https://github.com/dompdf/dompdf * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License */ - namespace Dompdf\Css; use Dompdf\Adapter\CPDF; @@ -22,36 +18,182 @@ use Dompdf\Frame; * It includes methods to resolve colors and lengths, as well as getters & * setters for many CSS properties. * + * Access to the different CSS properties is provided by the methods + * {@link Style::set_prop()} and {@link Style::get_specified()}, and the + * property overload methods {@link Style::__set()} and {@link Style::__get()}, + * as well as {@link Style::set_used()}. The latter methods operate on used + * values and permit access to any (CSS) property using the following syntax: + * + * ``` + * $style->margin_top = 10.0; + * echo $style->margin_top; // Returns `10.0` + * ``` + * + * To declare a property from a string, use {@link Style::set_prop()}: + * + * ``` + * $style->set_prop("margin_top", "1em"); + * echo $style->get_specified("margin_top"); // Returns `1em` + * echo $style->margin_top; // Returns `12.0`, assuming the default font size + * ``` + * * Actual CSS parsing is performed in the {@link Stylesheet} class. * + * @property string $azimuth + * @property string $background_attachment + * @property array|string $background_color + * @property string $background_image Image URL or `none` + * @property string $background_image_resolution + * @property array $background_position + * @property string $background_repeat + * @property array|string $background_size `cover`, `contain`, or `[width, height]`, each being a length, percentage, or `auto` + * @property string $border_collapse + * @property string $border_color Only use for setting all sides to the same color + * @property float[] $border_spacing Pair of `[horizontal, vertical]` spacing + * @property string $border_style Only use for setting all sides to the same style + * @property array|string $border_top_color + * @property array|string $border_right_color + * @property array|string $border_bottom_color + * @property array|string $border_left_color + * @property string $border_top_style Valid border style + * @property string $border_right_style Valid border style + * @property string $border_bottom_style Valid border style + * @property string $border_left_style Valid border style + * @property float $border_top_width Length in pt + * @property float $border_right_width Length in pt + * @property float $border_bottom_width Length in pt + * @property float $border_left_width Length in pt + * @property string $border_width Only use for setting all sides to the same width + * @property float|string $border_bottom_left_radius Radius in pt or a percentage value + * @property float|string $border_bottom_right_radius Radius in pt or a percentage value + * @property float|string $border_top_left_radius Radius in pt or a percentage value + * @property float|string $border_top_right_radius Radius in pt or a percentage value + * @property string $border_radius Only use for setting all corners to the same radius + * @property float|string $bottom Length in pt, a percentage value, or `auto` + * @property string $caption_side + * @property string $clear + * @property string $clip + * @property array|string $color + * @property string[]|string $content List of content components, `normal`, or `none` + * @property array|string $counter_increment Array defining the counters to increment or `none` + * @property array|string $counter_reset Array defining the counters to reset or `none` + * @property string $cue_after + * @property string $cue_before + * @property string $cue + * @property string $cursor + * @property string $direction + * @property string $display + * @property string $elevation + * @property string $empty_cells + * @property string $float + * @property string $font_family + * @property float $font_size Length in pt + * @property string $font_style + * @property string $font_variant + * @property string $font_weight + * @property float|string $height Length in pt, a percentage value, or `auto` + * @property string $image_resolution + * @property string $inset Only use for setting all box insets to the same length + * @property float|string $left Length in pt, a percentage value, or `auto` + * @property float $letter_spacing Length in pt + * @property float $line_height Length in pt + * @property string $list_style_image Image URL or `none` + * @property string $list_style_position + * @property string $list_style_type + * @property float|string $margin_right Length in pt, a percentage value, or `auto` + * @property float|string $margin_left Length in pt, a percentage value, or `auto` + * @property float|string $margin_top Length in pt, a percentage value, or `auto` + * @property float|string $margin_bottom Length in pt, a percentage value, or `auto` + * @property string $margin Only use for setting all sides to the same length + * @property float|string $max_height Length in pt, a percentage value, or `none` + * @property float|string $max_width Length in pt, a percentage value, or `none` + * @property float|string $min_height Length in pt, a percentage value, or `auto` + * @property float|string $min_width Length in pt, a percentage value, or `auto` + * @property float $opacity Number in the range [0, 1] + * @property int $orphans + * @property array|string $outline_color + * @property string $outline_style Valid border style, except for `hidden` + * @property float $outline_width Length in pt + * @property float $outline_offset Length in pt + * @property string $overflow + * @property string $overflow_wrap + * @property float|string $padding_top Length in pt or a percentage value + * @property float|string $padding_right Length in pt or a percentage value + * @property float|string $padding_bottom Length in pt or a percentage value + * @property float|string $padding_left Length in pt or a percentage value + * @property string $padding Only use for setting all sides to the same length + * @property string $page_break_after + * @property string $page_break_before + * @property string $page_break_inside + * @property string $pause_after + * @property string $pause_before + * @property string $pause + * @property string $pitch_range + * @property string $pitch + * @property string $play_during + * @property string $position + * @property string $quotes + * @property string $richness + * @property float|string $right Length in pt, a percentage value, or `auto` + * @property float[]|string $size Pair of `[width, height]` or `auto` + * @property string $speak_header + * @property string $speak_numeral + * @property string $speak_punctuation + * @property string $speak + * @property string $speech_rate + * @property string $src + * @property string $stress + * @property string $table_layout + * @property string $text_align + * @property string $text_decoration + * @property float|string $text_indent Length in pt or a percentage value + * @property string $text_transform + * @property float|string $top Length in pt, a percentage value, or `auto` + * @property array $transform List of transforms + * @property array $transform_origin + * @property string $unicode_bidi + * @property string $unicode_range + * @property string $vertical_align + * @property string $visibility + * @property string $voice_family + * @property string $volume + * @property string $white_space + * @property int $widows + * @property float|string $width Length in pt, a percentage value, or `auto` + * @property string $word_break + * @property float $word_spacing Length in pt + * @property int|string $z_index Integer value or `auto` + * @property string $_dompdf_keep + * * @package dompdf */ class Style { - const CSS_IDENTIFIER = "-?[_a-zA-Z]+[_a-zA-Z0-9-]*"; - const CSS_INTEGER = "[+-]?\d+"; - const CSS_NUMBER = "[+-]?\d*\.?\d+"; + protected const CSS_IDENTIFIER = "-?[_a-zA-Z]+[_a-zA-Z0-9-]*"; + protected const CSS_INTEGER = "[+-]?\d+"; + protected const CSS_NUMBER = "[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?"; /** * Default font size, in points. * * @var float */ - static $default_font_size = 12; + public static $default_font_size = 12; /** * Default line height, as a fraction of the font size. * * @var float */ - static $default_line_height = 1.2; + public static $default_line_height = 1.2; /** * Default "absolute" font sizes relative to the default font-size - * http://www.w3.org/TR/css3-fonts/#font-size-the-font-size-property + * https://www.w3.org/TR/css-fonts-3/#absolute-size-value + * * @var array */ - static $font_size_keywords = [ + public static $font_size_keywords = [ "xx-small" => 0.6, // 3/5 "x-small" => 0.75, // 3/4 "small" => 0.889, // 8/9 @@ -62,19 +204,15 @@ class Style ]; /** - * List of valid text-align keywords. Should also really be a constant. - * - * @var array + * List of valid text-align keywords. */ - static $text_align_keywords = ["left", "right", "center", "justify"]; + public const TEXT_ALIGN_KEYWORDS = ["left", "right", "center", "justify"]; /** - * List of valid vertical-align keywords. Should also really be a constant. - * - * @var array + * List of valid vertical-align keywords. */ - static $vertical_align_keywords = ["baseline", "bottom", "middle", "sub", - "super", "text-bottom", "text-top", "top"]; + public const VERTICAL_ALIGN_KEYWORDS = ["baseline", "bottom", "middle", + "sub", "super", "text-bottom", "text-top", "top"]; /** * List of all block-level (outer) display types. @@ -119,25 +257,19 @@ class Style ]; /** - * List of all inline (inner) display types. Should really be a constant. - * - * @var array + * List of all inline (inner) display types. */ - static $INLINE_TYPES = ["inline"]; + public const INLINE_TYPES = ["inline"]; /** - * List of all block (inner) display types. Should really be a constant. - * - * @var array + * List of all block (inner) display types. */ - static $BLOCK_TYPES = ["block", "inline-block", "table-cell", "list-item"]; + public const BLOCK_TYPES = ["block", "inline-block", "table-cell", "list-item"]; /** - * List of all table (inner) display types. Should really be a constant. - * - * @var array + * List of all table (inner) display types. */ - static $TABLE_TYPES = ["table", "inline-table"]; + public const TABLE_TYPES = ["table", "inline-table"]; /** * Lookup table for valid display types. Initially computed from the @@ -148,19 +280,30 @@ class Style protected static $valid_display_types = []; /** - * List of all positioned types. Should really be a constant. - * - * @var array + * List of all positioned types. */ - static $POSITIONNED_TYPES = ["relative", "absolute", "fixed"]; + public const POSITIONED_TYPES = ["relative", "absolute", "fixed"]; /** - * List of valid border styles. Should also really be a constant. - * - * @var array + * List of valid border styles. */ - static $BORDER_STYLES = ["none", "hidden", "dotted", "dashed", "solid", - "double", "groove", "ridge", "inset", "outset"]; + public const BORDER_STYLES = [ + "none", "hidden", + "dotted", "dashed", "solid", + "double", "groove", "ridge", "inset", "outset" + ]; + + /** + * List of valid outline-style values. + * Same as the border styles, except `auto` is allowed, `hidden` is not. + * + * @link https://www.w3.org/TR/css-ui-4/#typedef-outline-line-style + */ + protected const OUTLINE_STYLES = [ + "auto", "none", + "dotted", "dashed", "solid", + "double", "groove", "ridge", "inset", "outset" + ]; /** * Map of CSS shorthand properties and their corresponding sub-properties. @@ -181,9 +324,18 @@ class Style "background_color" ], "border" => [ - "border_width", - "border_style", - "border_color" + "border_top_width", + "border_right_width", + "border_bottom_width", + "border_left_width", + "border_top_style", + "border_right_style", + "border_bottom_style", + "border_left_style", + "border_top_color", + "border_right_color", + "border_bottom_color", + "border_left_color" ], "border_top" => [ "border_top_width", @@ -238,6 +390,12 @@ class Style "font_weight", "line_height" ], + "inset" => [ + "top", + "right", + "bottom", + "left" + ], "list_style" => [ "list_style_image", "list_style_position", @@ -278,7 +436,7 @@ class Style /** * Default style values. * - * @link http://www.w3.org/TR/CSS21/propidx.html + * @link https://www.w3.org/TR/CSS21/propidx.html * * @var array */ @@ -287,7 +445,7 @@ class Style /** * List of inherited properties * - * @link http://www.w3.org/TR/CSS21/propidx.html + * @link https://www.w3.org/TR/CSS21/propidx.html * * @var array */ @@ -314,14 +472,6 @@ class Style */ protected $_media_queries; - /** - * Specified (or declared) values of the CSS properties. - * https://www.w3.org/TR/css-cascade-3/#value-stages - * - * @var array - */ - protected $_props = []; - /** * Properties set by an `!important` declaration. * @@ -329,6 +479,15 @@ class Style */ protected $_important_props = []; + /** + * Specified (or declared) values of the CSS properties. + * + * https://www.w3.org/TR/css-cascade-3/#value-stages + * + * @var array + */ + protected $_props = []; + /** * Computed values of the CSS properties. * @@ -341,7 +500,15 @@ class Style * * @var array */ - protected $_prop_cache = []; + protected $_props_used = []; + + /** + * Marks properties with non-final used values that should be cleared on + * style reset. + * + * @var array + */ + protected $non_final_used = []; protected static $_dependency_map = [ "border_top_style" => [ @@ -366,6 +533,11 @@ class Style "border_right_width", "border_bottom_width", "border_left_width", + "border_top_left_radius", + "border_top_right_radius", + "border_bottom_right_radius", + "border_bottom_left_radius", + "letter_spacing", "line_height", "margin_top", "margin_right", @@ -376,7 +548,14 @@ class Style "padding_top", "padding_right", "padding_bottom", - "padding_left" + "padding_left", + "word_spacing", + "width", + "height", + "min-width", + "min-height", + "max-width", + "max-height" ], "float" => [ "display" @@ -405,7 +584,7 @@ class Style protected $parent_style; /** - * @var Frame + * @var Frame|null */ protected $_frame; @@ -416,19 +595,20 @@ class Style */ protected $_origin = Stylesheet::ORIG_AUTHOR; - // private members /** * The computed bottom spacing + * + * @var float|string|null */ private $_computed_bottom_spacing = null; /** - * @var bool + * @var bool|null */ private $has_border_radius_cache = null; /** - * @var array + * @var array|null */ private $resolved_border_radius = null; @@ -438,14 +618,12 @@ class Style private $fontMetrics; /** - * Class constructor - * - * @param Stylesheet $stylesheet the stylesheet this Style is associated with. - * @param int $origin + * @param Stylesheet $stylesheet The stylesheet the style is associated with. + * @param int $origin */ - public function __construct(Stylesheet $stylesheet, $origin = Stylesheet::ORIG_AUTHOR) + public function __construct(Stylesheet $stylesheet, int $origin = Stylesheet::ORIG_AUTHOR) { - $this->setFontMetrics($stylesheet->getFontMetrics()); + $this->fontMetrics = $stylesheet->getFontMetrics(); $this->_stylesheet = $stylesheet; $this->_media_queries = []; @@ -458,17 +636,20 @@ class Style $d =& self::$_defaults; // All CSS 2.1 properties, and their default values + // Some properties are specified with their computed value for + // efficiency; this only works if the computed value is not + // dependent on another property $d["azimuth"] = "center"; $d["background_attachment"] = "scroll"; $d["background_color"] = "transparent"; $d["background_image"] = "none"; $d["background_image_resolution"] = "normal"; - $d["background_position"] = "0% 0%"; + $d["background_position"] = ["0%", "0%"]; $d["background_repeat"] = "repeat"; $d["background"] = ""; $d["border_collapse"] = "separate"; $d["border_color"] = ""; - $d["border_spacing"] = "0"; + $d["border_spacing"] = [0.0, 0.0]; $d["border_style"] = ""; $d["border_top"] = ""; $d["border_right"] = ""; @@ -487,10 +668,10 @@ class Style $d["border_bottom_width"] = "medium"; $d["border_left_width"] = "medium"; $d["border_width"] = ""; - $d["border_bottom_left_radius"] = "0"; - $d["border_bottom_right_radius"] = "0"; - $d["border_top_left_radius"] = "0"; - $d["border_top_right_radius"] = "0"; + $d["border_bottom_left_radius"] = 0.0; + $d["border_bottom_right_radius"] = 0.0; + $d["border_top_left_radius"] = 0.0; + $d["border_top_right_radius"] = 0.0; $d["border_radius"] = ""; $d["border"] = ""; $d["bottom"] = "auto"; @@ -518,6 +699,7 @@ class Style $d["font"] = ""; $d["height"] = "auto"; $d["image_resolution"] = "normal"; + $d["inset"] = ""; $d["left"] = "auto"; $d["letter_spacing"] = "normal"; $d["line_height"] = "normal"; @@ -525,27 +707,27 @@ class Style $d["list_style_position"] = "outside"; $d["list_style_type"] = "disc"; $d["list_style"] = ""; - $d["margin_right"] = "0"; - $d["margin_left"] = "0"; - $d["margin_top"] = "0"; - $d["margin_bottom"] = "0"; + $d["margin_right"] = 0.0; + $d["margin_left"] = 0.0; + $d["margin_top"] = 0.0; + $d["margin_bottom"] = 0.0; $d["margin"] = ""; $d["max_height"] = "none"; $d["max_width"] = "none"; $d["min_height"] = "auto"; $d["min_width"] = "auto"; - $d["orphans"] = "2"; + $d["orphans"] = 2; $d["outline_color"] = "currentcolor"; // "invert" special color is not supported $d["outline_style"] = "none"; $d["outline_width"] = "medium"; - $d["outline_offset"] = "0"; + $d["outline_offset"] = 0.0; $d["outline"] = ""; $d["overflow"] = "visible"; $d["overflow_wrap"] = "normal"; - $d["padding_top"] = "0"; - $d["padding_right"] = "0"; - $d["padding_bottom"] = "0"; - $d["padding_left"] = "0"; + $d["padding_top"] = 0.0; + $d["padding_right"] = 0.0; + $d["padding_bottom"] = 0.0; + $d["padding_left"] = 0.0; $d["padding"] = ""; $d["page_break_after"] = "auto"; $d["page_break_before"] = "auto"; @@ -570,7 +752,7 @@ class Style $d["table_layout"] = "auto"; $d["text_align"] = ""; $d["text_decoration"] = "none"; - $d["text_indent"] = "0"; + $d["text_indent"] = 0.0; $d["text_transform"] = "none"; $d["top"] = "auto"; $d["unicode_bidi"] = "normal"; @@ -579,14 +761,15 @@ class Style $d["voice_family"] = ""; $d["volume"] = "medium"; $d["white_space"] = "normal"; - $d["widows"] = "2"; + $d["widows"] = 2; $d["width"] = "auto"; + $d["word_break"] = "normal"; $d["word_spacing"] = "normal"; $d["z_index"] = "auto"; // CSS3 - $d["opacity"] = "1.0"; - $d["background_size"] = "auto auto"; + $d["opacity"] = 1.0; + $d["background_size"] = ["auto", "auto"]; $d["transform"] = "none"; $d["transform_origin"] = "50% 50%"; @@ -642,6 +825,7 @@ class Style "volume", "white_space", "widows", + "word_break", "word_spacing", ]; @@ -673,24 +857,31 @@ class Style } /** - * "Destructor": forcibly free all references held by this object + * Clear all non-final used values. + * + * @return void */ - function dispose() + public function reset(): void { + foreach (array_keys($this->non_final_used) as $prop) { + unset($this->_props_used[$prop]); + } + + $this->non_final_used = []; } /** - * @param $media_queries + * @param array $media_queries */ - function set_media_queries($media_queries) + public function set_media_queries(array $media_queries): void { $this->_media_queries = $media_queries; } /** - * @return array|int + * @return array */ - function get_media_queries() + public function get_media_queries(): array { return $this->_media_queries; } @@ -698,23 +889,23 @@ class Style /** * @param Frame $frame */ - function set_frame(Frame $frame) + public function set_frame(Frame $frame): void { $this->_frame = $frame; } /** - * @return Frame + * @return Frame|null */ - function get_frame() + public function get_frame(): ?Frame { return $this->_frame; } /** - * @param $origin + * @param int $origin */ - function set_origin($origin) + public function set_origin(int $origin): void { $this->_origin = $origin; } @@ -722,17 +913,17 @@ class Style /** * @return int */ - function get_origin() + public function get_origin(): int { return $this->_origin; } /** - * returns the {@link Stylesheet} this Style is associated with. + * Returns the {@link Stylesheet} the style is associated with. * * @return Stylesheet */ - function get_stylesheet() + public function get_stylesheet(): Stylesheet { return $this->_stylesheet; } @@ -764,12 +955,12 @@ class Style * * @return float|string */ - function length_in_pt($length, ?float $ref_size = null) + public function length_in_pt($length, ?float $ref_size = null) { $font_size = $this->__get("font_size"); $ref_size = $ref_size ?? $font_size; - if (!is_array($length)) { + if (!\is_array($length)) { $length = [$length]; } @@ -787,13 +978,7 @@ class Style } $val = $this->single_length_in_pt((string) $l, $ref_size, $font_size); - - // FIXME: Using the ref size as fallback here currently ensures that - // invalid widths or heights are treated as the corresponding - // containing-block dimension, which can look like the declaration - // is being ignored. Implement proper compute methods instead, and - // fall back to 0 here - $ret += $val ?? $ref_size; + $ret += $val ?? 0; } return $ret; @@ -816,60 +1001,78 @@ class Style $key = "$l/$ref_size/$font_size"; - if (isset($cache[$key])) { + if (\array_key_exists($key, $cache)) { return $cache[$key]; } - if (is_numeric($l)) { + $number = self::CSS_NUMBER; + $pattern = "/^($number)(.*)?$/"; + + if (!preg_match($pattern, $l, $matches)) { + return null; + } + + $v = (float) $matches[1]; + $unit = mb_strtolower($matches[2]); + + if ($unit === "") { // Legacy support for unitless values, not covered by spec. Might // want to restrict this to unitless `0` in the future - $value = (float) $l; + $value = $v; } - elseif (($i = mb_stripos($l, "%")) !== false) { - $value = (float)mb_substr($l, 0, $i) / 100 * $ref_size; + elseif ($unit === "%") { + $value = $v / 100 * $ref_size; } - elseif (($i = mb_stripos($l, "px")) !== false) { + elseif ($unit === "px") { $dpi = $this->_stylesheet->get_dompdf()->getOptions()->getDpi(); - $value = ((float)mb_substr($l, 0, $i) * 72) / $dpi; + $value = ($v * 72) / $dpi; } - elseif (($i = mb_stripos($l, "pt")) !== false) { - $value = (float)mb_substr($l, 0, $i); + elseif ($unit === "pt") { + $value = $v; } - elseif (($i = mb_stripos($l, "rem")) !== false) { - $root_style = $this->_stylesheet->get_dompdf()->getTree()->get_root()->get_style(); + elseif ($unit === "rem") { + $tree = $this->_stylesheet->get_dompdf()->getTree(); + $root_style = $tree !== null ? $tree->get_root()->get_style() : null; $root_font_size = $root_style === null || $root_style === $this ? $font_size - : $root_style->font_size; - $value = (float)mb_substr($l, 0, $i) * $root_font_size; + : $root_style->__get("font_size"); + $value = $v * $root_font_size; + + // Skip caching if the root style is not available yet, as to avoid + // incorrectly cached values if the root font size is different from + // the default + if ($root_style === null) { + return $value; + } } - elseif (($i = mb_stripos($l, "em")) !== false) { - $value = (float)mb_substr($l, 0, $i) * $font_size; + elseif ($unit === "em") { + $value = $v * $font_size; } - elseif (($i = mb_stripos($l, "cm")) !== false) { - $value = (float)mb_substr($l, 0, $i) * 72 / 2.54; + elseif ($unit === "cm") { + $value = $v * 72 / 2.54; } - elseif (($i = mb_stripos($l, "mm")) !== false) { - $value = (float)mb_substr($l, 0, $i) * 72 / 25.4; + elseif ($unit === "mm") { + $value = $v * 72 / 25.4; } - elseif (($i = mb_stripos($l, "ex")) !== false) { + elseif ($unit === "ex") { // FIXME: em:ex ratio? - $value = (float)mb_substr($l, 0, $i) * $font_size / 2; + $value = $v * $font_size / 2; } - elseif (($i = mb_stripos($l, "in")) !== false) { - $value = (float)mb_substr($l, 0, $i) * 72; + elseif ($unit === "in") { + $value = $v * 72; } - elseif (($i = mb_stripos($l, "pc")) !== false) { - $value = (float)mb_substr($l, 0, $i) * 12; + elseif ($unit === "pc") { + $value = $v * 12; } else { @@ -880,7 +1083,6 @@ class Style return $cache[$key] = $value; } - /** * Resolve inherited property values using the provided parent style or the * default values, in case no parent style exists. @@ -888,17 +1090,15 @@ class Style * https://www.w3.org/TR/css-cascade-3/#inheriting * * @param Style|null $parent - * - * @return Style */ - function inherit(?Style $parent = null) + public function inherit(?Style $parent = null): void { $this->parent_style = $parent; // Clear the computed font size, as it might depend on the parent // font size unset($this->_props_computed["font_size"]); - unset($this->_prop_cache["font_size"]); + unset($this->_props_used["font_size"]); if ($parent) { foreach (self::$_inherited as $prop) { @@ -908,15 +1108,13 @@ class Style if (isset($this->_props[$prop]) || isset(self::$_props_shorthand[$prop])) { continue; } - + if (isset($parent->_props[$prop])) { - $parent_val = \array_key_exists($prop, $parent->_props_computed) - ? $parent->_props_computed[$prop] - : $parent->compute_prop($prop, $parent->_props[$prop]); - + $parent_val = $parent->computed($prop); + $this->_props[$prop] = $parent_val; $this->_props_computed[$prop] = $parent_val; - $this->_prop_cache[$prop] = null; + $this->_props_used[$prop] = null; } } } @@ -924,23 +1122,19 @@ class Style foreach ($this->_props as $prop => $val) { if ($val === "inherit") { if ($parent && isset($parent->_props[$prop])) { - $parent_val = \array_key_exists($prop, $parent->_props_computed) - ? $parent->_props_computed[$prop] - : $parent->compute_prop($prop, $parent->_props[$prop]); + $parent_val = $parent->computed($prop); $this->_props[$prop] = $parent_val; $this->_props_computed[$prop] = $parent_val; - $this->_prop_cache[$prop] = null; + $this->_props_used[$prop] = null; } else { // Parent prop not set, use default $this->_props[$prop] = self::$_defaults[$prop]; unset($this->_props_computed[$prop]); - unset($this->_prop_cache[$prop]); + unset($this->_props_used[$prop]); } } } - - return $this; } /** @@ -948,7 +1142,7 @@ class Style * * @param Style $style */ - function merge(Style $style) + public function merge(Style $style): void { foreach ($style->_props as $prop => $val) { $important = isset($style->_important_props[$prop]); @@ -958,68 +1152,26 @@ class Style continue; } - $computed = \array_key_exists($prop, $style->_props_computed) - ? $style->_props_computed[$prop] - : $style->compute_prop($prop, $val); - - // Skip invalid declarations. Because styles are merged into an - // initially empty style object during stylesheet loading, this - // handles all invalid declarations - if ($computed === null) { - continue; - } - if ($important) { $this->_important_props[$prop] = true; } $this->_props[$prop] = $val; - // Don't use the computed value for dependent properties; they will - // be computed on-demand during inheritance or property access - // instead - if (isset(self::$_dependent_props[$prop])) { - unset($this->_props_computed[$prop]); - unset($this->_prop_cache[$prop]); + // Copy an existing computed value only for non-dependent + // properties; otherwise it may be invalid for the current style + if (!isset(self::$_dependent_props[$prop]) + && \array_key_exists($prop, $style->_props_computed) + ) { + $this->_props_computed[$prop] = $style->_props_computed[$prop]; + $this->_props_used[$prop] = null; } else { - $this->_props_computed[$prop] = $computed; - $this->_prop_cache[$prop] = null; + unset($this->_props_computed[$prop]); + unset($this->_props_used[$prop]); } } } - /** - * Returns an array(r, g, b, "r"=> r, "g"=>g, "b"=>b, "alpha"=>alpha, "hex"=>"#rrggbb") - * based on the provided CSS color value. - * - * @param string $color - * @return array|string|null - */ - function munge_color($color) - { - return Color::parse($color); - } - - /** - * @deprecated - * @param string $prop - */ - function important_set($prop) - { - $prop = str_replace("-", "_", $prop); - $this->_important_props[$prop] = true; - } - - /** - * @deprecated - * @param string $prop - * @return bool - */ - function important_get($prop) - { - return isset($this->_important_props[$prop]); - } - /** * Clear information about important declarations after the style has been * finalized during stylesheet loading. @@ -1030,17 +1182,47 @@ class Style } /** - * Set the specified value of a property. + * Clear border-radius and bottom-spacing cache as necessary when a given + * property is set. + * + * @param string $prop The property that is set. + */ + protected function clear_cache(string $prop): void + { + // Clear border-radius cache on setting any border-radius + // property + if ($prop === "border_top_left_radius" + || $prop === "border_top_right_radius" + || $prop === "border_bottom_left_radius" + || $prop === "border_bottom_right_radius" + ) { + $this->has_border_radius_cache = null; + $this->resolved_border_radius = null; + } + + // Clear bottom-spacing cache if necessary. Border style can + // disable/enable border calculations + if ($prop === "margin_bottom" + || $prop === "padding_bottom" + || $prop === "border_bottom_width" + || $prop === "border_bottom_style" + ) { + $this->_computed_bottom_spacing = null; + } + } + + /** + * Set a style property from a value declaration. * * Setting `$clear_dependencies` to `false` is useful for saving a bit of * unnecessary work while loading stylesheets. * * @param string $prop The property to set. - * @param mixed $val The value declaration. + * @param mixed $val The value declaration or computed value. * @param bool $important Whether the declaration is important. * @param bool $clear_dependencies Whether to clear computed values of dependent properties. */ - function set_prop(string $prop, $val, bool $important = false, bool $clear_dependencies = true): void + public function set_prop(string $prop, $val, bool $important = false, bool $clear_dependencies = true): void { $prop = str_replace("-", "_", $prop); @@ -1055,9 +1237,8 @@ class Style return; } - if ($prop !== "content" && is_string($val) && mb_strpos($val, "url") === false && strlen($val) > 1) { + if ($prop !== "content" && \is_string($val) && mb_strpos($val, "url") === false && mb_strlen($val) > 1) { $val = mb_strtolower(trim(str_replace(["\n", "\t"], [" "], $val))); - $val = preg_replace("/([0-9]+) (pt|px|pc|rem|em|ex|in|cm|mm|%)/S", "\\1\\2", $val); } if (isset(self::$_props_shorthand[$prop])) { @@ -1068,17 +1249,35 @@ class Style $this->set_prop($sub_prop, $val, $important, $clear_dependencies); } } else { - $method = "set_$prop"; - + $method = "_set_$prop"; + if (!isset(self::$_methods_cache[$method])) { self::$_methods_cache[$method] = method_exists($this, $method); } - + if (self::$_methods_cache[$method]) { - $this->$method($val, $important); + $values = $this->$method($val); + + if ($values === []) { + return; + } + + // Each missing sub-property is assigned its initial value + // https://www.w3.org/TR/css-cascade-3/#shorthand + foreach (self::$_props_shorthand[$prop] as $sub_prop) { + $sub_val = $values[$sub_prop] ?? self::$_defaults[$sub_prop]; + $this->set_prop($sub_prop, $sub_val, $important, $clear_dependencies); + } } } } else { + // Legacy support for `word-break: break-word` + // https://www.w3.org/TR/css-text-3/#valdef-word-break-break-word + if ($prop === "word_break" && $val === "break-word") { + $val = "normal"; + $this->set_prop("overflow_wrap", "anywhere", $important, $clear_dependencies); + } + // `!important` declarations take precedence over normal ones if (!$important && isset($this->_important_props[$prop])) { return; @@ -1090,7 +1289,7 @@ class Style // https://www.w3.org/TR/css-cascade-3/#inherit-initial if ($val === "unset") { - $val = in_array($prop, self::$_inherited, true) + $val = \in_array($prop, self::$_inherited, true) ? "inherit" : "initial"; } @@ -1100,9 +1299,16 @@ class Style $val = self::$_defaults[$prop]; } + $computed = $this->compute_prop($prop, $val); + + // Skip invalid declarations + if ($computed === null) { + return; + } + $this->_props[$prop] = $val; - unset($this->_props_computed[$prop]); - unset($this->_prop_cache[$prop]); + $this->_props_computed[$prop] = $computed; + $this->_props_used[$prop] = null; if ($clear_dependencies) { // Clear the computed values of any dependent properties, so @@ -1110,40 +1316,24 @@ class Style if (isset(self::$_dependency_map[$prop])) { foreach (self::$_dependency_map[$prop] as $dependent) { unset($this->_props_computed[$dependent]); - unset($this->_prop_cache[$dependent]); + unset($this->_props_used[$dependent]); } } - // Clear border-radius cache on setting any border-radius - // property - if ($prop === "border_top_left_radius" - || $prop === "border_top_right_radius" - || $prop === "border_bottom_left_radius" - || $prop === "border_bottom_right_radius" - ) { - $this->has_border_radius_cache = null; - } - } - - // FIXME: temporary hack around lack of persistence of base href for - // URLs. Compute value immediately, before the original base href is - // no longer available - if ($prop === "background_image" || $prop === "list_style_image") { - $this->compute_prop($prop, $val); + $this->clear_cache($prop); } } } /** - * Similar to __get() without storing the result. Useful for accessing - * properties while loading stylesheets. + * Get the specified value of a style property. * * @param string $prop * * @return mixed * @throws Exception */ - function get_prop(string $prop) + public function get_specified(string $prop) { // Legacy property aliases if (isset(self::$_props_alias[$prop])) { @@ -1154,66 +1344,25 @@ class Style throw new Exception("'$prop' is not a recognized CSS property."); } - $method = "get_$prop"; - - if (isset($this->_props_computed[$prop])) { - if (method_exists($this, $method)) { - return $this->$method(); - } - - return $this->_props_computed[$prop]; - } - - // Fall back on defaults if property is not set return $this->_props[$prop] ?? self::$_defaults[$prop]; } /** - * PHP5 overloaded setter + * Set a style property to its final value. * - * This function along with {@link Style::__get()} permit a user of the - * Style class to access any (CSS) property using the following syntax: - * - * Style->margin_top = "1em"; - * echo (Style->margin_top); - * + * This sets the specified and used value of the style property to the given + * value, meaning the value is not parsed and thus should have a type + * compatible with the property. * - * __set() automatically calls the provided set function, if one exists, - * otherwise it sets the property directly. Typically, __set() is not - * called directly from outside of this class. + * If a shorthand property is specified, all of its sub-properties are set + * to the given value. * - * On each modification clear cache to return accurate setting. - * Also affects direct settings not using __set - * For easier finding all assignments, attempted to allowing only explicite assignment: - * Very many uses, e.g. AbstractFrameReflower.php -> for now leave as it is - * function __set($prop, $val) { - * throw new Exception("Implicit replacement of assignment by __set. Not good."); - * } - * function props_set($prop, $val) { ... } + * @param string $prop The property to set. + * @param mixed $val The final value of the property. * - * @param string $prop the property to set - * @param mixed $val the value of the property - * - */ - function __set($prop, $val) - { - $this->set_prop($prop, $val); - } - - /** - * PHP5 overloaded getter - * Along with {@link Style::__set()} __get() provides access to all CSS - * properties directly. Typically __get() is not called directly outside - * of this class. - * On each modification clear cache to return accurate setting. - * Also affects direct settings not using __set - * - * @param string $prop - * - * @return mixed * @throws Exception */ - function __get($prop) + public function __set(string $prop, $val) { // Legacy property aliases if (isset(self::$_props_alias[$prop])) { @@ -1224,59 +1373,33 @@ class Style throw new Exception("'$prop' is not a recognized CSS property."); } - if (isset($this->_prop_cache[$prop])) { - return $this->_prop_cache[$prop]; - } - - $method = "get_$prop"; - - if (!isset(self::$_methods_cache[$method])) { - self::$_methods_cache[$method] = method_exists($this, $method); - } - if (isset(self::$_props_shorthand[$prop])) { - // Don't cache shorthand values, always use getter. If no dedicated - // getter exists, use a simple fallback getter concatenating all - // sub-property values - if (self::$_methods_cache[$method]) { - return $this->$method(); - } else { - return implode(" ", array_map(function ($sub_prop) { - $val = $this->__get($sub_prop); - return is_array($val) ? implode(" ", $val) : $val; - }, self::$_props_shorthand[$prop])); + foreach (self::$_props_shorthand[$prop] as $sub_prop) { + $this->__set($sub_prop, $val); } } else { - // Compute the value if needed - if (!\array_key_exists($prop, $this->_props_computed)) { - $val = $this->_props[$prop] ?? self::$_defaults[$prop]; - $this->compute_prop($prop, $val); - } + $this->_props[$prop] = $val; + $this->_props_computed[$prop] = $val; + $this->_props_used[$prop] = $val; - // Invalid declarations are skipped on style merge, but during - // style parsing, styles might contain invalid declarations. Fall - // back to the default value in that case - $computed = $this->_props_computed[$prop] - ?? $this->compute_prop($prop, self::$_defaults[$prop]); - $used = self::$_methods_cache[$method] - ? $this->$method() - : $computed; - - $this->_prop_cache[$prop] = $used; - return $used; + $this->clear_cache($prop); } } /** - * Experimental fast setter for used values. + * Set the used value of a style property. + * + * Used values are cleared on style reset. * * If a shorthand property is specified, all of its sub-properties are set - * to the same value. + * to the given value. * - * @param string $prop - * @param mixed $val + * @param string $prop The property to set. + * @param mixed $val The used value of the property. + * + * @throws Exception */ - function set_used(string $prop, $val): void + public function set_used(string $prop, $val): void { // Legacy property aliases if (isset(self::$_props_alias[$prop])) { @@ -1292,27 +1415,72 @@ class Style $this->set_used($sub_prop, $val); } } else { - $this->_prop_cache[$prop] = $val; + $this->_props_used[$prop] = $val; + $this->non_final_used[$prop] = true; } } /** - * @param string $prop The property to compute. - * @param mixed $val The value to compute. + * Get the used or computed value of a style property, depending on whether + * the used value has been determined yet. * - * @return mixed The computed value. + * @param string $prop + * + * @return mixed + * @throws Exception */ - protected function compute_prop(string $prop, $val) + public function __get(string $prop) { - $this->_props_computed[$prop] = null; - $this->_prop_cache[$prop] = null; + // Legacy property aliases + if (isset(self::$_props_alias[$prop])) { + $prop = self::$_props_alias[$prop]; + } - $method = "set_$prop"; + if (!isset(self::$_defaults[$prop])) { + throw new Exception("'$prop' is not a recognized CSS property."); + } + + if (isset($this->_props_used[$prop])) { + return $this->_props_used[$prop]; + } + + $method = "_get_$prop"; if (!isset(self::$_methods_cache[$method])) { self::$_methods_cache[$method] = method_exists($this, $method); } + if (isset(self::$_props_shorthand[$prop])) { + // Don't cache shorthand values, always use getter. If no dedicated + // getter exists, use a simple fallback getter concatenating all + // sub-property values + if (self::$_methods_cache[$method]) { + return $this->$method(); + } else { + return implode(" ", array_map(function ($sub_prop) { + $val = $this->__get($sub_prop); + return \is_array($val) ? implode(" ", $val) : $val; + }, self::$_props_shorthand[$prop])); + } + } else { + $computed = $this->computed($prop); + $used = self::$_methods_cache[$method] + ? $this->$method($computed) + : $computed; + + $this->_props_used[$prop] = $used; + return $used; + } + } + + /** + * @param string $prop The property to compute. + * @param mixed $val The value to compute. Non-string values are treated as already computed. + * + * @return mixed The computed value. + */ + protected function compute_prop(string $prop, $val) + { // During style merge, the parent style is not available yet, so // temporarily use the initial value for `inherit` properties. The // keyword is properly resolved during inheritance @@ -1320,10 +1488,40 @@ class Style $val = self::$_defaults[$prop]; } + // Check for values which are already computed + if (!\is_string($val)) { + return $val; + } + + $method = "_compute_$prop"; + + if (!isset(self::$_methods_cache[$method])) { + self::$_methods_cache[$method] = method_exists($this, $method); + } + if (self::$_methods_cache[$method]) { - $this->$method($val); + return $this->$method($val); } elseif ($val !== "") { - $this->_props_computed[$prop] = $val; + return $val; + } else { + return null; + } + } + + /** + * Get the computed value for the given property. + * + * @param string $prop The property to get the computed value of. + * + * @return mixed The computed value. + */ + protected function computed(string $prop) + { + if (!\array_key_exists($prop, $this->_props_computed)) { + $val = $this->_props[$prop] ?? self::$_defaults[$prop]; + $computed = $this->compute_prop($prop, $val); + + $this->_props_computed[$prop] = $computed; } return $this->_props_computed[$prop]; @@ -1331,9 +1529,9 @@ class Style /** * @param float $cbw The width of the containing block. - * @return float|null|string + * @return float|string|null */ - function computed_bottom_spacing(float $cbw) + public function computed_bottom_spacing(float $cbw) { // Caching the bottom spacing independently of the given width is a bit // iffy, but should be okay, as the containing block should only @@ -1352,28 +1550,43 @@ class Style ); } + /** + * Returns an `array(r, g, b, "r" => r, "g" => g, "b" => b, "alpha" => alpha, "hex" => "#rrggbb")` + * based on the provided CSS color value. + * + * @param string|null $color + * @return array|string|null + */ + public function munge_color($color) + { + return Color::parse($color); + } + /** * @return string */ - function get_font_family_raw() + public function get_font_family_raw(): string { return trim($this->_props["font_family"], " \t\n\r\x0B\"'"); } /** - * Getter for the 'font-family' CSS property. + * Getter for the `font-family` CSS property. + * * Uses the {@link FontMetrics} class to resolve the font family into an * actual font file. * - * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-family + * @param string $computed + * @return string * @throws Exception * - * @return string + * @link https://www.w3.org/TR/CSS21/fonts.html#propdef-font-family */ - function get_font_family() + protected function _get_font_family($computed): string { //TODO: we should be using the calculated prop rather than perform the entire family parsing operation again + $fontMetrics = $this->getFontMetrics(); $DEBUGCSS = $this->_stylesheet->get_dompdf()->getOptions()->getDebugCss(); // Select the appropriate font. First determine the subtype, then check @@ -1391,9 +1604,9 @@ class Style // Resolve font-style $font_style = $this->__get("font_style"); - $subtype = $this->getFontMetrics()->getType($weight . ' ' . $font_style); + $subtype = $fontMetrics->getType($weight . ' ' . $font_style); - $families = preg_split("/\s*,\s*/", $this->_props_computed["font_family"]); + $families = preg_split("/\s*,\s*/", $computed); $font = null; foreach ($families as $family) { @@ -1403,12 +1616,12 @@ class Style if ($DEBUGCSS) { print '(' . $family . ')'; } - $font = $this->getFontMetrics()->getFont($family, $subtype); + $font = $fontMetrics->getFont($family, $subtype); if ($font) { if ($DEBUGCSS) { print "
[get_font_family:";
-                    print '(' . $this->_props_computed["font_family"] . '.' . $font_style . '.' . $weight . '.' . $subtype . ')';
+                    print '(' . $computed . '.' . $font_style . '.' . $weight . '.' . $subtype . ')';
                     print '(' . $font . ")get_font_family]\n
"; } return $font; @@ -1419,7 +1632,7 @@ class Style if ($DEBUGCSS) { print '(default)'; } - $font = $this->getFontMetrics()->getFont($family, $subtype); + $font = $fontMetrics->getFont($family, $subtype); if ($font) { if ($DEBUGCSS) { @@ -1428,224 +1641,189 @@ class Style return $font; } - throw new Exception("Unable to find a suitable font replacement for: '" . $this->_props_computed["font_family"] . "'"); + throw new Exception("Unable to find a suitable font replacement for: '" . $computed . "'"); } /** - * @link http://www.w3.org/TR/CSS21/text.html#propdef-word-spacing + * @param float|string $computed * @return float + * + * @link https://www.w3.org/TR/css-text-4/#word-spacing-property */ - function get_word_spacing() + protected function _get_word_spacing($computed) { - $word_spacing = $this->_props_computed["word_spacing"]; - - if ($word_spacing === "normal") { - return 0; + if (\is_float($computed)) { + return $computed; } - if (strpos($word_spacing, "%") !== false) { - return $word_spacing; - } - - return (float)$this->length_in_pt($word_spacing, $this->__get("font_size")); + // Resolve percentage values + $font_size = $this->__get("font_size"); + return $this->single_length_in_pt($computed, $font_size); } /** - * @link http://www.w3.org/TR/CSS21/text.html#propdef-letter-spacing + * @param float|string $computed * @return float + * + * @link https://www.w3.org/TR/css-text-4/#letter-spacing-property */ - function get_letter_spacing() + protected function _get_letter_spacing($computed) { - $letter_spacing = $this->_props_computed["letter_spacing"]; - - if ($letter_spacing === "normal") { - return 0; + if (\is_float($computed)) { + return $computed; } - return (float)$this->length_in_pt($letter_spacing, $this->__get("font_size")); + // Resolve percentage values + $font_size = $this->__get("font_size"); + return $this->single_length_in_pt($computed, $font_size); } /** - * @link http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height + * @param float|string $computed * @return float + * + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-line-height */ - function get_line_height() + protected function _get_line_height($computed) { - $line_height = $this->_props_computed["line_height"]; - - if ($line_height === "normal") { - return self::$default_line_height * $this->__get("font_size"); + // Lengths have been computed to float, number values to string + if (\is_float($computed)) { + return $computed; } - if (is_numeric($line_height)) { - return $line_height * $this->__get("font_size"); - } + $font_size = $this->__get("font_size"); + $factor = $computed === "normal" + ? self::$default_line_height + : (float) $computed; - return (float)$this->length_in_pt($line_height, $this->__get("font_size")); + return $factor * $font_size; } /** - * @param string $prop - * @param bool $current_is_parent + * @param string $computed + * @param bool $current_is_parent + * * @return array|string */ - protected function get_prop_color(string $prop, bool $current_is_parent = false) + protected function get_color_value($computed, bool $current_is_parent = false) { - $val = $this->_props_computed[$prop]; - - if ($val === "currentcolor") { + if ($computed === "currentcolor") { // https://www.w3.org/TR/css-color-4/#resolving-other-colors if ($current_is_parent) { // Use the `color` value from the parent for the `color` // property itself return isset($this->parent_style) ? $this->parent_style->__get("color") - : $this->munge_color(self::$_defaults[$prop]); + : $this->munge_color(self::$_defaults["color"]); } return $this->__get("color"); } - return $this->munge_color($val) ?? "transparent"; + return $this->munge_color($computed) ?? "transparent"; } /** * Returns the color as an array * * The array has the following format: - * array(r,g,b, "r" => r, "g" => g, "b" => b, "hex" => "#rrggbb") + * `array(r, g, b, "r" => r, "g" => g, "b" => b, "alpha" => alpha, "hex" => "#rrggbb")` * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color - * @return array + * @param string $computed + * @return array|string + * + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-color */ - function get_color() + protected function _get_color($computed) { - return $this->get_prop_color("color", true); + return $this->get_color_value($computed, true); } /** * Returns the background color as an array * - * The returned array has the same format as {@link Style::get_color()} + * See {@link Style::_get_color()} for format of the color array. * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color - * @return array + * @param string $computed + * @return array|string + * + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-color */ - function get_background_color() + protected function _get_background_color($computed) { - return $this->get_prop_color("background_color"); + return $this->get_color_value($computed); } /** * Returns the background image URI, or "none" * - * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-image + * @param string $computed * @return string + * + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-image */ - function get_background_image() + protected function _get_background_image($computed): string { - return $this->_stylesheet->resolve_url($this->_props_computed["background_image"]); + return $this->_stylesheet->resolve_url($computed); } /** - * Returns the background position as an array - * - * The returned array has the following format: - * array(x,y, "x" => x, "y" => y) - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position - * @return array - */ - function get_background_position() - { - $tmp = explode(" ", $this->_props_computed["background_position"]); - - return [ - 0 => $tmp[0], "x" => $tmp[0], - 1 => $tmp[1], "y" => $tmp[1], - ]; - } - - - /** - * Returns the background size as an array - * - * The return value has one of the following formats: - * "cover" - * "contain" - * array(width,height) - * - * @link https://www.w3.org/TR/css3-background/#background-size - * @return string|array - */ - function get_background_size() - { - switch ($this->_props_computed["background_size"]) { - case "cover": - return "cover"; - case "contain": - return "contain"; - default: - break; - } - - $result = explode(" ", $this->_props_computed["background_size"]); - return [$result[0], $result[1]]; - } - - /**#@+ * Returns the border color as an array * - * See {@link Style::get_color()} + * See {@link Style::_get_color()} for format of the color array. * - * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties - * @return array + * @param string $computed + * @return array|string + * + * @link https://www.w3.org/TR/CSS21/box.html#border-color-properties */ - function get_border_top_color() + protected function _get_border_top_color($computed) { - return $this->get_prop_color("border_top_color"); + return $this->get_color_value($computed); } /** - * @return array + * @param string $computed + * @return array|string */ - function get_border_right_color() + protected function _get_border_right_color($computed) { - return $this->get_prop_color("border_right_color"); + return $this->get_color_value($computed); } /** - * @return array + * @param string $computed + * @return array|string */ - function get_border_bottom_color() + protected function _get_border_bottom_color($computed) { - return $this->get_prop_color("border_bottom_color"); + return $this->get_color_value($computed); } /** - * @return array + * @param string $computed + * @return array|string */ - function get_border_left_color() + protected function _get_border_left_color($computed) { - return $this->get_prop_color("border_left_color"); + return $this->get_color_value($computed); } - /**#@-*/ - /** * Return an array of all border properties. * * The returned array has the following structure: - * + * + * ``` * array("top" => array("width" => [border-width], * "style" => [border-style], * "color" => [border-color (array)]), * "bottom" ... ) - * + * ``` * * @return array */ - function get_border_properties() + public function get_border_properties(): array { return [ "top" => [ @@ -1672,69 +1850,58 @@ class Style } /** - * Return a single border property + * Return a single border-side property * * @param string $side - * - * @return mixed + * @return string */ - protected function _get_border($side) + protected function get_border_side(string $side): string { - $color = $this->__get("border_" . $side . "_color"); + $color = $this->__get("border_{$side}_color"); - return $this->__get("border_" . $side . "_width") . " " . - $this->__get("border_" . $side . "_style") . " " . - (is_array($color) ? $color["hex"] : $color); + return $this->__get("border_{$side}_width") . " " . + $this->__get("border_{$side}_style") . " " . + (\is_array($color) ? $color["hex"] : $color); } - /**#@+ + /** * Return full border properties as a string * * Border properties are returned just as specified in CSS: - *
[width] [style] [color]
+ * `[width] [style] [color]` * e.g. "1px solid blue" * - * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties + * @return string + * + * @link https://www.w3.org/TR/CSS21/box.html#border-shorthand-properties + */ + protected function _get_border_top(): string + { + return $this->get_border_side("top"); + } + + /** * @return string */ - function get_border_top() + protected function _get_border_right(): string { - return $this->_get_border("top"); + return $this->get_border_side("right"); } /** - * @return mixed + * @return string */ - function get_border_right() + protected function _get_border_bottom(): string { - return $this->_get_border("right"); + return $this->get_border_side("bottom"); } /** - * @return mixed + * @return string */ - function get_border_bottom() + protected function _get_border_left(): string { - return $this->_get_border("bottom"); - } - - /** - * @return mixed - */ - function get_border_left() - { - return $this->_get_border("left"); - } - - /** - * @deprecated - * @param float $w - * @param float $h - * @return float[] - */ - function get_computed_border_radius($w, $h) - { - return $this->resolve_border_radius([0, 0, $w, $h]); + return $this->get_border_side("left"); } public function has_border_radius(): bool @@ -1746,10 +1913,10 @@ class Style // Use a fixed ref size here. We don't know the border-box width here // and font size might be 0. Since we are only interested in whether // there is any border radius at all, this should do - $tl = (float) $this->length_in_pt($this->border_top_left_radius, 10); - $tr = (float) $this->length_in_pt($this->border_top_right_radius, 10); - $br = (float) $this->length_in_pt($this->border_bottom_right_radius, 10); - $bl = (float) $this->length_in_pt($this->border_bottom_left_radius, 10); + $tl = (float) $this->length_in_pt($this->border_top_left_radius, 12); + $tr = (float) $this->length_in_pt($this->border_top_right_radius, 12); + $br = (float) $this->length_in_pt($this->border_bottom_right_radius, 12); + $bl = (float) $this->length_in_pt($this->border_bottom_left_radius, 12); $this->has_border_radius_cache = $tl + $tr + $br + $bl > 0; return $this->has_border_radius_cache; @@ -1842,61 +2009,60 @@ class Style /** * Returns the outline color as an array * - * See {@link Style::get_color()} + * See {@link Style::_get_color()} for format of the color array. * - * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties - * @return array + * @param string $computed + * @return array|string + * + * @link https://www.w3.org/TR/css-ui-4/#propdef-outline-color */ - function get_outline_color() + protected function _get_outline_color($computed) { - return $this->get_prop_color("outline_color"); + return $this->get_color_value($computed); + } + + /** + * @param string $computed + * @return string + * + * @link https://www.w3.org/TR/css-ui-4/#propdef-outline-style + */ + protected function _get_outline_style($computed): string + { + return $computed === "auto" ? "solid" : $computed; } /** * Return full outline properties as a string * * Outline properties are returned just as specified in CSS: - *
[width] [style] [color]
+ * `[width] [style] [color]` * e.g. "1px solid blue" * - * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties * @return string + * + * @link https://www.w3.org/TR/CSS21/box.html#border-shorthand-properties */ - function get_outline() + protected function _get_outline(): string { $color = $this->__get("outline_color"); return $this->__get("outline_width") . " " . $this->__get("outline_style") . " " . - (is_array($color) ? $color["hex"] : $color); - } - - /** - * Returns border spacing as an array - * - * The array has the format (h_space,v_space) - * - * @link http://www.w3.org/TR/CSS21/tables.html#propdef-border-spacing - * @return array - */ - function get_border_spacing() - { - $arr = explode(" ", $this->_props_computed["border_spacing"]); - if (count($arr) == 1) { - $arr[1] = $arr[0]; - } - return $arr; + (\is_array($color) ? $color["hex"] : $color); } /** * Returns the list style image URI, or "none" * - * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-image + * @param string $computed * @return string + * + * @link https://www.w3.org/TR/CSS21/generate.html#propdef-list-style-image */ - function get_list_style_image() + protected function _get_list_style_image($computed): string { - return $this->_stylesheet->resolve_url($this->_props_computed["list_style_image"]); + return $this->_stylesheet->resolve_url($computed); } /** @@ -1927,45 +2093,48 @@ class Style } /** + * @param string $computed * @return array|string + * + * @link https://www.w3.org/TR/CSS21/generate.html#propdef-counter-increment */ - function get_counter_increment() + protected function _get_counter_increment($computed) { - $val = $this->_props_computed["counter_increment"]; - - if ($val === "none" || $val === "inherit") { - return "none"; + if ($computed === "none") { + return $computed; } - return $this->parse_counter_prop($val, 1); + return $this->parse_counter_prop($computed, 1); } /** + * @param string $computed * @return array|string + * + * @link https://www.w3.org/TR/CSS21/generate.html#propdef-counter-reset */ - protected function get_counter_reset() + protected function _get_counter_reset($computed) { - $val = $this->_props_computed["counter_reset"]; - - if ($val === "none") { - return "none"; + if ($computed === "none") { + return $computed; } - return $this->parse_counter_prop($val, 0); + return $this->parse_counter_prop($computed, 0); } /** + * @param string $computed * @return string[]|string + * + * @link https://www.w3.org/TR/CSS21/generate.html#propdef-content */ - protected function get_content() + protected function _get_content($computed) { - $val = $this->_props_computed["content"]; - - if ($val === "normal" || $val === "none") { - return $val; + if ($computed === "normal" || $computed === "none") { + return $computed; } - return $this->parse_property_value($val); + return $this->parse_property_value($computed); } /*==============================*/ @@ -2007,143 +2176,175 @@ class Style || preg_match("/^#|rgb\(|rgba\(|cmyk\(/", $val); } - protected function prop_name(string $style, string $side, string $type): string + /** + * @param string $val + * @return string|null + */ + protected function compute_color_value(string $val): ?string { - $prop = $style; - if ($side !== "") { - $prop .= "_" . $side; - }; - if ($type !== "") { - $prop .= "_" . $type; - }; - return $prop; + // https://www.w3.org/TR/css-color-4/#resolving-other-colors + $munged_color = $val !== "currentcolor" + ? $this->munge_color($val) + : $val; + + if ($munged_color === null) { + return null; + } + + return \is_array($munged_color) ? $munged_color["hex"] : $munged_color; } /** - * Generalized set function for individual attribute of combined style. - * - * Applicable for margin, border, padding, outline. - * - * @param string $style - * @param string $side - * @param string $type - * @param mixed $val + * @param string $val + * @return int|null */ - protected function _set_style_side_type($style, $side, $type, $val) + protected function compute_integer(string $val): ?int { - $prop = $this->prop_name($style, $side, $type); + $integer = self::CSS_INTEGER; + return preg_match("/^$integer$/", $val) + ? (int) $val + : null; + } - $this->_prop_cache[$prop] = null; + /** + * @param string $val + * @return float|null + */ + protected function compute_length(string $val): ?float + { + return mb_strpos($val, "%") === false + ? $this->single_length_in_pt($val) + : null; + } - if ($val === "inherit") { - $this->_props_computed[$prop] = null; - return; + /** + * @param string $val + * @return float|null + */ + protected function compute_length_positive(string $val): ?float + { + $computed = $this->compute_length($val); + return $computed !== null && $computed >= 0 ? $computed : null; + } + + /** + * @param string $val + * @return float|string|null + */ + protected function compute_length_percentage(string $val) + { + // Compute with a fixed ref size to decide whether percentage values + // are valid + $computed = $this->single_length_in_pt($val, 12); + + if ($computed === null) { + return null; } - if ($side === "bottom") { - $this->_computed_bottom_spacing = null; //reset computed cache, border style can disable/enable border calculations + // Retain valid percentage declarations + return mb_strpos($val, "%") === false ? $computed : $val; + } + + /** + * @param string $val + * @return float|string|null + */ + protected function compute_length_percentage_positive(string $val) + { + // Compute with a fixed ref size to decide whether percentage values + // are valid + $computed = $this->single_length_in_pt($val, 12); + + if ($computed === null || $computed < 0) { + return null; } - if ($type === "color") { - $this->set_prop_color($prop, $val); - } elseif (($style === "border" || $style === "outline") && $type === "width") { - // Border-width keywords - if ($val === "thin") { - $val_computed = 0.5; - } elseif ($val === "medium") { - $val_computed = 1.5; - } elseif ($val === "thick") { - $val_computed = 2.5; - } elseif (mb_strpos($val, "%") !== false) { - $val_computed = null; - } else { - $val_computed = $this->single_length_in_pt($val); + // Retain valid percentage declarations + return mb_strpos($val, "%") === false ? $computed : $val; + } - if ($val_computed < 0) { - $val_computed = null; - } - } - - if ($val_computed === null) { - $this->_props_computed[$prop] = null; - } else { - $line_style_prop = $this->prop_name($style, $side, "style"); - $line_style = $this->__get($line_style_prop); - $has_line_style = $line_style !== "none" && $line_style !== "hidden"; - - $this->_props_computed[$prop] = $has_line_style ? $val_computed : 0; - } - } elseif (($style === "border" || $style === "outline") && $type === "style") { - if (in_array($val, Style::$BORDER_STYLES, true)) { - $this->_props_computed[$prop] = $val; - } else { - $this->_props_computed[$prop] = null; - } - } elseif ($style === "margin" || $style === "padding") { - if ($val === "none") { - // Legacy support for `none` keyword, not covered by spec - $val_computed = 0; - } elseif ($style === "margin" && $val === "auto") { - $val_computed = $val; - } elseif (mb_strpos($val, "%") !== false) { - $val_computed = $val; - } else { - $val_computed = $this->single_length_in_pt($val); - - if ($style === "padding" && $val_computed < 0) { - $val_computed = null; - } - } - - $this->_props_computed[$prop] = $val_computed; - } elseif ($val !== "") { - $this->_props_computed[$prop] = $val; + /** + * @param string $val + * @param string $style_prop The corresponding border-/outline-style property. + * + * @return float|null + * + * @link https://www.w3.org/TR/css-backgrounds-3/#typedef-line-width + */ + protected function compute_line_width(string $val, string $style_prop): ?float + { + // Border-width keywords + if ($val === "thin") { + $computed = 0.5; + } elseif ($val === "medium") { + $computed = 1.5; + } elseif ($val === "thick") { + $computed = 2.5; } else { - $this->_props_computed[$prop] = null; + $computed = $this->compute_length_positive($val); } + + if ($computed === null) { + return null; + } + + // Computed width is 0 if the line style is `none` or `hidden` + // https://www.w3.org/TR/css-backgrounds-3/#border-width + // https://www.w3.org/TR/css-ui-4/#outline-width + $lineStyle = $this->__get($style_prop); + $hasLineStyle = $lineStyle !== "none" && $lineStyle !== "hidden"; + + return $hasLineStyle ? $computed : 0.0; } /** - * @param string $style - * @param string $type - * @param mixed $val - * @param bool $important + * @param string $val + * @return string|null */ - protected function _set_style_type($style, $type, $val, $important) + protected function compute_border_style(string $val): ?string { - $v = $this->parse_property_value($val); + return \in_array($val, self::BORDER_STYLES, true) ? $val : null; + } - switch (count($v)) { + /** + * Parse a property value with 1 to 4 components into 4 values, as required + * by shorthand properties such as `margin`, `padding`, and `border-radius`. + * + * @param string $prop The shorthand property with exactly 4 sub-properties to handle. + * @param string $value The property value to parse. + * + * @return string[] + */ + protected function set_quad_shorthand(string $prop, string $value): array + { + $v = $this->parse_property_value($value); + + switch (\count($v)) { case 1: - [$top, $right, $bottom, $left] = [$v[0], $v[0], $v[0], $v[0]]; + $values = [$v[0], $v[0], $v[0], $v[0]]; break; case 2: - [$top, $right, $bottom, $left] = [$v[0], $v[1], $v[0], $v[1]]; + $values = [$v[0], $v[1], $v[0], $v[1]]; break; case 3: - [$top, $right, $bottom, $left] = [$v[0], $v[1], $v[2], $v[1]]; + $values = [$v[0], $v[1], $v[2], $v[1]]; break; case 4: - [$top, $right, $bottom, $left] = [$v[0], $v[1], $v[2], $v[3]]; + $values = [$v[0], $v[1], $v[2], $v[3]]; break; default: - return; + return []; } - $this->set_prop($this->prop_name($style, "top", $type), $top, $important); - $this->set_prop($this->prop_name($style, "right", $type), $right, $important); - $this->set_prop($this->prop_name($style, "bottom", $type), $bottom, $important); - $this->set_prop($this->prop_name($style, "left", $type), $left, $important); + return array_combine(self::$_props_shorthand[$prop], $values); } /*======================*/ /** - * https://www.w3.org/TR/CSS21/visuren.html#display-prop - * - * @param string $val + * @link https://www.w3.org/TR/CSS21/visuren.html#display-prop */ - protected function set_display(string $val): void + protected function _compute_display(string $val) { // Make sure that common valid, but unsupported display types have an // appropriate fallback display type @@ -2161,12 +2362,12 @@ class Style } if (!isset(self::$valid_display_types[$val])) { - return; + return null; } // https://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo if ($this->is_in_flow()) { - $computed = $val; + return $val; } else { switch ($val) { case "inline": @@ -2179,129 +2380,75 @@ class Style // case "table-column-group": // case "table-column": // case "table-caption": - $computed = "block"; - break; + return "block"; case "inline-table": - $computed = "table"; - break; + return "table"; default: - $computed = $val; - break; + return $val; } } - - $this->_props_computed["display"] = $computed; - } - - protected function set_prop_color($prop, $val) - { - $this->_prop_cache[$prop] = null; - - // https://www.w3.org/TR/css-color-4/#resolving-other-colors - $munged_color = $val !== "currentcolor" - ? $this->munge_color($val) - : $val; - - if (is_null($munged_color)) { - $this->_props_computed[$prop] = null; - return; - } - - $this->_props_computed[$prop] = is_array($munged_color) ? $munged_color["hex"] : $munged_color; } /** - * Sets color - * - * The color parameter can be any valid CSS color value - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color - * @param string $color + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-color */ - function set_color($color) + protected function _compute_color(string $color) { - $this->set_prop_color("color", $color); + return $this->compute_color_value($color); } /** - * Sets the background color - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color - * @param string $color + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-color */ - function set_background_color($color) + protected function _compute_background_color(string $color) { - $this->set_prop_color("background_color", $color); + return $this->compute_color_value($color); } /** - * Set the background image url * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-image - * - * @param string $val */ - function set_background_image($val) + protected function _compute_background_image(string $val) { - $this->_prop_cache["background_image"] = null; - $parsed_val = $this->_stylesheet->resolve_url($val); if ($parsed_val === "none") { - $this->_props_computed["background_image"] = "none"; + return "none"; } else { - $this->_props_computed["background_image"] = "url(" . $parsed_val . ")"; + return "url($parsed_val)"; } } /** - * Sets the background repeat - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat - * @param string $val + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat */ - function set_background_repeat($val) + protected function _compute_background_repeat(string $val) { - $this->_prop_cache["background_repeat"] = null; - - if ($val === "inherit") { - $this->_props_computed["background_repeat"] = null; - return; - } - - $this->_props_computed["background_repeat"] = $val; + $keywords = ["repeat", "repeat-x", "repeat-y", "no-repeat"]; + return \in_array($val, $keywords, true) ? $val : null; } /** - * Sets the background attachment - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment - * @param string $val + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment */ - function set_background_attachment($val) + protected function _compute_background_attachment(string $val) { - $this->_prop_cache["background_attachment"] = null; - - if ($val === "inherit") { - $this->_props_computed["background_attachment"] = null; - return; - } - - $this->_props_computed["background_attachment"] = $val; + $keywords = ["scroll", "fixed"]; + return \in_array($val, $keywords, true) ? $val : null; } /** - * Sets the background position - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position - * @param string $val + * @link https://www.w3.org/TR/CSS21/colors.html#propdef-background-position */ - function set_background_position($val) + protected function _compute_background_position(string $val) { - $this->_prop_cache["background_position"] = null; + $parts = preg_split("/\s+/", $val); - $tmp = explode(" ", $val); + if (\count($parts) > 2) { + return null; + } - switch ($tmp[0]) { + switch ($parts[0]) { case "left": $x = "0%"; break; @@ -2324,12 +2471,12 @@ class Style break; default: - $x = $tmp[0]; + $x = $parts[0]; break; } - if (isset($tmp[1])) { - switch ($tmp[1]) { + if (isset($parts[1])) { + switch ($parts[1]) { case "left": $x = "0%"; break; @@ -2347,7 +2494,7 @@ class Style break; case "center": - if ($tmp[0] === "left" || $tmp[0] === "right" || $tmp[0] === "center") { + if ($parts[0] === "left" || $parts[0] === "right" || $parts[0] === "center") { $y = "50%"; } else { $x = "50%"; @@ -2355,7 +2502,7 @@ class Style break; default: - $y = $tmp[1]; + $y = $parts[1]; break; } } else { @@ -2369,118 +2516,104 @@ class Style if (!isset($y)) { $y = "0%"; } - - $this->_props_computed["background_position"] = "$x $y"; + + return [$x, $y]; } /** - * Sets the background size + * Compute `background-size`. * - * @link https://www.w3.org/TR/css3-background/#background-size - * @param string $val + * Computes to one of the following values: + * * `cover` + * * `contain` + * * `[width, height]`, each being a length, percentage, or `auto` + * + * @link https://www.w3.org/TR/css-backgrounds-3/#background-size */ - function set_background_size($val) + protected function _compute_background_size(string $val) { - $this->_prop_cache["background_size"] = null; - - $result = explode(" ", $val); - $width = $result[0]; - - switch ($width) { - case "cover": - case "contain": - $this->_props_computed["background_size"] = $width; - return; - case "inherit": - $this->_props_computed["background_size"] = null; - return; + if ($val === "cover" || $val === "contain") { + return $val; } - if ($width !== "auto" && strpos($width, "%") === false) { - $width = (float)$this->length_in_pt($width); + $parts = preg_split("/\s+/", $val); + + if (\count($parts) > 2) { + return null; } - $height = $result[1] ?? "auto"; - if ($height !== "auto" && strpos($height, "%") === false) { - $height = (float)$this->length_in_pt($height); + $width = $parts[0]; + if ($width !== "auto") { + $width = $this->compute_length_percentage_positive($width); } - $this->_props_computed["background_size"] = "$width $height"; + $height = $parts[1] ?? "auto"; + if ($height !== "auto") { + $height = $this->compute_length_percentage_positive($height); + } + + if ($width === null || $height === null) { + return null; + } + + return [$width, $height]; } /** - * Sets the background - combined options - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background - * @param string $value - * @param bool $important + * @link https://www.w3.org/TR/css-backgrounds-3/#propdef-background */ - function set_background($value, bool $important = false) + protected function _set_background(string $value): array { - if ($value === "none") { - $this->set_prop("background_image", "none", $important); - $this->set_prop("background_color", "transparent", $important); - } else { - $components = $this->parse_property_value($value); - $pos_size = []; + $components = $this->parse_property_value($value); + $props = []; + $pos_size = []; - foreach ($components as $val) { - if ($val === "none" || mb_substr($val, 0, 4) === "url(") { - $this->set_prop("background_image", $val, $important); - } elseif ($val === "fixed" || $val === "scroll") { - $this->set_prop("background_attachment", $val, $important); - } elseif ($val === "repeat" || $val === "repeat-x" || $val === "repeat-y" || $val === "no-repeat") { - $this->set_prop("background_repeat", $val, $important); - } elseif ($this->is_color_value($val)) { - $this->set_prop("background_color", $val, $important); - } else { - $pos_size[] = $val; - } - } - - if (count($pos_size)) { - // Split value list at "/" - $index = array_search("/", $pos_size, true); - - if ($index !== false) { - $pos = array_slice($pos_size, 0, $index); - $size = array_slice($pos_size, $index + 1); - } else { - $pos = $pos_size; - $size = []; - } - - $this->set_prop("background_position", implode(" ", $pos), $important); - - if (count($size)) { - $this->set_prop("background_size", implode(" ", $size), $important); - } + foreach ($components as $val) { + if ($val === "none" || mb_substr($val, 0, 4) === "url(") { + $props["background_image"] = $val; + } elseif ($val === "scroll" || $val === "fixed") { + $props["background_attachment"] = $val; + } elseif ($val === "repeat" || $val === "repeat-x" || $val === "repeat-y" || $val === "no-repeat") { + $props["background_repeat"] = $val; + } elseif ($this->is_color_value($val)) { + $props["background_color"] = $val; + } else { + $pos_size[] = $val; } } + + if (\count($pos_size)) { + // Split value list at "/" + $index = array_search("/", $pos_size, true); + + if ($index !== false) { + $pos = \array_slice($pos_size, 0, $index); + $size = \array_slice($pos_size, $index + 1); + } else { + $pos = $pos_size; + $size = []; + } + + $props["background_position"] = implode(" ", $pos); + + if (\count($size)) { + $props["background_size"] = implode(" ", $size); + } + } + + return $props; } /** - * Sets the font size - * - * $size can be any acceptable CSS size - * - * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size - * @param string|float $size + * @link https://www.w3.org/TR/CSS21/fonts.html#propdef-font-size */ - function set_font_size($size) + protected function _compute_font_size(string $size) { - $this->_prop_cache["font_size"] = null; - - if ($size === "inherit") { - $this->_props_computed["font_size"] = null; - return; - } - $parent_font_size = isset($this->parent_style) ? $this->parent_style->__get("font_size") : self::$default_font_size; - switch ((string)$size) { + switch ($size) { case "xx-small": case "x-small": case "small": @@ -2504,23 +2637,14 @@ class Style break; } - $this->_props_computed["font_size"] = $fs; + return $fs; } /** - * Sets the font weight - * - * @param string|int $weight + * @link https://www.w3.org/TR/CSS21/fonts.html#font-boldness */ - function set_font_weight($weight) + protected function _compute_font_weight(string $weight) { - $this->_prop_cache["font_weight"] = null; - - if ($weight === "inherit") { - $this->_props_computed["font_weight"] = null; - return; - } - $computed_weight = $weight; if ($weight === "bolder") { @@ -2531,80 +2655,99 @@ class Style $computed_weight = "normal"; } - $this->_props_computed["font_weight"] = $computed_weight; + return $computed_weight; } /** - * Sets the font style + * Handle the `font` shorthand property. * - * combined attributes - * set individual attributes also, respecting !important mark - * exactly this order, separate by space. Multiple fonts separated by comma: - * font-style, font-variant, font-weight, font-size, line-height, font-family - * - * Other than with border and list, existing partial attributes should - * reset when starting here, even when not mentioned. - * If individual attribute is !important and explicit or implicit replacement is not, - * keep individual attribute - * - * require whitespace as delimiters for single value attributes - * On delimiter "/" treat first as font height, second as line height - * treat all remaining at the end of line as font - * font-style, font-variant, font-weight, font-size, line-height, font-family - * - * missing font-size and font-family might be not allowed, but accept it here and - * use default (medium size, empty font name) + * `[ font-style || font-variant || font-weight ] font-size [ / line-height ] font-family` * * @link https://www.w3.org/TR/CSS21/fonts.html#font-shorthand - * @param string $val - * @param bool $important */ - function set_font($val, bool $important = false) + protected function _set_font(string $value): array { - if (preg_match("/^(italic|oblique|normal)\s*(.*)$/i", $val, $match)) { - $this->set_prop("font_style", $match[1], $important); - $val = $match[2]; - } + $components = $this->parse_property_value($value); + $props = []; - if (preg_match("/^(small-caps|normal)\s*(.*)$/i", $val, $match)) { - $this->set_prop("font_variant", $match[1], $important); - $val = $match[2]; - } + $number = self::CSS_NUMBER; + $unit = "pt|px|pc|rem|em|ex|in|cm|mm|%"; + $sizePattern = "/^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger|$number(?:$unit))$/"; + $sizeIndex = null; - //matching numeric value followed by unit -> this is indeed a subsequent font size. Skip! - if (preg_match("/^(bold|bolder|lighter|100|200|300|400|500|600|700|800|900|normal)\s*(.*)$/i", $val, $match) && - !preg_match("/^(?:pt|px|pc|rem|em|ex|in|cm|mm|%)/", $match[2]) - ) { - $this->set_prop("font_weight", $match[1], $important); - $val = $match[2]; - } - - if (preg_match("/^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger|\d+\s*(?:pt|px|pc|rem|em|ex|in|cm|mm|%))(?:\/|\s*)(.*)$/i", $val, $match)) { - $this->set_prop("font_size", $match[1], $important); - $val = $match[2]; - if (preg_match("/^(?:\/|\s*)(\d+\s*(?:pt|px|pc|rem|em|ex|in|cm|mm|%)?)\s*(.*)$/i", $val, $match)) { - $this->set_prop("line_height", $match[1], $important); - $val = $match[2]; + // Find index of font-size to split the component list + foreach ($components as $i => $val) { + if (preg_match($sizePattern, $val)) { + $sizeIndex = $i; + $props["font_size"] = $val; + break; } } - if (strlen($val) != 0) { - $this->set_prop("font_family", $val, $important); + // `font-size` is mandatory + if ($sizeIndex === null) { + return []; } + + // `font-style`, `font-variant`, `font-weight` in any order + $styleVariantWeight = \array_slice($components, 0, $sizeIndex); + $stylePattern = "/^(italic|oblique)$/"; + $variantPattern = "/^(small-caps)$/"; + $weightPattern = "/^(bold|bolder|lighter|100|200|300|400|500|600|700|800|900)$/"; + + if (\count($styleVariantWeight) > 3) { + return []; + } + + foreach ($styleVariantWeight as $val) { + if ($val === "normal") { + // Ignore any `normal` value, as it is valid and the initial + // value for all three properties + } elseif (!isset($props["font_style"]) && preg_match($stylePattern, $val)) { + $props["font_style"] = $val; + } elseif (!isset($props["font_variant"]) && preg_match($variantPattern, $val)) { + $props["font_variant"] = $val; + } elseif (!isset($props["font_weight"]) && preg_match($weightPattern, $val)) { + $props["font_weight"] = $val; + } else { + // Duplicates and other values disallowed here + return []; + } + } + + // Optional slash + `line-height` followed by mandatory `font-family` + $lineFamily = \array_slice($components, $sizeIndex + 1); + $hasLineHeight = $lineFamily !== [] && $lineFamily[0] === "/"; + $lineHeight = $hasLineHeight ? \array_slice($lineFamily, 1, 1) : []; + $fontFamily = $hasLineHeight ? \array_slice($lineFamily, 2) : $lineFamily; + $lineHeightPattern = "/^(normal|$number(?:$unit)?)$/"; + + // Missing `font-family` or `line-height` after slash + if ($fontFamily === [] + || ($hasLineHeight && !preg_match($lineHeightPattern, $lineHeight[0])) + ) { + return []; + } + + if ($hasLineHeight) { + $props["line_height"] = $lineHeight[0]; + } + + $props["font_family"] = implode("", $fontFamily); + + return $props; } /** - * Sets the text alignment + * Compute `text-align`. * * If no alignment is set on the element and the direction is rtl then * the property is set to "right", otherwise it is set to "left". * * @link https://www.w3.org/TR/CSS21/text.html#propdef-text-align */ - public function set_text_align($val) + protected function _compute_text_align(string $val) { - $this->_prop_cache["text_align"] = null; - $alignment = $val; if ($alignment === "") { $alignment = "left"; @@ -2613,607 +2756,577 @@ class Style } } - if (!in_array($alignment, self::$text_align_keywords, true)) { - $this->_props_computed["text_align"] = null; - return; + if (!\in_array($alignment, self::TEXT_ALIGN_KEYWORDS, true)) { + return null; } - $this->_props_computed["text_align"] = $alignment; + return $alignment; } /** - * Sets word spacing property - * - * @link http://www.w3.org/TR/CSS21/text.html#propdef-word-spacing - * @param $val + * @link https://www.w3.org/TR/css-text-4/#word-spacing-property */ - function set_word_spacing($val) + protected function _compute_word_spacing(string $val) { - $this->_prop_cache["word_spacing"] = null; - - if ($val === "inherit") { - $this->_props_computed["word_spacing"] = null; - return; - } - - if ($val === "normal" || strpos($val, "%") !== false) { - $this->_props_computed["word_spacing"] = $val; - } else { - $this->_props_computed["word_spacing"] = ((float)$this->length_in_pt($val, $this->__get("font_size"))) . "pt"; - } - } - - /** - * Sets letter spacing property - * - * @link http://www.w3.org/TR/CSS21/text.html#propdef-letter-spacing - * @param $val - */ - function set_letter_spacing($val) - { - $this->_prop_cache["letter_spacing"] = null; - - if ($val === "inherit") { - $this->_props_computed["letter_spacing"] = null; - return; - } - if ($val === "normal") { - $this->_props_computed["letter_spacing"] = $val; - } else { - $this->_props_computed["letter_spacing"] = ((float)$this->length_in_pt($val, $this->__get("font_size"))) . "pt"; + return 0.0; } + + return $this->compute_length_percentage($val); } /** - * Sets line height property - * - * @link http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height - * @param $val + * @link https://www.w3.org/TR/css-text-4/#letter-spacing-property */ - function set_line_height($val) + protected function _compute_letter_spacing(string $val) { - $this->_prop_cache["line_height"] = null; - - if ($val === "inherit") { - $this->_props_computed["line_height"] = null; - return; + if ($val === "normal") { + return 0.0; } - if ($val === "normal" || is_numeric($val)) { - $this->_props_computed["line_height"] = $val; - } else { - $this->_props_computed["line_height"] = ((float)$this->length_in_pt($val, $this->__get("font_size"))) . "pt"; - } + return $this->compute_length_percentage($val); } /** - * Sets page break properties - * - * @link http://www.w3.org/TR/CSS21/page.html#page-breaks - * @param string $break + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-line-height */ - function set_page_break_before($break) + protected function _compute_line_height(string $val) { - $this->_prop_cache["page_break_before"] = null; - - if ($break === "inherit") { - $this->_props_computed["page_break_before"] = null; - return; + if ($val === "normal") { + return $val; } + // Compute number values to string and lengths to float (in pt) + if (is_numeric($val)) { + return (string) $val; + } + + $font_size = $this->__get("font_size"); + $computed = $this->single_length_in_pt($val, $font_size); + return $computed !== null && $computed >= 0 ? $computed : null; + } + + /** + * @link https://www.w3.org/TR/css-text-3/#text-indent-property + */ + protected function _compute_text_indent(string $val) + { + return $this->compute_length_percentage($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/page.html#propdef-page-break-before + */ + protected function _compute_page_break_before(string $break) + { if ($break === "left" || $break === "right") { $break = "always"; } - $this->_props_computed["page_break_before"] = $break; + return $break; } /** - * @param $break + * @link https://www.w3.org/TR/CSS21/page.html#propdef-page-break-after */ - function set_page_break_after($break) + protected function _compute_page_break_after(string $break) { - $this->_prop_cache["page_break_after"] = null; - - if ($break === "inherit") { - $this->_props_computed["page_break_after"] = null; - return; - } - if ($break === "left" || $break === "right") { $break = "always"; } - $this->_props_computed["page_break_after"] = $break; + return $break; } /** - * Sets the margin size - * - * @link http://www.w3.org/TR/CSS21/box.html#margin-properties - * @param $val + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-width */ - function set_margin_top($val) + protected function _compute_width(string $val) { - $this->_set_style_side_type("margin", "top", "", $val); - } - - /** - * @param $val - */ - function set_margin_right($val) - { - $this->_set_style_side_type("margin", "right", "", $val); - } - - /** - * @param $val - */ - function set_margin_bottom($val) - { - $this->_set_style_side_type("margin", "bottom", "", $val); - } - - /** - * @param $val - */ - function set_margin_left($val) - { - $this->_set_style_side_type("margin", "left", "", $val); - } - - /** - * @param string $val - * @param bool $important - */ - function set_margin($val, bool $important = false) - { - $this->_set_style_type("margin", "", $val, $important); - } - - /** - * Sets the padding size - * - * @link http://www.w3.org/TR/CSS21/box.html#padding-properties - * @param $val - */ - function set_padding_top($val) - { - $this->_set_style_side_type("padding", "top", "", $val); - } - - /** - * @param $val - */ - function set_padding_right($val) - { - $this->_set_style_side_type("padding", "right", "", $val); - } - - /** - * @param $val - */ - function set_padding_bottom($val) - { - $this->_set_style_side_type("padding", "bottom", "", $val); - } - - /** - * @param $val - */ - function set_padding_left($val) - { - $this->_set_style_side_type("padding", "left", "", $val); - } - - /** - * @param string $val - * @param bool $important - */ - function set_padding($val, bool $important = false) - { - $this->_set_style_type("padding", "", $val, $important); - } - - /** - * Sets a single border - * - * @param string $side - * @param string $border_spec ([width] [style] [color]) - * @param bool $important - */ - protected function _set_border($side, $border_spec, bool $important) - { - $components = $this->parse_property_value($border_spec); - - foreach ($components as $val) { - if (in_array($val, self::$BORDER_STYLES, true)) { - $this->set_prop("border_${side}_style", $val, $important); - } elseif ($this->is_color_value($val)) { - $this->set_prop("border_${side}_color", $val, $important); - } else { - // Assume width - $this->set_prop("border_${side}_width", $val, $important); - } - } - } - - /** - * @link http://www.w3.org/TR/CSS21/box.html#border-properties - * @param string $val - * @param bool $important - */ - function set_border_top($val, bool $important = false) - { - $this->_set_border("top", $val, $important); - } - - function set_border_top_color($val) - { - $this->_set_style_side_type("border", "top", "color", $val); - } - - function set_border_top_style($val) - { - $this->_set_style_side_type("border", "top", "style", $val); - } - - function set_border_top_width($val) - { - $this->_set_style_side_type("border", "top", "width", $val); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_right($val, bool $important = false) - { - $this->_set_border("right", $val, $important); - } - - function set_border_right_color($val) - { - $this->_set_style_side_type("border", "right", "color", $val); - } - - function set_border_right_style($val) - { - $this->_set_style_side_type("border", "right", "style", $val); - } - - function set_border_right_width($val) - { - $this->_set_style_side_type("border", "right", "width", $val); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_bottom($val, bool $important = false) - { - $this->_set_border("bottom", $val, $important); - } - - function set_border_bottom_color($val) - { - $this->_set_style_side_type("border", "bottom", "color", $val); - } - - function set_border_bottom_style($val) - { - $this->_set_style_side_type("border", "bottom", "style", $val); - } - - function set_border_bottom_width($val) - { - $this->_set_style_side_type("border", "bottom", "width", $val); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_left($val, bool $important = false) - { - $this->_set_border("left", $val, $important); - } - - function set_border_left_color($val) - { - $this->_set_style_side_type("border", "left", "color", $val); - } - - function set_border_left_style($val) - { - $this->_set_style_side_type("border", "left", "style", $val); - } - - function set_border_left_width($val) - { - $this->_set_style_side_type("border", "left", "width", $val); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border($val, bool $important = false) - { - $this->_set_border("top", $val, $important); - $this->_set_border("right", $val, $important); - $this->_set_border("bottom", $val, $important); - $this->_set_border("left", $val, $important); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_width($val, bool $important = false) - { - $this->_set_style_type("border", "width", $val, $important); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_color($val, bool $important = false) - { - $this->_set_style_type("border", "color", $val, $important); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_style($val, bool $important = false) - { - $this->_set_style_type("border", "style", $val, $important); - } - - /** - * Sets the border radius size - * - * http://www.w3.org/TR/css3-background/#corners - * - * @param string $val - */ - function set_border_top_left_radius($val) - { - $this->_set_border_radius_corner($val, "top_left"); - } - - /** - * @param string $val - */ - function set_border_top_right_radius($val) - { - $this->_set_border_radius_corner($val, "top_right"); - } - - /** - * @param string $val - */ - function set_border_bottom_left_radius($val) - { - $this->_set_border_radius_corner($val, "bottom_left"); - } - - /** - * @param string $val - */ - function set_border_bottom_right_radius($val) - { - $this->_set_border_radius_corner($val, "bottom_right"); - } - - /** - * @param string $val - * @param bool $important - */ - function set_border_radius($val, bool $important = false) - { - $r = $this->parse_property_value($val); - - switch (count($r)) { - case 1: - [$tl, $tr, $br, $bl] = [$r[0], $r[0], $r[0], $r[0]]; - break; - case 2: - [$tl, $tr, $br, $bl] = [$r[0], $r[1], $r[0], $r[1]]; - break; - case 3: - [$tl, $tr, $br, $bl] = [$r[0], $r[1], $r[2], $r[1]]; - break; - case 4: - [$tl, $tr, $br, $bl] = [$r[0], $r[1], $r[2], $r[3]]; - break; - default: - return; + if ($val === "auto") { + return $val; } - $this->set_prop("border_top_left_radius", $tl, $important); - $this->set_prop("border_top_right_radius", $tr, $important); - $this->set_prop("border_bottom_right_radius", $br, $important); - $this->set_prop("border_bottom_left_radius", $bl, $important); + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-height + */ + protected function _compute_height(string $val) + { + if ($val === "auto") { + return $val; + } + + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-min-width + */ + protected function _compute_min_width(string $val) + { + // Legacy support for `none`, not covered by spec + if ($val === "auto" || $val === "none") { + return "auto"; + } + + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-min-height + */ + protected function _compute_min_height(string $val) + { + // Legacy support for `none`, not covered by spec + if ($val === "auto" || $val === "none") { + return "auto"; + } + + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-max-width + */ + protected function _compute_max_width(string $val) + { + // Legacy support for `auto`, not covered by spec + if ($val === "none" || $val === "auto") { + return "none"; + } + + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/visudet.html#propdef-max-height + */ + protected function _compute_max_height(string $val) + { + // Legacy support for `auto`, not covered by spec + if ($val === "none" || $val === "auto") { + return "none"; + } + + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/css-position-3/#inset-properties + * @link https://www.w3.org/TR/css-position-3/#propdef-inset + */ + protected function _set_inset(string $val): array + { + return $this->set_quad_shorthand("inset", $val); } /** * @param string $val - * @param string $corner + * @return float|string|null */ - protected function _set_border_radius_corner($val, $corner) + protected function compute_box_inset(string $val) { - $prop = "border_" . $corner . "_radius"; - - $this->_prop_cache[$prop] = null; - - if ($val === "inherit") { - $this->_props_computed[$prop] = null; - return; + if ($val === "auto") { + return $val; } - $computed = mb_strpos($val, "%") === false - ? $this->single_length_in_pt($val) - : $val; + return $this->compute_length_percentage($val); + } - $this->_props_computed[$prop] = $computed; + protected function _compute_top(string $val) + { + return $this->compute_box_inset($val); + } + + protected function _compute_right(string $val) + { + return $this->compute_box_inset($val); + } + + protected function _compute_bottom(string $val) + { + return $this->compute_box_inset($val); + } + + protected function _compute_left(string $val) + { + return $this->compute_box_inset($val); } /** - * @return float|int|string + * @link https://www.w3.org/TR/CSS21/box.html#margin-properties + * @link https://www.w3.org/TR/CSS21/box.html#propdef-margin */ - function get_border_top_left_radius() + protected function _set_margin(string $val): array { - return $this->_get_border_radius_corner("top_left"); + return $this->set_quad_shorthand("margin", $val); } /** - * @return float|int|string + * @param string $val + * @return float|string|null */ - function get_border_top_right_radius() + protected function compute_margin(string $val) { - return $this->_get_border_radius_corner("top_right"); - } - - /** - * @return float|int|string - */ - function get_border_bottom_left_radius() - { - return $this->_get_border_radius_corner("bottom_left"); - } - - /** - * @return float|int|string - */ - function get_border_bottom_right_radius() - { - return $this->_get_border_radius_corner("bottom_right"); - } - - /** - * @param $corner - * @return float|int|string - */ - protected function _get_border_radius_corner($corner) - { - $prop = "border_" . $corner . "_radius"; - - if (!isset($this->_props_computed[$prop])) { - return 0; + // Legacy support for `none` keyword, not covered by spec + if ($val === "none") { + return 0.0; } - return $this->_props_computed[$prop]; + if ($val === "auto") { + return $val; + } + + return $this->compute_length_percentage($val); + } + + protected function _compute_margin_top(string $val) + { + return $this->compute_margin($val); + } + + protected function _compute_margin_right(string $val) + { + return $this->compute_margin($val); + } + + protected function _compute_margin_bottom(string $val) + { + return $this->compute_margin($val); + } + + protected function _compute_margin_left(string $val) + { + return $this->compute_margin($val); } /** - * Sets the outline styles + * @link https://www.w3.org/TR/CSS21/box.html#padding-properties + * @link https://www.w3.org/TR/CSS21/box.html#propdef-padding + */ + protected function _set_padding(string $val): array + { + return $this->set_quad_shorthand("padding", $val); + } + + /** + * @param string $val + * @return float|string|null + */ + protected function compute_padding(string $val) + { + // Legacy support for `none` keyword, not covered by spec + if ($val === "none") { + return 0.0; + } + + return $this->compute_length_percentage_positive($val); + } + + protected function _compute_padding_top(string $val) + { + return $this->compute_padding($val); + } + + protected function _compute_padding_right(string $val) + { + return $this->compute_padding($val); + } + + protected function _compute_padding_bottom(string $val) + { + return $this->compute_padding($val); + } + + protected function _compute_padding_left(string $val) + { + return $this->compute_padding($val); + } + + /** + * @param string $value `width || style || color` + * @param string[] $styles The list of border styles to accept. * - * @link http://www.w3.org/TR/CSS21/ui.html#dynamic-outlines - * @param string $value - * @param bool $important + * @return array Array of `[width, style, color]`, or `null` if the declaration is invalid. */ - function set_outline($value, bool $important = false) + protected function parse_border_side(string $value, array $styles = self::BORDER_STYLES): ?array { $components = $this->parse_property_value($value); + $width = null; + $style = null; + $color = null; foreach ($components as $val) { - if (in_array($val, self::$BORDER_STYLES, true)) { - $this->set_prop("outline_style", $val, $important); - } elseif ($this->is_color_value($val)) { - $this->set_prop("outline_color", $val, $important); - } else { + if ($style === null && \in_array($val, $styles, true)) { + $style = $val; + } elseif ($color === null && $this->is_color_value($val)) { + $color = $val; + } elseif ($width === null) { // Assume width - $this->set_prop("outline_width", $val, $important); + $width = $val; + } else { + // Duplicates are not allowed + return null; } } + + return [$width, $style, $color]; } /** - * @param $val + * @link https://www.w3.org/TR/CSS21/box.html#border-properties + * @link https://www.w3.org/TR/CSS21/box.html#propdef-border */ - function set_outline_width($val) + protected function _set_border(string $value): array { - $this->_set_style_side_type("outline", "", "width", $val); + $values = $this->parse_border_side($value); + + if ($values === null) { + return []; + } + + return array_merge( + array_combine(self::$_props_shorthand["border_top"], $values), + array_combine(self::$_props_shorthand["border_right"], $values), + array_combine(self::$_props_shorthand["border_bottom"], $values), + array_combine(self::$_props_shorthand["border_left"], $values) + ); } /** - * @param $val + * @param string $prop + * @param string $value + * @return array */ - function set_outline_color($val) + protected function set_border_side(string $prop, string $value): array { - $this->_set_style_side_type("outline", "", "color", $val); + $values = $this->parse_border_side($value); + + if ($values === null) { + return []; + } + + return array_combine(self::$_props_shorthand[$prop], $values); + } + + protected function _set_border_top(string $val): array + { + return $this->set_border_side("border_top", $val); + } + + protected function _set_border_right(string $val): array + { + return $this->set_border_side("border_right", $val); + } + + protected function _set_border_bottom(string $val): array + { + return $this->set_border_side("border_bottom", $val); + } + + protected function _set_border_left(string $val): array + { + return $this->set_border_side("border_left", $val); } /** - * @param $val + * @link https://www.w3.org/TR/CSS21/box.html#propdef-border-color */ - function set_outline_style($val) + protected function _set_border_color(string $val): array { - $this->_set_style_side_type("outline", "", "style", $val); + return $this->set_quad_shorthand("border_color", $val); + } + + protected function _compute_border_top_color(string $val) + { + return $this->compute_color_value($val); + } + + protected function _compute_border_right_color(string $val) + { + return $this->compute_color_value($val); + } + + protected function _compute_border_bottom_color(string $val) + { + return $this->compute_color_value($val); + } + + protected function _compute_border_left_color(string $val) + { + return $this->compute_color_value($val); } /** - * Sets the border spacing + * @link https://www.w3.org/TR/CSS21/box.html#propdef-border-style + */ + protected function _set_border_style(string $val): array + { + return $this->set_quad_shorthand("border_style", $val); + } + + protected function _compute_border_top_style(string $val) + { + return $this->compute_border_style($val); + } + + protected function _compute_border_right_style(string $val) + { + return $this->compute_border_style($val); + } + + protected function _compute_border_bottom_style(string $val) + { + return $this->compute_border_style($val); + } + + protected function _compute_border_left_style(string $val) + { + return $this->compute_border_style($val); + } + + /** + * @link https://www.w3.org/TR/CSS21/box.html#propdef-border-width + */ + protected function _set_border_width(string $val): array + { + return $this->set_quad_shorthand("border_width", $val); + } + + protected function _compute_border_top_width(string $val) + { + return $this->compute_line_width($val, "border_top_style"); + } + + protected function _compute_border_right_width(string $val) + { + return $this->compute_line_width($val, "border_right_style"); + } + + protected function _compute_border_bottom_width(string $val) + { + return $this->compute_line_width($val, "border_bottom_style"); + } + + protected function _compute_border_left_width(string $val) + { + return $this->compute_line_width($val, "border_left_style"); + } + + /** + * @link https://www.w3.org/TR/css-backgrounds-3/#corners + * @link https://www.w3.org/TR/css-backgrounds-3/#propdef-border-radius + */ + protected function _set_border_radius(string $val): array + { + return $this->set_quad_shorthand("border_radius", $val); + } + + protected function _compute_border_top_left_radius(string $val) + { + return $this->compute_length_percentage_positive($val); + } + + protected function _compute_border_top_right_radius(string $val) + { + return $this->compute_length_percentage_positive($val); + } + + protected function _compute_border_bottom_right_radius(string $val) + { + return $this->compute_length_percentage_positive($val); + } + + protected function _compute_border_bottom_left_radius(string $val) + { + return $this->compute_length_percentage_positive($val); + } + + /** + * @link https://www.w3.org/TR/css-ui-4/#outline-props + * @link https://www.w3.org/TR/css-ui-4/#propdef-outline + */ + protected function _set_outline(string $value): array + { + $values = $this->parse_border_side($value, self::OUTLINE_STYLES); + + if ($values === null) { + return []; + } + + return array_combine(self::$_props_shorthand["outline"], $values); + } + + protected function _compute_outline_color(string $val) + { + return $this->compute_color_value($val); + } + + protected function _compute_outline_style(string $val) + { + return \in_array($val, self::OUTLINE_STYLES, true) ? $val : null; + } + + protected function _compute_outline_width(string $val) + { + return $this->compute_line_width($val, "outline_style"); + } + + /** + * @link https://www.w3.org/TR/css-ui-4/#propdef-outline-offset + */ + protected function _compute_outline_offset(string $val) + { + return $this->compute_length($val); + } + + /** + * Compute `border-spacing` to two lengths of the form + * `[horizontal, vertical]`. * - * @link http://www.w3.org/TR/CSS21/box.html#border-properties - * @param float $val + * @link https://www.w3.org/TR/CSS21/tables.html#propdef-border-spacing */ - function set_border_spacing($val) + protected function _compute_border_spacing(string $val) { - $this->_prop_cache["border_spacing"] = null; + $parts = preg_split("/\s+/", $val); - if ($val === "inherit") { - $this->_props_computed["border_spacing"] = null; - return; + if (\count($parts) > 2) { + return null; } - $arr = explode(" ", $val); + $h = $this->compute_length_positive($parts[0]); + $v = isset($parts[1]) + ? $this->compute_length_positive($parts[1]) + : $h; - if (count($arr) === 1) { - $arr[1] = $arr[0]; + if ($h === null || $v === null) { + return null; } - $this->_props_computed["border_spacing"] = "$arr[0] $arr[1]"; + return [$h, $v]; } /** - * Sets the list style image - * - * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-image - * @param $val + * @link https://www.w3.org/TR/CSS21/generate.html#propdef-list-style-image */ - function set_list_style_image($val) + protected function _compute_list_style_image(string $val) { - $this->_prop_cache["list_style_image"] = null; - - if ($val === "inherit") { - $this->_props_computed["list_style_image"] = null; - return; - } - $parsed_val = $this->_stylesheet->resolve_url($val); if ($parsed_val === "none") { - $this->_props_computed["list_style_image"] = "none"; + return "none"; } else { - $this->_props_computed["list_style_image"] = "url(" . $parsed_val . ")"; + return "url($parsed_val)"; } } /** - * Sets the list style - * - * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style - * @param string $value - * @param bool $important + * @link https://www.w3.org/TR/CSS21/generate.html#propdef-list-style */ - function set_list_style($value, bool $important = false) + protected function _set_list_style(string $value): array { static $positions = ["inside", "outside"]; static $types = [ @@ -3229,14 +3342,15 @@ class Style ]; $components = $this->parse_property_value($value); + $props = []; foreach ($components as $val) { - /* http://www.w3.org/TR/CSS21/generate.html#list-style + /* https://www.w3.org/TR/CSS21/generate.html#list-style * A value of 'none' for the 'list-style' property sets both 'list-style-type' and 'list-style-image' to 'none' */ if ($val === "none") { - $this->set_prop("list_style_type", $val, $important); - $this->set_prop("list_style_image", $val, $important); + $props["list_style_type"] = $val; + $props["list_style_image"] = $val; continue; } @@ -3246,70 +3360,87 @@ class Style //Internet Explorer 7/8 and dompdf is right. if (mb_substr($val, 0, 4) === "url(") { - $this->set_prop("list_style_image", $val, $important); + $props["list_style_image"] = $val; continue; } - if (in_array($val, $types, true)) { - $this->set_prop("list_style_type", $val, $important); - } elseif (in_array($val, $positions, true)) { - $this->set_prop("list_style_position", $val, $important); + if (\in_array($val, $types, true)) { + $props["list_style_type"] = $val; + } elseif (\in_array($val, $positions, true)) { + $props["list_style_position"] = $val; } } + + return $props; } /** - * @param $val + * @link https://www.w3.org/TR/css-page-3/#page-size-prop */ - function set_size($val) + protected function _compute_size(string $val) { - $this->_prop_cache["size"] = null; - - $length_re = "/(\d+\s*(?:pt|px|pc|rem|em|ex|in|cm|mm|%))/"; - - $val = mb_strtolower($val); - if ($val === "auto") { - $this->_props_computed["size"] = $val; - return; + return $val; } - $parts = preg_split("/\s+/", $val); + $parts = $this->parse_property_value($val); + $count = \count($parts); - $computed = []; - if (preg_match($length_re, $parts[0])) { - $computed[] = $this->length_in_pt($parts[0]); + if ($count === 0 || $count > 3) { + return null; + } - if (isset($parts[1]) && preg_match($length_re, $parts[1])) { - $computed[] = $this->length_in_pt($parts[1]); + $size = null; + $orientation = null; + $lengths = []; + + foreach ($parts as $part) { + if ($size === null && isset(CPDF::$PAPER_SIZES[$part])) { + $size = $part; + } elseif ($orientation === null && ($part === "portrait" || $part === "landscape")) { + $orientation = $part; } else { - $computed[] = $computed[0]; + $lengths[] = $part; } - - if (isset($parts[2]) && $parts[2] === "landscape") { - $computed = array_reverse($computed); - } - } elseif (isset(CPDF::$PAPER_SIZES[$parts[0]])) { - $computed = array_slice(CPDF::$PAPER_SIZES[$parts[0]], 2, 2); - - if (isset($parts[1]) && $parts[1] === "landscape") { - $computed = array_reverse($computed); - } - } else { - $this->_props_computed["size"] = null; - return; } - $this->_props_computed["size"] = $computed; + if ($size !== null && $lengths !== []) { + return null; + } + + if ($size !== null) { + // Standard paper size + [$l1, $l2] = \array_slice(CPDF::$PAPER_SIZES[$size], 2, 2); + } elseif ($lengths === []) { + // Orientation only, use default paper size + $dims = $this->_stylesheet->get_dompdf()->getPaperSize(); + [$l1, $l2] = \array_slice($dims, 2, 2); + } else { + // Custom paper size + $l1 = $this->compute_length_positive($lengths[0]); + $l2 = isset($lengths[1]) ? $this->compute_length_positive($lengths[1]) : $l1; + + if ($l1 === null || $l2 === null) { + return null; + } + } + + if (($orientation === "portrait" && $l1 > $l2) + || ($orientation === "landscape" && $l2 > $l1) + ) { + return [$l2, $l1]; + } + + return [$l1, $l2]; } /** - * Gets the CSS3 transform property + * @param string $computed + * @return array * - * @link http://www.w3.org/TR/css3-2d-transforms/#transform-property - * @return array|null + * @link https://www.w3.org/TR/css-transforms-1/#transform-property */ - function get_transform() + protected function _get_transform($computed) { //TODO: should be handled in setter (lengths set to absolute) @@ -3317,8 +3448,8 @@ class Style $tr_value = "\s*([^,\s]+)\s*"; $angle = "\s*([^,\s]+(?:deg|rad)?)\s*"; - if (!preg_match_all("/[a-z]+\([^\)]+\)/i", $this->_props_computed["transform"], $parts, PREG_SET_ORDER)) { - return null; + if (!preg_match_all("/[a-z]+\([^\)]+\)/i", $computed, $parts, PREG_SET_ORDER)) { + return []; } $functions = [ @@ -3346,7 +3477,7 @@ class Style foreach ($functions as $name => $pattern) { if (preg_match("/$name\s*$pattern/i", $t, $matches)) { - $values = array_slice($matches, 1); + $values = \array_slice($matches, 1); switch ($name) { // units @@ -3357,9 +3488,9 @@ class Style foreach ($values as $i => $value) { if (strpos($value, "rad")) { - $values[$i] = rad2deg(floatval($value)); + $values[$i] = rad2deg((float) $value); } else { - $values[$i] = floatval($value); + $values[$i] = (float) $value; } } @@ -3431,54 +3562,21 @@ class Style } /** - * @param $val - */ - function set_transform($val) - { - $this->_prop_cache["transform"] = null; - - if ($val === "inherit") { - $this->_props_computed["transform"] = null; - return; - } - - $this->_props_computed["transform"] = $val; - } - - /** - * Sets the CSS3 transform-origin property + * @param string $computed + * @return array * - * @link http://www.w3.org/TR/css3-2d-transforms/#transform-origin - * @param string $val + * @link https://www.w3.org/TR/css-transforms-1/#transform-origin-property */ - function set_transform_origin($val) - { - $this->_prop_cache["transform_origin"] = null; - - if ($val === "inherit") { - $this->_props_computed["transform_origin"] = null; - return; - } - - $this->_props_computed["transform_origin"] = $val; - } - - /** - * Gets the CSS3 transform-origin property - * - * @link http://www.w3.org/TR/css3-2d-transforms/#transform-origin - * @return mixed[] - */ - function get_transform_origin() + protected function _get_transform_origin($computed) { //TODO: should be handled in setter - - $values = preg_split("/\s+/", $this->_props_computed["transform_origin"]); + + $values = preg_split("/\s+/", $computed); $values = array_map(function ($value) { - if (in_array($value, ["top", "left"])) { + if (\in_array($value, ["top", "left"], true)) { return 0; - } else if (in_array($value, ["bottom", "right"])) { + } elseif (\in_array($value, ["bottom", "right"], true)) { return "100%"; } else { return $value; @@ -3493,10 +3591,10 @@ class Style } /** - * @param $val - * @return null + * @param string $val + * @return string|null */ - protected function parse_image_resolution($val) + protected function parse_image_resolution(string $val): ?string { // If exif data could be get: // $re = '/^\s*(\d+|normal|auto)(?:\s*,\s*(\d+|normal))?\s*$/'; @@ -3512,60 +3610,65 @@ class Style /** * auto | normal | dpi - * - * @param $val */ - function set_background_image_resolution($val) + protected function _compute_background_image_resolution(string $val) { - $this->_prop_cache["background_image_resolution"] = null; - - if ($val === "inherit") { - $this->_props_computed["background_image_resolution"] = null; - return; - } - - $parsed = $this->parse_image_resolution($val); - - $this->_props_computed["background_image_resolution"] = $parsed; + return $this->parse_image_resolution($val); } /** * auto | normal | dpi - * - * @param $val */ - function set_image_resolution($val) + protected function _compute_image_resolution(string $val) { - $this->_prop_cache["image_resolution"] = null; - - if ($val === "inherit") { - $this->_props_computed["image_resolution"] = null; - return; - } - - $parsed = $this->parse_image_resolution($val); - - $this->_props_computed["image_resolution"] = $parsed; + return $this->parse_image_resolution($val); } /** - * @param $val + * @link https://www.w3.org/TR/css-break-3/#propdef-orphans */ - function set_z_index($val) + protected function _compute_orphans(string $val) { - $this->_prop_cache["z_index"] = null; + return $this->compute_integer($val); + } - if ($val === "inherit") { - $this->_props_computed["z_index"] = null; - return; + /** + * @link https://www.w3.org/TR/css-break-3/#propdef-widows + */ + protected function _compute_widows(string $val) + { + return $this->compute_integer($val); + } + + /** + * @link https://www.w3.org/TR/css-color-4/#propdef-opacity + */ + protected function _compute_opacity(string $val) + { + $number = self::CSS_NUMBER; + $pattern = "/^($number)(%?)$/"; + + if (!preg_match($pattern, $val, $matches)) { + return null; } - if ($val !== "auto" && round((float) $val) != $val) { - $this->_props_computed["z_index"] = null; - return; + $v = (float) $matches[1]; + $percent = $matches[2] === "%"; + $opacity = $percent ? ($v / 100) : $v; + + return max(0.0, min($opacity, 1.0)); + } + + /** + * @link https://www.w3.org/TR/CSS21//visuren.html#propdef-z-index + */ + protected function _compute_z_index(string $val) + { + if ($val === "auto") { + return $val; } - $this->_props_computed["z_index"] = $val; + return $this->compute_integer($val); } /** @@ -3595,18 +3698,18 @@ class Style * @return string */ /*DEBUGCSS print: see below additional debugging util*/ - function __toString() + public function __toString(): string { $parent_font_size = $this->parent_style ? $this->parent_style->font_size : self::$default_font_size; - return print_r(array_merge(["parent_font_size" => $parent_font_size ], + return print_r(array_merge(["parent_font_size" => $parent_font_size], $this->_props), true); } /*DEBUGCSS*/ - function debug_print() + public function debug_print(): void { $parent_font_size = $this->parent_style ? $this->parent_style->font_size @@ -3630,7 +3733,7 @@ class Style } print " ]\n"; print " cached [\n"; - foreach ($this->_prop_cache as $prop => $val) { + foreach ($this->_props_used as $prop => $val) { print ' ' . $prop . ': ' . preg_replace("/\r\n/", ' ', print_r($val, true)); print ";\n"; } diff --git a/library/vendor/dompdf/src/Css/Stylesheet.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Stylesheet.php similarity index 93% rename from library/vendor/dompdf/src/Css/Stylesheet.php rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Stylesheet.php index 93641841a..20e019ab0 100644 --- a/library/vendor/dompdf/src/Css/Stylesheet.php +++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Css/Stylesheet.php @@ -1,10 +1,7 @@ - * @author Helmut Tischer - * @author Fabien Ménager + * @link https://github.com/dompdf/dompdf * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License */ namespace Dompdf\Css; @@ -288,19 +285,6 @@ class Stylesheet $this->_styles[$key][] = $style; } - /** - * Lookup a specific Style collection - * - * @deprecated - * @param string $key the selector of the requested Style collection - * - * @return Style[] - */ - function lookup(string $key): array - { - return $this->_styles[$key] ?? []; - } - /** * load and parse a CSS string * @@ -338,46 +322,26 @@ class Stylesheet $parsed = Helpers::parse_data_uri($file); $css = $parsed["data"]; } else { - $parsed_url = Helpers::explode_url($file); - - [$this->_protocol, $this->_base_host, $this->_base_path, $filename] = $parsed_url; - - $file = Helpers::build_url($this->_protocol, $this->_base_host, $this->_base_path, $filename); - $options = $this->_dompdf->getOptions(); - // Download the remote file - if (!$options->isRemoteEnabled() && ($this->_protocol !== "" && $this->_protocol !== "file://")) { - Helpers::record_warnings(E_USER_WARNING, "Remote CSS resource '$file' referenced, but remote file download is disabled.", __FILE__, __LINE__); - return; - } - if ($this->_protocol === "" || $this->_protocol === "file://") { - $realfile = realpath($file); - $rootDir = realpath($options->getRootDir()); - if (strpos($realfile, $rootDir) !== 0) { - $chroot = $options->getChroot(); - $chrootValid = false; - foreach ($chroot as $chrootPath) { - $chrootPath = realpath($chrootPath); - if ($chrootPath !== false && strpos($realfile, $chrootPath) === 0) { - $chrootValid = true; - break; - } - } - if ($chrootValid !== true) { - Helpers::record_warnings(E_USER_WARNING, "Permission denied on $file. The file could not be found under the paths specified by Options::chroot.", __FILE__, __LINE__); + $parsed_url = Helpers::explode_url($file); + $protocol = $parsed_url["protocol"]; + + if ($file !== $this->getDefaultStylesheet()) { + $allowed_protocols = $options->getAllowedProtocols(); + if (!array_key_exists($protocol, $allowed_protocols)) { + Helpers::record_warnings(E_USER_WARNING, "Permission denied on $file. The communication protocol is not supported.", __FILE__, __LINE__); + return; + } + foreach ($allowed_protocols[$protocol]["rules"] as $rule) { + [$result, $message] = $rule($file); + if (!$result) { + Helpers::record_warnings(E_USER_WARNING, "Error loading $file: $message", __FILE__, __LINE__); return; } } - - if (!$realfile) { - Helpers::record_warnings(E_USER_WARNING, "File '$realfile' not found.", __FILE__, __LINE__); - return; - } - - $file = $realfile; } - + [$css, $http_response_header] = Helpers::getFileContent($file, $this->_dompdf->getHttpContext()); $good_mime_type = true; @@ -392,11 +356,12 @@ class Stylesheet } } } - if (!$good_mime_type || $css === null) { Helpers::record_warnings(E_USER_WARNING, "Unable to load css file $file", __FILE__, __LINE__); return; } + + [$this->_protocol, $this->_base_host, $this->_base_path] = $parsed_url; } $this->_parse_css($css); @@ -577,7 +542,7 @@ class Stylesheet // class=".* $tok .*" and class=".* $tok" // This doesn't work because libxml only supports XPath 1.0... - //$query .= "[matches(@$attr,\"^${tok}\$|^${tok}[ ]+|[ ]+${tok}\$|[ ]+${tok}[ ]+\")]"; + //$query .= "[matches(@$attr,\"^{$tok}\$|^{$tok}[ ]+|[ ]+{$tok}\$|[ ]+{$tok}[ ]+\")]"; $query .= "[contains(concat(' ', normalize-space(@$attr), ' '), concat(' ', '$tok', ' '))]"; $tok = ""; @@ -620,7 +585,7 @@ class Stylesheet switch ($tok) { case "first-child": - $query .= "[1]"; + $query .= "[not(preceding-sibling::*)]"; $tok = ""; break; @@ -653,16 +618,17 @@ class Stylesheet $pseudo_classes[$tok] = true; $p = $i + 1; $nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p)); + $position = $last ? "(last()-position()+1)" : "position()"; // 1 if (preg_match("/^\d+$/", $nth)) { - $condition = "position() = $nth"; + $condition = "$position = $nth"; } // odd elseif ($nth === "odd") { - $condition = "(position() mod 2) = 1"; + $condition = "($position mod 2) = 1"; } // even elseif ($nth === "even") { - $condition = "(position() mod 2) = 0"; + $condition = "($position mod 2) = 0"; } // an+b else { $condition = $this->_selector_an_plus_b($nth, $last); @@ -684,16 +650,17 @@ class Stylesheet $pseudo_classes[$tok] = true; $p = $i + 1; $nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p)); + $position = $last ? "(last()-position()+1)" : "position()"; // 1 if (preg_match("/^\d+$/", $nth)) { - $condition = "position() = $nth"; + $condition = "$position = $nth"; } // odd elseif ($nth === "odd") { - $condition = "(position() mod 2) = 1"; + $condition = "($position mod 2) = 1"; } // even elseif ($nth === "even") { - $condition = "(position() mod 2) = 0"; + $condition = "($position mod 2) = 0"; } // an+b else { $condition = $this->_selector_an_plus_b($nth, $last); @@ -920,26 +887,27 @@ class Stylesheet /** * https://github.com/tenderlove/nokogiri/blob/master/lib/nokogiri/css/xpath_visitor.rb * - * @param $expr + * @param string $expr * @param bool $last + * * @return string */ - protected function _selector_an_plus_b($expr, $last = false) + protected function _selector_an_plus_b(string $expr, bool $last = false): string { $expr = preg_replace("/\s/", "", $expr); if (!preg_match("/^(?P-?[0-9]*)?n(?P[-+]?[0-9]+)?$/", $expr, $matches)) { return "false()"; } - $a = ((isset($matches["a"]) && $matches["a"] !== "") ? intval($matches["a"]) : 1); - $b = ((isset($matches["b"]) && $matches["b"] !== "") ? intval($matches["b"]) : 0); + $a = (isset($matches["a"]) && $matches["a"] !== "") ? ($matches["a"] !== "-" ? intval($matches["a"]) : -1) : 1; + $b = (isset($matches["b"]) && $matches["b"] !== "") ? intval($matches["b"]) : 0; - $position = ($last ? "(last()-position()+1)" : "position()"); + $position = $last ? "(last()-position()+1)" : "position()"; if ($b == 0) { return "($position mod $a) = 0"; } else { - $compare = (($a < 0) ? "<=" : ">="); + $compare = ($a < 0) ? "<=" : ">="; $b2 = -$b; if ($b2 >= 0) { $b2 = "+$b2"; @@ -1006,7 +974,7 @@ class Stylesheet continue; } - $content = $style->get_prop("content"); + $content = $style->get_specified("content"); // Do not create non-displayed before/after pseudo elements // https://www.w3.org/TR/CSS21/generate.html#content @@ -1075,7 +1043,7 @@ class Stylesheet // Now create the styles and assign them to the appropriate frames. (We // iterate over the tree using an implicit FrameTree iterator.) $root_flg = false; - foreach ($tree->get_frames() as $frame) { + foreach ($tree as $frame) { // Helpers::pre_r($frame->get_node()->nodeName . ":"); if (!$root_flg && $this->_page_styles["base"]) { $style = $this->_page_styles["base"]; @@ -1330,7 +1298,7 @@ class Stylesheet $media_query_feature = strtolower($media_query_match[3]); $media_query_value = strtolower($media_query_match[2]); $mq[] = [$media_query_feature, $media_query_value]; - } else if (empty($media_query_match[4]) === false) { + } elseif (empty($media_query_match[4]) === false) { $media_query_feature = strtolower($media_query_match[5]); $media_query_value = (array_key_exists(8, $media_query_match) ? strtolower($media_query_match[8]) : null); $mq[] = [$media_query_feature, $media_query_value]; @@ -1431,20 +1399,16 @@ class Stylesheet $val = preg_replace("/url\(\s*['\"]?([^'\")]+)['\"]?\s*\)/", "\\1", trim($val)); // Resolve the url now in the context of the current stylesheet - $parsed_url = Helpers::explode_url($val); $path = Helpers::build_url($this->_protocol, $this->_base_host, $this->_base_path, $val); - if (($parsed_url["protocol"] === "" || $parsed_url["protocol"] === "file://") && ($this->_protocol === "" || $this->_protocol === "file://")) { - $path = realpath($path); - // If realpath returns FALSE then specifically state that there is no background image - if ($path === false) { - $path = "none"; - } + if ($path === null) { + $path = "none"; } } if ($DEBUGCSS) { + $parsed_url = Helpers::explode_url($path); print "
[_image\n";
             print_r($parsed_url);
             print $this->_protocol . "\n" . $this->_base_path . "\n" . $path . "\n";
@@ -1493,9 +1457,9 @@ class Stylesheet
             // Above does not work for subfolders and absolute urls.
             // Todo: As above, do we need to replace php or file to an empty protocol for local files?
 
-            $url = $this->resolve_url($url);
-
-            $this->load_css_file($url);
+            if (($url = $this->resolve_url($url)) !== "none") {
+                $this->load_css_file($url);
+            }
 
             // Restore the current base url
             $this->_protocol = $protocol;
@@ -1514,11 +1478,9 @@ class Stylesheet
     {
         $descriptors = $this->_parse_properties($str);
 
-        preg_match_all("/(url|local)\s*\([\"\']?([^\"\'\)]+)[\"\']?\)\s*(format\s*\([\"\']?([^\"\'\)]+)[\"\']?\))?/i", $descriptors->src, $src);
+        preg_match_all("/(url|local)\s*\(\s*[\"\']?([^\"\'\)]+)[\"\']?\s*\)\s*(format\s*\(\s*[\"\']?([^\"\'\)]+)[\"\']?\s*\))?/i", $descriptors->src, $src);
 
-        $sources = [];
         $valid_sources = [];
-
         foreach ($src[0] as $i => $value) {
             $source = [
                 "local" => strtolower($src[1][$i]) === "local",
@@ -1527,11 +1489,9 @@ class Stylesheet
                 "path" => Helpers::build_url($this->_protocol, $this->_base_host, $this->_base_path, $src[2][$i]),
             ];
 
-            if (!$source["local"] && in_array($source["format"], ["", "truetype"])) {
+            if (!$source["local"] && in_array($source["format"], ["", "truetype"]) && $source["path"] !== null) {
                 $valid_sources[] = $source;
             }
-
-            $sources[] = $source;
         }
 
         // No valid sources
@@ -1685,7 +1645,7 @@ class Stylesheet
     {
         $options = $this->_dompdf->getOptions();
         $rootDir = realpath($options->getRootDir());
-        return $rootDir . self::DEFAULT_STYLESHEET;
+        return Helpers::build_url("file://", "", $rootDir, $rootDir . self::DEFAULT_STYLESHEET);
     }
 
     /**
diff --git a/library/vendor/dompdf/src/Dompdf.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Dompdf.php
similarity index 82%
rename from library/vendor/dompdf/src/Dompdf.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Dompdf.php
index ad8ac53d4..6feec59a6 100644
--- a/library/vendor/dompdf/src/Dompdf.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Dompdf.php
@@ -1,9 +1,7 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
@@ -14,11 +12,10 @@ use Dompdf\Adapter\CPDF;
 use DOMXPath;
 use Dompdf\Frame\Factory;
 use Dompdf\Frame\FrameTree;
-use HTML5_Tokenizer;
-use HTML5_TreeBuilder;
 use Dompdf\Image\Cache;
 use Dompdf\Css\Stylesheet;
 use Dompdf\Helpers;
+use Masterminds\HTML5;
 
 /**
  * Dompdf - PHP5 HTML to PDF renderer
@@ -197,16 +194,6 @@ class Dompdf
      */
     private $quirksmode = false;
 
-    /**
-    * Protocol whitelist
-    *
-    * Protocols and PHP wrappers allowed in URLs. Full support is not
-    * guaranteed for the protocols/wrappers contained in this array.
-    *
-    * @var array
-    */
-    private $allowedProtocols = ["", "file://", "http://", "https://"];
-
     /**
     * Local file extension whitelist
     *
@@ -259,7 +246,7 @@ class Dompdf
     /**
      * Class constructor
      *
-     * @param array|Options $options
+     * @param Options|array|null $options
      */
     public function __construct($options = null)
     {
@@ -272,8 +259,11 @@ class Dompdf
         }
 
         $versionFile = realpath(__DIR__ . '/../VERSION');
-        if (file_exists($versionFile) && ($version = trim(file_get_contents($versionFile))) !== false && $version !== '$Format:<%h>$') {
-            $this->version = sprintf('dompdf %s', $version);
+        if (($version = file_get_contents($versionFile)) !== false) {
+            $version = trim($version);
+            if ($version !== '$Format:<%h>$') {
+                $this->version = sprintf('dompdf %s', $version);
+            }
         }
 
         $this->setPhpConfig();
@@ -281,8 +271,8 @@ class Dompdf
         $this->paperSize = $this->options->getDefaultPaperSize();
         $this->paperOrientation = $this->options->getDefaultPaperOrientation();
 
-        $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
-        $this->setFontMetrics(new FontMetrics($this->getCanvas(), $this->getOptions()));
+        $this->canvas = CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation);
+        $this->fontMetrics = new FontMetrics($this->canvas, $this->options);
         $this->css = new Stylesheet($this);
 
         $this->restorePhpConfig();
@@ -353,43 +343,25 @@ class Dompdf
             [$this->protocol, $this->baseHost, $this->basePath] = Helpers::explode_url($file);
         }
         $protocol = strtolower($this->protocol);
-        
         $uri = Helpers::build_url($this->protocol, $this->baseHost, $this->basePath, $file);
 
-        if (!in_array($protocol, $this->allowedProtocols, true)) {
+        $allowed_protocols = $this->options->getAllowedProtocols();
+        if (!array_key_exists($protocol, $allowed_protocols)) {
             throw new Exception("Permission denied on $file. The communication protocol is not supported.");
         }
 
-        if (!$this->options->isRemoteEnabled() && ($protocol !== "" && $protocol !== "file://")) {
-            throw new Exception("Remote file requested, but remote file download is disabled.");
+        if ($protocol === "file://") {
+            $ext = strtolower(pathinfo($uri, PATHINFO_EXTENSION));
+            if (!in_array($ext, $this->allowedLocalFileExtensions)) {
+                throw new Exception("Permission denied on $file: The file extension is forbidden.");
+            }
         }
 
-        if ($protocol === "" || $protocol === "file://") {
-            $realfile = realpath($uri);
-
-            $chroot = $this->options->getChroot();
-            $chrootValid = false;
-            foreach ($chroot as $chrootPath) {
-                $chrootPath = realpath($chrootPath);
-                if ($chrootPath !== false && strpos($realfile, $chrootPath) === 0) {
-                    $chrootValid = true;
-                    break;
-                }
+        foreach ($allowed_protocols[$protocol]["rules"] as $rule) {
+            [$result, $message] = $rule($uri);
+            if (!$result) {
+                throw new Exception("Error loading $file: $message");
             }
-            if ($chrootValid !== true) {
-                throw new Exception("Permission denied on $file. The file could not be found under the paths specified by Options::chroot.");
-            }
-
-            $ext = strtolower(pathinfo($realfile, PATHINFO_EXTENSION));
-            if (!in_array($ext, $this->allowedLocalFileExtensions)) {
-                throw new Exception("Permission denied on $file. This file extension is forbidden");
-            }
-
-            if (!$realfile) {
-                throw new Exception("File '$file' not found.");
-            }
-
-            $uri = $realfile;
         }
 
         [$contents, $http_response_header] = Helpers::getFileContent($uri, $this->options->getHttpContext());
@@ -498,43 +470,18 @@ class Dompdf
 
         try {
             // @todo Take the quirksmode into account
+            // https://quirks.spec.whatwg.org/
             // http://hsivonen.iki.fi/doctype/
-            // https://developer.mozilla.org/en/mozilla's_quirks_mode
             $quirksmode = false;
 
-            if ($this->options->isHtml5ParserEnabled() && class_exists(HTML5_Tokenizer::class)) {
-                $tokenizer = new HTML5_Tokenizer($str);
-                $tokenizer->parse();
-                $doc = $tokenizer->save();
+            $html5 = new HTML5(['encoding' => $encoding, 'disable_html_ns' => true]);
+            $dom = $html5->loadHTML($str);
 
-                $quirksmode = ($tokenizer->getTree()->getQuirksMode() > HTML5_TreeBuilder::NO_QUIRKS);
-            } else {
-                // loadHTML assumes ISO-8859-1 unless otherwise specified on the HTML document header.
-                // http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/ (see #4)
-                // http://stackoverflow.com/a/11310258/264628
-                $doc = new DOMDocument("1.0", $encoding);
-                $doc->preserveWhiteSpace = true;
-                $doc->loadHTML($str);
-                $doc->encoding = $encoding;
-
-                // If some text is before the doctype, we are in quirksmode
-                if (preg_match("/^(.+)
-                    if (!$doc->doctype->publicId && !$doc->doctype->systemId) {
-                        $quirksmode = false;
-                    }
-
-                    // not XHTML
-                    if (!preg_match("/xhtml/i", $doc->doctype->publicId)) {
-                        $quirksmode = true;
-                    }
-                }
-            }
+            // extra step to normalize the HTML document structure
+            // see Masterminds/html5-php#166
+            $doc = new DOMDocument("1.0", $encoding);
+            $doc->preserveWhiteSpace = true;
+            $doc->loadHTML($html5->saveHTML($dom), LIBXML_NOWARNING | LIBXML_NOERROR);
 
             $this->loadDOM($doc, $quirksmode);
         } finally {
@@ -584,9 +531,11 @@ class Dompdf
         $acceptedmedia[] = $this->options->getDefaultMediaType();
 
         // 
-        $base_nodes = $this->dom->getElementsByTagName("base");
-        if ($base_nodes->length && ($href = $base_nodes->item(0)->getAttribute("href"))) {
-            [$this->protocol, $this->baseHost, $this->basePath] = Helpers::explode_url($href);
+        /** @var \DOMElement|null */
+        $baseNode = $this->dom->getElementsByTagName("base")->item(0);
+        $baseHref = $baseNode ? $baseNode->getAttribute("href") : "";
+        if ($baseHref !== "") {
+            [$this->protocol, $this->baseHost, $this->basePath] = Helpers::explode_url($baseHref);
         }
 
         // Set the base path of the Stylesheet to that of the file being processed
@@ -628,7 +577,9 @@ class Dompdf
                         $url = $tag->getAttribute("href");
                         $url = Helpers::build_url($this->protocol, $this->baseHost, $this->basePath, $url);
 
-                        $this->css->load_css_file($url, Stylesheet::ORIG_AUTHOR);
+                        if ($url !== null) {
+                            $this->css->load_css_file($url, Stylesheet::ORIG_AUTHOR);
+                        }
                     }
                     break;
 
@@ -726,9 +677,8 @@ class Dompdf
     public function render()
     {
         $this->setPhpConfig();
-        $options = $this->options;
 
-        $logOutputFile = $options->getLogOutputFile();
+        $logOutputFile = $this->options->getLogOutputFile();
         if ($logOutputFile) {
             if (!file_exists($logOutputFile) && is_writable(dirname($logOutputFile))) {
                 touch($logOutputFile);
@@ -753,36 +703,31 @@ class Dompdf
             $pageStyle->inherit($basePageStyle);
         }
 
-        $defaultOptionPaperSize = $this->getPaperSize($options->getDefaultPaperSize());
-        // If there is a CSS defined paper size compare to the paper size used to create the canvas to determine a
-        // recreation need
+        // Set paper size if defined via CSS
         if (is_array($basePageStyle->size)) {
-            $basePageStyleSize = $basePageStyle->size;
-            $this->setPaper([0, 0, $basePageStyleSize[0], $basePageStyleSize[1]]);
+            [$width, $height] = $basePageStyle->size;
+            $this->setPaper([0, 0, $width, $height]);
         }
 
-        $paperSize = $this->getPaperSize();
-        if (
-            $defaultOptionPaperSize[2] !== $paperSize[2] ||
-            $defaultOptionPaperSize[3] !== $paperSize[3] ||
-            $options->getDefaultPaperOrientation() !== $this->paperOrientation
-        ) {
-            $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
-            $this->fontMetrics->setCanvas($this->getCanvas());
+        // Create a new canvas instance if the current one does not match the
+        // desired paper size
+        $canvasWidth = $this->canvas->get_width();
+        $canvasHeight = $this->canvas->get_height();
+        $size = $this->getPaperSize();
+
+        if ($canvasWidth !== $size[2] || $canvasHeight !== $size[3]) {
+            $this->canvas = CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation);
+            $this->fontMetrics->setCanvas($this->canvas);
         }
 
-        $canvas = $this->getCanvas();
+        $canvas = $this->canvas;
 
-        $root = null;
-
-        foreach ($this->tree->get_frames() as $frame) {
-            // Set up the root frame
-            if (is_null($root)) {
-                $root = Factory::decorate_root($this->tree->get_root(), $this);
+        $root_frame = $this->tree->get_root();
+        $root = Factory::decorate_root($root_frame, $this);
+        foreach ($this->tree as $frame) {
+            if ($frame === $root_frame) {
                 continue;
             }
-
-            // Create the appropriate decorators, reflowers & positioners.
             Factory::decorate_frame($frame, $this, $root);
         }
 
@@ -819,6 +764,14 @@ class Dompdf
         // This is where the magic happens:
         $root->reflow();
 
+        if (isset($this->callbacks["end_document"])) {
+            $fs = $this->callbacks["end_document"];
+
+            foreach ($fs as $f) {
+                $canvas->page_script($f);
+            }
+        }
+
         // Clean up cached images
         if (!$this->options->getDebugKeepTemp()) {
             Cache::clear($this->options->getDebugPng());
@@ -846,17 +799,6 @@ class Dompdf
         $this->restorePhpConfig();
     }
 
-    /**
-     * Add meta information to the PDF after rendering
-     */
-    public function add_info($label, $value)
-    {
-        $canvas = $this->getCanvas();
-        if (!is_null($canvas)) {
-            $canvas->add_info($label, $value);
-        }
-    }
-
     /**
      * Writes the output buffer in the log file
      *
@@ -883,6 +825,27 @@ class Dompdf
         file_put_contents($logOutputFile, $out);
     }
 
+    /**
+     * Add meta information to the PDF after rendering.
+     *
+     * @deprecated
+     */
+    public function add_info($label, $value)
+    {
+        $this->addInfo($label, $value);
+    }
+
+    /**
+     * Add meta information to the PDF after rendering.
+     *
+     * @param string $label Label of the value (Creator, Producer, etc.)
+     * @param string $value The text to set
+     */
+    public function addInfo(string $label, string $value): void
+    {
+        $this->canvas->add_info($label, $value);
+    }
+
     /**
      * Streams the PDF to the client.
      *
@@ -903,10 +866,7 @@ class Dompdf
     {
         $this->setPhpConfig();
 
-        $canvas = $this->getCanvas();
-        if (!is_null($canvas)) {
-            $canvas->stream($filename, $options);
-        }
+        $this->canvas->stream($filename, $options);
 
         $this->restorePhpConfig();
     }
@@ -927,12 +887,7 @@ class Dompdf
     {
         $this->setPhpConfig();
 
-        $canvas = $this->getCanvas();
-        if (is_null($canvas)) {
-            return null;
-        }
-
-        $output = $canvas->output($options);
+        $output = $this->canvas->output($options);
 
         $this->restorePhpConfig();
 
@@ -1006,7 +961,7 @@ class Dompdf
     /**
      * Sets the paper size & orientation
      *
-     * @param string|array $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}
+     * @param string|float[] $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES}
      * @param string $orientation 'portrait' or 'landscape'
      * @return $this
      */
@@ -1020,19 +975,25 @@ class Dompdf
     /**
      * Gets the paper size
      *
-     * @param null|string|array $paperSize
-     * @return int[] A four-element integer array
+     * @return float[] A four-element float array
      */
-    public function getPaperSize($paperSize = null)
+    public function getPaperSize()
     {
-        $size = $paperSize !== null ? $paperSize : $this->paperSize;
-        if (is_array($size)) {
-            return $size;
-        } else if (isset(Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)])) {
-            return Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)];
+        $paper = $this->paperSize;
+        $orientation = $this->paperOrientation;
+
+        if (is_array($paper)) {
+            $size = array_map("floatval", $paper);
         } else {
-            return Adapter\CPDF::$PAPER_SIZES["letter"];
+            $paper = strtolower($paper);
+            $size = CPDF::$PAPER_SIZES[$paper] ?? CPDF::$PAPER_SIZES["letter"];
         }
+
+        if (strtolower($orientation) === "landscape") {
+            [$size[2], $size[3]] = [$size[3], $size[2]];
+        }
+
+        return $size;
     }
 
     /**
@@ -1265,6 +1226,11 @@ class Dompdf
     }
 
     /**
+     * Set a custom `Canvas` instance to render the document to.
+     *
+     * Be aware that the instance will be replaced on render if the document
+     * defines a paper size different from the canvas.
+     *
      * @param Canvas $canvas
      * @return $this
      */
@@ -1361,7 +1327,7 @@ class Dompdf
         }
 
         $this->options = $options;
-        $fontMetrics = $this->getFontMetrics();
+        $fontMetrics = $this->fontMetrics;
         if (isset($fontMetrics)) {
             $fontMetrics->setOptions($options);
         }
@@ -1397,15 +1363,16 @@ class Dompdf
 
     /**
      * @param array $callbacks the set of callbacks to set
+     * @return $this
      * @deprecated
      */
     public function set_callbacks($callbacks)
     {
-        $this->setCallbacks($callbacks);
+        return $this->setCallbacks($callbacks);
     }
 
     /**
-     * Sets callbacks for events like rendering of pages and elements.
+     * Define callbacks that allow modifying the document during render.
      *
      * The callbacks array should contain arrays with `event` set to a callback
      * event name and `f` set to a function or any other callable.
@@ -1416,27 +1383,31 @@ class Dompdf
      * * `end_frame`: called after frame rendering is complete
      * * `begin_page_render`: called before a page is rendered
      * * `end_page_render`: called after page rendering is complete
+     * * `end_document`: called for every page after rendering is complete
      *
-     * The function `f` must take an array as argument, which contains info
-     * about the event (`[0 => Canvas, 1 => Frame, "canvas" => Canvas,
-     * "frame" => Frame]`).
+     * The function `f` receives three arguments `Frame $frame`, `Canvas $canvas`,
+     * and `FontMetrics $fontMetrics` for all events but `end_document`. For
+     * `end_document`, the function receives four arguments `int $pageNumber`,
+     * `int $pageCount`, `Canvas $canvas`, and `FontMetrics $fontMetrics` instead.
      *
-     * @param array $callbacks The set of callbacks to set
+     * @param array $callbacks The set of callbacks to set.
+     * @return $this
      */
-    public function setCallbacks($callbacks)
+    public function setCallbacks(array $callbacks): self
     {
-        if (is_array($callbacks)) {
-            $this->callbacks = [];
-            foreach ($callbacks as $c) {
-                if (is_array($c) && isset($c["event"]) && isset($c["f"])) {
-                    $event = $c["event"];
-                    $f = $c["f"];
-                    if (is_string($event) && is_callable($f)) {
-                        $this->callbacks[$event][] = $f;
-                    }
+        $this->callbacks = [];
+
+        foreach ($callbacks as $c) {
+            if (is_array($c) && isset($c["event"]) && isset($c["f"])) {
+                $event = $c["event"];
+                $f = $c["f"];
+                if (is_string($event) && is_callable($f)) {
+                    $this->callbacks[$event][] = $f;
                 }
             }
         }
+
+        return $this;
     }
 
     /**
diff --git a/library/vendor/dompdf/src/Exception.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Exception.php
similarity index 84%
rename from library/vendor/dompdf/src/Exception.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Exception.php
index c9fb0df07..3a90e4771 100644
--- a/library/vendor/dompdf/src/Exception.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Exception.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf;
 
 /**
diff --git a/library/vendor/dompdf/src/Exception/ImageException.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Exception/ImageException.php
similarity index 84%
rename from library/vendor/dompdf/src/Exception/ImageException.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Exception/ImageException.php
index 62b44b1c8..ea1dfe407 100644
--- a/library/vendor/dompdf/src/Exception/ImageException.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Exception/ImageException.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Exception;
diff --git a/library/vendor/dompdf/src/FontMetrics.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FontMetrics.php
similarity index 64%
rename from library/vendor/dompdf/src/FontMetrics.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FontMetrics.php
index a224081ac..5698c8823 100644
--- a/library/vendor/dompdf/src/FontMetrics.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FontMetrics.php
@@ -1,13 +1,9 @@
 
- * @author  Helmut Tischer 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf;
 
 use FontLib\Font;
@@ -25,7 +21,7 @@ use FontLib\Font;
 class FontMetrics
 {
     /**
-     * Name of the font cache file
+     * Name of the user font families file
      *
      * This file must be writable by the webserver process only to update it
      * with save_font_families() after adding the .afm file references of a new font family
@@ -33,13 +29,8 @@ class FontMetrics
      * This is typically done only from command line with load_font.php on converting
      * ttf fonts to ufm with php-font-lib.
      */
-    const CACHE_FILE = "dompdf_font_family_cache.php";
+    const USER_FONTS_FILE = "installed-fonts.json";
 
-    /**
-     * @var Canvas
-     * @deprecated
-     */
-    protected $pdf;
 
     /**
      * Underlying {@link Canvas} object to perform text size calculations
@@ -49,13 +40,25 @@ class FontMetrics
     protected $canvas;
 
     /**
-     * Array of font family names to font files
-     *
-     * Usually cached by the {@link load_font.php} script
+     * Array of bundled font family names to variants
      *
      * @var array
      */
-    protected $fontLookup = [];
+    protected $bundledFonts = [];
+
+    /**
+     * Array of user defined font family names to variants
+     *
+     * @var array
+     */
+    protected $userFonts = [];
+
+    /**
+     * combined list of all font families with absolute paths
+     *
+     * @var array
+     */
+    protected $fontFamilies;
 
     /**
      * @var Options
@@ -84,29 +87,14 @@ class FontMetrics
      * Saves the stored font family cache
      *
      * The name and location of the cache file are determined by {@link
-     * FontMetrics::CACHE_FILE}. This file should be writable by the
+     * FontMetrics::USER_FONTS_FILE}. This file should be writable by the
      * webserver process.
      *
      * @see FontMetrics::loadFontFamilies()
      */
     public function saveFontFamilies()
     {
-        // replace the path to the DOMPDF font directories with the corresponding constants (allows for more portability)
-        $cacheData = sprintf("fontLookup as $family => $variants) {
-            $cacheData .= sprintf("  '%s' => array(%s", addslashes($family), PHP_EOL);
-            foreach ($variants as $variant => $path) {
-                $path = sprintf("'%s'", $path);
-                $path = str_replace('\'' . $this->options->getFontDir(), '$fontDir . \'', $path);
-                $path = str_replace('\'' . $this->options->getRootDir(), '$rootDir . \'', $path);
-                $cacheData .= sprintf("    '%s' => %s,%s", $variant, $path, PHP_EOL);
-            }
-            $cacheData .= sprintf("  ),%s", PHP_EOL);
-        }
-        $cacheData .= ");" . PHP_EOL;
-        $cacheData .= "}; ?>";
-        file_put_contents($this->getCacheFile(), $cacheData);
+        file_put_contents($this->getUserFontsFilePath(), json_encode($this->userFonts, JSON_PRETTY_PRINT));
     }
 
     /**
@@ -124,33 +112,45 @@ class FontMetrics
      */
     public function loadFontFamilies()
     {
-        $fontDir = $this->options->getFontDir();
-        $rootDir = $this->options->getRootDir();
+        $file = $this->options->getRootDir() . "/lib/fonts/installed-fonts.dist.json";
+        $this->bundledFonts = json_decode(file_get_contents($file), true);
 
-        // FIXME: temporarily define constants for cache files <= v0.6.2
-        if (!defined("DOMPDF_DIR")) { define("DOMPDF_DIR", $rootDir); }
-        if (!defined("DOMPDF_FONT_DIR")) { define("DOMPDF_FONT_DIR", $fontDir); }
-
-        $file = $rootDir . "/lib/fonts/dompdf_font_family_cache.dist.php";
-        $distFontsClosure = require $file;
-        $distFonts = is_array($distFontsClosure) ? $distFontsClosure : $distFontsClosure($rootDir);
-        if (!is_readable($this->getCacheFile())) {
-            $this->fontLookup = $distFonts;
-            return;
+        if (is_readable($this->getUserFontsFilePath())) {
+            $this->userFonts = json_decode(file_get_contents($this->getUserFontsFilePath()), true);
+        } else {
+            $this->loadFontFamiliesLegacy();
         }
+    }
 
-        $cacheDataClosure = require $this->getCacheFile();
-        $cacheData = is_array($cacheDataClosure) ? $cacheDataClosure : $cacheDataClosure($fontDir, $rootDir);
-
-        $this->fontLookup = [];
-        if (is_array($this->fontLookup)) {
-            foreach ($cacheData as $key => $value) {
-                $this->fontLookup[stripslashes($key)] = $value;
+    private function loadFontFamiliesLegacy()
+    {
+        $legacyCacheFile = $this->options->getFontDir() . '/dompdf_font_family_cache.php';
+        if (is_readable($legacyCacheFile)) {
+            $fontDir = $this->options->getFontDir();
+            $rootDir = $this->options->getRootDir();
+    
+            if (!defined("DOMPDF_DIR")) { define("DOMPDF_DIR", $rootDir); }
+            if (!defined("DOMPDF_FONT_DIR")) { define("DOMPDF_FONT_DIR", $fontDir); }
+    
+            $cacheDataClosure = require $legacyCacheFile;
+            $cacheData = is_array($cacheDataClosure) ? $cacheDataClosure : $cacheDataClosure($fontDir, $rootDir);
+            if (is_array($cacheData)) {
+                foreach ($cacheData as $family => $variants) {
+                    if (!isset($this->bundledFonts[$family]) && is_array($variants)) {
+                        foreach ($variants as $variant => $variantPath) {
+                            $variantName = basename($variantPath);
+                            $variantDir = dirname($variantPath);
+                            if ($variantDir == $fontDir) {
+                                $this->userFonts[$family][$variant] = $variantName;
+                            } else {
+                                $this->userFonts[$family][$variant] = $variantPath;
+                            }
+                        }
+                    }
+                }
+                $this->saveFontFamilies();
             }
         }
-
-        // Merge provided fonts
-        $this->fontLookup += $distFonts;
     }
 
     /**
@@ -183,7 +183,6 @@ class FontMetrics
 
         $styleString = $this->getType("{$style['weight']} {$style['style']}");
 
-        $fontDir = $this->options->getFontDir();
         $remoteHash = md5($remoteFile);
 
         $prefix = $fontname . "_" . $styleString;
@@ -199,49 +198,32 @@ class FontMetrics
         $prefix = preg_replace("[\W]", "_", $prefix);
         $prefix = preg_replace("/[^-_\w]+/", "", $prefix);
 
-        $localFile = $fontDir . "/" . $prefix . "_" . $remoteHash;
+        $localFile = $prefix . "_" . $remoteHash;
+        $localFilePath = $this->getOptions()->getFontDir() . "/" . $localFile;
 
-        if (isset($entry[$styleString]) && $localFile == $entry[$styleString]) {
+        if (isset($entry[$styleString]) && $localFilePath == $entry[$styleString]) {
             return true;
         }
 
-        $cacheEntry = $localFile;
 
-        $entry[$styleString] = $cacheEntry;
+        $entry[$styleString] = $localFile;
 
         // Download the remote file
         [$protocol] = Helpers::explode_url($remoteFile);
-        if (!$this->options->isRemoteEnabled() && ($protocol !== "" && $protocol !== "file://")) {
-            Helpers::record_warnings(E_USER_WARNING, "Remote font resource $remoteFile referenced, but remote file download is disabled.", __FILE__, __LINE__);
+        $allowed_protocols = $this->options->getAllowedProtocols();
+        if (!array_key_exists($protocol, $allowed_protocols)) {
+            Helpers::record_warnings(E_USER_WARNING, "Permission denied on $remoteFile. The communication protocol is not supported.", __FILE__, __LINE__);
             return false;
         }
-        if ($protocol === "" || $protocol === "file://") {
-            $realfile = realpath($remoteFile);
 
-            $rootDir = realpath($this->options->getRootDir());
-            if (strpos($realfile, $rootDir) !== 0) {
-                $chroot = $this->options->getChroot();
-                $chrootValid = false;
-                foreach ($chroot as $chrootPath) {
-                    $chrootPath = realpath($chrootPath);
-                    if ($chrootPath !== false && strpos($realfile, $chrootPath) === 0) {
-                        $chrootValid = true;
-                        break;
-                    }
-                }
-                if ($chrootValid !== true) {
-                    Helpers::record_warnings(E_USER_WARNING, "Permission denied on $remoteFile. The file could not be found under the paths specified by Options::chroot.", __FILE__, __LINE__);
-                    return false;
-                }
-            }
-
-            if (!$realfile) {
-                Helpers::record_warnings(E_USER_WARNING, "File '$realfile' not found.", __FILE__, __LINE__);
+        foreach ($allowed_protocols[$protocol]["rules"] as $rule) {
+            [$result, $message] = $rule($remoteFile);
+            if ($result !== true) {
+                Helpers::record_warnings(E_USER_WARNING, "Error loading $remoteFile: $message", __FILE__, __LINE__);
                 return false;
             }
-
-            $remoteFile = $realfile;
         }
+
         list($remoteFileContent, $http_response_header) = @Helpers::getFileContent($remoteFile, $context);
         if ($remoteFileContent === null) {
             return false;
@@ -257,33 +239,33 @@ class FontMetrics
             return false;
         }
 
-        switch ($font->getFontType()) {
-            case "TrueType":
-            default:
-                $localFile .= ".ttf";
-                break;
-        }
-
         $font->parse();
-        $font->saveAdobeFontMetrics("$cacheEntry.ufm");
+        $font->saveAdobeFontMetrics("$localFilePath.ufm");
         $font->close();
 
         unlink($localTempFile);
 
-        if ( !file_exists("$cacheEntry.ufm") ) {
+        if ( !file_exists("$localFilePath.ufm") ) {
             return false;
         }
 
-        // Save the changes
-        file_put_contents($localFile, $remoteFileContent);
+        $fontExtension = ".ttf";
+        switch ($font->getFontType()) {
+            case "TrueType":
+            default:
+                $fontExtension = ".ttf";
+                break;
+        }
 
-        if ( !file_exists($localFile) ) {
-            unlink("$cacheEntry.ufm");
+        // Save the changes
+        file_put_contents($localFilePath.$fontExtension, $remoteFileContent);
+
+        if ( !file_exists($localFilePath.$fontExtension) ) {
+            unlink("$localFilePath.ufm");
             return false;
         }
 
         $this->setFontFamily($fontname, $entry);
-        $this->saveFontFamilies();
 
         return true;
     }
@@ -306,16 +288,15 @@ class FontMetrics
     /**
      * Calculates text size, in points
      *
-     * @param string $text the text to be sized
-     * @param string $font the desired font
-     * @param float $size  the desired font size
-     * @param float $wordSpacing
-     * @param float $charSpacing
+     * @param string $text        The text to be sized
+     * @param string $font        The font file to use
+     * @param float  $size        The font size, in points
+     * @param float  $wordSpacing Word spacing, if any
+     * @param float  $charSpacing Char spacing, if any
      *
-     * @internal param float $spacing word spacing, if any
      * @return float
      */
-    public function getTextWidth($text, $font, $size, $wordSpacing = 0.0, $charSpacing = 0.0)
+    public function getTextWidth(string $text, $font, float $size, float $wordSpacing = 0.0, float $charSpacing = 0.0): float
     {
         // @todo Make sure this cache is efficient before enabling it
         static $cache = [];
@@ -359,12 +340,12 @@ class FontMetrics
     /**
      * Calculates font height, in points
      *
-     * @param string $font
-     * @param float $size
+     * @param string $font The font file to use
+     * @param float  $size The font size, in points
      *
      * @return float
      */
-    public function getFontHeight($font, $size)
+    public function getFontHeight($font, float $size): float
     {
         return $this->canvas->get_font_height($font, $size);
     }
@@ -372,12 +353,12 @@ class FontMetrics
     /**
      * Calculates font baseline, in points
      *
-     * @param string $font
-     * @param float $size
+     * @param string $font The font file to use
+     * @param float  $size The font size, in points
      *
      * @return float
      */
-    public function getFontBaseline($font, $size)
+    public function getFontBaseline($font, float $size): float
     {
         return $this->canvas->get_font_baseline($font, $size);
     }
@@ -400,10 +381,10 @@ class FontMetrics
      * ({@link Options::defaultFont}) is used.  The font file returned
      * is the absolute pathname to the font file on the system.
      *
-     * @param string $familyRaw
-     * @param string $subtypeRaw
+     * @param string|null $familyRaw
+     * @param string      $subtypeRaw
      *
-     * @return string
+     * @return string|null
      */
     public function getFont($familyRaw, $subtypeRaw = "normal")
     {
@@ -423,11 +404,12 @@ class FontMetrics
 
         $subtype = strtolower($subtypeRaw);
 
+        $families = $this->getFontFamilies();
         if ($familyRaw) {
             $family = str_replace(["'", '"'], "", strtolower($familyRaw));
 
-            if (isset($this->fontLookup[$family][$subtype])) {
-                return $cache[$familyRaw][$subtypeRaw] = $this->fontLookup[$family][$subtype];
+            if (isset($families[$family][$subtype])) {
+                return $cache[$familyRaw][$subtypeRaw] = $families[$family][$subtype];
             }
 
             return null;
@@ -435,15 +417,15 @@ class FontMetrics
 
         $fallback_families = [strtolower($this->options->getDefaultFont()), "serif"];
         foreach ($fallback_families as $family) {
-            if (isset($this->fontLookup[$family][$subtype])) {
-                return $cache[$familyRaw][$subtypeRaw] = $this->fontLookup[$family][$subtype];
+            if (isset($families[$family][$subtype])) {
+                return $cache[$familyRaw][$subtypeRaw] = $families[$family][$subtype];
             }
     
-            if (!isset($this->fontLookup[$family])) {
+            if (!isset($families[$family])) {
                 continue;
             }
     
-            $family = $this->fontLookup[$family];
+            $family = $families[$family];
     
             foreach ($family as $sub => $font) {
                 if (strpos($subtype, $sub) !== false) {
@@ -486,9 +468,10 @@ class FontMetrics
     public function getFamily($family)
     {
         $family = str_replace(["'", '"'], "", mb_strtolower($family));
+        $families = $this->getFontFamilies();
 
-        if (isset($this->fontLookup[$family])) {
-            return $this->fontLookup[$family];
+        if (isset($families[$family])) {
+            return $families[$family];
         }
 
         return null;
@@ -547,7 +530,41 @@ class FontMetrics
      */
     public function getFontFamilies()
     {
-        return $this->fontLookup;
+        if (!isset($this->fontFamilies)) {
+            $this->setFontFamilies();
+        }
+        return $this->fontFamilies;
+    }
+
+    /**
+     * Convert loaded fonts to font lookup table
+     *
+     * @return array
+     */
+    public function setFontFamilies()
+    {
+        $fontFamilies = [];
+        if (isset($this->bundledFonts) && is_array($this->bundledFonts)) {
+            foreach ($this->bundledFonts as $family => $variants) {
+                if (!isset($fontFamilies[$family])) {
+                    $fontFamilies[$family] = array_map(function ($variant) {
+                        return $this->getOptions()->getRootDir() . '/lib/fonts/' . $variant;
+                    }, $variants);
+                }
+            }
+        }
+        if (isset($this->userFonts) && is_array($this->userFonts)) {
+            foreach ($this->userFonts as $family => $variants) {
+                $fontFamilies[$family] = array_map(function ($variant) {
+                    $variantName = basename($variant);
+                    if ($variantName === $variant) {
+                        return $this->getOptions()->getFontDir() . '/' . $variant;
+                    }
+                    return $variant;
+                }, $variants);
+            }
+        }
+        $this->fontFamilies = $fontFamilies;
     }
 
     /**
@@ -566,15 +583,17 @@ class FontMetrics
      */
     public function setFontFamily($fontname, $entry)
     {
-        $this->fontLookup[mb_strtolower($fontname)] = $entry;
+        $this->userFonts[mb_strtolower($fontname)] = $entry;
+        $this->saveFontFamilies();
+        unset($this->fontFamilies);
     }
 
     /**
      * @return string
      */
-    public function getCacheFile()
+    public function getUserFontsFilePath()
     {
-        return $this->options->getFontDir() . '/' . self::CACHE_FILE;
+        return $this->options->getFontDir() . '/' . self::USER_FONTS_FILE;
     }
 
     /**
@@ -584,6 +603,7 @@ class FontMetrics
     public function setOptions(Options $options)
     {
         $this->options = $options;
+        unset($this->fontFamilies);
         return $this;
     }
 
@@ -602,8 +622,6 @@ class FontMetrics
     public function setCanvas(Canvas $canvas)
     {
         $this->canvas = $canvas;
-        // Still write deprecated pdf for now. It might be used by a parent class.
-        $this->pdf = $canvas;
         return $this;
     }
 
diff --git a/library/vendor/dompdf/src/Frame.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame.php
similarity index 92%
rename from library/vendor/dompdf/src/Frame.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame.php
index db2eddf47..55136b22b 100644
--- a/library/vendor/dompdf/src/Frame.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame.php
@@ -1,16 +1,13 @@
 
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
+use Dompdf\Frame\FrameListIterator;
 
 /**
  * The main Frame class
@@ -57,14 +54,6 @@ class Frame
      */
     protected $_style;
 
-    /**
-     * This frame's original style.  Needed for cases where frames are
-     * split across pages.
-     *
-     * @var Style
-     */
-    protected $_original_style;
-
     /**
      * This frame's parent in the document tree.
      *
@@ -72,13 +61,6 @@ class Frame
      */
     protected $_parent;
 
-    /**
-     * This frame's children
-     *
-     * @var Frame[]
-     */
-    protected $_frame_list;
-
     /**
      * This frame's first child.  All children are handled as a
      * doubly-linked list.
@@ -133,7 +115,7 @@ class Frame
     /**
      * This frame's decorator
      *
-     * @var \Dompdf\FrameDecorator\AbstractFrameDecorator
+     * @var FrameDecorator\AbstractFrameDecorator
      */
     protected $_decorator;
 
@@ -161,13 +143,6 @@ class Frame
      */
     public $_float_next_line = false;
 
-    /**
-     * Whether the frame is a split-off frame
-     *
-     * @var bool
-     */
-    public $_splitted;
-
     /**
      * @var int
      */
@@ -188,7 +163,6 @@ class Frame
         $this->_prev_sibling = $this->_next_sibling = null;
 
         $this->_style = null;
-        $this->_original_style = null;
 
         $this->_containing_block = [
             "x" => null,
@@ -301,13 +275,8 @@ class Frame
             $this->_parent->get_node()->removeChild($this->_node);
         }
 
-        $this->_style->dispose();
         $this->_style = null;
         unset($this->_style);
-
-        $this->_original_style->dispose();
-        $this->_original_style = null;
-        unset($this->_original_style);
     }
 
     /**
@@ -323,9 +292,7 @@ class Frame
         $this->_containing_block["w"] = null;
         $this->_containing_block["h"] = null;
 
-        $this->_style = null;
-        unset($this->_style);
-        $this->_style = clone $this->_original_style;
+        $this->_style->reset();
     }
 
     /**
@@ -353,11 +320,12 @@ class Frame
     }
 
     /**
+     * @deprecated
      * @return Style
      */
     public function get_original_style()
     {
-        return $this->_original_style;
+        return $this->_style;
     }
 
     /**
@@ -369,7 +337,7 @@ class Frame
     }
 
     /**
-     * @return \Dompdf\FrameDecorator\AbstractFrameDecorator
+     * @return FrameDecorator\AbstractFrameDecorator
      */
     public function get_decorator()
     {
@@ -409,17 +377,11 @@ class Frame
     }
 
     /**
-     * @return FrameList|Frame[]
+     * @return FrameListIterator
      */
-    public function get_children()
+    public function get_children(): FrameListIterator
     {
-        if (isset($this->_frame_list)) {
-            return $this->_frame_list;
-        }
-
-        $this->_frame_list = new FrameList($this);
-
-        return $this->_frame_list;
+        return new FrameListIterator($this);
     }
 
     // Layout property accessors
@@ -650,11 +612,11 @@ class Frame
     }
 
     /**
-     * @param null $opacity
+     * @param float|null $opacity
      *
      * @return float
      */
-    public function get_opacity($opacity = null)
+    public function get_opacity(?float $opacity = null): float
     {
         if ($opacity !== null) {
             $this->set_opacity($opacity);
@@ -692,18 +654,14 @@ class Frame
     /**
      * @param Style $style
      */
-    public function set_style(Style $style)
+    public function set_style(Style $style): void
     {
-        if (is_null($this->_style)) {
-            $this->_original_style = clone $style;
-        }
-
-        //$style->set_frame($this);
+        // $style->set_frame($this);
         $this->_style = $style;
     }
 
     /**
-     * @param \Dompdf\FrameDecorator\AbstractFrameDecorator $decorator
+     * @param FrameDecorator\AbstractFrameDecorator $decorator
      */
     public function set_decorator(FrameDecorator\AbstractFrameDecorator $decorator)
     {
@@ -761,12 +719,12 @@ class Frame
     }
 
     /**
-     * @param $opacity
+     * @param float $opacity
      */
-    public function set_opacity($opacity)
+    public function set_opacity(float $opacity): void
     {
         $parent = $this->get_parent();
-        $base_opacity = (($parent && $parent->_opacity !== null) ? $parent->_opacity : 1.0);
+        $base_opacity = $parent && $parent->_opacity !== null ? $parent->_opacity : 1.0;
         $this->_opacity = $base_opacity * $opacity;
     }
 
@@ -833,7 +791,7 @@ class Frame
      *
      * @return bool
      */
-    public function is_text_node()
+    public function is_text_node(): bool
     {
         if (isset($this->_is_cache["text_node"])) {
             return $this->_is_cache["text_node"];
@@ -845,21 +803,21 @@ class Frame
     /**
      * @return bool
      */
-    public function is_positionned()
+    public function is_positioned(): bool
     {
-        if (isset($this->_is_cache["positionned"])) {
-            return $this->_is_cache["positionned"];
+        if (isset($this->_is_cache["positioned"])) {
+            return $this->_is_cache["positioned"];
         }
 
         $position = $this->get_style()->position;
 
-        return $this->_is_cache["positionned"] = in_array($position, Style::$POSITIONNED_TYPES, true);
+        return $this->_is_cache["positioned"] = in_array($position, Style::POSITIONED_TYPES, true);
     }
 
     /**
      * @return bool
      */
-    public function is_absolute()
+    public function is_absolute(): bool
     {
         if (isset($this->_is_cache["absolute"])) {
             return $this->_is_cache["absolute"];
@@ -873,13 +831,13 @@ class Frame
      *
      * @return bool
      */
-    public function is_block()
+    public function is_block(): bool
     {
         if (isset($this->_is_cache["block"])) {
             return $this->_is_cache["block"];
         }
 
-        return $this->_is_cache["block"] = in_array($this->get_style()->display, Style::$BLOCK_TYPES, true);
+        return $this->_is_cache["block"] = in_array($this->get_style()->display, Style::BLOCK_TYPES, true);
     }
 
     /**
@@ -915,22 +873,9 @@ class Frame
     }
 
     /**
-     * @deprecated
      * @return bool
      */
-    public function is_inline_block()
-    {
-        if (isset($this->_is_cache["inline_block"])) {
-            return $this->_is_cache["inline_block"];
-        }
-
-        return $this->_is_cache["inline_block"] = ($this->get_style()->display === "inline-block");
-    }
-
-    /**
-     * @return bool
-     */
-    public function is_in_flow()
+    public function is_in_flow(): bool
     {
         if (isset($this->_is_cache["in_flow"])) {
             return $this->_is_cache["in_flow"];
@@ -942,7 +887,7 @@ class Frame
     /**
      * @return bool
      */
-    public function is_pre()
+    public function is_pre(): bool
     {
         if (isset($this->_is_cache["pre"])) {
             return $this->_is_cache["pre"];
@@ -956,7 +901,7 @@ class Frame
     /**
      * @return bool
      */
-    public function is_table()
+    public function is_table(): bool
     {
         if (isset($this->_is_cache["table"])) {
             return $this->_is_cache["table"];
@@ -964,7 +909,7 @@ class Frame
 
         $display = $this->get_style()->display;
 
-        return $this->_is_cache["table"] = in_array($display, Style::$TABLE_TYPES, true);
+        return $this->_is_cache["table"] = in_array($display, Style::TABLE_TYPES, true);
     }
 
 
diff --git a/library/vendor/dompdf/src/Frame/Factory.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/Factory.php
similarity index 96%
rename from library/vendor/dompdf/src/Frame/Factory.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/Factory.php
index 88688632f..b4bab8871 100644
--- a/library/vendor/dompdf/src/Frame/Factory.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/Factory.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Frame;
@@ -24,7 +23,6 @@ use Dompdf\Positioner\AbstractPositioner;
  * objects.  This is determined primarily by the Frame's display type, but
  * also by the Frame's node's type (e.g. DomElement vs. #text)
  *
- * @access  private
  * @package dompdf
  */
 class Factory
@@ -190,7 +188,7 @@ class Factory
 
         // Handle nodeName
         if ($node->nodeName === "img") {
-            $style->display = "-dompdf-image";
+            $style->set_prop("display", "-dompdf-image");
             $decorator = "Image";
             $reflower = "Image";
         }
@@ -216,8 +214,7 @@ class Factory
 
             $node = $frame->get_node();
             $parent_node = $node->parentNode;
-
-            if ($parent_node) {
+            if ($parent_node && $parent_node instanceof \DOMElement) {
                 if (!$parent_node->hasAttribute("dompdf-children-count")) {
                     $xpath = new DOMXPath($xml);
                     $count = $xpath->query("li", $parent_node)->length;
@@ -239,7 +236,7 @@ class Factory
             }
 
             $new_style = $dompdf->getCss()->create_style();
-            $new_style->display = "-dompdf-list-bullet";
+            $new_style->set_prop("display", "-dompdf-list-bullet");
             $new_style->inherit($style);
             $b_f->set_style($new_style);
 
diff --git a/library/vendor/dompdf/src/Frame/FrameListIterator.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/FrameListIterator.php
similarity index 91%
rename from library/vendor/dompdf/src/Frame/FrameListIterator.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/FrameListIterator.php
index 14e21def6..01575505a 100644
--- a/library/vendor/dompdf/src/Frame/FrameListIterator.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/FrameListIterator.php
@@ -1,4 +1,9 @@
 
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
+use IteratorAggregate;
 
 /**
  * Represents an entire document as a tree of frames
@@ -27,7 +25,7 @@ use Dompdf\Frame;
  *
  * @package dompdf
  */
-class FrameTree
+class FrameTree implements IteratorAggregate
 {
     /**
      * Tags to ignore while parsing the tree
@@ -124,11 +122,22 @@ class FrameTree
     /**
      * Returns a post-order iterator for all frames in the tree
      *
-     * @return FrameTreeList|Frame[]
+     * @deprecated Iterate the tree directly instead
+     * @return FrameTreeIterator
      */
-    public function get_frames()
+    public function get_frames(): FrameTreeIterator
     {
-        return new FrameTreeList($this->_root);
+        return new FrameTreeIterator($this->_root);
+    }
+
+    /**
+     * Returns a post-order iterator for all frames in the tree
+     *
+     * @return FrameTreeIterator
+     */
+    public function getIterator(): FrameTreeIterator
+    {
+        return new FrameTreeIterator($this->_root);
     }
 
     /**
diff --git a/library/vendor/dompdf/src/Frame/FrameTreeIterator.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php
similarity index 87%
rename from library/vendor/dompdf/src/Frame/FrameTreeIterator.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php
index 56a7b6823..4da8da1ee 100644
--- a/library/vendor/dompdf/src/Frame/FrameTreeIterator.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php
@@ -1,4 +1,9 @@
 _stack);
-
-        // Pop last element
-        unset($this->_stack[key($this->_stack)]);
+        $b = array_pop($this->_stack);
         $this->_num++;
 
         // Push all children onto the stack in reverse order
diff --git a/library/vendor/dompdf/src/FrameDecorator/AbstractFrameDecorator.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php
similarity index 90%
rename from library/vendor/dompdf/src/FrameDecorator/AbstractFrameDecorator.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php
index b37ecd473..2c1fcc5df 100644
--- a/library/vendor/dompdf/src/FrameDecorator/AbstractFrameDecorator.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php
@@ -1,25 +1,23 @@
 
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
 
 /**
  * Base AbstractFrameDecorator class
@@ -84,7 +82,7 @@ abstract class AbstractFrameDecorator extends Frame
      *
      * @var AbstractFrameDecorator
      */
-    private $_positionned_parent;
+    private $_positioned_parent;
 
     /**
      * Cache for the get_parent while loop results
@@ -107,6 +105,13 @@ abstract class AbstractFrameDecorator extends Frame
      */
     public $is_split = false;
 
+    /**
+     * Whether the frame is a split-off frame
+     *
+     * @var bool
+     */
+    public $is_split_off = false;
+
     /**
      * Class constructor
      *
@@ -158,7 +163,10 @@ abstract class AbstractFrameDecorator extends Frame
     function copy(DOMNode $node)
     {
         $frame = new Frame($node);
-        $frame->set_style(clone $this->_frame->get_original_style());
+        $style = clone $this->_frame->get_style();
+
+        $style->reset();
+        $frame->set_style($style);
 
         if ($node instanceof DOMElement && $node->hasAttribute("id")) {
             $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
@@ -177,7 +185,10 @@ abstract class AbstractFrameDecorator extends Frame
     {
         $node = $this->_frame->get_node()->cloneNode();
         $frame = new Frame($node);
-        $frame->set_style(clone $this->_frame->get_original_style());
+        $style = clone $this->_frame->get_style();
+
+        $style->reset();
+        $frame->set_style($style);
 
         if ($node instanceof DOMElement && $node->hasAttribute("id")) {
             $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
@@ -205,8 +216,8 @@ abstract class AbstractFrameDecorator extends Frame
     {
         $style = $this->get_style();
         $child_style = $style->get_stylesheet()->create_style();
+        $child_style->set_prop("display", $display);
         $child_style->inherit($style);
-        $child_style->display = $display;
 
         $node = $this->get_node()->ownerDocument->createElement($node_name);
         $frame = new Frame($node);
@@ -228,7 +239,7 @@ abstract class AbstractFrameDecorator extends Frame
         // clear parent lookup caches
         $this->_cached_parent = null;
         $this->_block_parent = null;
-        $this->_positionned_parent = null;
+        $this->_positioned_parent = null;
 
         // Reset all children
         foreach ($this->get_children() as $child) {
@@ -295,9 +306,12 @@ abstract class AbstractFrameDecorator extends Frame
         return $this->_frame->get_style();
     }
 
+    /**
+     * @deprecated
+     */
     function get_original_style()
     {
-        return $this->_frame->get_original_style();
+        return $this->_frame->get_style();
     }
 
     function get_containing_block($i = null)
@@ -348,7 +362,7 @@ abstract class AbstractFrameDecorator extends Frame
         $this->_frame->set_id($id);
     }
 
-    function set_style(Style $style)
+    public function set_style(Style $style): void
     {
         $this->_frame->set_style($style);
     }
@@ -539,11 +553,19 @@ abstract class AbstractFrameDecorator extends Frame
     }
 
     /**
-     * @return FrameTreeList
+     * @return FrameListIterator
      */
-    function get_subtree()
+    public function get_children(): FrameListIterator
     {
-        return new FrameTreeList($this);
+        return new FrameListIterator($this);
+    }
+
+    /**
+     * @return FrameTreeIterator
+     */
+    function get_subtree(): FrameTreeIterator
+    {
+        return new FrameTreeIterator($this);
     }
 
     function set_positioner(AbstractPositioner $posn)
@@ -624,16 +646,16 @@ abstract class AbstractFrameDecorator extends Frame
     /**
      * @return AbstractFrameDecorator
      */
-    function find_positionned_parent()
+    function find_positioned_parent()
     {
         // Find our nearest relative positioned parent
-        if (isset($this->_positionned_parent)) {
-            return $this->_positionned_parent;
+        if (isset($this->_positioned_parent)) {
+            return $this->_positioned_parent;
         }
 
         $p = $this->get_parent();
         while ($p) {
-            if ($p->is_positionned()) {
+            if ($p->is_positioned()) {
                 break;
             }
 
@@ -644,7 +666,7 @@ abstract class AbstractFrameDecorator extends Frame
             $p = $this->_root;
         }
 
-        return $this->_positionned_parent = $p;
+        return $this->_positioned_parent = $p;
     }
 
     /**
@@ -671,36 +693,36 @@ abstract class AbstractFrameDecorator extends Frame
         }
 
         $this->revert_counter_increment();
+
         $node = $this->_frame->get_node();
         $split = $this->copy($node->cloneNode());
 
         $style = $this->_frame->get_style();
-        $split_style = $split->get_original_style();
+        $split_style = $split->get_style();
 
         // Truncate the box decoration at the split, except for the body
         if ($node->nodeName !== "body") {
-            // Style reset on the first and second parts
-            $style->margin_bottom = 0;
-            $style->padding_bottom = 0;
-            $style->border_bottom = 0;
-            $style->border_bottom_left_radius = 0;
-            $style->border_bottom_right_radius = 0;
+            // Clear bottom decoration of original frame
+            $style->margin_bottom = 0.0;
+            $style->padding_bottom = 0.0;
+            $style->border_bottom_width = 0.0;
+            $style->border_bottom_left_radius = 0.0;
+            $style->border_bottom_right_radius = 0.0;
 
-            // second
-            $split_style->margin_top = 0;
-            $split_style->padding_top = 0;
-            $split_style->border_top = 0;
-            $split_style->border_top_left_radius = 0;
-            $split_style->border_top_right_radius = 0;
+            // Clear top decoration of split frame
+            $split_style->margin_top = 0.0;
+            $split_style->padding_top = 0.0;
+            $split_style->border_top_width = 0.0;
+            $split_style->border_top_left_radius = 0.0;
+            $split_style->border_top_right_radius = 0.0;
             $split_style->page_break_before = "auto";
         }
 
-        $split_style->text_indent = 0;
+        $split_style->text_indent = 0.0;
         $split_style->counter_reset = "none";
 
-        $split->set_style(clone $split_style);
         $this->is_split = true;
-        $split->_splitted = true;
+        $split->is_split_off = true;
         $split->_already_pushed = true;
 
         $this->get_parent()->insert_child_after($split, $this);
@@ -719,7 +741,7 @@ abstract class AbstractFrameDecorator extends Frame
         if (!$forced) {
             // Reset top margin in case of an unforced page break
             // https://www.w3.org/TR/CSS21/page.html#allowed-page-breaks
-            $child->get_original_style()->margin_top = 0;
+            $child->get_style()->margin_top = 0.0;
         }
 
         // Add $child and all following siblings to the new split node
@@ -873,9 +895,9 @@ abstract class AbstractFrameDecorator extends Frame
     /**
      * @param float $offset_x
      * @param float $offset_y
-     * @param bool $ignore_self
+     * @param bool  $ignore_self
      */
-    final function move($offset_x, $offset_y, $ignore_self = false)
+    final function move(float $offset_x, float $offset_y, bool $ignore_self = false): void
     {
         $this->_positioner->move($this, $offset_x, $offset_y, $ignore_self);
     }
diff --git a/library/vendor/dompdf/src/FrameDecorator/Block.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Block.php
similarity index 95%
rename from library/vendor/dompdf/src/FrameDecorator/Block.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Block.php
index de8c07916..1fcf134d8 100644
--- a/library/vendor/dompdf/src/FrameDecorator/Block.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Block.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -14,7 +13,6 @@ use Dompdf\LineBox;
 /**
  * Decorates frames for block layout
  *
- * @access  private
  * @package dompdf
  */
 class Block extends AbstractFrameDecorator
@@ -114,7 +112,7 @@ class Block extends AbstractFrameDecorator
      * @param Frame $frame
      * @return LineBox|null
      */
-    public function add_frame_to_line(Frame $frame)
+    public function add_frame_to_line(Frame $frame): ?LineBox
     {
         $current_line = $this->_line_boxes[$this->_cl];
         $frame->set_containing_line($current_line);
@@ -203,7 +201,7 @@ class Block extends AbstractFrameDecorator
     /**
      * @param float $w
      */
-    function increase_line_width($w)
+    public function increase_line_width(float $w): void
     {
         $this->_line_boxes[$this->_cl]->w += $w;
     }
@@ -212,7 +210,7 @@ class Block extends AbstractFrameDecorator
      * @param float $val
      * @param Frame $frame
      */
-    function maximize_line_height($val, Frame $frame)
+    public function maximize_line_height(float $val, Frame $frame): void
     {
         if ($val > $this->_line_boxes[$this->_cl]->h) {
             $this->_line_boxes[$this->_cl]->tallest_frame = $frame;
@@ -223,7 +221,7 @@ class Block extends AbstractFrameDecorator
     /**
      * @param bool $br
      */
-    function add_line(bool $br = false)
+    public function add_line(bool $br = false): void
     {
         $line = $this->_line_boxes[$this->_cl];
 
diff --git a/library/vendor/dompdf/src/FrameDecorator/Image.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Image.php
similarity index 83%
rename from library/vendor/dompdf/src/FrameDecorator/Image.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Image.php
index 453adbade..92ac491a4 100644
--- a/library/vendor/dompdf/src/FrameDecorator/Image.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Image.php
@@ -1,9 +1,7 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -57,15 +55,21 @@ class Image extends AbstractFrameDecorator
             $dompdf->getProtocol(),
             $dompdf->getBaseHost(),
             $dompdf->getBasePath(),
-            $dompdf
+            $dompdf->getOptions()
         );
 
         if (Cache::is_broken($this->_image_url) &&
             $alt = $frame->get_node()->getAttribute("alt")
         ) {
+            $fontMetrics = $dompdf->getFontMetrics();
             $style = $frame->get_style();
-            $style->width = (4 / 3) * $dompdf->getFontMetrics()->getTextWidth($alt, $style->font_family, $style->font_size, $style->word_spacing);
-            $style->height = $dompdf->getFontMetrics()->getFontHeight($style->font_family, $style->font_size);
+            $font = $style->font_family;
+            $size = $style->font_size;
+            $word_spacing = $style->word_spacing;
+            $letter_spacing = $style->letter_spacing;
+
+            $style->width = (4 / 3) * $fontMetrics->getTextWidth($alt, $font, $size, $word_spacing, $letter_spacing);
+            $style->height = $fontMetrics->getFontHeight($font, $size);
         }
     }
 
diff --git a/library/vendor/dompdf/src/FrameDecorator/Inline.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Inline.php
similarity index 81%
rename from library/vendor/dompdf/src/FrameDecorator/Inline.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Inline.php
index c30990f2a..668d795e0 100644
--- a/library/vendor/dompdf/src/FrameDecorator/Inline.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Inline.php
@@ -1,9 +1,7 @@
 
- * @author  Helmut Tischer 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -15,7 +13,6 @@ use Dompdf\Exception;
 /**
  * Decorates frames for inline layout
  *
- * @access  private
  * @package dompdf
  */
 class Inline extends AbstractFrameDecorator
@@ -70,18 +67,22 @@ class Inline extends AbstractFrameDecorator
         $split = $this->copy($node->cloneNode());
 
         $style = $this->_frame->get_style();
-        $split_style = $split->get_original_style();
+        $split_style = $split->get_style();
 
         // Unset the current node's right style properties
-        $style->margin_right = 0;
-        $style->padding_right = 0;
-        $style->border_right_width = 0;
+        $style->margin_right = 0.0;
+        $style->padding_right = 0.0;
+        $style->border_right_width = 0.0;
+        $style->border_top_right_radius = 0.0;
+        $style->border_bottom_right_radius = 0.0;
 
         // Unset the split node's left style properties since we don't want them
         // to propagate
-        $split_style->margin_left = 0;
-        $split_style->padding_left = 0;
-        $split_style->border_left_width = 0;
+        $split_style->margin_left = 0.0;
+        $split_style->padding_left = 0.0;
+        $split_style->border_left_width = 0.0;
+        $split_style->border_top_left_radius = 0.0;
+        $split_style->border_bottom_left_radius = 0.0;
 
         // If this is a generated node don't propagate the content style
         if ($split->get_node()->nodeName == "dompdf_generated") {
@@ -91,14 +92,12 @@ class Inline extends AbstractFrameDecorator
         //On continuation of inline element on next line,
         //don't repeat non-horizontally repeatable background images
         //See e.g. in testcase image_variants, long descriptions
-        if (($url = $split->get_style()->background_image) && $url !== "none"
-            && ($repeat = $split->get_style()->background_repeat) && $repeat !== "repeat" && $repeat !== "repeat-x"
+        if (($url = $style->background_image) && $url !== "none"
+            && ($repeat = $style->background_repeat) && $repeat !== "repeat" && $repeat !== "repeat-x"
         ) {
             $split_style->background_image = "none";
         }
 
-        $split->set_style(clone $split_style);
-
         $this->get_parent()->insert_child_after($split, $this);
 
         // Add $child and all following siblings to the new split node
diff --git a/library/vendor/dompdf/src/FrameDecorator/ListBullet.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php
similarity index 88%
rename from library/vendor/dompdf/src/FrameDecorator/ListBullet.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php
index 19f0e801f..703f46767 100644
--- a/library/vendor/dompdf/src/FrameDecorator/ListBullet.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php
@@ -1,9 +1,7 @@
 
- * @author  Helmut Tischer 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -39,21 +37,6 @@ class ListBullet extends AbstractFrameDecorator
      */
     public const MARKER_INDENT = 0.52;
 
-    /**
-     * @deprecated
-     */
-    const BULLET_PADDING = 1;
-
-    /**
-     * @deprecated
-     */
-    const BULLET_DESCENT = 0.3;
-
-    /**
-     * @deprecated
-     */
-    static $BULLET_TYPES = ["disc", "circle", "square"];
-
     /**
      * ListBullet constructor.
      * @param Frame $frame
diff --git a/library/vendor/dompdf/src/FrameDecorator/ListBulletImage.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php
similarity index 94%
rename from library/vendor/dompdf/src/FrameDecorator/ListBulletImage.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php
index 19fed1c09..d921929c2 100644
--- a/library/vendor/dompdf/src/FrameDecorator/ListBulletImage.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php
@@ -1,9 +1,7 @@
 
- * @author  Helmut Tischer 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
diff --git a/library/vendor/dompdf/src/FrameDecorator/NullFrameDecorator.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php
similarity index 87%
rename from library/vendor/dompdf/src/FrameDecorator/NullFrameDecorator.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php
index e3457cfe7..f08381675 100644
--- a/library/vendor/dompdf/src/FrameDecorator/NullFrameDecorator.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
diff --git a/library/vendor/dompdf/src/FrameDecorator/Page.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Page.php
similarity index 98%
rename from library/vendor/dompdf/src/FrameDecorator/Page.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Page.php
index 43d10bafd..25ef2408f 100644
--- a/library/vendor/dompdf/src/FrameDecorator/Page.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Page.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -15,7 +14,6 @@ use Dompdf\Renderer;
 /**
  * Decorates frames for page layout
  *
- * @access  private
  * @package dompdf
  */
 class Page extends AbstractFrameDecorator
@@ -178,9 +176,7 @@ class Page extends AbstractFrameDecorator
         ) {
             // Prevent cascading splits
             $frame->split(null, true, true);
-            // We have to grab the style again here because split() resets
-            // $frame->style to the frame's original style.
-            $frame->get_style()->page_break_before = "auto";
+            $style->page_break_before = "auto";
             $this->_page_full = true;
             $frame->_already_pushed = true;
 
@@ -472,7 +468,7 @@ class Page extends AbstractFrameDecorator
                         $prev_group = $frame->get_parent()->get_prev_sibling();
 
                         if ($prev_group
-                            && in_array($prev_group->get_style()->display, Table::$ROW_GROUPS, true)
+                            && in_array($prev_group->get_style()->display, Table::ROW_GROUPS, true)
                         ) {
                             $prev = $prev_group->get_last_child();
                         }
@@ -511,7 +507,7 @@ class Page extends AbstractFrameDecorator
 
                     return true;
                 } else {
-                    if (in_array($display, Table::$ROW_GROUPS, true)) {
+                    if (in_array($display, Table::ROW_GROUPS, true)) {
 
                         // Disallow breaks at row-groups: only split at row boundaries
                         return false;
@@ -640,7 +636,7 @@ class Page extends AbstractFrameDecorator
 
                 if ($next->is_table() && !$iter->is_table()) {
                     $this->_in_table++;
-                } else if (!$next->is_table() && $iter->is_table()) {
+                } elseif (!$next->is_table() && $iter->is_table()) {
                     $this->_in_table--;
                 }
 
diff --git a/library/vendor/dompdf/src/FrameDecorator/Table.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Table.php
similarity index 82%
rename from library/vendor/dompdf/src/FrameDecorator/Table.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Table.php
index 107ffdb4a..2770cbecb 100644
--- a/library/vendor/dompdf/src/FrameDecorator/Table.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Table.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -20,9 +19,12 @@ use Dompdf\Frame;
  */
 class Table extends AbstractFrameDecorator
 {
-    public static $VALID_CHILDREN = Style::TABLE_INTERNAL_TYPES;
+    public const VALID_CHILDREN = Style::TABLE_INTERNAL_TYPES;
 
-    public static $ROW_GROUPS = [
+    /**
+     * List of all row-group display types.
+     */
+    public const ROW_GROUPS = [
         "table-row-group",
         "table-header-group",
         "table-footer-group"
@@ -36,20 +38,6 @@ class Table extends AbstractFrameDecorator
      */
     protected $_cellmap;
 
-    /**
-     * The minimum width of the table, in pt
-     *
-     * @var float
-     */
-    protected $_min_width;
-
-    /**
-     * The maximum width of the table, in pt
-     *
-     * @var float
-     */
-    protected $_max_width;
-
     /**
      * Table header rows.  Each table header is duplicated when a table
      * spans pages.
@@ -81,8 +69,6 @@ class Table extends AbstractFrameDecorator
             $this->_cellmap->set_layout_fixed(true);
         }
 
-        $this->_min_width = null;
-        $this->_max_width = null;
         $this->_headers = [];
         $this->_footers = [];
     }
@@ -91,8 +77,6 @@ class Table extends AbstractFrameDecorator
     {
         parent::reset();
         $this->_cellmap->reset();
-        $this->_min_width = null;
-        $this->_max_width = null;
         $this->_headers = [];
         $this->_footers = [];
         $this->_reflower->reset();
@@ -134,7 +118,7 @@ class Table extends AbstractFrameDecorator
 
             parent::split($first_header, $page_break, $forced);
 
-        } elseif (in_array($child->get_style()->display, self::$ROW_GROUPS, true)) {
+        } elseif (in_array($child->get_style()->display, self::ROW_GROUPS, true)) {
 
             // Individual rows should have already been handled
             parent::split($child, $page_break, $forced);
@@ -191,46 +175,6 @@ class Table extends AbstractFrameDecorator
         return $this->_cellmap;
     }
 
-    /**
-     * Return the minimum width of this table
-     *
-     * @return float
-     */
-    public function get_min_width()
-    {
-        return $this->_min_width;
-    }
-
-    /**
-     * Return the maximum width of this table
-     *
-     * @return float
-     */
-    public function get_max_width()
-    {
-        return $this->_max_width;
-    }
-
-    /**
-     * Set the minimum width of the table
-     *
-     * @param float $width the new minimum width
-     */
-    public function set_min_width($width)
-    {
-        $this->_min_width = $width;
-    }
-
-    /**
-     * Set the maximum width of the table
-     *
-     * @param float $width the new maximum width
-     */
-    public function set_max_width($width)
-    {
-        $this->_max_width = $width;
-    }
-
     //........................................................................
 
     /**
@@ -248,10 +192,11 @@ class Table extends AbstractFrameDecorator
         $wsPattern = '/^[^\S\xA0\x{202F}\x{2007}]*$/u';
         $validChildOrNull = function ($frame) {
             return $frame === null
-                || in_array($frame->get_style()->display, self::$VALID_CHILDREN, true);
+                || in_array($frame->get_style()->display, self::VALID_CHILDREN, true);
         };
 
-        return $frame->is_text_node() && !$frame->is_pre()
+        return $frame instanceof Text
+            && !$frame->is_pre()
             && preg_match($wsPattern, $frame->get_text())
             && $validChildOrNull($frame->get_prev_sibling())
             && $validChildOrNull($frame->get_next_sibling());
@@ -273,7 +218,7 @@ class Table extends AbstractFrameDecorator
         foreach ($children as $child) {
             $display = $child->get_style()->display;
 
-            if (in_array($display, self::$ROW_GROUPS, true)) {
+            if (in_array($display, self::ROW_GROUPS, true)) {
                 // Reset anonymous tbody
                 $tbody = null;
 
@@ -314,7 +259,7 @@ class Table extends AbstractFrameDecorator
         foreach ($this->get_children() as $child) {
             $display = $child->get_style()->display;
 
-            if (in_array($display, self::$ROW_GROUPS, true)) {
+            if (in_array($display, self::ROW_GROUPS, true)) {
                 $this->normalizeRowGroup($child);
             }
         }
@@ -395,26 +340,4 @@ class Table extends AbstractFrameDecorator
             $frame->append_child($td);
         }
     }
-
-    //........................................................................
-
-    /**
-     * @deprecated
-     */
-    public function normalise()
-    {
-        $this->normalize();
-    }
-
-    /**
-     * Moves the specified frame and it's corresponding node outside of
-     * the table.
-     *
-     * @deprecated
-     * @param Frame $frame the frame to move
-     */
-    public function move_after(Frame $frame)
-    {
-        $this->get_parent()->insert_child_after($frame, $this);
-    }
 }
diff --git a/library/vendor/dompdf/src/FrameDecorator/TableCell.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php
similarity index 96%
rename from library/vendor/dompdf/src/FrameDecorator/TableCell.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php
index 996e16f00..d382164a3 100644
--- a/library/vendor/dompdf/src/FrameDecorator/TableCell.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -81,7 +80,7 @@ class TableCell extends BlockFrameDecorator
         );
 
         $new_height = $height - $v_space;
-        $style->height = $new_height;
+        $style->set_used("height", $new_height);
 
         if ($new_height > $this->_content_height) {
             $y_offset = 0;
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php
new file mode 100644
index 000000000..ba985c916
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php
@@ -0,0 +1,28 @@
+
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -43,7 +42,9 @@ class TableRowGroup extends AbstractFrameDecorator
         }
 
         // Remove child & all subsequent rows from the cellmap
-        $cellmap = $this->get_parent()->get_cellmap();
+        /** @var Table $parent */
+        $parent = $this->get_parent();
+        $cellmap = $parent->get_cellmap();
         $iter = $child;
 
         while ($iter) {
diff --git a/library/vendor/dompdf/src/FrameDecorator/Text.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Text.php
similarity index 78%
rename from library/vendor/dompdf/src/FrameDecorator/Text.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Text.php
index dcc16a815..9d6693464 100644
--- a/library/vendor/dompdf/src/FrameDecorator/Text.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameDecorator/Text.php
@@ -1,10 +1,7 @@
 
- * @author  Brian Sweeney 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameDecorator;
@@ -16,15 +13,14 @@ use Dompdf\Exception;
 /**
  * Decorates Frame objects for text layout
  *
- * @access  private
  * @package dompdf
  */
 class Text extends AbstractFrameDecorator
 {
     /**
-     * @var float|null
+     * @var float
      */
-    protected $_text_spacing;
+    protected $text_spacing;
 
     /**
      * Text constructor.
@@ -39,23 +35,23 @@ class Text extends AbstractFrameDecorator
         }
 
         parent::__construct($frame, $dompdf);
-        $this->_text_spacing = null;
+        $this->text_spacing = 0.0;
     }
 
     function reset()
     {
         parent::reset();
-        $this->_text_spacing = null;
+        $this->text_spacing = 0.0;
     }
 
     // Accessor methods
 
     /**
-     * @return float|null
+     * @return float
      */
-    function get_text_spacing()
+    public function get_text_spacing(): float
     {
-        return $this->_text_spacing;
+        return $this->text_spacing;
     }
 
     /**
@@ -118,15 +114,10 @@ class Text extends AbstractFrameDecorator
     /**
      * @param float $spacing
      */
-    function set_text_spacing($spacing)
+    public function set_text_spacing(float $spacing): void
     {
-        $style = $this->_frame->get_style();
-
-        $this->_text_spacing = $spacing;
-        $char_spacing = (float)$style->length_in_pt($style->letter_spacing);
-
-        // Re-adjust our width to account for the change in spacing
-        $style->width = $this->_dompdf->getFontMetrics()->getTextWidth($this->get_text(), $style->font_family, $style->font_size, $spacing, $char_spacing);
+        $this->text_spacing = $spacing;
+        $this->recalculate_width();
     }
 
     /**
@@ -134,16 +125,19 @@ class Text extends AbstractFrameDecorator
      *
      * @return float
      */
-    function recalculate_width()
+    public function recalculate_width(): float
     {
+        $fontMetrics = $this->_dompdf->getFontMetrics();
         $style = $this->get_style();
         $text = $this->get_text();
-        $size = $style->font_size;
         $font = $style->font_family;
-        $word_spacing = (float)$style->length_in_pt($style->word_spacing);
-        $char_spacing = (float)$style->length_in_pt($style->letter_spacing);
+        $size = $style->font_size;
+        $word_spacing = $this->text_spacing + $style->word_spacing;
+        $letter_spacing = $style->letter_spacing;
+        $text_width = $fontMetrics->getTextWidth($text, $font, $size, $word_spacing, $letter_spacing);
 
-        return $style->width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $char_spacing);
+        $style->set_used("width", $text_width);
+        return $text_width;
     }
 
     // Text manipulation methods
diff --git a/library/vendor/dompdf/src/FrameReflower/AbstractFrameReflower.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php
similarity index 92%
rename from library/vendor/dompdf/src/FrameReflower/AbstractFrameReflower.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php
index 75d5ebbe8..fa0cc511b 100644
--- a/library/vendor/dompdf/src/FrameReflower/AbstractFrameReflower.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -57,10 +56,6 @@ abstract class AbstractFrameReflower
         $this->_min_max_cache = null;
     }
 
-    function dispose()
-    {
-    }
-
     /**
      * @return Dompdf
      */
@@ -87,7 +82,7 @@ abstract class AbstractFrameReflower
 
         switch ($style->position) {
             case "absolute":
-                $parent = $frame->find_positionned_parent();
+                $parent = $frame->find_positioned_parent();
                 if ($parent !== $frame->get_root()) {
                     $parent_style = $parent->get_style();
                     $parent_padding_box = $parent->get_padding_box();
@@ -124,7 +119,7 @@ abstract class AbstractFrameReflower
      * Collapse frames margins
      * http://www.w3.org/TR/CSS21/box.html#collapsing-margins
      */
-    protected function _collapse_margins()
+    protected function _collapse_margins(): void
     {
         $frame = $this->_frame;
 
@@ -143,13 +138,13 @@ abstract class AbstractFrameReflower
 
         // Handle 'auto' values
         if ($t === "auto") {
-            $style->margin_top = 0;
-            $t = 0;
+            $style->set_used("margin_top", 0.0);
+            $t = 0.0;
         }
 
         if ($b === "auto") {
-            $style->margin_bottom = 0;
-            $b = 0;
+            $style->set_used("margin_bottom", 0.0);
+            $b = 0.0;
         }
 
         // Collapse vertical margins:
@@ -171,9 +166,9 @@ abstract class AbstractFrameReflower
             $n_style = $n->get_style();
             $n_t = (float)$n_style->length_in_pt($n_style->margin_top, $cb["w"]);
 
-            $b = $this->_get_collapsed_margin_length($b, $n_t);
-            $style->margin_bottom = $b;
-            $n_style->margin_top = 0;
+            $b = $this->get_collapsed_margin_length($b, $n_t);
+            $style->set_used("margin_bottom", $b);
+            $n_style->set_used("margin_top", 0.0);
         }
 
         // Collapse our first child's margin, if there is no border or padding
@@ -197,9 +192,9 @@ abstract class AbstractFrameReflower
                 $f_style = $f->get_style();
                 $f_t = (float)$f_style->length_in_pt($f_style->margin_top, $cb["w"]);
 
-                $t = $this->_get_collapsed_margin_length($t, $f_t);
-                $style->margin_top = $t;
-                $f_style->margin_top = 0;
+                $t = $this->get_collapsed_margin_length($t, $f_t);
+                $style->set_used("margin_top", $t);
+                $f_style->set_used("margin_top", 0.0);
             }
         }
 
@@ -224,9 +219,9 @@ abstract class AbstractFrameReflower
                 $l_style = $l->get_style();
                 $l_b = (float)$l_style->length_in_pt($l_style->margin_bottom, $cb["w"]);
 
-                $b = $this->_get_collapsed_margin_length($b, $l_b);
-                $style->margin_bottom = $b;
-                $l_style->margin_bottom = 0;
+                $b = $this->get_collapsed_margin_length($b, $l_b);
+                $style->set_used("margin_bottom", $b);
+                $l_style->set_used("margin_bottom", 0.0);
             }
         }
     }
@@ -236,21 +231,22 @@ abstract class AbstractFrameReflower
      *
      * See http://www.w3.org/TR/CSS21/box.html#collapsing-margins.
      *
-     * @param float $length1
-     * @param float $length2
+     * @param float $l1
+     * @param float $l2
+     *
      * @return float
      */
-    private function _get_collapsed_margin_length($length1, $length2)
+    private function get_collapsed_margin_length(float $l1, float $l2): float
     {
-        if ($length1 < 0 && $length2 < 0) {
-            return min($length1, $length2); // min(x, y) = - max(abs(x), abs(y)), if x < 0 && y < 0
+        if ($l1 < 0 && $l2 < 0) {
+            return min($l1, $l2); // min(x, y) = - max(abs(x), abs(y)), if x < 0 && y < 0
         }
         
-        if ($length1 < 0 || $length2 < 0) {
-            return $length1 + $length2; // x + y = x - abs(y), if y < 0
+        if ($l1 < 0 || $l2 < 0) {
+            return $l1 + $l2; // x + y = x - abs(y), if y < 0
         }
         
-        return max($length1, $length2);
+        return max($l1, $l2);
     }
 
     /**
@@ -275,16 +271,16 @@ abstract class AbstractFrameReflower
             if ($left === "auto" && $right === "auto") {
                 $left = 0;
             } elseif ($left === "auto") {
-                $left = -(float) $right;
+                $left = -$right;
             }
 
             if ($top === "auto" && $bottom === "auto") {
                 $top = 0;
             } elseif ($top === "auto") {
-                $top = -(float) $bottom;
+                $top = -$bottom;
             }
 
-            $frame->move((float) $left, (float) $top);
+            $frame->move($left, $top);
         }
     }
 
@@ -308,7 +304,7 @@ abstract class AbstractFrameReflower
         $style = $this->_frame->get_style();
         $min_width = $style->min_width;
 
-        return $min_width !== "auto" && $min_width !== "none"
+        return $min_width !== "auto"
             ? $style->length_in_pt($min_width, $cbw ?? 0)
             : 0.0;
     }
@@ -328,7 +324,7 @@ abstract class AbstractFrameReflower
         $style = $this->_frame->get_style();
         $max_width = $style->max_width;
 
-        return $max_width !== "none" && $max_width !== "auto"
+        return $max_width !== "none"
             ? $style->length_in_pt($max_width, $cbw ?? INF)
             : INF;
     }
@@ -348,7 +344,7 @@ abstract class AbstractFrameReflower
         $style = $this->_frame->get_style();
         $min_height = $style->min_height;
 
-        return $min_height !== "auto" && $min_height !== "none"
+        return $min_height !== "auto"
             ? $style->length_in_pt($min_height, $cbh ?? 0)
             : 0.0;
     }
@@ -368,7 +364,7 @@ abstract class AbstractFrameReflower
         $style = $this->_frame->get_style();
         $max_height = $style->max_height;
 
-        return $max_height !== "none" && $max_height !== "auto"
+        return $max_height !== "none"
             ? $style->length_in_pt($style->max_height, $cbh ?? INF)
             : INF;
     }
@@ -388,12 +384,13 @@ abstract class AbstractFrameReflower
         $low = [];
         $high = [];
 
-        for ($iter = $this->_frame->get_children()->getIterator(); $iter->valid(); $iter->next()) {
+        for ($iter = $this->_frame->get_children(); $iter->valid(); $iter->next()) {
             $inline_min = 0;
             $inline_max = 0;
 
             // Add all adjacent inline widths together to calculate max width
             while ($iter->valid() && ($iter->current()->is_inline_level() || $iter->current()->get_style()->display === "-dompdf-image")) {
+                /** @var AbstractFrameDecorator */
                 $child = $iter->current();
                 $child->get_reflower()->_set_content();
                 $minmax = $child->get_min_max_width();
@@ -417,6 +414,7 @@ abstract class AbstractFrameReflower
 
             // Skip children with absolute position
             if ($iter->valid() && !$iter->current()->is_absolute()) {
+                /** @var AbstractFrameDecorator */
                 $child = $iter->current();
                 $child->get_reflower()->_set_content();
                 list($low[], $high[]) = $child->get_min_max_width();
@@ -549,7 +547,6 @@ abstract class AbstractFrameReflower
      */
     protected function _parse_content(): string
     {
-        // The `content` property will be returned parsed into its components
         $style = $this->_frame->get_style();
         $content = $style->content;
 
diff --git a/library/vendor/dompdf/src/FrameReflower/Block.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Block.php
similarity index 96%
rename from library/vendor/dompdf/src/FrameReflower/Block.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Block.php
index 9b5daccd2..f9e50a678 100644
--- a/library/vendor/dompdf/src/FrameReflower/Block.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Block.php
@@ -1,14 +1,13 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
 
 use Dompdf\Frame;
+use Dompdf\FrameDecorator\AbstractFrameDecorator;
 use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
 use Dompdf\FrameDecorator\TableCell as TableCellFrameDecorator;
 use Dompdf\FrameDecorator\Text as TextFrameDecorator;
@@ -27,6 +26,8 @@ class Block extends AbstractFrameReflower
     const MIN_JUSTIFY_WIDTH = 0.80;
 
     /**
+     * Frame for this reflower
+     *
      * @var BlockFrameDecorator
      */
     protected $_frame;
@@ -603,7 +604,7 @@ class Block extends AbstractFrameReflower
                     $imageHeightDiff = $height * 0.8 - $marginHeight;
 
                     $align = $frame->get_style()->vertical_align;
-                    if (in_array($align, Style::$vertical_align_keywords, true)) {
+                    if (in_array($align, Style::VERTICAL_ALIGN_KEYWORDS, true)) {
                         switch ($align) {
                             case "middle":
                                 $y_offset = $imageHeightDiff / 2;
@@ -644,7 +645,7 @@ class Block extends AbstractFrameReflower
                     } else {
                         $align = $parent->get_style()->vertical_align;
                     }
-                    if (in_array($align, Style::$vertical_align_keywords, true)) {
+                    if (in_array($align, Style::VERTICAL_ALIGN_KEYWORDS, true)) {
                         switch ($align) {
                             case "middle":
                                 $y_offset = ($height * 0.8 - $baseline) / 2;
@@ -685,9 +686,9 @@ class Block extends AbstractFrameReflower
     }
 
     /**
-     * @param Frame $child
+     * @param AbstractFrameDecorator $child
      */
-    function process_clear(Frame $child)
+    function process_clear(AbstractFrameDecorator $child)
     {
         $child_style = $child->get_style();
         $root = $this->_frame->get_root();
@@ -719,11 +720,11 @@ class Block extends AbstractFrameReflower
     }
 
     /**
-     * @param Frame $child
+     * @param AbstractFrameDecorator $child
      * @param float $cb_x
      * @param float $cb_w
      */
-    function process_float(Frame $child, $cb_x, $cb_w)
+    function process_float(AbstractFrameDecorator $child, $cb_x, $cb_w)
     {
         $child_style = $child->get_style();
         $root = $this->_frame->get_root();
@@ -808,14 +809,14 @@ class Block extends AbstractFrameReflower
 
         // Determine the constraints imposed by this frame: calculate the width
         // of the content area:
-        list($width, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width();
+        [$width, $margin_left, $margin_right, $left, $right] = $this->_calculate_restricted_width();
 
         // Store the calculated properties
-        $style->width = $width;
-        $style->margin_left = $left_margin;
-        $style->margin_right = $right_margin;
-        $style->left = $left;
-        $style->right = $right;
+        $style->set_used("width", $width);
+        $style->set_used("margin_left", $margin_left);
+        $style->set_used("margin_right", $margin_right);
+        $style->set_used("left", $left);
+        $style->set_used("right", $right);
 
         $margin_top = $style->length_in_pt($style->margin_top, $cb["w"]);
         $margin_bottom = $style->length_in_pt($style->margin_bottom, $cb["w"]);
@@ -825,7 +826,7 @@ class Block extends AbstractFrameReflower
 
         // Update the position
         $this->_frame->position();
-        list($x, $y) = $this->_frame->get_position();
+        [$x, $y] = $this->_frame->get_position();
 
         // Adjust the first line based on the text-indent property
         $indent = (float)$style->length_in_pt($style->text_indent, $cb["w"]);
@@ -843,7 +844,7 @@ class Block extends AbstractFrameReflower
             $style->padding_bottom
         ], $cb["w"]);
 
-        $cb_x = $x + (float)$left_margin + (float)$style->length_in_pt([$style->border_left_width,
+        $cb_x = $x + (float)$margin_left + (float)$style->length_in_pt([$style->border_left_width,
                 $style->padding_left], $cb["w"]);
 
         $cb_y = $y + $top;
@@ -884,12 +885,13 @@ class Block extends AbstractFrameReflower
         }
 
         // Determine our height
-        list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height();
-        $style->height = $height;
-        $style->margin_top = $margin_top;
-        $style->margin_bottom = $margin_bottom;
-        $style->top = $top;
-        $style->bottom = $bottom;
+        [$height, $margin_top, $margin_bottom, $top, $bottom] = $this->_calculate_restricted_height();
+
+        $style->set_used("height", $height);
+        $style->set_used("margin_top", $margin_top);
+        $style->set_used("margin_bottom", $margin_bottom);
+        $style->set_used("top", $top);
+        $style->set_used("bottom", $bottom);
 
         if ($this->_frame->is_absolute()) {
             if ($auto_top) {
diff --git a/library/vendor/dompdf/src/FrameReflower/Image.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Image.php
similarity index 93%
rename from library/vendor/dompdf/src/FrameReflower/Image.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Image.php
index 77b1d4925..eae34087b 100644
--- a/library/vendor/dompdf/src/FrameReflower/Image.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Image.php
@@ -1,9 +1,7 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -69,7 +67,9 @@ class Image extends AbstractFrameReflower
         [$width] = $this->calculate_size(null, null);
         $min_width = $this->resolve_min_width(null);
         $percent_width = Helpers::is_percent($style->width)
-            || Helpers::is_percent($style->max_width);
+            || Helpers::is_percent($style->max_width)
+            || ($style->width === "auto"
+                && (Helpers::is_percent($style->height) || Helpers::is_percent($style->max_height)));
 
         // Use the specified min width as minimum when width or max width depend
         // on the containing block and cannot be resolved yet. This mimics
@@ -186,8 +186,8 @@ class Image extends AbstractFrameReflower
             print $width . " " . $height . ";";
         }
 
-        $style->width = $width;
-        $style->height = $height;
+        $style->set_used("width", $width);
+        $style->set_used("height", $height);
     }
 
     protected function resolve_margins(): void
@@ -198,16 +198,16 @@ class Image extends AbstractFrameReflower
         $style = $this->_frame->get_style();
 
         if ($style->margin_left === "auto") {
-            $style->margin_left = 0;
+            $style->set_used("margin_left", 0.0);
         }
         if ($style->margin_right === "auto") {
-            $style->margin_right = 0;
+            $style->set_used("margin_right", 0.0);
         }
         if ($style->margin_top === "auto") {
-            $style->margin_top = 0;
+            $style->set_used("margin_top", 0.0);
         }
         if ($style->margin_bottom === "auto") {
-            $style->margin_bottom = 0;
+            $style->set_used("margin_bottom", 0.0);
         }
     }
 }
diff --git a/library/vendor/dompdf/src/FrameReflower/Inline.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Inline.php
similarity index 87%
rename from library/vendor/dompdf/src/FrameReflower/Inline.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Inline.php
index faf787934..34a66860d 100644
--- a/library/vendor/dompdf/src/FrameReflower/Inline.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Inline.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -43,7 +42,7 @@ class Inline extends AbstractFrameReflower
         $style = $frame->get_style();
 
         // Resolve width, so the margin width can be checked
-        $style->width = 0;
+        $style->set_used("width", 0.0);
 
         $cb = $frame->get_containing_block();
         $line = $block->get_current_line_box();
@@ -97,16 +96,16 @@ class Inline extends AbstractFrameReflower
         // https://www.w3.org/TR/CSS21/visudet.html#inline-width
         // https://www.w3.org/TR/CSS21/visudet.html#inline-non-replaced
         if ($style->margin_left === "auto") {
-            $style->margin_left = 0;
+            $style->set_used("margin_left", 0.0);
         }
         if ($style->margin_right === "auto") {
-            $style->margin_right = 0;
+            $style->set_used("margin_right", 0.0);
         }
         if ($style->margin_top === "auto") {
-            $style->margin_top = 0;
+            $style->set_used("margin_top", 0.0);
         }
         if ($style->margin_bottom === "auto") {
-            $style->margin_bottom = 0;
+            $style->set_used("margin_bottom", 0.0);
         }
 
         // Handle line breaks
@@ -140,14 +139,18 @@ class Inline extends AbstractFrameReflower
             $f_style = $f->get_style();
             $f_style->margin_left = $style->margin_left;
             $f_style->padding_left = $style->padding_left;
-            $f_style->border_left = $style->border_left;
+            $f_style->border_left_width = $style->border_left_width;
+            $f_style->border_left_style = $style->border_left_style;
+            $f_style->border_left_color = $style->border_left_color;
         }
 
         if (($l = $frame->get_last_child()) && $l instanceof TextFrameDecorator) {
             $l_style = $l->get_style();
             $l_style->margin_right = $style->margin_right;
             $l_style->padding_right = $style->padding_right;
-            $l_style->border_right = $style->border_right;
+            $l_style->border_right_width = $style->border_right_width;
+            $l_style->border_right_style = $style->border_right_style;
+            $l_style->border_right_color = $style->border_right_color;
         }
 
         $cb = $frame->get_containing_block();
@@ -165,6 +168,10 @@ class Inline extends AbstractFrameReflower
             }
         }
 
+        if (!$frame->get_first_child()) {
+            return;
+        }
+
         // Assume the position of the first child
         [$x, $y] = $frame->get_first_child()->get_position();
         $frame->set_position($x, $y);
diff --git a/library/vendor/dompdf/src/FrameReflower/ListBullet.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php
similarity index 88%
rename from library/vendor/dompdf/src/FrameReflower/ListBullet.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php
index 6eff48533..f735bae16 100644
--- a/library/vendor/dompdf/src/FrameReflower/ListBullet.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -36,7 +35,7 @@ class ListBullet extends AbstractFrameReflower
         $frame = $this->_frame;
         $style = $frame->get_style();
 
-        $style->width = $frame->get_width();
+        $style->set_used("width", $frame->get_width());
         $frame->position();
 
         if ($style->list_style_position === "inside") {
diff --git a/library/vendor/dompdf/src/FrameReflower/NullFrameReflower.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php
similarity index 87%
rename from library/vendor/dompdf/src/FrameReflower/NullFrameReflower.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php
index 8bdb0f1ad..8d7e5583c 100644
--- a/library/vendor/dompdf/src/FrameReflower/NullFrameReflower.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\FrameReflower;
 
 use Dompdf\Frame;
diff --git a/library/vendor/dompdf/src/FrameReflower/Page.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Page.php
similarity index 86%
rename from library/vendor/dompdf/src/FrameReflower/Page.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Page.php
index 5d81e1530..923865b53 100644
--- a/library/vendor/dompdf/src/FrameReflower/Page.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Page.php
@@ -1,9 +1,7 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -95,18 +93,20 @@ class Page extends AbstractFrameReflower
      */
     function reflow(BlockFrameDecorator $block = null)
     {
+        /** @var PageFrameDecorator $frame */
+        $frame = $this->_frame;
+        $child = $frame->get_first_child();
         $fixed_children = [];
         $prev_child = null;
-        $child = $this->_frame->get_first_child();
         $current_page = 0;
 
         while ($child) {
-            $this->apply_page_style($this->_frame, $current_page + 1);
+            $this->apply_page_style($frame, $current_page + 1);
 
-            $style = $this->_frame->get_style();
+            $style = $frame->get_style();
 
             // Pages are only concerned with margins
-            $cb = $this->_frame->get_containing_block();
+            $cb = $frame->get_containing_block();
             $left = (float)$style->length_in_pt($style->margin_left, $cb["w"]);
             $right = (float)$style->length_in_pt($style->margin_right, $cb["w"]);
             $top = (float)$style->length_in_pt($style->margin_top, $cb["h"]);
@@ -119,8 +119,7 @@ class Page extends AbstractFrameReflower
 
             // Only if it's the first page, we save the nodes with a fixed position
             if ($current_page == 0) {
-                $children = $child->get_children();
-                foreach ($children as $onechild) {
+                foreach ($child->get_children() as $onechild) {
                     if ($onechild->get_style()->position === "fixed") {
                         $fixed_children[] = $onechild->deep_copy();
                     }
@@ -147,13 +146,13 @@ class Page extends AbstractFrameReflower
             $this->_check_callbacks("begin_page_render", $child);
 
             // Render the page
-            $this->_frame->get_renderer()->render($child);
+            $frame->get_renderer()->render($child);
 
             // Check for end render callback
             $this->_check_callbacks("end_page_render", $child);
 
             if ($next_child) {
-                $this->_frame->next_page();
+                $frame->next_page();
             }
 
             // Wait to dispose of all frames on the previous page
@@ -182,20 +181,18 @@ class Page extends AbstractFrameReflower
     protected function _check_callbacks(string $event, Frame $frame): void
     {
         if (!isset($this->_callbacks)) {
-            $dompdf = $this->_frame->get_dompdf();
+            $dompdf = $this->get_dompdf();
             $this->_callbacks = $dompdf->getCallbacks();
             $this->_canvas = $dompdf->getCanvas();
         }
 
         if (isset($this->_callbacks[$event])) {
             $fs = $this->_callbacks[$event];
-            $info = [
-                0 => $this->_canvas, "canvas" => $this->_canvas,
-                1 => $frame,         "frame"  => $frame,
-            ];
+            $canvas = $this->_canvas;
+            $fontMetrics = $this->get_dompdf()->getFontMetrics();
 
             foreach ($fs as $f) {
-                $f($info);
+                $f($frame, $canvas, $fontMetrics);
             }
         }
     }
diff --git a/library/vendor/dompdf/src/FrameReflower/Table.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Table.php
similarity index 89%
rename from library/vendor/dompdf/src/FrameReflower/Table.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Table.php
index 24aeb3500..5173738e9 100644
--- a/library/vendor/dompdf/src/FrameReflower/Table.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Table.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -14,7 +13,6 @@ use Dompdf\Helpers;
 /**
  * Reflows tables
  *
- * @access  private
  * @package dompdf
  */
 class Table extends AbstractFrameReflower
@@ -93,7 +91,7 @@ class Table extends AbstractFrameReflower
         } else {
             if ($max_width + $delta < $cb["w"]) {
                 $width = $max_width;
-            } else if ($cb["w"] - $delta > $min_width) {
+            } elseif ($cb["w"] - $delta > $min_width) {
                 $width = $cb["w"] - $delta;
             } else {
                 $width = $min_width;
@@ -106,7 +104,7 @@ class Table extends AbstractFrameReflower
         }
 
         // Store our resolved width
-        $style->width = $width;
+        $style->set_used("width", $width);
 
         $cellmap = $this->_frame->get_cellmap();
 
@@ -116,8 +114,8 @@ class Table extends AbstractFrameReflower
 
         // If the whole table fits on the page, then assign each column it's max width
         if ($width == $max_width) {
-            foreach (array_keys($columns) as $i) {
-                $cellmap->set_column_width($i, $columns[$i]["max-width"]);
+            foreach ($columns as $i => $col) {
+                $cellmap->set_column_width($i, $col["max-width"]);
             }
 
             return;
@@ -179,10 +177,9 @@ class Table extends AbstractFrameReflower
                 $increment = $width - $absolute_used;
 
                 foreach ($absolute as $i) {
-                    $min = $columns[$i]["min-width"];
-                    $abs = $columns[$i]["absolute"];
+                    $abs = $columns[$i]["min-width"];
                     $f = $absolute_used > 0 ? $abs / $absolute_used : 1 / count($absolute);
-                    $w = $min + $increment * $f;
+                    $w = $abs + $increment * $f;
                     $cellmap->set_column_width($i, $w);
                 }
                 return;
@@ -246,8 +243,8 @@ class Table extends AbstractFrameReflower
         } else {
             // We are over-constrained:
             // Each column gets its minimum width
-            foreach (array_keys($columns) as $i) {
-                $cellmap->set_column_width($i, $columns[$i]["min-width"]);
+            foreach ($columns as $i => $col) {
+                $cellmap->set_column_width($i, $col["min-width"]);
             }
         }
     }
@@ -341,15 +338,14 @@ class Table extends AbstractFrameReflower
         // border-spacing to the table as padding.  The other half is added to
         // the cells themselves.
         if ($style->border_collapse === "separate") {
-            list($h, $v) = $style->border_spacing;
+            [$h, $v] = $style->border_spacing;
+            $v = $v / 2;
+            $h = $h / 2;
 
-            $v = (float)$style->length_in_pt($v) / 2;
-            $h = (float)$style->length_in_pt($h) / 2;
-
-            $style->padding_left = (float)$style->length_in_pt($style->padding_left, $cb["w"]) + $h;
-            $style->padding_right = (float)$style->length_in_pt($style->padding_right, $cb["w"]) + $h;
-            $style->padding_top = (float)$style->length_in_pt($style->padding_top, $cb["w"]) + $v;
-            $style->padding_bottom = (float)$style->length_in_pt($style->padding_bottom, $cb["w"]) + $v;
+            $style->set_used("padding_left", (float)$style->length_in_pt($style->padding_left, $cb["w"]) + $h);
+            $style->set_used("padding_right", (float)$style->length_in_pt($style->padding_right, $cb["w"]) + $h);
+            $style->set_used("padding_top", (float)$style->length_in_pt($style->padding_top, $cb["w"]) + $v);
+            $style->set_used("padding_bottom", (float)$style->length_in_pt($style->padding_bottom, $cb["w"]) + $v);
         }
 
         $this->_assign_widths();
@@ -378,11 +374,11 @@ class Table extends AbstractFrameReflower
             }
         }
 
-        $style->margin_left = $left;
-        $style->margin_right = $right;
+        $style->set_used("margin_left", $left);
+        $style->set_used("margin_right", $right);
 
         $frame->position();
-        list($x, $y) = $frame->get_position();
+        [$x, $y] = $frame->get_position();
 
         // Determine the content edge
         $offset_x = (float)$left + (float)$style->length_in_pt([
@@ -435,7 +431,7 @@ class Table extends AbstractFrameReflower
         }
 
         // Assign heights to our cells:
-        $style->height = $this->_calculate_height();
+        $style->set_used("height", $this->_calculate_height());
 
         $page->table_reflow_end();
 
@@ -478,19 +474,19 @@ class Table extends AbstractFrameReflower
         $this->_state["auto"] = [];
 
         $columns =& $cellmap->get_columns();
-        foreach (array_keys($columns) as $i) {
-            $this->_state["min_width"] += $columns[$i]["min-width"];
-            $this->_state["max_width"] += $columns[$i]["max-width"];
+        foreach ($columns as $i => $col) {
+            $this->_state["min_width"] += $col["min-width"];
+            $this->_state["max_width"] += $col["max-width"];
 
-            if ($columns[$i]["absolute"] > 0) {
+            if ($col["absolute"] > 0) {
                 $this->_state["absolute"][] = $i;
-                $this->_state["absolute_used"] += $columns[$i]["absolute"];
-            } else if ($columns[$i]["percent"] > 0) {
+                $this->_state["absolute_used"] += $col["min-width"];
+            } elseif ($col["percent"] > 0) {
                 $this->_state["percent"][] = $i;
-                $this->_state["percent_used"] += $columns[$i]["percent"];
+                $this->_state["percent_used"] += $col["percent"];
             } else {
                 $this->_state["auto"][] = $i;
-                $this->_state["auto_min"] += $columns[$i]["min-width"];
+                $this->_state["auto_min"] += $col["min-width"];
             }
         }
 
diff --git a/library/vendor/dompdf/src/FrameReflower/TableCell.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableCell.php
similarity index 91%
rename from library/vendor/dompdf/src/FrameReflower/TableCell.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableCell.php
index aae338028..f5ce35da6 100644
--- a/library/vendor/dompdf/src/FrameReflower/TableCell.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableCell.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -73,7 +72,8 @@ class TableCell extends Block
                 $style->border_bottom_width],
             $h);
 
-        $style->width = $cb_w = $w - $left_space - $right_space;
+        $cb_w = $w - $left_space - $right_space;
+        $style->set_used("width", $cb_w);
 
         $content_x = $x + $left_space;
         $content_y = $line_y = $y + $top_space;
@@ -103,9 +103,12 @@ class TableCell extends Block
         // Determine our height
         $style_height = (float)$style->length_in_pt($style->height, $h);
 
-        $this->_frame->set_content_height($this->_calculate_content_height());
+        /** @var FrameDecorator\TableCell */
+        $frame = $this->_frame;
 
-        $height = max($style_height, (float)$this->_frame->get_content_height());
+        $frame->set_content_height($this->_calculate_content_height());
+
+        $height = max($style_height, (float)$frame->get_content_height());
 
         // Let the cellmap know our height
         $cell_height = $height / count($cells["rows"]);
@@ -118,7 +121,8 @@ class TableCell extends Block
             $cellmap->set_row_height($i, $cell_height);
         }
 
-        $style->height = $height;
+        $style->set_used("height", $height);
+
         $this->_text_align();
         $this->vertical_align();
 
diff --git a/library/vendor/dompdf/src/FrameReflower/TableRow.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableRow.php
similarity index 89%
rename from library/vendor/dompdf/src/FrameReflower/TableRow.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableRow.php
index ef9dced06..f84c1258b 100644
--- a/library/vendor/dompdf/src/FrameReflower/TableRow.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableRow.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -67,8 +66,8 @@ class TableRow extends AbstractFrameReflower
 
         $table = TableFrameDecorator::find_parent_table($this->_frame);
         $cellmap = $table->get_cellmap();
-        $style->width = $cellmap->get_frame_width($this->_frame);
-        $style->height = $cellmap->get_frame_height($this->_frame);
+        $style->set_used("width", $cellmap->get_frame_width($this->_frame));
+        $style->set_used("height", $cellmap->get_frame_height($this->_frame));
 
         $this->_frame->set_position($cellmap->get_frame_position($this->_frame));
     }
diff --git a/library/vendor/dompdf/src/FrameReflower/TableRowGroup.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php
similarity index 89%
rename from library/vendor/dompdf/src/FrameReflower/TableRowGroup.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php
index 662be1b3a..c8b19aa53 100644
--- a/library/vendor/dompdf/src/FrameReflower/TableRowGroup.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -64,8 +63,8 @@ class TableRowGroup extends AbstractFrameReflower
             return;
         }
 
-        $style->width = $cellmap->get_frame_width($frame);
-        $style->height = $cellmap->get_frame_height($frame);
+        $style->set_used("width", $cellmap->get_frame_width($frame));
+        $style->set_used("height", $cellmap->get_frame_height($frame));
 
         $frame->set_position($cellmap->get_frame_position($frame));
     }
diff --git a/library/vendor/dompdf/src/FrameReflower/Text.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Text.php
similarity index 90%
rename from library/vendor/dompdf/src/FrameReflower/Text.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Text.php
index ddfd7a721..57439ae70 100644
--- a/library/vendor/dompdf/src/FrameReflower/Text.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/FrameReflower/Text.php
@@ -1,9 +1,7 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\FrameReflower;
@@ -45,6 +43,8 @@ class Text extends AbstractFrameReflower
     public static $_wordbreak_pattern = '/([^\S\xA0\x{202F}\x{2007}\n]+|\R|\-+|\xAD+)/u';
 
     /**
+     * Frame for this reflower
+     *
      * @var TextFrameDecorator
      */
     protected $_frame;
@@ -123,31 +123,31 @@ class Text extends AbstractFrameReflower
     }
 
     /**
-     * @param string $text
+     * @param string              $text
      * @param BlockFrameDecorator $block
+     * @param bool                $nowrap
+     *
      * @return bool|int
      */
-    protected function line_break(string $text, BlockFrameDecorator $block)
+    protected function line_break(string $text, BlockFrameDecorator $block, bool $nowrap = false)
     {
+        $fontMetrics = $this->getFontMetrics();
         $frame = $this->_frame;
         $style = $frame->get_style();
-        $size = $style->font_size;
         $font = $style->font_family;
-        $current_line = $block->get_current_line_box();
-        $fontMetrics = $this->getFontMetrics();
+        $size = $style->font_size;
+        $word_spacing = $style->word_spacing;
+        $letter_spacing = $style->letter_spacing;
 
         // Determine the available width
+        $current_line = $block->get_current_line_box();
         $line_width = $frame->get_containing_block("w");
         $current_line_width = $current_line->left + $current_line->w + $current_line->right;
         $available_width = $line_width - $current_line_width;
 
-        // Account for word and letter spacing
-        $word_spacing = (float) $style->length_in_pt($style->word_spacing);
-        $char_spacing = (float) $style->length_in_pt($style->letter_spacing);
-
         // Determine the frame width including margin, padding & border
         $visible_text = preg_replace('/\xAD/u', "", $text);
-        $text_width = $fontMetrics->getTextWidth($visible_text, $font, $size, $word_spacing, $char_spacing);
+        $text_width = $fontMetrics->getTextWidth($visible_text, $font, $size, $word_spacing, $letter_spacing);
         $mbp_width = (float) $style->length_in_pt([
             $style->margin_left,
             $style->border_left_width,
@@ -162,15 +162,19 @@ class Text extends AbstractFrameReflower
             return false;
         }
 
+        if ($nowrap) {
+            return $current_line_width == 0 ? false : 0;
+        }
+
         // Split the text into words
         $words = preg_split(self::$_wordbreak_pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE);
         $wc = count($words);
 
         // Determine the split point
-        $width = 0;
+        $width = 0.0;
         $str = "";
 
-        $space_width = $fontMetrics->getTextWidth(" ", $font, $size, $word_spacing, $char_spacing);
+        $space_width = $fontMetrics->getTextWidth(" ", $font, $size, $word_spacing, $letter_spacing);
         $shy_width = $fontMetrics->getTextWidth(self::SOFT_HYPHEN, $font, $size);
 
         // @todo support 
@@ -180,7 +184,7 @@ class Text extends AbstractFrameReflower
             // handle that for now
             $sep = $words[$i + 1] ?? "";
             $word = $sep === " " ? $words[$i] : $words[$i] . $sep;
-            $word_width = $fontMetrics->getTextWidth($word, $font, $size, $word_spacing, $char_spacing);
+            $word_width = $fontMetrics->getTextWidth($word, $font, $size, $word_spacing, $letter_spacing);
             $used_width = $width + $word_width + $mbp_width;
 
             if (Helpers::lengthGreater($used_width, $available_width)) {
@@ -210,7 +214,7 @@ class Text extends AbstractFrameReflower
 
         // The first word has overflowed. Force it onto the line, or as many
         // characters as fit if breaking words is allowed
-        if ($current_line_width == 0 && $width == 0) {
+        if ($current_line_width == 0 && $width === 0.0) {
             if ($sep === " ") {
                 $word .= $sep;
             }
@@ -224,7 +228,7 @@ class Text extends AbstractFrameReflower
 
                 for ($j = 0; $j < mb_strlen($word); $j++) {
                     $c = mb_substr($word, $j, 1);
-                    $w = $fontMetrics->getTextWidth($s . $c, $font, $size, $word_spacing, $char_spacing);
+                    $w = $fontMetrics->getTextWidth($s . $c, $font, $size, $word_spacing, $letter_spacing);
 
                     if (Helpers::lengthGreater($w, $available_width)) {
                         break;
@@ -278,36 +282,31 @@ class Text extends AbstractFrameReflower
         // elements in case white space is collapsed
         if ($text === "") {
             $frame->set_text("");
-            $style->width = 0.0;
+            $style->set_used("width", 0.0);
             return null;
         }
 
         // Determine the next line break
         // http://www.w3.org/TR/CSS21/text.html#propdef-white-space
-        switch ($style->white_space) {
+        $white_space = $style->white_space;
+        $nowrap = $white_space === "nowrap" || $white_space === "pre";
+
+        switch ($white_space) {
             default:
             case "normal":
-                $split = $this->line_break($text, $block);
-                $add_line = false;
-                break;
-
             case "nowrap":
-                $split = false;
+                $split = $this->line_break($text, $block, $nowrap);
                 $add_line = false;
                 break;
 
             case "pre":
-                $split = $this->newline_break($text);
-                $add_line = $split !== false;
-                break;
-
             case "pre-line":
             case "pre-wrap":
                 $hard_split = $this->newline_break($text);
                 $first_line = $hard_split !== false
                     ? mb_substr($text, 0, $hard_split)
                     : $text;
-                $soft_split = $this->line_break($first_line, $block);
+                $soft_split = $this->line_break($first_line, $block, $nowrap);
 
                 $split = $soft_split !== false ? $soft_split : $hard_split;
                 $add_line = $hard_split !== false;
@@ -391,7 +390,8 @@ class Text extends AbstractFrameReflower
         $style = $frame->get_style();
         $size = $style->font_size;
         $font = $style->font_family;
-        $style->height = $this->getFontMetrics()->getFontHeight($font, $size);
+        $font_height = $this->getFontMetrics()->getFontHeight($font, $size);
+        $style->set_used("height", $font_height);
 
         // Handle text transform and white space
         $text = $this->pre_process_text($frame->get_text());
@@ -457,12 +457,14 @@ class Text extends AbstractFrameReflower
 
     public function get_min_max_width(): array
     {
+        $fontMetrics = $this->getFontMetrics();
         $frame = $this->_frame;
         $style = $frame->get_style();
-        $size = $style->font_size;
-        $font = $style->font_family;
         $text = $frame->get_text();
-        $fontMetrics = $this->getFontMetrics();
+        $font = $style->font_family;
+        $size = $style->font_size;
+        $word_spacing = $style->word_spacing;
+        $letter_spacing = $style->letter_spacing;
 
         // Handle text transform and white space
         $text = $this->pre_process_text($frame->get_text());
@@ -498,10 +500,6 @@ class Text extends AbstractFrameReflower
         // Strip soft hyphens for max-line-width calculations
         $visible_text = preg_replace('/\xAD/u', "", $text);
 
-        // Account for word and letter spacing
-        $word_spacing = (float) $style->length_in_pt($style->word_spacing);
-        $char_spacing = (float) $style->length_in_pt($style->letter_spacing);
-
         // Determine minimum text width
         switch ($style->white_space) {
             default:
@@ -515,16 +513,16 @@ class Text extends AbstractFrameReflower
                 // https://www.w3.org/TR/css-text-3/#overflow-wrap-property
                 if ($style->overflow_wrap === "anywhere") {
                     $char = mb_substr($visible_text, 0, 1);
-                    $min = $fontMetrics->getTextWidth($char, $font, $size, $word_spacing, $char_spacing);
+                    $min = $fontMetrics->getTextWidth($char, $font, $size, $word_spacing, $letter_spacing);
                 } else {
                     // Find the longest word
                     $words = preg_split(self::$_wordbreak_pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE);
-                    $lengths = array_map(function ($chunk) use ($fontMetrics, $font, $size, $word_spacing, $char_spacing) {
+                    $lengths = array_map(function ($chunk) use ($fontMetrics, $font, $size, $word_spacing, $letter_spacing) {
                         // Allow trailing white space to overflow. As in actual
                         // layout above, only handle a single space for now
                         $sep = $chunk[1] ?? "";
                         $word = $sep === " " ? $chunk[0] : $chunk[0] . $sep;
-                        return $fontMetrics->getTextWidth($word, $font, $size, $word_spacing, $char_spacing);
+                        return $fontMetrics->getTextWidth($word, $font, $size, $word_spacing, $letter_spacing);
                     }, array_chunk($words, 2));
                     $min = max($lengths);
                 }
@@ -533,15 +531,15 @@ class Text extends AbstractFrameReflower
             case "pre":
                 // Find the longest line
                 $lines = array_flip(preg_split("/\R/u", $visible_text));
-                array_walk($lines, function(&$chunked_text_width, $chunked_text) use ($fontMetrics, $font, $size, $word_spacing, $char_spacing) {
-                    $chunked_text_width = $fontMetrics->getTextWidth($chunked_text, $font, $size, $word_spacing, $char_spacing);
+                array_walk($lines, function (&$chunked_text_width, $chunked_text) use ($fontMetrics, $font, $size, $word_spacing, $letter_spacing) {
+                    $chunked_text_width = $fontMetrics->getTextWidth($chunked_text, $font, $size, $word_spacing, $letter_spacing);
                 });
                 arsort($lines);
                 $min = reset($lines);
                 break;
 
             case "nowrap":
-                $min = $fontMetrics->getTextWidth($visible_text, $font, $size, $word_spacing, $char_spacing);
+                $min = $fontMetrics->getTextWidth($visible_text, $font, $size, $word_spacing, $letter_spacing);
                 break;
         }
 
@@ -549,15 +547,15 @@ class Text extends AbstractFrameReflower
         switch ($style->white_space) {
             default:
             case "normal":
-                $max = $fontMetrics->getTextWidth($visible_text, $font, $size, $word_spacing, $char_spacing);
+                $max = $fontMetrics->getTextWidth($visible_text, $font, $size, $word_spacing, $letter_spacing);
                 break;
 
             case "pre-line":
             case "pre-wrap":
                 // Find the longest line
                 $lines = array_flip(preg_split("/\R/u", $visible_text));
-                array_walk($lines, function(&$chunked_text_width, $chunked_text) use ($fontMetrics, $font, $size, $word_spacing, $char_spacing) {
-                    $chunked_text_width = $fontMetrics->getTextWidth($chunked_text, $font, $size, $word_spacing, $char_spacing);
+                array_walk($lines, function (&$chunked_text_width, $chunked_text) use ($fontMetrics, $font, $size, $word_spacing, $letter_spacing) {
+                    $chunked_text_width = $fontMetrics->getTextWidth($chunked_text, $font, $size, $word_spacing, $letter_spacing);
                 });
                 arsort($lines);
                 $max = reset($lines);
diff --git a/library/vendor/dompdf/src/Helpers.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Helpers.php
similarity index 87%
rename from library/vendor/dompdf/src/Helpers.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Helpers.php
index 6c9b24750..ba78515a4 100644
--- a/library/vendor/dompdf/src/Helpers.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Helpers.php
@@ -1,4 +1,9 @@
  1) {
+        if (isset($arr["scheme"]) && $arr["scheme"] !== "file" && $arr["scheme"] !== "phar" && strlen($arr["scheme"]) > 1) {
             $protocol = $arr["scheme"] . "://";
 
             if (isset($arr["user"])) {
@@ -480,42 +511,32 @@ class Helpers
 
         } else {
 
-            $i = mb_stripos($url, "file://");
-            if ($i !== false) {
-                $url = mb_substr($url, $i + 7);
-            }
-
-            $protocol = ""; // "file://"; ? why doesn't this work... It's because of
-            // network filenames like //COMPU/SHARENAME
-
+            $protocol = "";
             $host = ""; // localhost, really
-            $file = basename($url);
-
-            $path = dirname($url);
-
-            // Check that the path exists
-            if ($path !== false) {
-                $path .= '/';
 
+            $i = mb_stripos($url, "://");
+            if ($i !== false) {
+                $protocol = mb_strtolower(mb_substr($url, 0, $i + 3));
+                $url = mb_substr($url, $i + 3);
             } else {
-                // generate a url to access the file if no real path found.
-                $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
-
-                $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : php_uname("n");
-
-                if (substr($arr["path"], 0, 1) === '/') {
-                    $path = dirname($arr["path"]);
-                } else {
-                    $path = '/' . rtrim(dirname($_SERVER["SCRIPT_NAME"]), '/') . '/' . $arr["path"];
-                }
+                $protocol = "file://";
             }
+
+            if ($protocol === "phar://") {
+                $res = substr($url, stripos($url, ".phar")+5);
+                $url = substr($url, 7, stripos($url, ".phar")-2);
+            }
+
+            $file = basename($url);
+            $path = dirname($url) . "/";
         }
 
         $ret = [$protocol, $host, $path, $file,
             "protocol" => $protocol,
             "host" => $host,
             "path" => $path,
-            "file" => $file];
+            "file" => $file,
+            "resource" => $res];
         return $ret;
     }
 
@@ -576,12 +597,12 @@ class Helpers
     {
         if ($c <= 0x7F) {
             return chr($c);
-        } else if ($c <= 0x7FF) {
+        } elseif ($c <= 0x7FF) {
             return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F);
-        } else if ($c <= 0xFFFF) {
+        } elseif ($c <= 0xFFFF) {
             return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F)
             . chr(0x80 | $c & 0x3F);
-        } else if ($c <= 0x10FFFF) {
+        } elseif ($c <= 0x10FFFF) {
             return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F)
             . chr(0x80 | $c >> 6 & 0x3F)
             . chr(0x80 | $c & 0x3F);
@@ -868,9 +889,9 @@ class Helpers
      *  - curl: if allow_url_fopen is false and curl is available
      *
      * @param string $uri
-     * @param resource $context (ignored if curl is used)
+     * @param resource $context
      * @param int $offset
-     * @param int $maxlen (ignored if curl is used)
+     * @param int $maxlen
      * @return string[]
      */
     public static function getFileContent($uri, $context = null, $offset = 0, $maxlen = null)
@@ -878,12 +899,13 @@ class Helpers
         $content = null;
         $headers = null;
         [$protocol] = Helpers::explode_url($uri);
-        $is_local_path = ($protocol === "" || $protocol === "file://");
+        $is_local_path = in_array(strtolower($protocol), ["", "file://", "phar://"], true);
+        $can_use_curl = in_array(strtolower($protocol), ["http://", "https://"], true);
 
         set_error_handler([self::class, 'record_warnings']);
 
         try {
-            if ($is_local_path || ini_get('allow_url_fopen')) {
+            if ($is_local_path || ini_get('allow_url_fopen') || !$can_use_curl) {
                 if ($is_local_path === false) {
                     $uri = Helpers::encodeURI($uri);
                 }
@@ -899,18 +921,61 @@ class Helpers
                     $headers = $http_response_header;
                 }
 
-            } elseif (function_exists('curl_exec')) {
+            } elseif ($can_use_curl && function_exists('curl_exec')) {
                 $curl = curl_init($uri);
 
-                //TODO: use $context to define additional curl options
-                curl_setopt($curl, CURLOPT_TIMEOUT, 10);
-                curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
                 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
                 curl_setopt($curl, CURLOPT_HEADER, true);
                 if ($offset > 0) {
                     curl_setopt($curl, CURLOPT_RESUME_FROM, $offset);
                 }
 
+                if ($maxlen > 0) {
+                    curl_setopt($curl, CURLOPT_BUFFERSIZE, 128);
+                    curl_setopt($curl, CURLOPT_NOPROGRESS, false);
+                    curl_setopt($curl, CURLOPT_PROGRESSFUNCTION, function ($res, $download_size_total, $download_size, $upload_size_total, $upload_size) use ($maxlen) {
+                        return ($download_size > $maxlen) ? 1 : 0;
+                    });
+                }
+
+                $context_options = [];
+                if (!is_null($context)) {
+                    $context_options = stream_context_get_options($context);
+                }
+                foreach ($context_options as $stream => $options) {
+                    foreach ($options as $option => $value) {
+                        $key = strtolower($stream) . ":" . strtolower($option);
+                        switch ($key) {
+                            case "curl:curl_verify_ssl_host":
+                                curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, !$value ? 0 : 2);
+                                break;
+                            case "curl:max_redirects":
+                                curl_setopt($curl, CURLOPT_MAXREDIRS, $value);
+                                break;
+                            case "http:follow_location":
+                                curl_setopt($curl, CURLOPT_FOLLOWLOCATION, $value);
+                                break;
+                            case "http:header":
+                                if (is_string($value)) {
+                                    curl_setopt($curl, CURLOPT_HTTPHEADER, [$value]);
+                                } else {
+                                    curl_setopt($curl, CURLOPT_HTTPHEADER, $value);
+                                }
+                                break;
+                            case "http:timeout":
+                                curl_setopt($curl, CURLOPT_TIMEOUT, $value);
+                                break;
+                            case "http:user_agent":
+                                curl_setopt($curl, CURLOPT_USERAGENT, $value);
+                                break;
+                            case "curl:curl_verify_ssl_peer":
+                            case "ssl:verify_peer":
+                                curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $value);
+                                break;
+                        }
+                    }
+                }
+
                 $data = curl_exec($curl);
 
                 if ($data !== false && !curl_errno($curl)) {
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/src/Image/Cache.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Image/Cache.php
new file mode 100644
index 000000000..f337bbb47
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Image/Cache.php
@@ -0,0 +1,254 @@
+getAllowedProtocols();
+                if (!array_key_exists($protocol, $allowed_protocols)) {
+                    throw new ImageException("Permission denied on $url. The communication protocol is not supported.", E_WARNING);
+                }
+                foreach ($allowed_protocols[$protocol]["rules"] as $rule) {
+                    [$result, $message] = $rule($full_url);
+                    if (!$result) {
+                        throw new ImageException("Error loading $url: $message", E_WARNING);
+                    }
+                }
+            }
+
+            if ($protocol === "file://") {
+                $resolved_url = $full_url;
+            } elseif (isset(self::$_cache[$full_url])) {
+                $resolved_url = self::$_cache[$full_url];
+            } else {
+                $tmp_dir = $options->getTempDir();
+                if (($resolved_url = @tempnam($tmp_dir, "ca_dompdf_img_")) === false) {
+                    throw new ImageException("Unable to create temporary image in " . $tmp_dir, E_WARNING);
+                }
+                $tempfile = $resolved_url;
+
+                $image = null;
+                if ($is_data_uri) {
+                    if (($parsed_data_uri = Helpers::parse_data_uri($url)) !== false) {
+                        $image = $parsed_data_uri["data"];
+                    }
+                } else {
+                    list($image, $http_response_header) = Helpers::getFileContent($full_url, $options->getHttpContext());
+                }
+
+                // Image not found or invalid
+                if ($image === null) {
+                    $msg = ($is_data_uri ? "Data-URI could not be parsed" : "Image not found");
+                    throw new ImageException($msg, E_WARNING);
+                }
+
+                if (@file_put_contents($resolved_url, $image) === false) {
+                    throw new ImageException("Unable to create temporary image in " . $tmp_dir, E_WARNING);
+                }
+
+                self::$_cache[$full_url] = $resolved_url;
+            }
+
+            // Check if the local file is readable
+            if (!is_readable($resolved_url) || !filesize($resolved_url)) {
+                throw new ImageException("Image not readable or empty", E_WARNING);
+            }
+
+            list($width, $height, $type) = Helpers::dompdf_getimagesize($resolved_url, $options->getHttpContext());
+
+            if (($width && $height && in_array($type, ["gif", "png", "jpeg", "bmp", "svg","webp"], true)) === false) {
+                throw new ImageException("Image type unknown", E_WARNING);
+            }
+
+            if ($type === "svg") {
+                $parser = xml_parser_create("utf-8");
+                xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
+                xml_set_element_handler(
+                    $parser,
+                    function ($parser, $name, $attributes) use ($options, $parsed_url, $full_url) {
+                        if ($name === "image") {
+                            $attributes = array_change_key_case($attributes, CASE_LOWER);
+                            $url = $attributes["xlink:href"] ?? $attributes["href"];
+                            if (!empty($url)) {
+                                $inner_full_url = Helpers::build_url($parsed_url["protocol"], $parsed_url["host"], $parsed_url["path"], $url);
+                                if ($inner_full_url === $full_url) {
+                                    throw new ImageException("SVG self-reference is not allowed", E_WARNING);
+                                }
+                                [$resolved_url, $type, $message] = self::resolve_url($url, $parsed_url["protocol"], $parsed_url["host"], $parsed_url["path"], $options);
+                                if (!empty($message)) {
+                                    throw new ImageException("This SVG document references a restricted resource. $message", E_WARNING);
+                                }
+                            }
+                        }
+                    },
+                    false
+                );
+        
+                if (($fp = fopen($resolved_url, "r")) !== false) {
+                    while ($line = fread($fp, 8192)) {
+                        xml_parse($parser, $line, false);
+                    }
+                    fclose($fp);
+                }
+                xml_parser_free($parser);
+            }
+        } catch (ImageException $e) {
+            if ($tempfile) {
+                unlink($tempfile);
+            }
+            $resolved_url = self::$broken_image;
+            list($width, $height, $type) = Helpers::dompdf_getimagesize($resolved_url, $options->getHttpContext());
+            $message = self::$error_message;
+            Helpers::record_warnings($e->getCode(), $e->getMessage() . " \n $url", $e->getFile(), $e->getLine());
+            self::$_cache[$full_url] = $resolved_url;
+        }
+
+        return [$resolved_url, $type, $message];
+    }
+
+    /**
+     * Register a temp file for the given original image file.
+     *
+     * @param string $filePath The path of the original image.
+     * @param string $tempPath The path of the temp file to register.
+     * @param string $key      An optional key to register the temp file at.
+     */
+    static function addTempImage(string $filePath, string $tempPath, string $key = "default"): void
+    {
+        if (!isset(self::$tempImages[$filePath])) {
+            self::$tempImages[$filePath] = [];
+        }
+
+        self::$tempImages[$filePath][$key] = $tempPath;
+    }
+
+    /**
+     * Get the path of a temp file registered for the given original image file.
+     *
+     * @param string $filePath The path of the original image.
+     * @param string $key      The key the temp file is registered at.
+     */
+    static function getTempImage(string $filePath, string $key = "default"): ?string
+    {
+        return self::$tempImages[$filePath][$key] ?? null;
+    }
+
+    /**
+     * Unlink all cached images (i.e. temporary images either downloaded
+     * or converted) except for the bundled "broken image"
+     */
+    static function clear(bool $debugPng = false)
+    {
+        foreach (self::$_cache as $file) {
+            if ($file === self::$broken_image) {
+                continue;
+            }
+            if ($debugPng) {
+                print "[clear unlink $file]";
+            }
+            if (file_exists($file)) {
+                unlink($file);
+            }
+        }
+
+        foreach (self::$tempImages as $versions) {
+            foreach ($versions as $file) {
+                if ($file === self::$broken_image) {
+                    continue;
+                }
+                if ($debugPng) {
+                    print "[unlink temp image $file]";
+                }
+                if (file_exists($file)) {
+                    unlink($file);
+                }
+            }
+        }
+
+        self::$_cache = [];
+        self::$tempImages = [];
+    }
+
+    static function detect_type($file, $context = null)
+    {
+        list(, , $type) = Helpers::dompdf_getimagesize($file, $context);
+
+        return $type;
+    }
+
+    static function is_broken($url)
+    {
+        return $url === self::$broken_image;
+    }
+}
+
+if (file_exists(realpath(__DIR__ . "/../../lib/res/broken_image.svg"))) {
+    Cache::$broken_image = realpath(__DIR__ . "/../../lib/res/broken_image.svg");
+}
diff --git a/library/vendor/dompdf/src/JavascriptEmbedder.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/JavascriptEmbedder.php
similarity index 90%
rename from library/vendor/dompdf/src/JavascriptEmbedder.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/JavascriptEmbedder.php
index 7a8fce53b..f4b9bc25a 100644
--- a/library/vendor/dompdf/src/JavascriptEmbedder.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/JavascriptEmbedder.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
diff --git a/library/vendor/dompdf/src/LineBox.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/LineBox.php
similarity index 97%
rename from library/vendor/dompdf/src/LineBox.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/LineBox.php
index 7ab5f4cf8..11b83c15c 100644
--- a/library/vendor/dompdf/src/LineBox.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/LineBox.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
@@ -266,7 +265,7 @@ class LineBox
     /**
      * @param AbstractFrameDecorator $frame
      */
-    public function add_frame(Frame $frame)
+    public function add_frame(Frame $frame): void
     {
         $this->_frames[] = $frame;
 
@@ -377,7 +376,7 @@ class LineBox
      *
      * @return float
      */
-    public function recalculate_width()
+    public function recalculate_width(): float
     {
         $width = 0.0;
 
@@ -391,7 +390,7 @@ class LineBox
     /**
      * @return string
      */
-    public function __toString()
+    public function __toString(): string
     {
         $props = ["wc", "y", "w", "h", "left", "right", "br"];
         $s = "";
diff --git a/library/vendor/dompdf/src/Options.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Options.php
similarity index 81%
rename from library/vendor/dompdf/src/Options.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Options.php
index 20e99253e..de127d2d5 100644
--- a/library/vendor/dompdf/src/Options.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Options.php
@@ -1,4 +1,9 @@
  ["rules" => []],
+        "http://" => ["rules" => []],
+        "https://" => ["rules" => []]
+    ];
+
     /**
      * @var string
      */
     private $logOutputFile;
 
     /**
-     * html target media view which should be rendered into pdf.
-     * List of types and parsing rules for future extensions:
-     * http://www.w3.org/TR/REC-html40/types.html
-     *   screen, tty, tv, projection, handheld, print, braille, aural, all
-     * Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
-     * Note, even though the generated pdf file is intended for print output,
-     * the desired content might be different (e.g. screen or projection view of html file).
-     * Therefore allow specification of content here.
+     * Styles targeted to this media type are applied to the document.
+     * This is on top of the media types that are always applied:
+     *    all, static, visual, bitmap, paged, dompdf
      *
      * @var string
      */
@@ -183,21 +199,26 @@ class Options
     private $isRemoteEnabled = false;
 
     /**
-     * Enable inline Javascript
+     * Enable inline JavaScript
      *
      * If this setting is set to true then DOMPDF will automatically insert
-     * JavaScript code contained within  tags.
+     * JavaScript code contained within 
+     * tags as written into the PDF.
+     *
+     * NOTE: This is PDF-based JavaScript to be executed by the PDF viewer,
+     * not browser-based JavaScript executed by Dompdf.
      *
      * @var bool
      */
     private $isJavascriptEnabled = true;
 
     /**
-     * Use the more-than-experimental HTML5 Lib parser
+     * Use the HTML5 Lib parser
      *
+     * @deprecated
      * @var bool
      */
-    private $isHtml5ParserEnabled = false;
+    private $isHtml5ParserEnabled = true;
 
     /**
      * Whether to enable font subsetting or not.
@@ -296,7 +317,23 @@ class Options
         $this->setTempDir(sys_get_temp_dir());
         $this->setFontDir($rootDir . "/lib/fonts");
         $this->setFontCache($this->getFontDir());
-        $this->setLogOutputFile($this->getTempDir() . "/log.htm");
+
+        $ver = "";
+        $versionFile = realpath(__DIR__ . '/../VERSION');
+        if (($version = file_get_contents($versionFile)) !== false) {
+            $version = trim($version);
+            if ($version !== '$Format:<%h>$') {
+                $ver = "/$version";
+            }
+        }
+        $this->setHttpContext([
+            "http" => [
+                "follow_location" => false,
+                "user_agent" => "Dompdf$ver https://github.com/dompdf/dompdf"
+            ]
+        ]);
+
+        $this->setAllowedProtocols(["file://", "http://", "https://"]);
 
         if (null !== $attributes) {
             $this->set($attributes);
@@ -322,6 +359,8 @@ class Options
                 $this->setFontCache($value);
             } elseif ($key === 'chroot') {
                 $this->setChroot($value);
+            } elseif ($key === 'allowedProtocols') {
+                $this->setAllowedProtocols($value);
             } elseif ($key === 'logOutputFile' || $key === 'log_output_file') {
                 $this->setLogOutputFile($value);
             } elseif ($key === 'defaultMediaType' || $key === 'default_media_type') {
@@ -387,6 +426,8 @@ class Options
             return $this->getFontCache();
         } elseif ($key === 'chroot') {
             return $this->getChroot();
+        } elseif ($key === 'allowedProtocols') {
+            return $this->getAllowedProtocols();
         } elseif ($key === 'logOutputFile' || $key === 'log_output_file') {
             return $this->getLogOutputFile();
         } elseif ($key === 'defaultMediaType' || $key === 'default_media_type') {
@@ -487,6 +528,70 @@ class Options
         return $this;
     }
 
+    /**
+     * @return array
+     */
+    public function getAllowedProtocols()
+    {
+        return $this->allowedProtocols;
+    }
+
+    /**
+     * @param array $allowedProtocols The protocols to allow, as an array
+     * formatted as ["protocol://" => ["rules" => [callable]], ...]
+     * or ["protocol://", ...]
+     *
+     * @return $this
+     */
+    public function setAllowedProtocols(array $allowedProtocols)
+    {
+        $protocols = [];
+        foreach ($allowedProtocols as $protocol => $config) {
+            if (is_string($protocol)) {
+                $protocols[$protocol] = [];
+                if (is_array($config)) {
+                    $protocols[$protocol] = $config;
+                }
+            } elseif (is_string($config)) {
+                $protocols[$config] = [];
+            }
+        }
+        $this->allowedProtocols = [];
+        foreach ($protocols as $protocol => $config) {
+            $this->addAllowedProtocol($protocol, ...($config["rules"] ?? []));
+        }
+        return $this;
+    }
+
+    /**
+     * Adds a new protocol to the allowed protocols collection
+     *
+     * @param string $protocol The scheme to add (e.g. "http://")
+     * @param callable $rule A callable that validates the protocol
+     * @return $this
+     */
+    public function addAllowedProtocol(string $protocol, callable ...$rules)
+    {
+        $protocol = strtolower($protocol);
+        if (empty($rules)) {
+            $rules = [];
+            switch ($protocol) {
+                case "file://":
+                    $rules[] = [$this, "validateLocalUri"];
+                    break;
+                case "http://":
+                case "https://":
+                    $rules[] = [$this, "validateRemoteUri"];
+                    break;
+                case "phar://":
+                    $rules[] = [$this, "validatePharUri"];
+                    break;
+            }
+        }
+        $this->allowedProtocols[$protocol] = ["rules" => $rules];
+        return $this;
+    }
+
     /**
      * @return array
      */
@@ -818,6 +923,7 @@ class Options
     }
 
     /**
+     * @deprecated
      * @param boolean $isHtml5ParserEnabled
      * @return $this
      */
@@ -828,6 +934,7 @@ class Options
     }
 
     /**
+     * @deprecated
      * @return boolean
      */
     public function getIsHtml5ParserEnabled()
@@ -836,6 +943,7 @@ class Options
     }
 
     /**
+     * @deprecated
      * @return boolean
      */
     public function isHtml5ParserEnabled()
@@ -996,4 +1104,56 @@ class Options
     {
         return $this->httpContext;
     }
+
+    public function validateLocalUri(string $uri)
+    {
+        if ($uri === null || strlen($uri) === 0) {
+            return [false, "The URI must not be empty."];
+        }
+
+        $realfile = realpath(str_replace("file://", "", $uri));
+
+        $dirs = $this->chroot;
+        $dirs[] = $this->rootDir;
+        $chrootValid = false;
+        foreach ($dirs as $chrootPath) {
+            $chrootPath = realpath($chrootPath);
+            if ($chrootPath !== false && strpos($realfile, $chrootPath) === 0) {
+                $chrootValid = true;
+                break;
+            }
+        }
+        if ($chrootValid !== true) {
+            return [false, "Permission denied. The file could not be found under the paths specified by Options::chroot."];
+        }
+
+        if (!$realfile) {
+            return [false, "File not found."];
+        }
+
+        return [true, null];
+    }
+
+    public function validatePharUri(string $uri)
+    {
+        if ($uri === null || strlen($uri) === 0) {
+            return [false, "The URI must not be empty."];
+        }
+
+        $file = substr(substr($uri, 0, strpos($uri, ".phar") + 5), 7);
+        return $this->validateLocalUri($file);
+    }
+
+    public function validateRemoteUri(string $uri)
+    {
+        if ($uri === null || strlen($uri) === 0) {
+            return [false, "The URI must not be empty."];
+        }
+
+        if (!$this->isRemoteEnabled) {
+            return [false, "Remote file requested, but remote file download is disabled."];
+        }
+
+        return [true, null];
+    }
 }
diff --git a/library/vendor/dompdf/src/PhpEvaluator.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/PhpEvaluator.php
similarity index 93%
rename from library/vendor/dompdf/src/PhpEvaluator.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/PhpEvaluator.php
index cdebc7a41..4a46555ca 100644
--- a/library/vendor/dompdf/src/PhpEvaluator.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/PhpEvaluator.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
diff --git a/library/vendor/dompdf/src/Positioner/Absolute.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Absolute.php
similarity index 93%
rename from library/vendor/dompdf/src/Positioner/Absolute.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Absolute.php
index 18b232d13..2df9a742b 100644
--- a/library/vendor/dompdf/src/Positioner/Absolute.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Absolute.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -20,7 +18,7 @@ class Absolute extends AbstractPositioner
     /**
      * @param AbstractFrameDecorator $frame
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         if ($frame->get_reflower() instanceof Block) {
             $style = $frame->get_style();
@@ -51,9 +49,8 @@ class Absolute extends AbstractPositioner
 
             list($width, $height) = [$frame->get_margin_width(), $frame->get_margin_height()];
 
-            $orig_style = $frame->get_original_style();
-            $orig_width = $orig_style->width;
-            $orig_height = $orig_style->height;
+            $orig_width = $style->get_specified("width");
+            $orig_height = $style->get_specified("height");
 
             /****************************
              *
diff --git a/library/vendor/dompdf/src/Positioner/AbstractPositioner.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php
similarity index 57%
rename from library/vendor/dompdf/src/Positioner/AbstractPositioner.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php
index 54161b4a5..a75c09fb9 100644
--- a/library/vendor/dompdf/src/Positioner/AbstractPositioner.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -13,9 +11,8 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
 /**
  * Base AbstractPositioner class
  *
- * Defines postioner interface
+ * Defines positioner interface
  *
- * @access  private
  * @package dompdf
  */
 abstract class AbstractPositioner
@@ -23,19 +20,22 @@ abstract class AbstractPositioner
 
     /**
      * @param AbstractFrameDecorator $frame
-     * @return mixed
      */
-    abstract function position(AbstractFrameDecorator $frame);
+    abstract function position(AbstractFrameDecorator $frame): void;
 
     /**
      * @param AbstractFrameDecorator $frame
-     * @param float $offset_x
-     * @param float $offset_y
-     * @param bool $ignore_self
+     * @param float                  $offset_x
+     * @param float                  $offset_y
+     * @param bool                   $ignore_self
      */
-    function move(AbstractFrameDecorator $frame, $offset_x, $offset_y, $ignore_self = false)
-    {
-        list($x, $y) = $frame->get_position();
+    function move(
+        AbstractFrameDecorator $frame,
+        float $offset_x,
+        float $offset_y,
+        bool $ignore_self = false
+    ): void {
+        [$x, $y] = $frame->get_position();
 
         if (!$ignore_self) {
             $frame->set_position($x + $offset_x, $y + $offset_y);
diff --git a/library/vendor/dompdf/src/Positioner/Block.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Block.php
similarity index 81%
rename from library/vendor/dompdf/src/Positioner/Block.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Block.php
index 74de5c990..e6f65eab9 100644
--- a/library/vendor/dompdf/src/Positioner/Block.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Block.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -13,13 +11,12 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
 /**
  * Positions block frames
  *
- * @access  private
  * @package dompdf
  */
 class Block extends AbstractPositioner
 {
 
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         $style = $frame->get_style();
         $cb = $frame->get_containing_block();
diff --git a/library/vendor/dompdf/src/Positioner/Fixed.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Fixed.php
similarity index 77%
rename from library/vendor/dompdf/src/Positioner/Fixed.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Fixed.php
index 6ab42e0e4..13eb9e9c0 100644
--- a/library/vendor/dompdf/src/Positioner/Fixed.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Fixed.php
@@ -1,12 +1,9 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -21,7 +18,7 @@ class Fixed extends Absolute
     /**
      * @param AbstractFrameDecorator $frame
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         if ($frame->get_reflower() instanceof Block) {
             parent::position($frame);
@@ -29,7 +26,7 @@ class Fixed extends Absolute
             // Legacy positioning logic for image and table frames
             // TODO: Resolve dimensions, margins, and offsets similar to the
             // block case in the reflowers and use the simplified logic above
-            $style = $frame->get_original_style();
+            $style = $frame->get_style();
             $root = $frame->get_root();
             $initialcb = $root->get_containing_block();
             $initialcb_style = $root->get_style();
@@ -45,13 +42,13 @@ class Fixed extends Absolute
             $margin_left = (float)$initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]);
 
             // The needed computed style of the element
-            $height = (float)$style->length_in_pt($style->height, $initialcb["h"]);
-            $width = (float)$style->length_in_pt($style->width, $initialcb["w"]);
+            $height = (float)$style->length_in_pt($style->get_specified("height"), $initialcb["h"]);
+            $width = (float)$style->length_in_pt($style->get_specified("width"), $initialcb["w"]);
 
-            $top = $style->length_in_pt($style->top, $initialcb["h"]);
-            $right = $style->length_in_pt($style->right, $initialcb["w"]);
-            $bottom = $style->length_in_pt($style->bottom, $initialcb["h"]);
-            $left = $style->length_in_pt($style->left, $initialcb["w"]);
+            $top = $style->length_in_pt($style->get_specified("top"), $initialcb["h"]);
+            $right = $style->length_in_pt($style->get_specified("right"), $initialcb["w"]);
+            $bottom = $style->length_in_pt($style->get_specified("bottom"), $initialcb["h"]);
+            $left = $style->length_in_pt($style->get_specified("left"), $initialcb["w"]);
 
             $y = $margin_top;
             if (isset($top)) {
@@ -87,8 +84,7 @@ class Fixed extends Absolute
 
             $frame->set_position($x, $y);
 
-            $children = $frame->get_children();
-            foreach ($children as $child) {
+            foreach ($frame->get_children() as $child) {
                 $child->set_position($x, $y);
             }
         }
diff --git a/library/vendor/dompdf/src/Positioner/Inline.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Inline.php
similarity index 90%
rename from library/vendor/dompdf/src/Positioner/Inline.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Inline.php
index cb1216368..c0bdaf263 100644
--- a/library/vendor/dompdf/src/Positioner/Inline.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/Inline.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -25,7 +23,7 @@ class Inline extends AbstractPositioner
      * @param AbstractFrameDecorator $frame
      * @throws Exception
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         // Find our nearest block level parent and access its lines property
         $block = $frame->find_block_parent();
diff --git a/library/vendor/dompdf/src/Positioner/ListBullet.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/ListBullet.php
similarity index 85%
rename from library/vendor/dompdf/src/Positioner/ListBullet.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/ListBullet.php
index 8db27169d..081d59419 100644
--- a/library/vendor/dompdf/src/Positioner/ListBullet.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/ListBullet.php
@@ -1,12 +1,9 @@
 
- * @author  Helmut Tischer 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -22,7 +19,7 @@ class ListBullet extends AbstractPositioner
     /**
      * @param ListBulletFrameDecorator $frame
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         // List markers are positioned to the left of the border edge of their
         // parent element (FIXME: right for RTL)
diff --git a/library/vendor/dompdf/src/Positioner/NullPositioner.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/NullPositioner.php
similarity index 72%
rename from library/vendor/dompdf/src/Positioner/NullPositioner.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/NullPositioner.php
index afdef1901..6ad425c34 100644
--- a/library/vendor/dompdf/src/Positioner/NullPositioner.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/NullPositioner.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -21,7 +19,7 @@ class NullPositioner extends AbstractPositioner
     /**
      * @param AbstractFrameDecorator $frame
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         return;
     }
diff --git a/library/vendor/dompdf/src/Positioner/TableCell.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/TableCell.php
similarity index 79%
rename from library/vendor/dompdf/src/Positioner/TableCell.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/TableCell.php
index 42b0042e4..1a6ac6298 100644
--- a/library/vendor/dompdf/src/Positioner/TableCell.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/TableCell.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -22,7 +20,7 @@ class TableCell extends AbstractPositioner
     /**
      * @param AbstractFrameDecorator $frame
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         $table = Table::find_parent_table($frame);
         $cellmap = $table->get_cellmap();
diff --git a/library/vendor/dompdf/src/Positioner/TableRow.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/TableRow.php
similarity index 81%
rename from library/vendor/dompdf/src/Positioner/TableRow.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/TableRow.php
index aee20453f..79c0fcf25 100644
--- a/library/vendor/dompdf/src/Positioner/TableRow.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Positioner/TableRow.php
@@ -1,11 +1,9 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
-
 namespace Dompdf\Positioner;
 
 use Dompdf\FrameDecorator\AbstractFrameDecorator;
@@ -21,7 +19,7 @@ class TableRow extends AbstractPositioner
     /**
      * @param AbstractFrameDecorator $frame
      */
-    function position(AbstractFrameDecorator $frame)
+    function position(AbstractFrameDecorator $frame): void
     {
         $cb = $frame->get_containing_block();
         $p = $frame->get_prev_sibling();
diff --git a/library/vendor/dompdf/src/Renderer.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer.php
similarity index 92%
rename from library/vendor/dompdf/src/Renderer.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer.php
index 9b9680132..e3cacc104 100644
--- a/library/vendor/dompdf/src/Renderer.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf;
@@ -65,19 +64,21 @@ class Renderer extends AbstractRenderer
 
         $style = $frame->get_style();
 
-        if (in_array($style->visibility, ["hidden", "collapse"])) {
+        if (in_array($style->visibility, ["hidden", "collapse"], true)) {
             return;
         }
 
         $display = $style->display;
+        $transformList = $style->transform;
+        $hasTransform = $transformList !== [];
 
         // Starts the CSS transformation
-        if ($style->transform && is_array($style->transform)) {
+        if ($hasTransform) {
             $this->_canvas->save();
             list($x, $y) = $frame->get_padding_box();
             $origin = $style->transform_origin;
 
-            foreach ($style->transform as $transform) {
+            foreach ($transformList as $transform) {
                 list($function, $values) = $transform;
                 if ($function === "matrix") {
                     $function = "transform";
@@ -179,8 +180,8 @@ class Renderer extends AbstractRenderer
             $z_index = 0;
 
             if ($child_z_index !== "auto") {
-                $z_index = intval($child_z_index) + 1;
-            } elseif ($child_style->float !== "none" || $child->is_positionned()) {
+                $z_index = $child_z_index + 1;
+            } elseif ($child_style->float !== "none" || $child->is_positioned()) {
                 $z_index = 1;
             }
 
@@ -200,7 +201,7 @@ class Renderer extends AbstractRenderer
             $this->_canvas->clipping_end();
         }
 
-        if ($style->transform && is_array($style->transform)) {
+        if ($hasTransform) {
             $this->_canvas->restore();
         }
 
@@ -223,13 +224,11 @@ class Renderer extends AbstractRenderer
 
         if (isset($this->_callbacks[$event])) {
             $fs = $this->_callbacks[$event];
-            $info = [
-                0 => $this->_canvas, "canvas" => $this->_canvas,
-                1 => $frame,         "frame"  => $frame
-            ];
+            $canvas = $this->_canvas;
+            $fontMetrics = $this->_dompdf->getFontMetrics();
 
             foreach ($fs as $f) {
-                $f($info);
+                $f($frame, $canvas, $fontMetrics);
             }
         }
     }
diff --git a/library/vendor/dompdf/src/Renderer/AbstractRenderer.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php
similarity index 59%
rename from library/vendor/dompdf/src/Renderer/AbstractRenderer.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php
index c76b5ff25..8b01ef8c0 100644
--- a/library/vendor/dompdf/src/Renderer/AbstractRenderer.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php
@@ -1,10 +1,7 @@
 
- * @author  Helmut Tischer 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Renderer;
@@ -59,15 +56,225 @@ abstract class AbstractRenderer
      */
     abstract function render(Frame $frame);
 
+    /**
+     * @param Frame   $frame
+     * @param float[] $border_box
+     */
+    protected function _render_background(Frame $frame, array $border_box): void
+    {
+        $style = $frame->get_style();
+        $color = $style->background_color;
+        $image = $style->background_image;
+        [$x, $y, $w, $h] = $border_box;
+
+        if ($color === "transparent" && $image === "none") {
+            return;
+        }
+
+        if ($style->has_border_radius()) {
+            [$tl, $tr, $br, $bl] = $style->resolve_border_radius($border_box);
+            $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl);
+        }
+
+        if ($color !== "transparent") {
+            $this->_canvas->filled_rectangle($x, $y, $w, $h, $color);
+        }
+
+        if ($image !== "none") {
+            $this->_background_image($image, $x, $y, $w, $h, $style);
+        }
+
+        if ($style->has_border_radius()) {
+            $this->_canvas->clipping_end();
+        }
+    }
+
+    /**
+     * @param Frame   $frame
+     * @param float[] $border_box
+     * @param string  $corner_style
+     */
+    protected function _render_border(Frame $frame, array $border_box, string $corner_style = "bevel"): void
+    {
+        $style = $frame->get_style();
+        $bp = $style->get_border_properties();
+        [$x, $y, $w, $h] = $border_box;
+        [$tl, $tr, $br, $bl] = $style->resolve_border_radius($border_box);
+
+        // Short-cut: If all the borders are "solid" with the same color and
+        // style, and no radius, we'd better draw a rectangle
+        if ($bp["top"]["style"] === "solid" &&
+            $bp["top"] === $bp["right"] &&
+            $bp["right"] === $bp["bottom"] &&
+            $bp["bottom"] === $bp["left"] &&
+            !$style->has_border_radius()
+        ) {
+            $props = $bp["top"];
+            if ($props["color"] === "transparent" || $props["width"] <= 0) {
+                return;
+            }
+
+            $width = (float)$style->length_in_pt($props["width"]);
+            $this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width);
+            return;
+        }
+
+        // Do it the long way
+        $widths = [
+            (float)$style->length_in_pt($bp["top"]["width"]),
+            (float)$style->length_in_pt($bp["right"]["width"]),
+            (float)$style->length_in_pt($bp["bottom"]["width"]),
+            (float)$style->length_in_pt($bp["left"]["width"])
+        ];
+
+        foreach ($bp as $side => $props) {
+            if ($props["style"] === "none" ||
+                $props["style"] === "hidden" ||
+                $props["color"] === "transparent" ||
+                $props["width"] <= 0
+            ) {
+                continue;
+            }
+
+            [$x, $y, $w, $h] = $border_box;
+            $method = "_border_" . $props["style"];
+
+            switch ($side) {
+                case "top":
+                    $length = $w;
+                    $r1 = $tl;
+                    $r2 = $tr;
+                    break;
+
+                case "bottom":
+                    $length = $w;
+                    $y += $h;
+                    $r1 = $bl;
+                    $r2 = $br;
+                    break;
+
+                case "left":
+                    $length = $h;
+                    $r1 = $tl;
+                    $r2 = $bl;
+                    break;
+
+                case "right":
+                    $length = $h;
+                    $x += $w;
+                    $r1 = $tr;
+                    $r2 = $br;
+                    break;
+
+                default:
+                    break;
+            }
+
+            // draw rounded corners
+            $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style, $r1, $r2);
+        }
+    }
+
+    /**
+     * @param Frame   $frame
+     * @param float[] $border_box
+     * @param string  $corner_style
+     */
+    protected function _render_outline(Frame $frame, array $border_box, string $corner_style = "bevel"): void
+    {
+        $style = $frame->get_style();
+
+        $width = $style->outline_width;
+        $outline_style = $style->outline_style;
+        $color = $style->outline_color;
+
+        if ($outline_style === "none" || $color === "transparent" || $width <= 0) {
+            return;
+        }
+
+        $offset = $style->outline_offset;
+
+        [$x, $y, $w, $h] = $border_box;
+        $d = $width + $offset;
+        $outline_box = [$x - $d, $y - $d, $w + $d * 2, $h + $d * 2];
+        [$tl, $tr, $br, $bl] = $style->resolve_border_radius($border_box, $outline_box);
+
+        $x -= $offset;
+        $y -= $offset;
+        $w += $offset * 2;
+        $h += $offset * 2;
+
+        // For a simple outline, we can draw a rectangle
+        if ($outline_style === "solid" && !$style->has_border_radius()) {
+            $x -= $width / 2;
+            $y -= $width / 2;
+            $w += $width;
+            $h += $width;
+
+            $this->_canvas->rectangle($x, $y, $w, $h, $color, $width);
+            return;
+        }
+
+        $x -= $width;
+        $y -= $width;
+        $w += $width * 2;
+        $h += $width * 2;
+
+        $method = "_border_" . $outline_style;
+        $widths = array_fill(0, 4, $width);
+        $sides = ["top", "right", "left", "bottom"];
+
+        foreach ($sides as $side) {
+            switch ($side) {
+                case "top":
+                    $length = $w;
+                    $side_x = $x;
+                    $side_y = $y;
+                    $r1 = $tl;
+                    $r2 = $tr;
+                    break;
+
+                case "bottom":
+                    $length = $w;
+                    $side_x = $x;
+                    $side_y = $y + $h;
+                    $r1 = $bl;
+                    $r2 = $br;
+                    break;
+
+                case "left":
+                    $length = $h;
+                    $side_x = $x;
+                    $side_y = $y;
+                    $r1 = $tl;
+                    $r2 = $bl;
+                    break;
+
+                case "right":
+                    $length = $h;
+                    $side_x = $x + $w;
+                    $side_y = $y;
+                    $r1 = $tr;
+                    $r2 = $br;
+                    break;
+
+                default:
+                    break;
+            }
+
+            $this->$method($side_x, $side_y, $length, $color, $widths, $side, $corner_style, $r1, $r2);
+        }
+    }
+
     /**
      * Render a background image over a rectangular area
      *
-     * @param string $url   The background image to load
-     * @param float $x      The left edge of the rectangular area
-     * @param float $y      The top edge of the rectangular area
-     * @param float $width  The width of the rectangular area
-     * @param float $height The height of the rectangular area
-     * @param Style $style  The associated Style object
+     * @param string $url    The background image to load
+     * @param float  $x      The left edge of the rectangular area
+     * @param float  $y      The top edge of the rectangular area
+     * @param float  $width  The width of the rectangular area
+     * @param float  $height The height of the rectangular area
+     * @param Style  $style  The associated Style object
      *
      * @throws \Exception
      */
@@ -97,7 +304,7 @@ abstract class AbstractRenderer
             $sheet->get_protocol(),
             $sheet->get_host(),
             $sheet->get_base_path(),
-            $this->_dompdf
+            $this->_dompdf->getOptions()
         );
 
         // Bail if the image is no good
@@ -358,7 +565,7 @@ abstract class AbstractRenderer
                 // Simply place the image on the background
                 imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h);
 
-            } else if ($repeat === "repeat-x") {
+            } elseif ($repeat === "repeat-x") {
                 for ($bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w) {
                     if ($bg_x < 0) {
                         $dst_x = 0;
@@ -371,7 +578,7 @@ abstract class AbstractRenderer
                     }
                     imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h);
                 }
-            } else if ($repeat === "repeat-y") {
+            } elseif ($repeat === "repeat-y") {
 
                 for ($bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h) {
                     if ($bg_y < 0) {
@@ -385,7 +592,7 @@ abstract class AbstractRenderer
                     }
                     imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h);
                 }
-            } else if ($repeat === "repeat") {
+            } elseif ($repeat === "repeat") {
                 for ($bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h) {
                     for ($bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w) {
                         if ($bg_x < 0) {
@@ -456,183 +663,68 @@ abstract class AbstractRenderer
         $this->_canvas->clipping_end();
     }
 
-    /**
-     * @param $style
-     * @param $width
-     * @return array
-     */
-    protected function _get_dash_pattern($style, $width)
-    {
-        $pattern = [];
-
-        switch ($style) {
-            default:
-                /*case "solid":
-                case "double":
-                case "groove":
-                case "inset":
-                case "outset":
-                case "ridge":*/
-            case "none":
-                break;
-
-            case "dotted":
-                if ($width <= 1) {
-                    $pattern = [$width, $width * 2];
-                } else {
-                    $pattern = [$width];
-                }
-                break;
-
-            case "dashed":
-                $pattern = [3 * $width];
-                break;
-        }
-
-        return $pattern;
-    }
-
-    /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
-     */
-    protected function _border_none($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
-    {
-        return;
-    }
-
-    /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
-     */
-    protected function _border_hidden($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
-    {
-        return;
-    }
-
     // Border rendering functions
 
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_dotted($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
         $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dotted", $r1, $r2);
     }
 
-
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_dashed($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
         $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dashed", $r1, $r2);
     }
 
-
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_solid($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
-        // TODO: Solve rendering where one corner is beveled (radius == 0), one corner isn't.
-        if ($corner_style !== "bevel" || $r1 > 0 || $r2 > 0) {
-            // do it the simple way
-            $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "solid", $r1, $r2);
-            return;
-        }
-
-        list($top, $right, $bottom, $left) = $widths;
-
-        // All this polygon business is for beveled corners...
-        switch ($side) {
-            case "top":
-                $points = [$x, $y,
-                    $x + $length, $y,
-                    $x + $length - $right, $y + $top,
-                    $x + $left, $y + $top];
-                $this->_canvas->polygon($points, $color, null, null, true);
-                break;
-
-            case "bottom":
-                $points = [$x, $y,
-                    $x + $length, $y,
-                    $x + $length - $right, $y - $bottom,
-                    $x + $left, $y - $bottom];
-                $this->_canvas->polygon($points, $color, null, null, true);
-                break;
-
-            case "left":
-                $points = [$x, $y,
-                    $x, $y + $length,
-                    $x + $left, $y + $length - $bottom,
-                    $x + $left, $y + $top];
-                $this->_canvas->polygon($points, $color, null, null, true);
-                break;
-
-            case "right":
-                $points = [$x, $y,
-                    $x, $y + $length,
-                    $x - $right, $y + $length - $bottom,
-                    $x - $right, $y + $top];
-                $this->_canvas->polygon($points, $color, null, null, true);
-                break;
-
-            default:
-                return;
-        }
+        $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "solid", $r1, $r2);
     }
 
     /**
-     * @param $side
-     * @param $ratio
-     * @param $top
-     * @param $right
-     * @param $bottom
-     * @param $left
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $r1
-     * @param $r2
+     * @param string $side
+     * @param float  $ratio
+     * @param float  $top
+     * @param float  $right
+     * @param float  $bottom
+     * @param float  $left
+     * @param float  $x
+     * @param float  $y
+     * @param float  $length
+     * @param float  $r1
+     * @param float  $r2
      */
     protected function _apply_ratio($side, $ratio, $top, $right, $bottom, $left, &$x, &$y, &$length, &$r1, &$r2)
     {
@@ -675,15 +767,15 @@ abstract class AbstractRenderer
     }
 
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_double($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
@@ -700,15 +792,15 @@ abstract class AbstractRenderer
     }
 
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_groove($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
@@ -724,15 +816,15 @@ abstract class AbstractRenderer
     }
 
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_ridge($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
@@ -774,15 +866,15 @@ abstract class AbstractRenderer
     }
 
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_inset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
@@ -805,15 +897,15 @@ abstract class AbstractRenderer
     }
 
     /**
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param int $r1
-     * @param int $r2
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_outset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0)
     {
@@ -835,113 +927,238 @@ abstract class AbstractRenderer
         }
     }
 
+    /**
+     * Get the dash pattern and cap style for the given border style, width, and
+     * line length.
+     *
+     * The base pattern is adjusted so that it fits the given line length
+     * symmetrically.
+     *
+     * @param string $style
+     * @param float  $width
+     * @param float  $length
+     *
+     * @return array
+     */
+    protected function dashPattern(string $style, float $width, float $length): array
+    {
+        if ($style === "dashed") {
+            $w = 3 * $width;
+
+            if ($length < $w) {
+                $s = $w;
+            } else {
+                // Scale dashes and gaps
+                $r = round($length / $w);
+                $r = $r % 2 === 0 ? $r + 1 : $r;
+                $s = $length / $r;
+            }
+
+            return [[$s], "butt"];
+        }
+
+        if ($style === "dotted") {
+            // Draw circles along the line
+            // Round caps extend outwards by half line width, so a zero dash
+            // width results in a circle
+            $gap = $width <= 1 ? 2 : 1;
+            $w = ($gap + 1) * $width;
+
+            if ($length < $w) {
+                $s = $w;
+            } else {
+                // Only scale gaps
+                $l = $length - $width;
+                $r = max(round($l / $w), 1);
+                $s = $l / $r;
+            }
+
+            return [[0, $s], "round"];
+        }
+
+        return [[], "butt"];
+    }
+
     /**
      * Draws a solid, dotted, or dashed line, observing the border radius
      *
-     * @param $x
-     * @param $y
-     * @param $length
-     * @param $color
-     * @param $widths
-     * @param $side
-     * @param string $corner_style
-     * @param $pattern_name
-     * @param int $r1
-     * @param int $r2
-     *
-     * @var $top
+     * @param float   $x
+     * @param float   $y
+     * @param float   $length
+     * @param array   $color
+     * @param float[] $widths
+     * @param string  $side
+     * @param string  $corner_style
+     * @param string  $pattern_name
+     * @param float   $r1
+     * @param float   $r2
      */
     protected function _border_line($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $pattern_name = "none", $r1 = 0, $r2 = 0)
     {
         /** used by $$side */
-        list($top, $right, $bottom, $left) = $widths;
+        [$top, $right, $bottom, $left] = $widths;
         $width = $$side;
 
-        $pattern = $this->_get_dash_pattern($pattern_name, $width);
+        // No need to clip corners if border radius is large enough
+        $cornerClip = $corner_style === "bevel" && ($r1 < $width || $r2 < $width);
+        $lineLength = $length - $r1 - $r2;
+        [$pattern, $cap] = $this->dashPattern($pattern_name, $width, $lineLength);
 
-        $half_width = $width / 2;
-        $r1 -= $half_width;
-        $r2 -= $half_width;
-        $adjust = $r1 / 80;
-        $length -= $width;
+        // Determine arc border radius for corner arcs
+        $halfWidth = $width / 2;
+        $ar1 = max($r1 - $halfWidth, 0);
+        $ar2 = max($r2 - $halfWidth, 0);
+
+        // Small angle adjustments to prevent the background from shining through
+        $adj1 = $ar1 / 80;
+        $adj2 = $ar2 / 80;
+
+        // Adjust line width and corner angles to account for the fact that
+        // round caps extend outwards. The line is actually only shifted below,
+        // not shortened, as otherwise the end dash (circle) will vanish
+        // occasionally
+        $dl = $cap === "round" ? $halfWidth : 0;
+
+        if ($cap === "round" && $ar1 > 0) {
+            $adj1 -= rad2deg(asin($halfWidth / $ar1));
+        }
+        if ($cap === "round" && $ar2 > 0) {
+            $adj2 -= rad2deg(asin($halfWidth / $ar2));
+        }
 
         switch ($side) {
             case "top":
-                $x += $half_width;
-                $y += $half_width;
-
-                if ($r1 > 0) {
-                    $this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 90 - $adjust, 135 + $adjust, $color, $width, $pattern);
+                if ($cornerClip) {
+                    $points = [
+                        $x, $y,
+                        $x, $y - 1, // Extend outwards to avoid gaps
+                        $x + $length, $y - 1, // Extend outwards to avoid gaps
+                        $x + $length, $y,
+                        $x + $length - max($right, $r2), $y + max($width, $r2),
+                        $x + max($left, $r1), $y + max($width, $r1)
+                    ];
+                    $this->_canvas->clipping_polygon($points);
                 }
 
-                $this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern);
+                $y += $halfWidth;
 
-                if ($r2 > 0) {
-                    $this->_canvas->arc($x + $length - $r2, $y + $r2, $r2, $r2, 45 - $adjust, 90 + $adjust, $color, $width, $pattern);
+                if ($ar1 > 0 && $adj1 > -22.5) {
+                    $this->_canvas->arc($x + $r1, $y + $ar1, $ar1, $ar1, 90 - $adj1, 135 + $adj1, $color, $width, $pattern, $cap);
+                }
+
+                if ($lineLength > 0) {
+                    $this->_canvas->line($x + $dl + $r1, $y, $x + $dl + $length - $r2, $y, $color, $width, $pattern, $cap);
+                }
+
+                if ($ar2 > 0 && $adj2 > -22.5) {
+                    $this->_canvas->arc($x + $length - $r2, $y + $ar2, $ar2, $ar2, 45 - $adj2, 90 + $adj2, $color, $width, $pattern, $cap);
                 }
                 break;
 
             case "bottom":
-                $x += $half_width;
-                $y -= $half_width;
-
-                if ($r1 > 0) {
-                    $this->_canvas->arc($x + $r1, $y - $r1, $r1, $r1, 225 - $adjust, 270 + $adjust, $color, $width, $pattern);
+                if ($cornerClip) {
+                    $points = [
+                        $x, $y,
+                        $x, $y + 1, // Extend outwards to avoid gaps
+                        $x + $length, $y + 1, // Extend outwards to avoid gaps
+                        $x + $length, $y,
+                        $x + $length - max($right, $r2), $y - max($width, $r2),
+                        $x + max($left, $r1), $y - max($width, $r1)
+                    ];
+                    $this->_canvas->clipping_polygon($points);
                 }
 
-                $this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern);
+                $y -= $halfWidth;
 
-                if ($r2 > 0) {
-                    $this->_canvas->arc($x + $length - $r2, $y - $r2, $r2, $r2, 270 - $adjust, 315 + $adjust, $color, $width, $pattern);
+                if ($ar1 > 0 && $adj1 > -22.5) {
+                    $this->_canvas->arc($x + $r1, $y - $ar1, $ar1, $ar1, 225 - $adj1, 270 + $adj1, $color, $width, $pattern, $cap);
+                }
+
+                if ($lineLength > 0) {
+                    $this->_canvas->line($x + $dl + $r1, $y, $x + $dl + $length - $r2, $y, $color, $width, $pattern, $cap);
+                }
+
+                if ($ar2 > 0 && $adj2 > -22.5) {
+                    $this->_canvas->arc($x + $length - $r2, $y - $ar2, $ar2, $ar2, 270 - $adj2, 315 + $adj2, $color, $width, $pattern, $cap);
                 }
                 break;
 
             case "left":
-                $y += $half_width;
-                $x += $half_width;
-
-                if ($r1 > 0) {
-                    $this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 135 - $adjust, 180 + $adjust, $color, $width, $pattern);
+                if ($cornerClip) {
+                    $points = [
+                        $x, $y,
+                        $x - 1, $y, // Extend outwards to avoid gaps
+                        $x - 1, $y + $length, // Extend outwards to avoid gaps
+                        $x, $y + $length,
+                        $x + max($width, $r2), $y + $length - max($bottom, $r2),
+                        $x + max($width, $r1), $y + max($top, $r1)
+                    ];
+                    $this->_canvas->clipping_polygon($points);
                 }
 
-                $this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern);
+                $x += $halfWidth;
 
-                if ($r2 > 0) {
-                    $this->_canvas->arc($x + $r2, $y + $length - $r2, $r2, $r2, 180 - $adjust, 225 + $adjust, $color, $width, $pattern);
+                if ($ar1 > 0 && $adj1 > -22.5) {
+                    $this->_canvas->arc($x + $ar1, $y + $r1, $ar1, $ar1, 135 - $adj1, 180 + $adj1, $color, $width, $pattern, $cap);
+                }
+
+                if ($lineLength > 0) {
+                    $this->_canvas->line($x, $y + $dl + $r1, $x, $y + $dl + $length - $r2, $color, $width, $pattern, $cap);
+                }
+
+                if ($ar2 > 0 && $adj2 > -22.5) {
+                    $this->_canvas->arc($x + $ar2, $y + $length - $r2, $ar2, $ar2, 180 - $adj2, 225 + $adj2, $color, $width, $pattern, $cap);
                 }
                 break;
 
             case "right":
-                $y += $half_width;
-                $x -= $half_width;
-
-                if ($r1 > 0) {
-                    $this->_canvas->arc($x - $r1, $y + $r1, $r1, $r1, 0 - $adjust, 45 + $adjust, $color, $width, $pattern);
+                if ($cornerClip) {
+                    $points = [
+                        $x, $y,
+                        $x + 1, $y, // Extend outwards to avoid gaps
+                        $x + 1, $y + $length, // Extend outwards to avoid gaps
+                        $x, $y + $length,
+                        $x - max($width, $r2), $y + $length - max($bottom, $r2),
+                        $x - max($width, $r1), $y + max($top, $r1)
+                    ];
+                    $this->_canvas->clipping_polygon($points);
                 }
 
-                $this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern);
+                $x -= $halfWidth;
 
-                if ($r2 > 0) {
-                    $this->_canvas->arc($x - $r2, $y + $length - $r2, $r2, $r2, 315 - $adjust, 360 + $adjust, $color, $width, $pattern);
+                if ($ar1 > 0 && $adj1 > -22.5) {
+                    $this->_canvas->arc($x - $ar1, $y + $r1, $ar1, $ar1, 0 - $adj1, 45 + $adj1, $color, $width, $pattern, $cap);
+                }
+
+                if ($lineLength > 0) {
+                    $this->_canvas->line($x, $y + $dl + $r1, $x, $y + $dl + $length - $r2, $color, $width, $pattern, $cap);
+                }
+
+                if ($ar2 > 0 && $adj2 > -22.5) {
+                    $this->_canvas->arc($x - $ar2, $y + $length - $r2, $ar2, $ar2, 315 - $adj2, 360 + $adj2, $color, $width, $pattern, $cap);
                 }
                 break;
         }
+
+        if ($cornerClip) {
+            $this->_canvas->clipping_end();
+        }
     }
 
     /**
-     * @param $opacity
+     * @param float $opacity
      */
-    protected function _set_opacity($opacity)
+    protected function _set_opacity(float $opacity): void
     {
-        if (is_numeric($opacity) && $opacity <= 1.0 && $opacity >= 0.0) {
+        if ($opacity >= 0.0 && $opacity <= 1.0) {
             $this->_canvas->set_opacity($opacity);
         }
     }
 
     /**
-     * @param array $box
-     * @param string $color
-     * @param array $style
+     * @param float[] $box
+     * @param string  $color
+     * @param array   $style
      */
     protected function _debug_layout($box, $color = "red", $style = [])
     {
@@ -949,12 +1166,13 @@ abstract class AbstractRenderer
     }
 
     /**
-     * @param float $img_width
-     * @param float $img_height
-     * @param float $container_width
-     * @param float $container_height
+     * @param float        $img_width
+     * @param float        $img_height
+     * @param float        $container_width
+     * @param float        $container_height
      * @param array|string $bg_resize
-     * @param int $dpi
+     * @param int          $dpi
+     *
      * @return array
      */
     protected function _resize_background_image(
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Block.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Block.php
new file mode 100644
index 000000000..99db1929a
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Block.php
@@ -0,0 +1,88 @@
+get_style();
+        $node = $frame->get_node();
+        $dompdf = $this->_dompdf;
+
+        $this->_set_opacity($frame->get_opacity($style->opacity));
+
+        [$x, $y, $w, $h] = $frame->get_border_box();
+
+        if ($node->nodeName === "body") {
+            // Margins should be fully resolved at this point
+            $mt = $style->margin_top;
+            $mb = $style->margin_bottom;
+            $h = $frame->get_containing_block("h") - $mt - $mb;
+        }
+
+        $border_box = [$x, $y, $w, $h];
+
+        // Draw our background, border and content
+        $this->_render_background($frame, $border_box);
+        $this->_render_border($frame, $border_box);
+        $this->_render_outline($frame, $border_box);
+
+        // Handle anchors & links
+        if ($node->nodeName === "a" && $href = $node->getAttribute("href")) {
+            $href = Helpers::build_url($dompdf->getProtocol(), $dompdf->getBaseHost(), $dompdf->getBasePath(), $href) ?? $href;
+            $this->_canvas->add_link($href, $x, $y, $w, $h);
+        }
+
+        $id = $frame->get_node()->getAttribute("id");
+        if (strlen($id) > 0) {
+            $this->_canvas->add_named_dest($id);
+        }
+
+        $this->debugBlockLayout($frame, "red", false);
+    }
+
+    protected function debugBlockLayout(Frame $frame, ?string $color, bool $lines = false): void
+    {
+        $options = $this->_dompdf->getOptions();
+        $debugLayout = $options->getDebugLayout();
+
+        if (!$debugLayout) {
+            return;
+        }
+
+        if ($color && $options->getDebugLayoutBlocks()) {
+            $this->_debug_layout($frame->get_border_box(), $color);
+
+            if ($options->getDebugLayoutPaddingBox()) {
+                $this->_debug_layout($frame->get_padding_box(), $color, [0.5, 0.5]);
+            }
+        }
+
+        if ($lines && $options->getDebugLayoutLines() && $frame instanceof BlockFrameDecorator) {
+            [$cx, , $cw] = $frame->get_content_box();
+
+            foreach ($frame->get_line_boxes() as $line) {
+                $lw = $cw - $line->left - $line->right;
+                $this->_debug_layout([$cx + $line->left, $line->y, $lw, $line->h], "orange");
+            }
+        }
+    }
+}
diff --git a/library/vendor/dompdf/src/Renderer/Image.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Image.php
similarity index 88%
rename from library/vendor/dompdf/src/Renderer/Image.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Image.php
index 71b773047..61f684f94 100644
--- a/library/vendor/dompdf/src/Renderer/Image.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Image.php
@@ -1,9 +1,7 @@
 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Renderer;
@@ -15,7 +13,6 @@ use Dompdf\Image\Cache;
 /**
  * Image renderer
  *
- * @access  private
  * @package dompdf
  */
 class Image extends Block
@@ -46,7 +43,9 @@ class Image extends Block
         ) {
             $font = $style->font_family;
             $size = $style->font_size;
-            $spacing = $style->word_spacing;
+            $word_spacing = $style->word_spacing;
+            $letter_spacing = $style->letter_spacing;
+
             $this->_canvas->text(
                 $x,
                 $y,
@@ -54,7 +53,8 @@ class Image extends Block
                 $font,
                 $size,
                 $style->color,
-                $spacing
+                $word_spacing,
+                $letter_spacing
             );
         } elseif ($w > 0 && $h > 0) {
             if ($style->has_border_radius()) {
@@ -71,11 +71,12 @@ class Image extends Block
 
         if ($msg = $frame->get_image_msg()) {
             $parts = preg_split("/\s*\n\s*/", $msg);
+            $font = $style->font_family;
             $height = 10;
             $_y = $alt ? $y + $h - count($parts) * $height : $y;
 
             foreach ($parts as $i => $_part) {
-                $this->_canvas->text($x, $_y + $i * $height, $_part, "times", $height * 0.8, [0.5, 0.5, 0.5]);
+                $this->_canvas->text($x, $_y + $i * $height, $_part, $font, $height * 0.8, [0.5, 0.5, 0.5]);
             }
         }
 
diff --git a/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Inline.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Inline.php
new file mode 100644
index 000000000..ad3546492
--- /dev/null
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Inline.php
@@ -0,0 +1,126 @@
+get_first_child()) {
+            return; // No children, no service
+        }
+
+        $style = $frame->get_style();
+        $dompdf = $this->_dompdf;
+
+        $this->_set_opacity($frame->get_opacity($style->opacity));
+
+        $do_debug_layout_line = $dompdf->getOptions()->getDebugLayout()
+            && $dompdf->getOptions()->getDebugLayoutInline();
+
+        // Draw the background & border behind each child.  To do this we need
+        // to figure out just how much space each child takes:
+        [$x, $y] = $frame->get_first_child()->get_position();
+        [$w, $h] = $this->get_child_size($frame, $do_debug_layout_line);
+
+        [, , $cbw] = $frame->get_containing_block();
+        $margin_left = $style->length_in_pt($style->margin_left, $cbw);
+        $pt = $style->length_in_pt($style->padding_top, $cbw);
+        $pb = $style->length_in_pt($style->padding_bottom, $cbw);
+
+        // Make sure that border and background start inside the left margin
+        // Extend the drawn box by border and padding in vertical direction, as
+        // these do not affect layout
+        // FIXME: Using a small vertical offset of a fraction of the height here
+        // to work around the vertical position being slightly off in general
+        $x += $margin_left;
+        $y -= $style->border_top_width + $pt - ($h * 0.1);
+        $w += $style->border_left_width + $style->border_right_width;
+        $h += $style->border_top_width + $pt + $style->border_bottom_width + $pb;
+
+        $border_box = [$x, $y, $w, $h];
+        $this->_render_background($frame, $border_box);
+        $this->_render_border($frame, $border_box);
+        $this->_render_outline($frame, $border_box);
+
+        $node = $frame->get_node();
+        $id = $node->getAttribute("id");
+        if (strlen($id) > 0) {
+            $this->_canvas->add_named_dest($id);
+        }
+
+        // Only two levels of links frames
+        $is_link_node = $node->nodeName === "a";
+        if ($is_link_node) {
+            if (($name = $node->getAttribute("name"))) {
+                $this->_canvas->add_named_dest($name);
+            }
+        }
+
+        if ($frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a") {
+            $link_node = $frame->get_parent()->get_node();
+        }
+
+        // Handle anchors & links
+        if ($is_link_node) {
+            if ($href = $node->getAttribute("href")) {
+                $href = Helpers::build_url($dompdf->getProtocol(), $dompdf->getBaseHost(), $dompdf->getBasePath(), $href) ?? $href;
+                $this->_canvas->add_link($href, $x, $y, $w, $h);
+            }
+        }
+    }
+
+    protected function get_child_size(Frame $frame, bool $do_debug_layout_line): array
+    {
+        $w = 0.0;
+        $h = 0.0;
+
+        foreach ($frame->get_children() as $child) {
+            if ($child->get_node()->nodeValue === " " && $child->get_prev_sibling() && !$child->get_next_sibling()) {
+                break;
+            }
+
+            $style = $child->get_style();
+            $auto_width = $style->width === "auto";
+            $auto_height = $style->height === "auto";
+            [, , $child_w, $child_h] = $child->get_padding_box();
+
+            if ($auto_width || $auto_height) {
+                [$child_w2, $child_h2] = $this->get_child_size($child, $do_debug_layout_line);
+
+                if ($auto_width) {
+                    $child_w = $child_w2;
+                }
+    
+                if ($auto_height) {
+                    $child_h = $child_h2;
+                }
+            }
+
+            $w += $child_w;
+            $h = max($h, $child_h);
+
+            if ($do_debug_layout_line) {
+                $this->_debug_layout($child->get_border_box(), "blue");
+
+                if ($this->_dompdf->getOptions()->getDebugLayoutPaddingBox()) {
+                    $this->_debug_layout($child->get_padding_box(), "blue", [0.5, 0.5]);
+                }
+            }
+        }
+
+        return [$w, $h];
+    }
+}
diff --git a/library/vendor/dompdf/src/Renderer/ListBullet.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/ListBullet.php
similarity index 93%
rename from library/vendor/dompdf/src/Renderer/ListBullet.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/ListBullet.php
index 943f99667..2df6696ad 100644
--- a/library/vendor/dompdf/src/Renderer/ListBullet.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/ListBullet.php
@@ -1,9 +1,7 @@
 
- * @author  Helmut Tischer 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Renderer;
@@ -11,12 +9,12 @@ namespace Dompdf\Renderer;
 use Dompdf\Helpers;
 use Dompdf\Frame;
 use Dompdf\FrameDecorator\ListBullet as ListBulletFrameDecorator;
+use Dompdf\FrameDecorator\ListBulletImage;
 use Dompdf\Image\Cache;
 
 /**
  * Renders list bullets
  *
- * @access  private
  * @package dompdf
  */
 class ListBullet extends AbstractRenderer
@@ -139,7 +137,7 @@ class ListBullet extends AbstractRenderer
         $this->_set_opacity($frame->get_opacity($style->opacity));
 
         // Don't render bullets twice if the list item was split
-        if ($li->_splitted) {
+        if ($li->is_split_off) {
             return;
         }
 
@@ -149,7 +147,7 @@ class ListBullet extends AbstractRenderer
 
         // Handle list-style-image
         // If list style image is requested but missing, fall back to predefined types
-        if ($style->list_style_image !== "none" && !Cache::is_broken($img = $frame->get_image_url())) {
+        if ($frame instanceof ListBulletImage && !Cache::is_broken($img = $frame->get_image_url())) {
             [$x, $y] = $frame->get_position();
             $w = $frame->get_width();
             $h = $frame->get_height();
@@ -212,8 +210,8 @@ class ListBullet extends AbstractRenderer
                         return;
                     }
 
-                    $word_spacing = (float) $style->length_in_pt($style->word_spacing);
-                    $letter_spacing = (float) $style->length_in_pt($style->letter_spacing);
+                    $word_spacing = $style->word_spacing;
+                    $letter_spacing = $style->letter_spacing;
                     $text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font_family, $font_size, $word_spacing, $letter_spacing);
 
                     [$x, $y] = $frame->get_position();
diff --git a/library/vendor/dompdf/src/Renderer/TableCell.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/TableCell.php
similarity index 98%
rename from library/vendor/dompdf/src/Renderer/TableCell.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/TableCell.php
index 3cddff5b7..cbbffd34c 100644
--- a/library/vendor/dompdf/src/Renderer/TableCell.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/TableCell.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Renderer;
diff --git a/library/vendor/dompdf/src/Renderer/TableRowGroup.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php
similarity index 89%
rename from library/vendor/dompdf/src/Renderer/TableRowGroup.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php
index 93e9b97d6..295ccde3e 100644
--- a/library/vendor/dompdf/src/Renderer/TableRowGroup.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php
@@ -1,8 +1,7 @@
 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Renderer;
diff --git a/library/vendor/dompdf/src/Renderer/Text.php b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Text.php
similarity index 82%
rename from library/vendor/dompdf/src/Renderer/Text.php
rename to library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Text.php
index 1bf35a16f..e7baa0a01 100644
--- a/library/vendor/dompdf/src/Renderer/Text.php
+++ b/library/vendor/dompdf/vendor/dompdf/dompdf/src/Renderer/Text.php
@@ -1,10 +1,7 @@
 
- * @author  Helmut Tischer 
- * @author  Fabien Ménager 
+ * @link    https://github.com/dompdf/dompdf
  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  */
 namespace Dompdf\Renderer;
@@ -45,35 +42,29 @@ class Text extends AbstractRenderer
      */
     function render(Frame $frame)
     {
+        $style = $frame->get_style();
         $text = $frame->get_text();
+
         if (trim($text) === "") {
             return;
         }
 
-        $style = $frame->get_style();
+        $this->_set_opacity($frame->get_opacity($style->opacity));
+
         list($x, $y) = $frame->get_position();
         $cb = $frame->get_containing_block();
 
-        if (($ml = $style->margin_left) === "auto" || $ml === "none") {
-            $ml = 0;
-        }
-
-        if (($pl = $style->padding_left) === "auto" || $pl === "none") {
-            $pl = 0;
-        }
-
-        if (($bl = $style->border_left_width) === "auto" || $bl === "none") {
-            $bl = 0;
-        }
-
-        $x += (float)$style->length_in_pt([$ml, $pl, $bl], $cb["w"]);
+        $ml = $style->margin_left;
+        $pl = $style->padding_left;
+        $bl = $style->border_left_width;
+        $x += (float) $style->length_in_pt([$ml, $pl, $bl], $cb["w"]);
 
         $font = $style->font_family;
         $size = $style->font_size;
         $frame_font_size = $frame->get_dompdf()->getFontMetrics()->getFontHeight($font, $size);
-        $word_spacing = $frame->get_text_spacing() + (float)$style->length_in_pt($style->word_spacing);
-        $char_spacing = (float)$style->length_in_pt($style->letter_spacing);
-        $width = $style->width;
+        $word_spacing = $frame->get_text_spacing() + $style->word_spacing;
+        $letter_spacing = $style->letter_spacing;
+        $width = (float) $style->width;
 
         /*$text = str_replace(
           array("{PAGE_NUM}"),
@@ -83,7 +74,7 @@ class Text extends AbstractRenderer
 
         $this->_canvas->text($x, $y, $text,
             $font, $size,
-            $style->color, $word_spacing, $char_spacing);
+            $style->color, $word_spacing, $letter_spacing);
 
         $line = $frame->get_containing_line();
 
@@ -155,12 +146,12 @@ class Text extends AbstractRenderer
 
             $dx = 0;
             $x1 = $x - self::DECO_EXTENSION;
-            $x2 = $x + (float)$width + $dx + self::DECO_EXTENSION;
+            $x2 = $x + $width + $dx + self::DECO_EXTENSION;
             $this->_canvas->line($x1, $deco_y, $x2, $deco_y, $color, $line_thickness);
         }
 
         if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines()) {
-            $text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $char_spacing);
+            $text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $letter_spacing);
             $this->_debug_layout([$x, $y, $text_width, $frame_font_size], "orange", [0.5, 0.5]);
         }
     }
diff --git a/library/vendor/dompdf/vendor/masterminds/html5/CREDITS b/library/vendor/dompdf/vendor/masterminds/html5/CREDITS
new file mode 100644
index 000000000..c2dbc4b64
--- /dev/null
+++ b/library/vendor/dompdf/vendor/masterminds/html5/CREDITS
@@ -0,0 +1,11 @@
+Matt Butcher [technosophos]  (lead)
+Matt Farina  [mattfarina]  (lead)
+Asmir Mustafic [goetas]  (contributor)
+Edward Z. Yang [ezyang]  (contributor)
+Geoffrey Sneddon [gsnedders]  (contributor)
+Kukhar Vasily [ngreduce]  (contributor)
+Rune Christensen [MrElectronic]  (contributor)
+Mišo Belica [miso-belica]  (contributor)
+Asmir Mustafic [goetas]  (contributor)
+KITAITI Makoto [KitaitiMakoto]  (contributor) 
+Jacob Floyd [cognifloyd]  (contributor)
diff --git a/library/vendor/dompdf/vendor/masterminds/html5/LICENSE.txt b/library/vendor/dompdf/vendor/masterminds/html5/LICENSE.txt
new file mode 100644
index 000000000..3c275b54a
--- /dev/null
+++ b/library/vendor/dompdf/vendor/masterminds/html5/LICENSE.txt
@@ -0,0 +1,66 @@
+## HTML5-PHP License
+
+Copyright (c) 2013 The Authors of HTML5-PHP
+
+Matt Butcher - mattbutcher@google.com
+Matt Farina - matt@mattfarina.com
+Asmir Mustafic - goetas@gmail.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+## HTML5Lib License
+
+Portions of this are based on html5lib's PHP version, which was a
+sub-project of html5lib. The following is the list of contributors from
+html5lib:
+
+html5lib:
+
+Copyright (c) 2006-2009 The Authors
+
+Contributors:
+James Graham - jg307@cam.ac.uk
+Anne van Kesteren - annevankesteren@gmail.com
+Lachlan Hunt - lachlan.hunt@lachy.id.au
+Matt McDonald - kanashii@kanashii.ca
+Sam Ruby - rubys@intertwingly.net
+Ian Hickson (Google) - ian@hixie.ch
+Thomas Broyer - t.broyer@ltgt.net
+Jacques Distler - distler@golem.ph.utexas.edu
+Henri Sivonen - hsivonen@iki.fi
+Adam Barth - abarth@webkit.org
+Eric Seidel - eric@webkit.org
+The Mozilla Foundation (contributions from Henri Sivonen since 2008)
+David Flanagan (Mozilla) - dflanagan@mozilla.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/library/vendor/dompdf/vendor/masterminds/html5/README.md b/library/vendor/dompdf/vendor/masterminds/html5/README.md
new file mode 100644
index 000000000..b1ca1e371
--- /dev/null
+++ b/library/vendor/dompdf/vendor/masterminds/html5/README.md
@@ -0,0 +1,270 @@
+> # UKRAINE NEEDS YOUR HELP NOW!
+>
+> On 24 February 2022, Russian [President Vladimir Putin ordered an invasion of Ukraine by Russian Armed Forces](https://www.bbc.com/news/world-europe-60504334).
+>
+> Your support is urgently needed.
+>
+> - Donate to the volunteers. Here is the volunteer fund helping the Ukrainian army to provide all the necessary equipment:
+>  https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi or https://savelife.in.ua/en/donate/
+> - Triple-check social media sources. Russian disinformation is attempting to coverup and distort the reality in Ukraine.
+> - Help Ukrainian refugees who are fleeing Russian attacks and shellings: https://www.globalcitizen.org/en/content/ways-to-help-ukraine-conflict/
+> -  Put pressure on your political representatives to provide help to Ukraine.
+> -  Believe in the Ukrainian people, they will not surrender, they don't have another Ukraine.
+>
+> THANK YOU!
+----
+
+# HTML5-PHP
+
+HTML5 is a standards-compliant HTML5 parser and writer written entirely in PHP.
+It is stable and used in many production websites, and has
+well over [five million downloads](https://packagist.org/packages/masterminds/html5).
+
+HTML5 provides the following features.
+
+- An HTML5 serializer
+- Support for PHP namespaces
+- Composer support
+- Event-based (SAX-like) parser
+- A DOM tree builder
+- Interoperability with [QueryPath](https://github.com/technosophos/querypath)
+- Runs on **PHP** 5.3.0 or newer
+
+[![Build Status](https://travis-ci.org/Masterminds/html5-php.png?branch=master)](https://travis-ci.org/Masterminds/html5-php)
+[![Latest Stable Version](https://poser.pugx.org/masterminds/html5/v/stable.png)](https://packagist.org/packages/masterminds/html5)
+[![Code Coverage](https://scrutinizer-ci.com/g/Masterminds/html5-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Masterminds/html5-php/?branch=master)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Masterminds/html5-php/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Masterminds/html5-php/?branch=master)
+[![Stability: Sustained](https://masterminds.github.io/stability/sustained.svg)](https://masterminds.github.io/stability/sustained.html)
+
+## Installation
+
+Install HTML5-PHP using [composer](http://getcomposer.org/).
+
+By adding the `masterminds/html5` dependency to your `composer.json` file:
+
+```json
+{
+  "require" : {
+    "masterminds/html5": "^2.0"
+  },
+}
+```
+
+By invoking require command via composer executable:
+
+```bash
+composer require masterminds/html5
+```
+
+## Basic Usage
+
+HTML5-PHP has a high-level API and a low-level API.
+
+Here is how you use the high-level `HTML5` library API:
+
+```php
+
+  
+    TEST
+  
+  
+    

Hello World

+

This is a test of the HTML5 parser.

+ + +HERE; + +// Parse the document. $dom is a DOMDocument. +$html5 = new HTML5(); +$dom = $html5->loadHTML($html); + +// Render it as HTML5: +print $html5->saveHTML($dom); + +// Or save it to a file: +$html5->save($dom, 'out.html'); +``` + +The `$dom` created by the parser is a full `DOMDocument` object. And the +`save()` and `saveHTML()` methods will take any DOMDocument. + +### Options + +It is possible to pass in an array of configuration options when loading +an HTML5 document. + +```php +// An associative array of options +$options = array( + 'option_name' => 'option_value', +); + +// Provide the options to the constructor +$html5 = new HTML5($options); + +$dom = $html5->loadHTML($html); +``` + +The following options are supported: + +* `encode_entities` (boolean): Indicates that the serializer should aggressively + encode characters as entities. Without this, it only encodes the bare + minimum. +* `disable_html_ns` (boolean): Prevents the parser from automatically + assigning the HTML5 namespace to the DOM document. This is for + non-namespace aware DOM tools. +* `target_document` (\DOMDocument): A DOM document that will be used as the + destination for the parsed nodes. +* `implicit_namespaces` (array): An assoc array of namespaces that should be + used by the parser. Name is tag prefix, value is NS URI. + +## The Low-Level API + +This library provides the following low-level APIs that you can use to +create more customized HTML5 tools: + +- A SAX-like event-based parser that you can hook into for special kinds +of parsing. +- A flexible error-reporting mechanism that can be tuned to document +syntax checking. +- A DOM implementation that uses PHP's built-in DOM library. + +The unit tests exercise each piece of the API, and every public function +is well-documented. + +### Parser Design + +The parser is designed as follows: + +- The `Scanner` handles scanning on behalf of the parser. +- The `Tokenizer` requests data off of the scanner, parses it, clasifies +it, and sends it to an `EventHandler`. It is a *recursive descent parser.* +- The `EventHandler` receives notifications and data for each specific +semantic event that occurs during tokenization. +- The `DOMBuilder` is an `EventHandler` that listens for tokenizing +events and builds a document tree (`DOMDocument`) based on the events. + +### Serializer Design + +The serializer takes a data structure (the `DOMDocument`) and transforms +it into a character representation -- an HTML5 document. + +The serializer is broken into three parts: + +- The `OutputRules` contain the rules to turn DOM elements into strings. The +rules are an implementation of the interface `RulesInterface` allowing for +different rule sets to be used. +- The `Traverser`, which is a special-purpose tree walker. It visits +each node node in the tree and uses the `OutputRules` to transform the node +into a string. +- `HTML5` manages the `Traverser` and stores the resultant data +in the correct place. + +The serializer (`save()`, `saveHTML()`) follows the +[section 8.9 of the HTML 5.0 spec](http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#serializing-html-fragments). +So tags are serialized according to these rules: + +- A tag with children: <foo>CHILDREN</foo> +- A tag that cannot have content: <foo> (no closing tag) +- A tag that could have content, but doesn't: <foo></foo> + +## Known Issues (Or, Things We Designed Against the Spec) + +Please check the issue queue for a full list, but the following are +issues known issues that are not presently on the roadmap: + +- Namespaces: HTML5 only [supports a selected list of namespaces](http://www.w3.org/TR/html5/infrastructure.html#namespaces) + and they do not operate in the same way as XML namespaces. A `:` has no special + meaning. + By default the parser does not support XML style namespaces via `:`; + to enable the XML namespaces see the [XML Namespaces section](#xml-namespaces) +- Scripts: This parser does not contain a JavaScript or a CSS + interpreter. While one may be supplied, not all features will be + supported. +- Rentrance: The current parser is not re-entrant. (Thus you can't pause + the parser to modify the HTML string mid-parse.) +- Validation: The current tree builder is **not** a validating parser. + While it will correct some HTML, it does not check that the HTML + conforms to the standard. (Should you wish, you can build a validating + parser by extending DOMTree or building your own EventHandler + implementation.) + * There is limited support for insertion modes. + * Some autocorrection is done automatically. + * Per the spec, many legacy tags are admitted and correctly handled, + even though they are technically not part of HTML5. +- Attribute names and values: Due to the implementation details of the + PHP implementation of DOM, attribute names that do not follow the + XML 1.0 standard are not inserted into the DOM. (Effectively, they + are ignored.) If you've got a clever fix for this, jump in! +- Processor Instructions: The HTML5 spec does not allow processor + instructions. We do. Since this is a server-side library, we think + this is useful. And that means, dear reader, that in some cases you + can parse the HTML from a mixed PHP/HTML document. This, however, + is an incidental feature, not a core feature. +- HTML manifests: Unsupported. +- PLAINTEXT: Unsupported. +- Adoption Agency Algorithm: Not yet implemented. (8.2.5.4.7) + +## XML Namespaces + +To use XML style namespaces you have to configure well the main `HTML5` instance. + +```php +use Masterminds\HTML5; +$html = new HTML5(array( + "xmlNamespaces" => true +)); + +$dom = $html->loadHTML(''); + +$dom->documentElement->namespaceURI; // http://www.example.com + +``` + +You can also add some default prefixes that will not require the namespace declaration, +but its elements will be namespaced. + +```php +use Masterminds\HTML5; +$html = new HTML5(array( + "implicitNamespaces"=>array( + "t"=>"http://www.example.com" + ) +)); + +$dom = $html->loadHTML(''); + +$dom->documentElement->namespaceURI; // http://www.example.com + +``` + +## Thanks to... + +The dedicated (and patient) contributors of patches small and large, +who have already made this library better.See the CREDITS file for +a list of contributors. + +We owe a huge debt of gratitude to the original authors of html5lib. + +While not much of the original parser remains, we learned a lot from +reading the html5lib library. And some pieces remain here. In +particular, much of the UTF-8 and Unicode handling is derived from the +html5lib project. + +## License + +This software is released under the MIT license. The original html5lib +library was also released under the MIT license. + +See LICENSE.txt + +Certain files contain copyright assertions by specific individuals +involved with html5lib. Those have been retained where appropriate. diff --git a/library/vendor/dompdf/vendor/masterminds/html5/RELEASE.md b/library/vendor/dompdf/vendor/masterminds/html5/RELEASE.md new file mode 100644 index 000000000..33007ed69 --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/RELEASE.md @@ -0,0 +1,157 @@ +# Release Notes + +2.7.6 (2021-08-18) + +- #218: Address comment handling issues + +2.7.5 (2021-07-01) + +- #204: Travis: Enable tests on PHP 8.0 +- #207: Fix PHP 8.1 deprecations + +2.7.4 (2020-10-01) + +- #191: Fix travisci build +- #195: Add .gitattributes file with export-ignore rules +- #194: Fix query parameter parsed as character entity + +2.7.3 (2020-07-05) + +- #190: mitigate cyclic reference between output rules and the traverser objects + +2.7.2 (2020-07-01) + +- #187: Fixed memory leak in HTML5::saveHTML() +- #186: Add special case for end tag
+ +2.7.1 (2020-06-14) + +- #171: add PHP 7.4 job +- #178: Prevent infinite loop on un-terminated entity declaration at EOF + +2.7.0 (2019-07-25) + +- #164: Drop HHVM support +- #168: Set default encoding in the DOMDocument object + +2.6.0 (2019-03-10) + +- #163: Allow to pass a charset to the Scanner + +2.5.0 (2018-12-27) + +- #162, #161, #155, #154, #153, #151: big performance improvements +- #156: fixed typos +- #160: adopt and enforce code style +- #159: remove deprecated php unit base test case +- #150: backport changes from old master branch + +2.4.0 (2018-11-17) + +- #148: Improve performance by moving sequence matching +- #147: Improve the Tokenizer performance +- #146: Improve performance by relying on a native string instead of InputStream +- #144: Add DOM extension in composer.json +- #145: Add more extensions on composer.json, improve phpdocs and remove dead code +- #143: Remove experimental comment + +2.3.1 (2018-10-18) + +- #121: Audio is not a block tag (fixed by #141) +- #136: Handle illegal self-closing according to spec (fixed by #137) +- #141: Minor fixes in the README + +2.3.0 (2017-09-04) + +- #129: image within inline svg breaks system (fixed by #133) +- #131: ² does not work (fixed by #132) +- #134: Improve tokenizer performance by 20% (alternative version of #130 thanks to @MichaelHeerklotz) +- #135: Raw & in attributes + +2.2.2 (2016-09-22) + +- #116: In XML mode, tags are case sensitive +- #115: Fix PHP Notice in OutputRules +- #112: fix parsing of options of an optgroup +- #111: Adding test for the address tag + +2.2.1 (2016-05-10) + +- #109: Fixed issue where address tag could be written without closing tag (thanks sylus) + +2.2.0 (2016-04-11) + +- #105: Enable composer cache (for CI/CD) +- #100: Use mb_substitute_character inset of ini_set for environments where ini_set is disable (e.g., shared hosting) +- #98: Allow link, meta, style tags in noscript tags +- #96: Fixed xml:href on svgs that use the "use" breaking +- #94: Counting UTF8 characters performance improvement +- #93: Use newer version of coveralls package +- #90: Remove duplicate test +- #87: Allow multiple root nodes + +2.1.2 (2015-06-07) +- #82: Support for PHP7 +- #84: Improved boolean attribute handling + +2.1.1 (2015-03-23) +- #78: Fixes bug where unmatched entity like string drops everything after &. + +2.1.0 (2015-02-01) +- #74: Added `disable_html_ns` and `target_doc` dom parsing options +- Unified option names +- #73: Fixed alphabet, ß now can be detected +- #75 and #76: Allow whitespace in RCDATA tags +- #77: Fixed parsing blunder for json embeds +- #72: Add options to HTML methods + +2.0.2 (2014-12-17) +- #50: empty document handling +- #63: tags with strange capitalization +- #65: dashes and underscores as allowed characters in tag names +- #68: Fixed issue with non-inline elements inside inline containers + +2.0.1 (2014-09-23) +- #59: Fixed issue parsing some fragments. +- #56: Incorrectly saw 0 as empty string +- Sami as new documentation generator + +2.0.0 (2014-07-28) +- #53: Improved boolean attributes handling +- #52: Facebook HHVM compatibility +- #48: Adopted PSR-2 as coding standard +- #47: Moved everything to Masterminds namespace +- #45: Added custom namespaces +- #44: Added support to XML-style namespaces +- #37: Refactored HTML5 class removing static methods + +1.0.5 (2014-06-10) +- #38: Set the dev-master branch as the 1.0.x branch for composer (goetas) +- #34: Tests use PSR-4 for autoloading. (goetas) +- #40, #41: Fix entity handling in RCDATA sections. (KitaitiMakoto) +- #32: Fixed issue where wharacter references were being incorrectly encoded in style tags. + +1.0.4 (2014-04-29) +- #30/#31 Don't throw an exception for invalid tag names. + +1.0.3 (2014-02-28) +- #23 and #29: Ignore attributes with illegal chars in name for the PHP DOM. + +1.0.2 (2014-02-12) +- #23: Handle missing tag close in attribute list. +- #25: Fixed text escaping in the serializer (HTML% 8.3). +- #27: Fixed tests on Windows: changed "\n" -> PHP_EOL. +- #28: Fixed infinite loop for char "&" in unquoted attribute in parser. +- #26: Updated tag name case handling to deal with uppercase usage. +- #24: Newlines and tabs are allowed inside quoted attributes (HTML5 8.2.4). +- Fixed Travis CI testing. + +1.0.1 (2013-11-07) +- CDATA encoding is improved. (Non-standard; Issue #19) +- Some parser rules were not returning the new current element. (Issue #20) +- Added, to the README, details on code test coverage and to packagist version. +- Fixed processor instructions. +- Improved test coverage and documentation coverage. + +1.0.0 (2013-10-02) +- Initial release. diff --git a/library/vendor/dompdf/vendor/masterminds/html5/UPGRADING.md b/library/vendor/dompdf/vendor/masterminds/html5/UPGRADING.md new file mode 100644 index 000000000..76e3a19bc --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/UPGRADING.md @@ -0,0 +1,21 @@ +From 1.x to 2.x +================= + +- All classes uses `Masterminds` namespace. +- All public static methods has been removed from `HTML5` class and the general API to access the HTML5 functionalities has changed. + + Before: + + $dom = \HTML5::loadHTML('....'); + \HTML5::saveHTML($dom); + + After: + + use Masterminds\HTML5; + + $html5 = new HTML5(); + + $dom = $html5->loadHTML('....'); + echo $html5->saveHTML($dom); + + diff --git a/library/vendor/dompdf/vendor/masterminds/html5/bin/entities.php b/library/vendor/dompdf/vendor/masterminds/html5/bin/entities.php new file mode 100644 index 000000000..56323a341 --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/bin/entities.php @@ -0,0 +1,26 @@ + $obj) { + $sname = substr($name, 1, -1); + $table[$sname] = $obj->characters; +} + +echo '=5.3.0" + }, + "require-dev": { + "phpunit/phpunit" : "^4.8.35 || ^5.7.21 || ^6 || ^7" + }, + "autoload": { + "psr-4": {"Masterminds\\": "src"} + }, + "autoload-dev": { + "psr-4": {"Masterminds\\HTML5\\Tests\\": "test/HTML5"} + }, + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5.php new file mode 100644 index 000000000..c857145fb --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5.php @@ -0,0 +1,246 @@ + false, + + // Prevents the parser from automatically assigning the HTML5 namespace to the DOM document. + 'disable_html_ns' => false, + ); + + protected $errors = array(); + + public function __construct(array $defaultOptions = array()) + { + $this->defaultOptions = array_merge($this->defaultOptions, $defaultOptions); + } + + /** + * Get the current default options. + * + * @return array + */ + public function getOptions() + { + return $this->defaultOptions; + } + + /** + * Load and parse an HTML file. + * + * This will apply the HTML5 parser, which is tolerant of many + * varieties of HTML, including XHTML 1, HTML 4, and well-formed HTML + * 3. Note that in these cases, not all of the old data will be + * preserved. For example, XHTML's XML declaration will be removed. + * + * The rules governing parsing are set out in the HTML 5 spec. + * + * @param string|resource $file The path to the file to parse. If this is a resource, it is + * assumed to be an open stream whose pointer is set to the first + * byte of input. + * @param array $options Configuration options when parsing the HTML. + * + * @return \DOMDocument A DOM document. These object type is defined by the libxml + * library, and should have been included with your version of PHP. + */ + public function load($file, array $options = array()) + { + // Handle the case where file is a resource. + if (is_resource($file)) { + return $this->parse(stream_get_contents($file), $options); + } + + return $this->parse(file_get_contents($file), $options); + } + + /** + * Parse a HTML Document from a string. + * + * Take a string of HTML 5 (or earlier) and parse it into a + * DOMDocument. + * + * @param string $string A html5 document as a string. + * @param array $options Configuration options when parsing the HTML. + * + * @return \DOMDocument A DOM document. DOM is part of libxml, which is included with + * almost all distribtions of PHP. + */ + public function loadHTML($string, array $options = array()) + { + return $this->parse($string, $options); + } + + /** + * Convenience function to load an HTML file. + * + * This is here to provide backwards compatibility with the + * PHP DOM implementation. It simply calls load(). + * + * @param string $file The path to the file to parse. If this is a resource, it is + * assumed to be an open stream whose pointer is set to the first + * byte of input. + * @param array $options Configuration options when parsing the HTML. + * + * @return \DOMDocument A DOM document. These object type is defined by the libxml + * library, and should have been included with your version of PHP. + */ + public function loadHTMLFile($file, array $options = array()) + { + return $this->load($file, $options); + } + + /** + * Parse a HTML fragment from a string. + * + * @param string $string the HTML5 fragment as a string + * @param array $options Configuration options when parsing the HTML + * + * @return \DOMDocumentFragment A DOM fragment. The DOM is part of libxml, which is included with + * almost all distributions of PHP. + */ + public function loadHTMLFragment($string, array $options = array()) + { + return $this->parseFragment($string, $options); + } + + /** + * Return all errors encountered into parsing phase. + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * Return true it some errors were encountered into parsing phase. + * + * @return bool + */ + public function hasErrors() + { + return count($this->errors) > 0; + } + + /** + * Parse an input string. + * + * @param string $input + * @param array $options + * + * @return \DOMDocument + */ + public function parse($input, array $options = array()) + { + $this->errors = array(); + $options = array_merge($this->defaultOptions, $options); + $events = new DOMTreeBuilder(false, $options); + $scanner = new Scanner($input, !empty($options['encoding']) ? $options['encoding'] : 'UTF-8'); + $parser = new Tokenizer($scanner, $events, !empty($options['xmlNamespaces']) ? Tokenizer::CONFORMANT_XML : Tokenizer::CONFORMANT_HTML); + + $parser->parse(); + $this->errors = $events->getErrors(); + + return $events->document(); + } + + /** + * Parse an input stream where the stream is a fragment. + * + * Lower-level loading function. This requires an input stream instead + * of a string, file, or resource. + * + * @param string $input The input data to parse in the form of a string. + * @param array $options An array of options. + * + * @return \DOMDocumentFragment + */ + public function parseFragment($input, array $options = array()) + { + $options = array_merge($this->defaultOptions, $options); + $events = new DOMTreeBuilder(true, $options); + $scanner = new Scanner($input, !empty($options['encoding']) ? $options['encoding'] : 'UTF-8'); + $parser = new Tokenizer($scanner, $events, !empty($options['xmlNamespaces']) ? Tokenizer::CONFORMANT_XML : Tokenizer::CONFORMANT_HTML); + + $parser->parse(); + $this->errors = $events->getErrors(); + + return $events->fragment(); + } + + /** + * Save a DOM into a given file as HTML5. + * + * @param mixed $dom The DOM to be serialized. + * @param string|resource $file The filename to be written or resource to write to. + * @param array $options Configuration options when serializing the DOM. These include: + * - encode_entities: Text written to the output is escaped by default and not all + * entities are encoded. If this is set to true all entities will be encoded. + * Defaults to false. + */ + public function save($dom, $file, $options = array()) + { + $close = true; + if (is_resource($file)) { + $stream = $file; + $close = false; + } else { + $stream = fopen($file, 'wb'); + } + $options = array_merge($this->defaultOptions, $options); + $rules = new OutputRules($stream, $options); + $trav = new Traverser($dom, $stream, $rules, $options); + + $trav->walk(); + /* + * release the traverser to avoid cyclic references and allow PHP to free memory without waiting for gc_collect_cycles + */ + $rules->unsetTraverser(); + if ($close) { + fclose($stream); + } + } + + /** + * Convert a DOM into an HTML5 string. + * + * @param mixed $dom The DOM to be serialized. + * @param array $options Configuration options when serializing the DOM. These include: + * - encode_entities: Text written to the output is escaped by default and not all + * entities are encoded. If this is set to true all entities will be encoded. + * Defaults to false. + * + * @return string A HTML5 documented generated from the DOM. + */ + public function saveHTML($dom, $options = array()) + { + $stream = fopen('php://temp', 'wb'); + $this->save($dom, $stream, array_merge($this->defaultOptions, $options)); + + $html = stream_get_contents($stream, -1, 0); + + fclose($stream); + + return $html; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Elements.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Elements.php new file mode 100644 index 000000000..8fe798789 --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Elements.php @@ -0,0 +1,619 @@ + 1, + 'abbr' => 1, + 'address' => 65, // NORMAL | BLOCK_TAG + 'area' => 9, // NORMAL | VOID_TAG + 'article' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'aside' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'audio' => 1, // NORMAL + 'b' => 1, + 'base' => 9, // NORMAL | VOID_TAG + 'bdi' => 1, + 'bdo' => 1, + 'blockquote' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'body' => 1, + 'br' => 9, // NORMAL | VOID_TAG + 'button' => 1, + 'canvas' => 65, // NORMAL | BLOCK_TAG + 'caption' => 1, + 'cite' => 1, + 'code' => 1, + 'col' => 9, // NORMAL | VOID_TAG + 'colgroup' => 1, + 'command' => 9, // NORMAL | VOID_TAG + // "data" => 1, // This is highly experimental and only part of the whatwg spec (not w3c). See https://developer.mozilla.org/en-US/docs/HTML/Element/data + 'datalist' => 1, + 'dd' => 65, // NORMAL | BLOCK_TAG + 'del' => 1, + 'details' => 17, // NORMAL | AUTOCLOSE_P, + 'dfn' => 1, + 'dialog' => 17, // NORMAL | AUTOCLOSE_P, + 'div' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'dl' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'dt' => 1, + 'em' => 1, + 'embed' => 9, // NORMAL | VOID_TAG + 'fieldset' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'figcaption' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'figure' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'footer' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'form' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h1' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h2' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h3' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h4' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h5' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'h6' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'head' => 1, + 'header' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'hgroup' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'hr' => 73, // NORMAL | VOID_TAG + 'html' => 1, + 'i' => 1, + 'iframe' => 3, // NORMAL | TEXT_RAW + 'img' => 9, // NORMAL | VOID_TAG + 'input' => 9, // NORMAL | VOID_TAG + 'kbd' => 1, + 'ins' => 1, + 'keygen' => 9, // NORMAL | VOID_TAG + 'label' => 1, + 'legend' => 1, + 'li' => 1, + 'link' => 9, // NORMAL | VOID_TAG + 'map' => 1, + 'mark' => 1, + 'menu' => 17, // NORMAL | AUTOCLOSE_P, + 'meta' => 9, // NORMAL | VOID_TAG + 'meter' => 1, + 'nav' => 17, // NORMAL | AUTOCLOSE_P, + 'noscript' => 65, // NORMAL | BLOCK_TAG + 'object' => 1, + 'ol' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'optgroup' => 1, + 'option' => 1, + 'output' => 65, // NORMAL | BLOCK_TAG + 'p' => 209, // NORMAL | AUTOCLOSE_P | BLOCK_TAG | BLOCK_ONLY_INLINE + 'param' => 9, // NORMAL | VOID_TAG + 'pre' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'progress' => 1, + 'q' => 1, + 'rp' => 1, + 'rt' => 1, + 'ruby' => 1, + 's' => 1, + 'samp' => 1, + 'script' => 3, // NORMAL | TEXT_RAW + 'section' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'select' => 1, + 'small' => 1, + 'source' => 9, // NORMAL | VOID_TAG + 'span' => 1, + 'strong' => 1, + 'style' => 3, // NORMAL | TEXT_RAW + 'sub' => 1, + 'summary' => 17, // NORMAL | AUTOCLOSE_P, + 'sup' => 1, + 'table' => 65, // NORMAL | BLOCK_TAG + 'tbody' => 1, + 'td' => 1, + 'textarea' => 5, // NORMAL | TEXT_RCDATA + 'tfoot' => 65, // NORMAL | BLOCK_TAG + 'th' => 1, + 'thead' => 1, + 'time' => 1, + 'title' => 5, // NORMAL | TEXT_RCDATA + 'tr' => 1, + 'track' => 9, // NORMAL | VOID_TAG + 'u' => 1, + 'ul' => 81, // NORMAL | AUTOCLOSE_P | BLOCK_TAG + 'var' => 1, + 'video' => 65, // NORMAL | BLOCK_TAG + 'wbr' => 9, // NORMAL | VOID_TAG + + // Legacy? + 'basefont' => 8, // VOID_TAG + 'bgsound' => 8, // VOID_TAG + 'noframes' => 2, // RAW_TEXT + 'frame' => 9, // NORMAL | VOID_TAG + 'frameset' => 1, + 'center' => 16, + 'dir' => 16, + 'listing' => 16, // AUTOCLOSE_P + 'plaintext' => 48, // AUTOCLOSE_P | TEXT_PLAINTEXT + 'applet' => 0, + 'marquee' => 0, + 'isindex' => 8, // VOID_TAG + 'xmp' => 20, // AUTOCLOSE_P | VOID_TAG | RAW_TEXT + 'noembed' => 2, // RAW_TEXT + ); + + /** + * The MathML elements. + * See http://www.w3.org/wiki/MathML/Elements. + * + * In our case we are only concerned with presentation MathML and not content + * MathML. There is a nice list of this subset at https://developer.mozilla.org/en-US/docs/MathML/Element. + * + * @var array + */ + public static $mathml = array( + 'maction' => 1, + 'maligngroup' => 1, + 'malignmark' => 1, + 'math' => 1, + 'menclose' => 1, + 'merror' => 1, + 'mfenced' => 1, + 'mfrac' => 1, + 'mglyph' => 1, + 'mi' => 1, + 'mlabeledtr' => 1, + 'mlongdiv' => 1, + 'mmultiscripts' => 1, + 'mn' => 1, + 'mo' => 1, + 'mover' => 1, + 'mpadded' => 1, + 'mphantom' => 1, + 'mroot' => 1, + 'mrow' => 1, + 'ms' => 1, + 'mscarries' => 1, + 'mscarry' => 1, + 'msgroup' => 1, + 'msline' => 1, + 'mspace' => 1, + 'msqrt' => 1, + 'msrow' => 1, + 'mstack' => 1, + 'mstyle' => 1, + 'msub' => 1, + 'msup' => 1, + 'msubsup' => 1, + 'mtable' => 1, + 'mtd' => 1, + 'mtext' => 1, + 'mtr' => 1, + 'munder' => 1, + 'munderover' => 1, + ); + + /** + * The svg elements. + * + * The Mozilla documentation has a good list at https://developer.mozilla.org/en-US/docs/SVG/Element. + * The w3c list appears to be lacking in some areas like filter effect elements. + * That list can be found at http://www.w3.org/wiki/SVG/Elements. + * + * Note, FireFox appears to do a better job rendering filter effects than chrome. + * While they are in the spec I'm not sure how widely implemented they are. + * + * @var array + */ + public static $svg = array( + 'a' => 1, + 'altGlyph' => 1, + 'altGlyphDef' => 1, + 'altGlyphItem' => 1, + 'animate' => 1, + 'animateColor' => 1, + 'animateMotion' => 1, + 'animateTransform' => 1, + 'circle' => 1, + 'clipPath' => 1, + 'color-profile' => 1, + 'cursor' => 1, + 'defs' => 1, + 'desc' => 1, + 'ellipse' => 1, + 'feBlend' => 1, + 'feColorMatrix' => 1, + 'feComponentTransfer' => 1, + 'feComposite' => 1, + 'feConvolveMatrix' => 1, + 'feDiffuseLighting' => 1, + 'feDisplacementMap' => 1, + 'feDistantLight' => 1, + 'feFlood' => 1, + 'feFuncA' => 1, + 'feFuncB' => 1, + 'feFuncG' => 1, + 'feFuncR' => 1, + 'feGaussianBlur' => 1, + 'feImage' => 1, + 'feMerge' => 1, + 'feMergeNode' => 1, + 'feMorphology' => 1, + 'feOffset' => 1, + 'fePointLight' => 1, + 'feSpecularLighting' => 1, + 'feSpotLight' => 1, + 'feTile' => 1, + 'feTurbulence' => 1, + 'filter' => 1, + 'font' => 1, + 'font-face' => 1, + 'font-face-format' => 1, + 'font-face-name' => 1, + 'font-face-src' => 1, + 'font-face-uri' => 1, + 'foreignObject' => 1, + 'g' => 1, + 'glyph' => 1, + 'glyphRef' => 1, + 'hkern' => 1, + 'image' => 1, + 'line' => 1, + 'linearGradient' => 1, + 'marker' => 1, + 'mask' => 1, + 'metadata' => 1, + 'missing-glyph' => 1, + 'mpath' => 1, + 'path' => 1, + 'pattern' => 1, + 'polygon' => 1, + 'polyline' => 1, + 'radialGradient' => 1, + 'rect' => 1, + 'script' => 3, // NORMAL | RAW_TEXT + 'set' => 1, + 'stop' => 1, + 'style' => 3, // NORMAL | RAW_TEXT + 'svg' => 1, + 'switch' => 1, + 'symbol' => 1, + 'text' => 1, + 'textPath' => 1, + 'title' => 1, + 'tref' => 1, + 'tspan' => 1, + 'use' => 1, + 'view' => 1, + 'vkern' => 1, + ); + + /** + * Some attributes in SVG are case sensitive. + * + * This map contains key/value pairs with the key as the lowercase attribute + * name and the value with the correct casing. + */ + public static $svgCaseSensitiveAttributeMap = array( + 'attributename' => 'attributeName', + 'attributetype' => 'attributeType', + 'basefrequency' => 'baseFrequency', + 'baseprofile' => 'baseProfile', + 'calcmode' => 'calcMode', + 'clippathunits' => 'clipPathUnits', + 'contentscripttype' => 'contentScriptType', + 'contentstyletype' => 'contentStyleType', + 'diffuseconstant' => 'diffuseConstant', + 'edgemode' => 'edgeMode', + 'externalresourcesrequired' => 'externalResourcesRequired', + 'filterres' => 'filterRes', + 'filterunits' => 'filterUnits', + 'glyphref' => 'glyphRef', + 'gradienttransform' => 'gradientTransform', + 'gradientunits' => 'gradientUnits', + 'kernelmatrix' => 'kernelMatrix', + 'kernelunitlength' => 'kernelUnitLength', + 'keypoints' => 'keyPoints', + 'keysplines' => 'keySplines', + 'keytimes' => 'keyTimes', + 'lengthadjust' => 'lengthAdjust', + 'limitingconeangle' => 'limitingConeAngle', + 'markerheight' => 'markerHeight', + 'markerunits' => 'markerUnits', + 'markerwidth' => 'markerWidth', + 'maskcontentunits' => 'maskContentUnits', + 'maskunits' => 'maskUnits', + 'numoctaves' => 'numOctaves', + 'pathlength' => 'pathLength', + 'patterncontentunits' => 'patternContentUnits', + 'patterntransform' => 'patternTransform', + 'patternunits' => 'patternUnits', + 'pointsatx' => 'pointsAtX', + 'pointsaty' => 'pointsAtY', + 'pointsatz' => 'pointsAtZ', + 'preservealpha' => 'preserveAlpha', + 'preserveaspectratio' => 'preserveAspectRatio', + 'primitiveunits' => 'primitiveUnits', + 'refx' => 'refX', + 'refy' => 'refY', + 'repeatcount' => 'repeatCount', + 'repeatdur' => 'repeatDur', + 'requiredextensions' => 'requiredExtensions', + 'requiredfeatures' => 'requiredFeatures', + 'specularconstant' => 'specularConstant', + 'specularexponent' => 'specularExponent', + 'spreadmethod' => 'spreadMethod', + 'startoffset' => 'startOffset', + 'stddeviation' => 'stdDeviation', + 'stitchtiles' => 'stitchTiles', + 'surfacescale' => 'surfaceScale', + 'systemlanguage' => 'systemLanguage', + 'tablevalues' => 'tableValues', + 'targetx' => 'targetX', + 'targety' => 'targetY', + 'textlength' => 'textLength', + 'viewbox' => 'viewBox', + 'viewtarget' => 'viewTarget', + 'xchannelselector' => 'xChannelSelector', + 'ychannelselector' => 'yChannelSelector', + 'zoomandpan' => 'zoomAndPan', + ); + + /** + * Some SVG elements are case sensitive. + * This map contains these. + * + * The map contains key/value store of the name is lowercase as the keys and + * the correct casing as the value. + */ + public static $svgCaseSensitiveElementMap = array( + 'altglyph' => 'altGlyph', + 'altglyphdef' => 'altGlyphDef', + 'altglyphitem' => 'altGlyphItem', + 'animatecolor' => 'animateColor', + 'animatemotion' => 'animateMotion', + 'animatetransform' => 'animateTransform', + 'clippath' => 'clipPath', + 'feblend' => 'feBlend', + 'fecolormatrix' => 'feColorMatrix', + 'fecomponenttransfer' => 'feComponentTransfer', + 'fecomposite' => 'feComposite', + 'feconvolvematrix' => 'feConvolveMatrix', + 'fediffuselighting' => 'feDiffuseLighting', + 'fedisplacementmap' => 'feDisplacementMap', + 'fedistantlight' => 'feDistantLight', + 'feflood' => 'feFlood', + 'fefunca' => 'feFuncA', + 'fefuncb' => 'feFuncB', + 'fefuncg' => 'feFuncG', + 'fefuncr' => 'feFuncR', + 'fegaussianblur' => 'feGaussianBlur', + 'feimage' => 'feImage', + 'femerge' => 'feMerge', + 'femergenode' => 'feMergeNode', + 'femorphology' => 'feMorphology', + 'feoffset' => 'feOffset', + 'fepointlight' => 'fePointLight', + 'fespecularlighting' => 'feSpecularLighting', + 'fespotlight' => 'feSpotLight', + 'fetile' => 'feTile', + 'feturbulence' => 'feTurbulence', + 'foreignobject' => 'foreignObject', + 'glyphref' => 'glyphRef', + 'lineargradient' => 'linearGradient', + 'radialgradient' => 'radialGradient', + 'textpath' => 'textPath', + ); + + /** + * Check whether the given element meets the given criterion. + * + * Example: + * + * Elements::isA('script', Elements::TEXT_RAW); // Returns true. + * + * Elements::isA('script', Elements::TEXT_RCDATA); // Returns false. + * + * @param string $name The element name. + * @param int $mask One of the constants on this class. + * + * @return bool true if the element matches the mask, false otherwise. + */ + public static function isA($name, $mask) + { + return (static::element($name) & $mask) === $mask; + } + + /** + * Test if an element is a valid html5 element. + * + * @param string $name The name of the element. + * + * @return bool true if a html5 element and false otherwise. + */ + public static function isHtml5Element($name) + { + // html5 element names are case insensitive. Forcing lowercase for the check. + // Do we need this check or will all data passed here already be lowercase? + return isset(static::$html5[strtolower($name)]); + } + + /** + * Test if an element name is a valid MathML presentation element. + * + * @param string $name The name of the element. + * + * @return bool true if a MathML name and false otherwise. + */ + public static function isMathMLElement($name) + { + // MathML is case-sensitive unlike html5 elements. + return isset(static::$mathml[$name]); + } + + /** + * Test if an element is a valid SVG element. + * + * @param string $name The name of the element. + * + * @return bool true if a SVG element and false otherise. + */ + public static function isSvgElement($name) + { + // SVG is case-sensitive unlike html5 elements. + return isset(static::$svg[$name]); + } + + /** + * Is an element name valid in an html5 document. + * This includes html5 elements along with other allowed embedded content + * such as svg and mathml. + * + * @param string $name The name of the element. + * + * @return bool true if valid and false otherwise. + */ + public static function isElement($name) + { + return static::isHtml5Element($name) || static::isMathMLElement($name) || static::isSvgElement($name); + } + + /** + * Get the element mask for the given element name. + * + * @param string $name The name of the element. + * + * @return int the element mask. + */ + public static function element($name) + { + if (isset(static::$html5[$name])) { + return static::$html5[$name]; + } + if (isset(static::$svg[$name])) { + return static::$svg[$name]; + } + if (isset(static::$mathml[$name])) { + return static::$mathml[$name]; + } + + return 0; + } + + /** + * Normalize a SVG element name to its proper case and form. + * + * @param string $name The name of the element. + * + * @return string the normalized form of the element name. + */ + public static function normalizeSvgElement($name) + { + $name = strtolower($name); + if (isset(static::$svgCaseSensitiveElementMap[$name])) { + $name = static::$svgCaseSensitiveElementMap[$name]; + } + + return $name; + } + + /** + * Normalize a SVG attribute name to its proper case and form. + * + * @param string $name The name of the attribute. + * + * @return string The normalized form of the attribute name. + */ + public static function normalizeSvgAttribute($name) + { + $name = strtolower($name); + if (isset(static::$svgCaseSensitiveAttributeMap[$name])) { + $name = static::$svgCaseSensitiveAttributeMap[$name]; + } + + return $name; + } + + /** + * Normalize a MathML attribute name to its proper case and form. + * Note, all MathML element names are lowercase. + * + * @param string $name The name of the attribute. + * + * @return string The normalized form of the attribute name. + */ + public static function normalizeMathMlAttribute($name) + { + $name = strtolower($name); + + // Only one attribute has a mixed case form for MathML. + if ('definitionurl' === $name) { + $name = 'definitionURL'; + } + + return $name; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Entities.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Entities.php new file mode 100644 index 000000000..0e7227dc1 --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Entities.php @@ -0,0 +1,2236 @@ + 'Á', + 'Aacut' => 'Á', + 'aacute' => 'á', + 'aacut' => 'á', + 'Abreve' => 'Ă', + 'abreve' => 'ă', + 'ac' => '∾', + 'acd' => '∿', + 'acE' => '∾̳', + 'Acirc' => 'Â', + 'Acir' => 'Â', + 'acirc' => 'â', + 'acir' => 'â', + 'acute' => '´', + 'acut' => '´', + 'Acy' => 'А', + 'acy' => 'а', + 'AElig' => 'Æ', + 'AEli' => 'Æ', + 'aelig' => 'æ', + 'aeli' => 'æ', + 'af' => '⁡', + 'Afr' => '𝔄', + 'afr' => '𝔞', + 'Agrave' => 'À', + 'Agrav' => 'À', + 'agrave' => 'à', + 'agrav' => 'à', + 'alefsym' => 'ℵ', + 'aleph' => 'ℵ', + 'Alpha' => 'Α', + 'alpha' => 'α', + 'Amacr' => 'Ā', + 'amacr' => 'ā', + 'amalg' => '⨿', + 'AMP' => '&', + 'AM' => '&', + 'amp' => '&', + 'am' => '&', + 'And' => '⩓', + 'and' => '∧', + 'andand' => '⩕', + 'andd' => '⩜', + 'andslope' => '⩘', + 'andv' => '⩚', + 'ang' => '∠', + 'ange' => '⦤', + 'angle' => '∠', + 'angmsd' => '∡', + 'angmsdaa' => '⦨', + 'angmsdab' => '⦩', + 'angmsdac' => '⦪', + 'angmsdad' => '⦫', + 'angmsdae' => '⦬', + 'angmsdaf' => '⦭', + 'angmsdag' => '⦮', + 'angmsdah' => '⦯', + 'angrt' => '∟', + 'angrtvb' => '⊾', + 'angrtvbd' => '⦝', + 'angsph' => '∢', + 'angst' => 'Å', + 'angzarr' => '⍼', + 'Aogon' => 'Ą', + 'aogon' => 'ą', + 'Aopf' => '𝔸', + 'aopf' => '𝕒', + 'ap' => '≈', + 'apacir' => '⩯', + 'apE' => '⩰', + 'ape' => '≊', + 'apid' => '≋', + 'apos' => '\'', + 'ApplyFunction' => '⁡', + 'approx' => '≈', + 'approxeq' => '≊', + 'Aring' => 'Å', + 'Arin' => 'Å', + 'aring' => 'å', + 'arin' => 'å', + 'Ascr' => '𝒜', + 'ascr' => '𝒶', + 'Assign' => '≔', + 'ast' => '*', + 'asymp' => '≈', + 'asympeq' => '≍', + 'Atilde' => 'Ã', + 'Atild' => 'Ã', + 'atilde' => 'ã', + 'atild' => 'ã', + 'Auml' => 'Ä', + 'Aum' => 'Ä', + 'auml' => 'ä', + 'aum' => 'ä', + 'awconint' => '∳', + 'awint' => '⨑', + 'backcong' => '≌', + 'backepsilon' => '϶', + 'backprime' => '‵', + 'backsim' => '∽', + 'backsimeq' => '⋍', + 'Backslash' => '∖', + 'Barv' => '⫧', + 'barvee' => '⊽', + 'Barwed' => '⌆', + 'barwed' => '⌅', + 'barwedge' => '⌅', + 'bbrk' => '⎵', + 'bbrktbrk' => '⎶', + 'bcong' => '≌', + 'Bcy' => 'Б', + 'bcy' => 'б', + 'bdquo' => '„', + 'becaus' => '∵', + 'Because' => '∵', + 'because' => '∵', + 'bemptyv' => '⦰', + 'bepsi' => '϶', + 'bernou' => 'ℬ', + 'Bernoullis' => 'ℬ', + 'Beta' => 'Β', + 'beta' => 'β', + 'beth' => 'ℶ', + 'between' => '≬', + 'Bfr' => '𝔅', + 'bfr' => '𝔟', + 'bigcap' => '⋂', + 'bigcirc' => '◯', + 'bigcup' => '⋃', + 'bigodot' => '⨀', + 'bigoplus' => '⨁', + 'bigotimes' => '⨂', + 'bigsqcup' => '⨆', + 'bigstar' => '★', + 'bigtriangledown' => '▽', + 'bigtriangleup' => '△', + 'biguplus' => '⨄', + 'bigvee' => '⋁', + 'bigwedge' => '⋀', + 'bkarow' => '⤍', + 'blacklozenge' => '⧫', + 'blacksquare' => '▪', + 'blacktriangle' => '▴', + 'blacktriangledown' => '▾', + 'blacktriangleleft' => '◂', + 'blacktriangleright' => '▸', + 'blank' => '␣', + 'blk12' => '▒', + 'blk14' => '░', + 'blk34' => '▓', + 'block' => '█', + 'bne' => '=⃥', + 'bnequiv' => '≡⃥', + 'bNot' => '⫭', + 'bnot' => '⌐', + 'Bopf' => '𝔹', + 'bopf' => '𝕓', + 'bot' => '⊥', + 'bottom' => '⊥', + 'bowtie' => '⋈', + 'boxbox' => '⧉', + 'boxDL' => '╗', + 'boxDl' => '╖', + 'boxdL' => '╕', + 'boxdl' => '┐', + 'boxDR' => '╔', + 'boxDr' => '╓', + 'boxdR' => '╒', + 'boxdr' => '┌', + 'boxH' => '═', + 'boxh' => '─', + 'boxHD' => '╦', + 'boxHd' => '╤', + 'boxhD' => '╥', + 'boxhd' => '┬', + 'boxHU' => '╩', + 'boxHu' => '╧', + 'boxhU' => '╨', + 'boxhu' => '┴', + 'boxminus' => '⊟', + 'boxplus' => '⊞', + 'boxtimes' => '⊠', + 'boxUL' => '╝', + 'boxUl' => '╜', + 'boxuL' => '╛', + 'boxul' => '┘', + 'boxUR' => '╚', + 'boxUr' => '╙', + 'boxuR' => '╘', + 'boxur' => '└', + 'boxV' => '║', + 'boxv' => '│', + 'boxVH' => '╬', + 'boxVh' => '╫', + 'boxvH' => '╪', + 'boxvh' => '┼', + 'boxVL' => '╣', + 'boxVl' => '╢', + 'boxvL' => '╡', + 'boxvl' => '┤', + 'boxVR' => '╠', + 'boxVr' => '╟', + 'boxvR' => '╞', + 'boxvr' => '├', + 'bprime' => '‵', + 'Breve' => '˘', + 'breve' => '˘', + 'brvbar' => '¦', + 'brvba' => '¦', + 'Bscr' => 'ℬ', + 'bscr' => '𝒷', + 'bsemi' => '⁏', + 'bsim' => '∽', + 'bsime' => '⋍', + 'bsol' => '\\', + 'bsolb' => '⧅', + 'bsolhsub' => '⟈', + 'bull' => '•', + 'bullet' => '•', + 'bump' => '≎', + 'bumpE' => '⪮', + 'bumpe' => '≏', + 'Bumpeq' => '≎', + 'bumpeq' => '≏', + 'Cacute' => 'Ć', + 'cacute' => 'ć', + 'Cap' => '⋒', + 'cap' => '∩', + 'capand' => '⩄', + 'capbrcup' => '⩉', + 'capcap' => '⩋', + 'capcup' => '⩇', + 'capdot' => '⩀', + 'CapitalDifferentialD' => 'ⅅ', + 'caps' => '∩︀', + 'caret' => '⁁', + 'caron' => 'ˇ', + 'Cayleys' => 'ℭ', + 'ccaps' => '⩍', + 'Ccaron' => 'Č', + 'ccaron' => 'č', + 'Ccedil' => 'Ç', + 'Ccedi' => 'Ç', + 'ccedil' => 'ç', + 'ccedi' => 'ç', + 'Ccirc' => 'Ĉ', + 'ccirc' => 'ĉ', + 'Cconint' => '∰', + 'ccups' => '⩌', + 'ccupssm' => '⩐', + 'Cdot' => 'Ċ', + 'cdot' => 'ċ', + 'cedil' => '¸', + 'cedi' => '¸', + 'Cedilla' => '¸', + 'cemptyv' => '⦲', + 'cent' => '¢', + 'cen' => '¢', + 'CenterDot' => '·', + 'centerdot' => '·', + 'Cfr' => 'ℭ', + 'cfr' => '𝔠', + 'CHcy' => 'Ч', + 'chcy' => 'ч', + 'check' => '✓', + 'checkmark' => '✓', + 'Chi' => 'Χ', + 'chi' => 'χ', + 'cir' => '○', + 'circ' => 'ˆ', + 'circeq' => '≗', + 'circlearrowleft' => '↺', + 'circlearrowright' => '↻', + 'circledast' => '⊛', + 'circledcirc' => '⊚', + 'circleddash' => '⊝', + 'CircleDot' => '⊙', + 'circledR' => '®', + 'circledS' => 'Ⓢ', + 'CircleMinus' => '⊖', + 'CirclePlus' => '⊕', + 'CircleTimes' => '⊗', + 'cirE' => '⧃', + 'cire' => '≗', + 'cirfnint' => '⨐', + 'cirmid' => '⫯', + 'cirscir' => '⧂', + 'ClockwiseContourIntegral' => '∲', + 'CloseCurlyDoubleQuote' => '”', + 'CloseCurlyQuote' => '’', + 'clubs' => '♣', + 'clubsuit' => '♣', + 'Colon' => '∷', + 'colon' => ':', + 'Colone' => '⩴', + 'colone' => '≔', + 'coloneq' => '≔', + 'comma' => ',', + 'commat' => '@', + 'comp' => '∁', + 'compfn' => '∘', + 'complement' => '∁', + 'complexes' => 'ℂ', + 'cong' => '≅', + 'congdot' => '⩭', + 'Congruent' => '≡', + 'Conint' => '∯', + 'conint' => '∮', + 'ContourIntegral' => '∮', + 'Copf' => 'ℂ', + 'copf' => '𝕔', + 'coprod' => '∐', + 'Coproduct' => '∐', + 'COPY' => '©', + 'COP' => '©', + 'copy' => '©', + 'cop' => '©', + 'copysr' => '℗', + 'CounterClockwiseContourIntegral' => '∳', + 'crarr' => '↵', + 'Cross' => '⨯', + 'cross' => '✗', + 'Cscr' => '𝒞', + 'cscr' => '𝒸', + 'csub' => '⫏', + 'csube' => '⫑', + 'csup' => '⫐', + 'csupe' => '⫒', + 'ctdot' => '⋯', + 'cudarrl' => '⤸', + 'cudarrr' => '⤵', + 'cuepr' => '⋞', + 'cuesc' => '⋟', + 'cularr' => '↶', + 'cularrp' => '⤽', + 'Cup' => '⋓', + 'cup' => '∪', + 'cupbrcap' => '⩈', + 'CupCap' => '≍', + 'cupcap' => '⩆', + 'cupcup' => '⩊', + 'cupdot' => '⊍', + 'cupor' => '⩅', + 'cups' => '∪︀', + 'curarr' => '↷', + 'curarrm' => '⤼', + 'curlyeqprec' => '⋞', + 'curlyeqsucc' => '⋟', + 'curlyvee' => '⋎', + 'curlywedge' => '⋏', + 'curren' => '¤', + 'curre' => '¤', + 'curvearrowleft' => '↶', + 'curvearrowright' => '↷', + 'cuvee' => '⋎', + 'cuwed' => '⋏', + 'cwconint' => '∲', + 'cwint' => '∱', + 'cylcty' => '⌭', + 'Dagger' => '‡', + 'dagger' => '†', + 'daleth' => 'ℸ', + 'Darr' => '↡', + 'dArr' => '⇓', + 'darr' => '↓', + 'dash' => '‐', + 'Dashv' => '⫤', + 'dashv' => '⊣', + 'dbkarow' => '⤏', + 'dblac' => '˝', + 'Dcaron' => 'Ď', + 'dcaron' => 'ď', + 'Dcy' => 'Д', + 'dcy' => 'д', + 'DD' => 'ⅅ', + 'dd' => 'ⅆ', + 'ddagger' => '‡', + 'ddarr' => '⇊', + 'DDotrahd' => '⤑', + 'ddotseq' => '⩷', + 'deg' => '°', + 'de' => '°', + 'Del' => '∇', + 'Delta' => 'Δ', + 'delta' => 'δ', + 'demptyv' => '⦱', + 'dfisht' => '⥿', + 'Dfr' => '𝔇', + 'dfr' => '𝔡', + 'dHar' => '⥥', + 'dharl' => '⇃', + 'dharr' => '⇂', + 'DiacriticalAcute' => '´', + 'DiacriticalDot' => '˙', + 'DiacriticalDoubleAcute' => '˝', + 'DiacriticalGrave' => '`', + 'DiacriticalTilde' => '˜', + 'diam' => '⋄', + 'Diamond' => '⋄', + 'diamond' => '⋄', + 'diamondsuit' => '♦', + 'diams' => '♦', + 'die' => '¨', + 'DifferentialD' => 'ⅆ', + 'digamma' => 'ϝ', + 'disin' => '⋲', + 'div' => '÷', + 'divide' => '÷', + 'divid' => '÷', + 'divideontimes' => '⋇', + 'divonx' => '⋇', + 'DJcy' => 'Ђ', + 'djcy' => 'ђ', + 'dlcorn' => '⌞', + 'dlcrop' => '⌍', + 'dollar' => '$', + 'Dopf' => '𝔻', + 'dopf' => '𝕕', + 'Dot' => '¨', + 'dot' => '˙', + 'DotDot' => '⃜', + 'doteq' => '≐', + 'doteqdot' => '≑', + 'DotEqual' => '≐', + 'dotminus' => '∸', + 'dotplus' => '∔', + 'dotsquare' => '⊡', + 'doublebarwedge' => '⌆', + 'DoubleContourIntegral' => '∯', + 'DoubleDot' => '¨', + 'DoubleDownArrow' => '⇓', + 'DoubleLeftArrow' => '⇐', + 'DoubleLeftRightArrow' => '⇔', + 'DoubleLeftTee' => '⫤', + 'DoubleLongLeftArrow' => '⟸', + 'DoubleLongLeftRightArrow' => '⟺', + 'DoubleLongRightArrow' => '⟹', + 'DoubleRightArrow' => '⇒', + 'DoubleRightTee' => '⊨', + 'DoubleUpArrow' => '⇑', + 'DoubleUpDownArrow' => '⇕', + 'DoubleVerticalBar' => '∥', + 'DownArrow' => '↓', + 'Downarrow' => '⇓', + 'downarrow' => '↓', + 'DownArrowBar' => '⤓', + 'DownArrowUpArrow' => '⇵', + 'DownBreve' => '̑', + 'downdownarrows' => '⇊', + 'downharpoonleft' => '⇃', + 'downharpoonright' => '⇂', + 'DownLeftRightVector' => '⥐', + 'DownLeftTeeVector' => '⥞', + 'DownLeftVector' => '↽', + 'DownLeftVectorBar' => '⥖', + 'DownRightTeeVector' => '⥟', + 'DownRightVector' => '⇁', + 'DownRightVectorBar' => '⥗', + 'DownTee' => '⊤', + 'DownTeeArrow' => '↧', + 'drbkarow' => '⤐', + 'drcorn' => '⌟', + 'drcrop' => '⌌', + 'Dscr' => '𝒟', + 'dscr' => '𝒹', + 'DScy' => 'Ѕ', + 'dscy' => 'ѕ', + 'dsol' => '⧶', + 'Dstrok' => 'Đ', + 'dstrok' => 'đ', + 'dtdot' => '⋱', + 'dtri' => '▿', + 'dtrif' => '▾', + 'duarr' => '⇵', + 'duhar' => '⥯', + 'dwangle' => '⦦', + 'DZcy' => 'Џ', + 'dzcy' => 'џ', + 'dzigrarr' => '⟿', + 'Eacute' => 'É', + 'Eacut' => 'É', + 'eacute' => 'é', + 'eacut' => 'é', + 'easter' => '⩮', + 'Ecaron' => 'Ě', + 'ecaron' => 'ě', + 'ecir' => 'ê', + 'Ecirc' => 'Ê', + 'Ecir' => 'Ê', + 'ecirc' => 'ê', + 'ecolon' => '≕', + 'Ecy' => 'Э', + 'ecy' => 'э', + 'eDDot' => '⩷', + 'Edot' => 'Ė', + 'eDot' => '≑', + 'edot' => 'ė', + 'ee' => 'ⅇ', + 'efDot' => '≒', + 'Efr' => '𝔈', + 'efr' => '𝔢', + 'eg' => '⪚', + 'Egrave' => 'È', + 'Egrav' => 'È', + 'egrave' => 'è', + 'egrav' => 'è', + 'egs' => '⪖', + 'egsdot' => '⪘', + 'el' => '⪙', + 'Element' => '∈', + 'elinters' => '⏧', + 'ell' => 'ℓ', + 'els' => '⪕', + 'elsdot' => '⪗', + 'Emacr' => 'Ē', + 'emacr' => 'ē', + 'empty' => '∅', + 'emptyset' => '∅', + 'EmptySmallSquare' => '◻', + 'emptyv' => '∅', + 'EmptyVerySmallSquare' => '▫', + 'emsp' => ' ', + 'emsp13' => ' ', + 'emsp14' => ' ', + 'ENG' => 'Ŋ', + 'eng' => 'ŋ', + 'ensp' => ' ', + 'Eogon' => 'Ę', + 'eogon' => 'ę', + 'Eopf' => '𝔼', + 'eopf' => '𝕖', + 'epar' => '⋕', + 'eparsl' => '⧣', + 'eplus' => '⩱', + 'epsi' => 'ε', + 'Epsilon' => 'Ε', + 'epsilon' => 'ε', + 'epsiv' => 'ϵ', + 'eqcirc' => '≖', + 'eqcolon' => '≕', + 'eqsim' => '≂', + 'eqslantgtr' => '⪖', + 'eqslantless' => '⪕', + 'Equal' => '⩵', + 'equals' => '=', + 'EqualTilde' => '≂', + 'equest' => '≟', + 'Equilibrium' => '⇌', + 'equiv' => '≡', + 'equivDD' => '⩸', + 'eqvparsl' => '⧥', + 'erarr' => '⥱', + 'erDot' => '≓', + 'Escr' => 'ℰ', + 'escr' => 'ℯ', + 'esdot' => '≐', + 'Esim' => '⩳', + 'esim' => '≂', + 'Eta' => 'Η', + 'eta' => 'η', + 'ETH' => 'Ð', + 'ET' => 'Ð', + 'eth' => 'ð', + 'et' => 'ð', + 'Euml' => 'Ë', + 'Eum' => 'Ë', + 'euml' => 'ë', + 'eum' => 'ë', + 'euro' => '€', + 'excl' => '!', + 'exist' => '∃', + 'Exists' => '∃', + 'expectation' => 'ℰ', + 'ExponentialE' => 'ⅇ', + 'exponentiale' => 'ⅇ', + 'fallingdotseq' => '≒', + 'Fcy' => 'Ф', + 'fcy' => 'ф', + 'female' => '♀', + 'ffilig' => 'ffi', + 'fflig' => 'ff', + 'ffllig' => 'ffl', + 'Ffr' => '𝔉', + 'ffr' => '𝔣', + 'filig' => 'fi', + 'FilledSmallSquare' => '◼', + 'FilledVerySmallSquare' => '▪', + 'fjlig' => 'fj', + 'flat' => '♭', + 'fllig' => 'fl', + 'fltns' => '▱', + 'fnof' => 'ƒ', + 'Fopf' => '𝔽', + 'fopf' => '𝕗', + 'ForAll' => '∀', + 'forall' => '∀', + 'fork' => '⋔', + 'forkv' => '⫙', + 'Fouriertrf' => 'ℱ', + 'fpartint' => '⨍', + 'frac12' => '½', + 'frac1' => '¼', + 'frac13' => '⅓', + 'frac14' => '¼', + 'frac15' => '⅕', + 'frac16' => '⅙', + 'frac18' => '⅛', + 'frac23' => '⅔', + 'frac25' => '⅖', + 'frac34' => '¾', + 'frac3' => '¾', + 'frac35' => '⅗', + 'frac38' => '⅜', + 'frac45' => '⅘', + 'frac56' => '⅚', + 'frac58' => '⅝', + 'frac78' => '⅞', + 'frasl' => '⁄', + 'frown' => '⌢', + 'Fscr' => 'ℱ', + 'fscr' => '𝒻', + 'gacute' => 'ǵ', + 'Gamma' => 'Γ', + 'gamma' => 'γ', + 'Gammad' => 'Ϝ', + 'gammad' => 'ϝ', + 'gap' => '⪆', + 'Gbreve' => 'Ğ', + 'gbreve' => 'ğ', + 'Gcedil' => 'Ģ', + 'Gcirc' => 'Ĝ', + 'gcirc' => 'ĝ', + 'Gcy' => 'Г', + 'gcy' => 'г', + 'Gdot' => 'Ġ', + 'gdot' => 'ġ', + 'gE' => '≧', + 'ge' => '≥', + 'gEl' => '⪌', + 'gel' => '⋛', + 'geq' => '≥', + 'geqq' => '≧', + 'geqslant' => '⩾', + 'ges' => '⩾', + 'gescc' => '⪩', + 'gesdot' => '⪀', + 'gesdoto' => '⪂', + 'gesdotol' => '⪄', + 'gesl' => '⋛︀', + 'gesles' => '⪔', + 'Gfr' => '𝔊', + 'gfr' => '𝔤', + 'Gg' => '⋙', + 'gg' => '≫', + 'ggg' => '⋙', + 'gimel' => 'ℷ', + 'GJcy' => 'Ѓ', + 'gjcy' => 'ѓ', + 'gl' => '≷', + 'gla' => '⪥', + 'glE' => '⪒', + 'glj' => '⪤', + 'gnap' => '⪊', + 'gnapprox' => '⪊', + 'gnE' => '≩', + 'gne' => '⪈', + 'gneq' => '⪈', + 'gneqq' => '≩', + 'gnsim' => '⋧', + 'Gopf' => '𝔾', + 'gopf' => '𝕘', + 'grave' => '`', + 'GreaterEqual' => '≥', + 'GreaterEqualLess' => '⋛', + 'GreaterFullEqual' => '≧', + 'GreaterGreater' => '⪢', + 'GreaterLess' => '≷', + 'GreaterSlantEqual' => '⩾', + 'GreaterTilde' => '≳', + 'Gscr' => '𝒢', + 'gscr' => 'ℊ', + 'gsim' => '≳', + 'gsime' => '⪎', + 'gsiml' => '⪐', + 'GT' => '>', + 'G' => '>', + 'Gt' => '≫', + 'gt' => '>', + 'g' => '>', + 'gtcc' => '⪧', + 'gtcir' => '⩺', + 'gtdot' => '⋗', + 'gtlPar' => '⦕', + 'gtquest' => '⩼', + 'gtrapprox' => '⪆', + 'gtrarr' => '⥸', + 'gtrdot' => '⋗', + 'gtreqless' => '⋛', + 'gtreqqless' => '⪌', + 'gtrless' => '≷', + 'gtrsim' => '≳', + 'gvertneqq' => '≩︀', + 'gvnE' => '≩︀', + 'Hacek' => 'ˇ', + 'hairsp' => ' ', + 'half' => '½', + 'hamilt' => 'ℋ', + 'HARDcy' => 'Ъ', + 'hardcy' => 'ъ', + 'hArr' => '⇔', + 'harr' => '↔', + 'harrcir' => '⥈', + 'harrw' => '↭', + 'Hat' => '^', + 'hbar' => 'ℏ', + 'Hcirc' => 'Ĥ', + 'hcirc' => 'ĥ', + 'hearts' => '♥', + 'heartsuit' => '♥', + 'hellip' => '…', + 'hercon' => '⊹', + 'Hfr' => 'ℌ', + 'hfr' => '𝔥', + 'HilbertSpace' => 'ℋ', + 'hksearow' => '⤥', + 'hkswarow' => '⤦', + 'hoarr' => '⇿', + 'homtht' => '∻', + 'hookleftarrow' => '↩', + 'hookrightarrow' => '↪', + 'Hopf' => 'ℍ', + 'hopf' => '𝕙', + 'horbar' => '―', + 'HorizontalLine' => '─', + 'Hscr' => 'ℋ', + 'hscr' => '𝒽', + 'hslash' => 'ℏ', + 'Hstrok' => 'Ħ', + 'hstrok' => 'ħ', + 'HumpDownHump' => '≎', + 'HumpEqual' => '≏', + 'hybull' => '⁃', + 'hyphen' => '‐', + 'Iacute' => 'Í', + 'Iacut' => 'Í', + 'iacute' => 'í', + 'iacut' => 'í', + 'ic' => '⁣', + 'Icirc' => 'Î', + 'Icir' => 'Î', + 'icirc' => 'î', + 'icir' => 'î', + 'Icy' => 'И', + 'icy' => 'и', + 'Idot' => 'İ', + 'IEcy' => 'Е', + 'iecy' => 'е', + 'iexcl' => '¡', + 'iexc' => '¡', + 'iff' => '⇔', + 'Ifr' => 'ℑ', + 'ifr' => '𝔦', + 'Igrave' => 'Ì', + 'Igrav' => 'Ì', + 'igrave' => 'ì', + 'igrav' => 'ì', + 'ii' => 'ⅈ', + 'iiiint' => '⨌', + 'iiint' => '∭', + 'iinfin' => '⧜', + 'iiota' => '℩', + 'IJlig' => 'IJ', + 'ijlig' => 'ij', + 'Im' => 'ℑ', + 'Imacr' => 'Ī', + 'imacr' => 'ī', + 'image' => 'ℑ', + 'ImaginaryI' => 'ⅈ', + 'imagline' => 'ℐ', + 'imagpart' => 'ℑ', + 'imath' => 'ı', + 'imof' => '⊷', + 'imped' => 'Ƶ', + 'Implies' => '⇒', + 'in' => '∈', + 'incare' => '℅', + 'infin' => '∞', + 'infintie' => '⧝', + 'inodot' => 'ı', + 'Int' => '∬', + 'int' => '∫', + 'intcal' => '⊺', + 'integers' => 'ℤ', + 'Integral' => '∫', + 'intercal' => '⊺', + 'Intersection' => '⋂', + 'intlarhk' => '⨗', + 'intprod' => '⨼', + 'InvisibleComma' => '⁣', + 'InvisibleTimes' => '⁢', + 'IOcy' => 'Ё', + 'iocy' => 'ё', + 'Iogon' => 'Į', + 'iogon' => 'į', + 'Iopf' => '𝕀', + 'iopf' => '𝕚', + 'Iota' => 'Ι', + 'iota' => 'ι', + 'iprod' => '⨼', + 'iquest' => '¿', + 'iques' => '¿', + 'Iscr' => 'ℐ', + 'iscr' => '𝒾', + 'isin' => '∈', + 'isindot' => '⋵', + 'isinE' => '⋹', + 'isins' => '⋴', + 'isinsv' => '⋳', + 'isinv' => '∈', + 'it' => '⁢', + 'Itilde' => 'Ĩ', + 'itilde' => 'ĩ', + 'Iukcy' => 'І', + 'iukcy' => 'і', + 'Iuml' => 'Ï', + 'Ium' => 'Ï', + 'iuml' => 'ï', + 'ium' => 'ï', + 'Jcirc' => 'Ĵ', + 'jcirc' => 'ĵ', + 'Jcy' => 'Й', + 'jcy' => 'й', + 'Jfr' => '𝔍', + 'jfr' => '𝔧', + 'jmath' => 'ȷ', + 'Jopf' => '𝕁', + 'jopf' => '𝕛', + 'Jscr' => '𝒥', + 'jscr' => '𝒿', + 'Jsercy' => 'Ј', + 'jsercy' => 'ј', + 'Jukcy' => 'Є', + 'jukcy' => 'є', + 'Kappa' => 'Κ', + 'kappa' => 'κ', + 'kappav' => 'ϰ', + 'Kcedil' => 'Ķ', + 'kcedil' => 'ķ', + 'Kcy' => 'К', + 'kcy' => 'к', + 'Kfr' => '𝔎', + 'kfr' => '𝔨', + 'kgreen' => 'ĸ', + 'KHcy' => 'Х', + 'khcy' => 'х', + 'KJcy' => 'Ќ', + 'kjcy' => 'ќ', + 'Kopf' => '𝕂', + 'kopf' => '𝕜', + 'Kscr' => '𝒦', + 'kscr' => '𝓀', + 'lAarr' => '⇚', + 'Lacute' => 'Ĺ', + 'lacute' => 'ĺ', + 'laemptyv' => '⦴', + 'lagran' => 'ℒ', + 'Lambda' => 'Λ', + 'lambda' => 'λ', + 'Lang' => '⟪', + 'lang' => '⟨', + 'langd' => '⦑', + 'langle' => '⟨', + 'lap' => '⪅', + 'Laplacetrf' => 'ℒ', + 'laquo' => '«', + 'laqu' => '«', + 'Larr' => '↞', + 'lArr' => '⇐', + 'larr' => '←', + 'larrb' => '⇤', + 'larrbfs' => '⤟', + 'larrfs' => '⤝', + 'larrhk' => '↩', + 'larrlp' => '↫', + 'larrpl' => '⤹', + 'larrsim' => '⥳', + 'larrtl' => '↢', + 'lat' => '⪫', + 'lAtail' => '⤛', + 'latail' => '⤙', + 'late' => '⪭', + 'lates' => '⪭︀', + 'lBarr' => '⤎', + 'lbarr' => '⤌', + 'lbbrk' => '❲', + 'lbrace' => '{', + 'lbrack' => '[', + 'lbrke' => '⦋', + 'lbrksld' => '⦏', + 'lbrkslu' => '⦍', + 'Lcaron' => 'Ľ', + 'lcaron' => 'ľ', + 'Lcedil' => 'Ļ', + 'lcedil' => 'ļ', + 'lceil' => '⌈', + 'lcub' => '{', + 'Lcy' => 'Л', + 'lcy' => 'л', + 'ldca' => '⤶', + 'ldquo' => '“', + 'ldquor' => '„', + 'ldrdhar' => '⥧', + 'ldrushar' => '⥋', + 'ldsh' => '↲', + 'lE' => '≦', + 'le' => '≤', + 'LeftAngleBracket' => '⟨', + 'LeftArrow' => '←', + 'Leftarrow' => '⇐', + 'leftarrow' => '←', + 'LeftArrowBar' => '⇤', + 'LeftArrowRightArrow' => '⇆', + 'leftarrowtail' => '↢', + 'LeftCeiling' => '⌈', + 'LeftDoubleBracket' => '⟦', + 'LeftDownTeeVector' => '⥡', + 'LeftDownVector' => '⇃', + 'LeftDownVectorBar' => '⥙', + 'LeftFloor' => '⌊', + 'leftharpoondown' => '↽', + 'leftharpoonup' => '↼', + 'leftleftarrows' => '⇇', + 'LeftRightArrow' => '↔', + 'Leftrightarrow' => '⇔', + 'leftrightarrow' => '↔', + 'leftrightarrows' => '⇆', + 'leftrightharpoons' => '⇋', + 'leftrightsquigarrow' => '↭', + 'LeftRightVector' => '⥎', + 'LeftTee' => '⊣', + 'LeftTeeArrow' => '↤', + 'LeftTeeVector' => '⥚', + 'leftthreetimes' => '⋋', + 'LeftTriangle' => '⊲', + 'LeftTriangleBar' => '⧏', + 'LeftTriangleEqual' => '⊴', + 'LeftUpDownVector' => '⥑', + 'LeftUpTeeVector' => '⥠', + 'LeftUpVector' => '↿', + 'LeftUpVectorBar' => '⥘', + 'LeftVector' => '↼', + 'LeftVectorBar' => '⥒', + 'lEg' => '⪋', + 'leg' => '⋚', + 'leq' => '≤', + 'leqq' => '≦', + 'leqslant' => '⩽', + 'les' => '⩽', + 'lescc' => '⪨', + 'lesdot' => '⩿', + 'lesdoto' => '⪁', + 'lesdotor' => '⪃', + 'lesg' => '⋚︀', + 'lesges' => '⪓', + 'lessapprox' => '⪅', + 'lessdot' => '⋖', + 'lesseqgtr' => '⋚', + 'lesseqqgtr' => '⪋', + 'LessEqualGreater' => '⋚', + 'LessFullEqual' => '≦', + 'LessGreater' => '≶', + 'lessgtr' => '≶', + 'LessLess' => '⪡', + 'lesssim' => '≲', + 'LessSlantEqual' => '⩽', + 'LessTilde' => '≲', + 'lfisht' => '⥼', + 'lfloor' => '⌊', + 'Lfr' => '𝔏', + 'lfr' => '𝔩', + 'lg' => '≶', + 'lgE' => '⪑', + 'lHar' => '⥢', + 'lhard' => '↽', + 'lharu' => '↼', + 'lharul' => '⥪', + 'lhblk' => '▄', + 'LJcy' => 'Љ', + 'ljcy' => 'љ', + 'Ll' => '⋘', + 'll' => '≪', + 'llarr' => '⇇', + 'llcorner' => '⌞', + 'Lleftarrow' => '⇚', + 'llhard' => '⥫', + 'lltri' => '◺', + 'Lmidot' => 'Ŀ', + 'lmidot' => 'ŀ', + 'lmoust' => '⎰', + 'lmoustache' => '⎰', + 'lnap' => '⪉', + 'lnapprox' => '⪉', + 'lnE' => '≨', + 'lne' => '⪇', + 'lneq' => '⪇', + 'lneqq' => '≨', + 'lnsim' => '⋦', + 'loang' => '⟬', + 'loarr' => '⇽', + 'lobrk' => '⟦', + 'LongLeftArrow' => '⟵', + 'Longleftarrow' => '⟸', + 'longleftarrow' => '⟵', + 'LongLeftRightArrow' => '⟷', + 'Longleftrightarrow' => '⟺', + 'longleftrightarrow' => '⟷', + 'longmapsto' => '⟼', + 'LongRightArrow' => '⟶', + 'Longrightarrow' => '⟹', + 'longrightarrow' => '⟶', + 'looparrowleft' => '↫', + 'looparrowright' => '↬', + 'lopar' => '⦅', + 'Lopf' => '𝕃', + 'lopf' => '𝕝', + 'loplus' => '⨭', + 'lotimes' => '⨴', + 'lowast' => '∗', + 'lowbar' => '_', + 'LowerLeftArrow' => '↙', + 'LowerRightArrow' => '↘', + 'loz' => '◊', + 'lozenge' => '◊', + 'lozf' => '⧫', + 'lpar' => '(', + 'lparlt' => '⦓', + 'lrarr' => '⇆', + 'lrcorner' => '⌟', + 'lrhar' => '⇋', + 'lrhard' => '⥭', + 'lrm' => '‎', + 'lrtri' => '⊿', + 'lsaquo' => '‹', + 'Lscr' => 'ℒ', + 'lscr' => '𝓁', + 'Lsh' => '↰', + 'lsh' => '↰', + 'lsim' => '≲', + 'lsime' => '⪍', + 'lsimg' => '⪏', + 'lsqb' => '[', + 'lsquo' => '‘', + 'lsquor' => '‚', + 'Lstrok' => 'Ł', + 'lstrok' => 'ł', + 'LT' => '<', + 'L' => '<', + 'Lt' => '≪', + 'lt' => '<', + 'l' => '<', + 'ltcc' => '⪦', + 'ltcir' => '⩹', + 'ltdot' => '⋖', + 'lthree' => '⋋', + 'ltimes' => '⋉', + 'ltlarr' => '⥶', + 'ltquest' => '⩻', + 'ltri' => '◃', + 'ltrie' => '⊴', + 'ltrif' => '◂', + 'ltrPar' => '⦖', + 'lurdshar' => '⥊', + 'luruhar' => '⥦', + 'lvertneqq' => '≨︀', + 'lvnE' => '≨︀', + 'macr' => '¯', + 'mac' => '¯', + 'male' => '♂', + 'malt' => '✠', + 'maltese' => '✠', + 'Map' => '⤅', + 'map' => '↦', + 'mapsto' => '↦', + 'mapstodown' => '↧', + 'mapstoleft' => '↤', + 'mapstoup' => '↥', + 'marker' => '▮', + 'mcomma' => '⨩', + 'Mcy' => 'М', + 'mcy' => 'м', + 'mdash' => '—', + 'mDDot' => '∺', + 'measuredangle' => '∡', + 'MediumSpace' => ' ', + 'Mellintrf' => 'ℳ', + 'Mfr' => '𝔐', + 'mfr' => '𝔪', + 'mho' => '℧', + 'micro' => 'µ', + 'micr' => 'µ', + 'mid' => '∣', + 'midast' => '*', + 'midcir' => '⫰', + 'middot' => '·', + 'middo' => '·', + 'minus' => '−', + 'minusb' => '⊟', + 'minusd' => '∸', + 'minusdu' => '⨪', + 'MinusPlus' => '∓', + 'mlcp' => '⫛', + 'mldr' => '…', + 'mnplus' => '∓', + 'models' => '⊧', + 'Mopf' => '𝕄', + 'mopf' => '𝕞', + 'mp' => '∓', + 'Mscr' => 'ℳ', + 'mscr' => '𝓂', + 'mstpos' => '∾', + 'Mu' => 'Μ', + 'mu' => 'μ', + 'multimap' => '⊸', + 'mumap' => '⊸', + 'nabla' => '∇', + 'Nacute' => 'Ń', + 'nacute' => 'ń', + 'nang' => '∠⃒', + 'nap' => '≉', + 'napE' => '⩰̸', + 'napid' => '≋̸', + 'napos' => 'ʼn', + 'napprox' => '≉', + 'natur' => '♮', + 'natural' => '♮', + 'naturals' => 'ℕ', + 'nbsp' => ' ', + 'nbs' => ' ', + 'nbump' => '≎̸', + 'nbumpe' => '≏̸', + 'ncap' => '⩃', + 'Ncaron' => 'Ň', + 'ncaron' => 'ň', + 'Ncedil' => 'Ņ', + 'ncedil' => 'ņ', + 'ncong' => '≇', + 'ncongdot' => '⩭̸', + 'ncup' => '⩂', + 'Ncy' => 'Н', + 'ncy' => 'н', + 'ndash' => '–', + 'ne' => '≠', + 'nearhk' => '⤤', + 'neArr' => '⇗', + 'nearr' => '↗', + 'nearrow' => '↗', + 'nedot' => '≐̸', + 'NegativeMediumSpace' => '​', + 'NegativeThickSpace' => '​', + 'NegativeThinSpace' => '​', + 'NegativeVeryThinSpace' => '​', + 'nequiv' => '≢', + 'nesear' => '⤨', + 'nesim' => '≂̸', + 'NestedGreaterGreater' => '≫', + 'NestedLessLess' => '≪', + 'NewLine' => ' +', + 'nexist' => '∄', + 'nexists' => '∄', + 'Nfr' => '𝔑', + 'nfr' => '𝔫', + 'ngE' => '≧̸', + 'nge' => '≱', + 'ngeq' => '≱', + 'ngeqq' => '≧̸', + 'ngeqslant' => '⩾̸', + 'nges' => '⩾̸', + 'nGg' => '⋙̸', + 'ngsim' => '≵', + 'nGt' => '≫⃒', + 'ngt' => '≯', + 'ngtr' => '≯', + 'nGtv' => '≫̸', + 'nhArr' => '⇎', + 'nharr' => '↮', + 'nhpar' => '⫲', + 'ni' => '∋', + 'nis' => '⋼', + 'nisd' => '⋺', + 'niv' => '∋', + 'NJcy' => 'Њ', + 'njcy' => 'њ', + 'nlArr' => '⇍', + 'nlarr' => '↚', + 'nldr' => '‥', + 'nlE' => '≦̸', + 'nle' => '≰', + 'nLeftarrow' => '⇍', + 'nleftarrow' => '↚', + 'nLeftrightarrow' => '⇎', + 'nleftrightarrow' => '↮', + 'nleq' => '≰', + 'nleqq' => '≦̸', + 'nleqslant' => '⩽̸', + 'nles' => '⩽̸', + 'nless' => '≮', + 'nLl' => '⋘̸', + 'nlsim' => '≴', + 'nLt' => '≪⃒', + 'nlt' => '≮', + 'nltri' => '⋪', + 'nltrie' => '⋬', + 'nLtv' => '≪̸', + 'nmid' => '∤', + 'NoBreak' => '⁠', + 'NonBreakingSpace' => ' ', + 'Nopf' => 'ℕ', + 'nopf' => '𝕟', + 'Not' => '⫬', + 'not' => '¬', + 'no' => '¬', + 'NotCongruent' => '≢', + 'NotCupCap' => '≭', + 'NotDoubleVerticalBar' => '∦', + 'NotElement' => '∉', + 'NotEqual' => '≠', + 'NotEqualTilde' => '≂̸', + 'NotExists' => '∄', + 'NotGreater' => '≯', + 'NotGreaterEqual' => '≱', + 'NotGreaterFullEqual' => '≧̸', + 'NotGreaterGreater' => '≫̸', + 'NotGreaterLess' => '≹', + 'NotGreaterSlantEqual' => '⩾̸', + 'NotGreaterTilde' => '≵', + 'NotHumpDownHump' => '≎̸', + 'NotHumpEqual' => '≏̸', + 'notin' => '∉', + 'notindot' => '⋵̸', + 'notinE' => '⋹̸', + 'notinva' => '∉', + 'notinvb' => '⋷', + 'notinvc' => '⋶', + 'NotLeftTriangle' => '⋪', + 'NotLeftTriangleBar' => '⧏̸', + 'NotLeftTriangleEqual' => '⋬', + 'NotLess' => '≮', + 'NotLessEqual' => '≰', + 'NotLessGreater' => '≸', + 'NotLessLess' => '≪̸', + 'NotLessSlantEqual' => '⩽̸', + 'NotLessTilde' => '≴', + 'NotNestedGreaterGreater' => '⪢̸', + 'NotNestedLessLess' => '⪡̸', + 'notni' => '∌', + 'notniva' => '∌', + 'notnivb' => '⋾', + 'notnivc' => '⋽', + 'NotPrecedes' => '⊀', + 'NotPrecedesEqual' => '⪯̸', + 'NotPrecedesSlantEqual' => '⋠', + 'NotReverseElement' => '∌', + 'NotRightTriangle' => '⋫', + 'NotRightTriangleBar' => '⧐̸', + 'NotRightTriangleEqual' => '⋭', + 'NotSquareSubset' => '⊏̸', + 'NotSquareSubsetEqual' => '⋢', + 'NotSquareSuperset' => '⊐̸', + 'NotSquareSupersetEqual' => '⋣', + 'NotSubset' => '⊂⃒', + 'NotSubsetEqual' => '⊈', + 'NotSucceeds' => '⊁', + 'NotSucceedsEqual' => '⪰̸', + 'NotSucceedsSlantEqual' => '⋡', + 'NotSucceedsTilde' => '≿̸', + 'NotSuperset' => '⊃⃒', + 'NotSupersetEqual' => '⊉', + 'NotTilde' => '≁', + 'NotTildeEqual' => '≄', + 'NotTildeFullEqual' => '≇', + 'NotTildeTilde' => '≉', + 'NotVerticalBar' => '∤', + 'npar' => '∦', + 'nparallel' => '∦', + 'nparsl' => '⫽⃥', + 'npart' => '∂̸', + 'npolint' => '⨔', + 'npr' => '⊀', + 'nprcue' => '⋠', + 'npre' => '⪯̸', + 'nprec' => '⊀', + 'npreceq' => '⪯̸', + 'nrArr' => '⇏', + 'nrarr' => '↛', + 'nrarrc' => '⤳̸', + 'nrarrw' => '↝̸', + 'nRightarrow' => '⇏', + 'nrightarrow' => '↛', + 'nrtri' => '⋫', + 'nrtrie' => '⋭', + 'nsc' => '⊁', + 'nsccue' => '⋡', + 'nsce' => '⪰̸', + 'Nscr' => '𝒩', + 'nscr' => '𝓃', + 'nshortmid' => '∤', + 'nshortparallel' => '∦', + 'nsim' => '≁', + 'nsime' => '≄', + 'nsimeq' => '≄', + 'nsmid' => '∤', + 'nspar' => '∦', + 'nsqsube' => '⋢', + 'nsqsupe' => '⋣', + 'nsub' => '⊄', + 'nsubE' => '⫅̸', + 'nsube' => '⊈', + 'nsubset' => '⊂⃒', + 'nsubseteq' => '⊈', + 'nsubseteqq' => '⫅̸', + 'nsucc' => '⊁', + 'nsucceq' => '⪰̸', + 'nsup' => '⊅', + 'nsupE' => '⫆̸', + 'nsupe' => '⊉', + 'nsupset' => '⊃⃒', + 'nsupseteq' => '⊉', + 'nsupseteqq' => '⫆̸', + 'ntgl' => '≹', + 'Ntilde' => 'Ñ', + 'Ntild' => 'Ñ', + 'ntilde' => 'ñ', + 'ntild' => 'ñ', + 'ntlg' => '≸', + 'ntriangleleft' => '⋪', + 'ntrianglelefteq' => '⋬', + 'ntriangleright' => '⋫', + 'ntrianglerighteq' => '⋭', + 'Nu' => 'Ν', + 'nu' => 'ν', + 'num' => '#', + 'numero' => '№', + 'numsp' => ' ', + 'nvap' => '≍⃒', + 'nVDash' => '⊯', + 'nVdash' => '⊮', + 'nvDash' => '⊭', + 'nvdash' => '⊬', + 'nvge' => '≥⃒', + 'nvgt' => '>⃒', + 'nvHarr' => '⤄', + 'nvinfin' => '⧞', + 'nvlArr' => '⤂', + 'nvle' => '≤⃒', + 'nvlt' => '<⃒', + 'nvltrie' => '⊴⃒', + 'nvrArr' => '⤃', + 'nvrtrie' => '⊵⃒', + 'nvsim' => '∼⃒', + 'nwarhk' => '⤣', + 'nwArr' => '⇖', + 'nwarr' => '↖', + 'nwarrow' => '↖', + 'nwnear' => '⤧', + 'Oacute' => 'Ó', + 'Oacut' => 'Ó', + 'oacute' => 'ó', + 'oacut' => 'ó', + 'oast' => '⊛', + 'ocir' => 'ô', + 'Ocirc' => 'Ô', + 'Ocir' => 'Ô', + 'ocirc' => 'ô', + 'Ocy' => 'О', + 'ocy' => 'о', + 'odash' => '⊝', + 'Odblac' => 'Ő', + 'odblac' => 'ő', + 'odiv' => '⨸', + 'odot' => '⊙', + 'odsold' => '⦼', + 'OElig' => 'Œ', + 'oelig' => 'œ', + 'ofcir' => '⦿', + 'Ofr' => '𝔒', + 'ofr' => '𝔬', + 'ogon' => '˛', + 'Ograve' => 'Ò', + 'Ograv' => 'Ò', + 'ograve' => 'ò', + 'ograv' => 'ò', + 'ogt' => '⧁', + 'ohbar' => '⦵', + 'ohm' => 'Ω', + 'oint' => '∮', + 'olarr' => '↺', + 'olcir' => '⦾', + 'olcross' => '⦻', + 'oline' => '‾', + 'olt' => '⧀', + 'Omacr' => 'Ō', + 'omacr' => 'ō', + 'Omega' => 'Ω', + 'omega' => 'ω', + 'Omicron' => 'Ο', + 'omicron' => 'ο', + 'omid' => '⦶', + 'ominus' => '⊖', + 'Oopf' => '𝕆', + 'oopf' => '𝕠', + 'opar' => '⦷', + 'OpenCurlyDoubleQuote' => '“', + 'OpenCurlyQuote' => '‘', + 'operp' => '⦹', + 'oplus' => '⊕', + 'Or' => '⩔', + 'or' => '∨', + 'orarr' => '↻', + 'ord' => 'º', + 'order' => 'ℴ', + 'orderof' => 'ℴ', + 'ordf' => 'ª', + 'ordm' => 'º', + 'origof' => '⊶', + 'oror' => '⩖', + 'orslope' => '⩗', + 'orv' => '⩛', + 'oS' => 'Ⓢ', + 'Oscr' => '𝒪', + 'oscr' => 'ℴ', + 'Oslash' => 'Ø', + 'Oslas' => 'Ø', + 'oslash' => 'ø', + 'oslas' => 'ø', + 'osol' => '⊘', + 'Otilde' => 'Õ', + 'Otild' => 'Õ', + 'otilde' => 'õ', + 'otild' => 'õ', + 'Otimes' => '⨷', + 'otimes' => '⊗', + 'otimesas' => '⨶', + 'Ouml' => 'Ö', + 'Oum' => 'Ö', + 'ouml' => 'ö', + 'oum' => 'ö', + 'ovbar' => '⌽', + 'OverBar' => '‾', + 'OverBrace' => '⏞', + 'OverBracket' => '⎴', + 'OverParenthesis' => '⏜', + 'par' => '¶', + 'para' => '¶', + 'parallel' => '∥', + 'parsim' => '⫳', + 'parsl' => '⫽', + 'part' => '∂', + 'PartialD' => '∂', + 'Pcy' => 'П', + 'pcy' => 'п', + 'percnt' => '%', + 'period' => '.', + 'permil' => '‰', + 'perp' => '⊥', + 'pertenk' => '‱', + 'Pfr' => '𝔓', + 'pfr' => '𝔭', + 'Phi' => 'Φ', + 'phi' => 'φ', + 'phiv' => 'ϕ', + 'phmmat' => 'ℳ', + 'phone' => '☎', + 'Pi' => 'Π', + 'pi' => 'π', + 'pitchfork' => '⋔', + 'piv' => 'ϖ', + 'planck' => 'ℏ', + 'planckh' => 'ℎ', + 'plankv' => 'ℏ', + 'plus' => '+', + 'plusacir' => '⨣', + 'plusb' => '⊞', + 'pluscir' => '⨢', + 'plusdo' => '∔', + 'plusdu' => '⨥', + 'pluse' => '⩲', + 'PlusMinus' => '±', + 'plusmn' => '±', + 'plusm' => '±', + 'plussim' => '⨦', + 'plustwo' => '⨧', + 'pm' => '±', + 'Poincareplane' => 'ℌ', + 'pointint' => '⨕', + 'Popf' => 'ℙ', + 'popf' => '𝕡', + 'pound' => '£', + 'poun' => '£', + 'Pr' => '⪻', + 'pr' => '≺', + 'prap' => '⪷', + 'prcue' => '≼', + 'prE' => '⪳', + 'pre' => '⪯', + 'prec' => '≺', + 'precapprox' => '⪷', + 'preccurlyeq' => '≼', + 'Precedes' => '≺', + 'PrecedesEqual' => '⪯', + 'PrecedesSlantEqual' => '≼', + 'PrecedesTilde' => '≾', + 'preceq' => '⪯', + 'precnapprox' => '⪹', + 'precneqq' => '⪵', + 'precnsim' => '⋨', + 'precsim' => '≾', + 'Prime' => '″', + 'prime' => '′', + 'primes' => 'ℙ', + 'prnap' => '⪹', + 'prnE' => '⪵', + 'prnsim' => '⋨', + 'prod' => '∏', + 'Product' => '∏', + 'profalar' => '⌮', + 'profline' => '⌒', + 'profsurf' => '⌓', + 'prop' => '∝', + 'Proportion' => '∷', + 'Proportional' => '∝', + 'propto' => '∝', + 'prsim' => '≾', + 'prurel' => '⊰', + 'Pscr' => '𝒫', + 'pscr' => '𝓅', + 'Psi' => 'Ψ', + 'psi' => 'ψ', + 'puncsp' => ' ', + 'Qfr' => '𝔔', + 'qfr' => '𝔮', + 'qint' => '⨌', + 'Qopf' => 'ℚ', + 'qopf' => '𝕢', + 'qprime' => '⁗', + 'Qscr' => '𝒬', + 'qscr' => '𝓆', + 'quaternions' => 'ℍ', + 'quatint' => '⨖', + 'quest' => '?', + 'questeq' => '≟', + 'QUOT' => '"', + 'QUO' => '"', + 'quot' => '"', + 'quo' => '"', + 'rAarr' => '⇛', + 'race' => '∽̱', + 'Racute' => 'Ŕ', + 'racute' => 'ŕ', + 'radic' => '√', + 'raemptyv' => '⦳', + 'Rang' => '⟫', + 'rang' => '⟩', + 'rangd' => '⦒', + 'range' => '⦥', + 'rangle' => '⟩', + 'raquo' => '»', + 'raqu' => '»', + 'Rarr' => '↠', + 'rArr' => '⇒', + 'rarr' => '→', + 'rarrap' => '⥵', + 'rarrb' => '⇥', + 'rarrbfs' => '⤠', + 'rarrc' => '⤳', + 'rarrfs' => '⤞', + 'rarrhk' => '↪', + 'rarrlp' => '↬', + 'rarrpl' => '⥅', + 'rarrsim' => '⥴', + 'Rarrtl' => '⤖', + 'rarrtl' => '↣', + 'rarrw' => '↝', + 'rAtail' => '⤜', + 'ratail' => '⤚', + 'ratio' => '∶', + 'rationals' => 'ℚ', + 'RBarr' => '⤐', + 'rBarr' => '⤏', + 'rbarr' => '⤍', + 'rbbrk' => '❳', + 'rbrace' => '}', + 'rbrack' => ']', + 'rbrke' => '⦌', + 'rbrksld' => '⦎', + 'rbrkslu' => '⦐', + 'Rcaron' => 'Ř', + 'rcaron' => 'ř', + 'Rcedil' => 'Ŗ', + 'rcedil' => 'ŗ', + 'rceil' => '⌉', + 'rcub' => '}', + 'Rcy' => 'Р', + 'rcy' => 'р', + 'rdca' => '⤷', + 'rdldhar' => '⥩', + 'rdquo' => '”', + 'rdquor' => '”', + 'rdsh' => '↳', + 'Re' => 'ℜ', + 'real' => 'ℜ', + 'realine' => 'ℛ', + 'realpart' => 'ℜ', + 'reals' => 'ℝ', + 'rect' => '▭', + 'REG' => '®', + 'RE' => '®', + 'reg' => '®', + 're' => '®', + 'ReverseElement' => '∋', + 'ReverseEquilibrium' => '⇋', + 'ReverseUpEquilibrium' => '⥯', + 'rfisht' => '⥽', + 'rfloor' => '⌋', + 'Rfr' => 'ℜ', + 'rfr' => '𝔯', + 'rHar' => '⥤', + 'rhard' => '⇁', + 'rharu' => '⇀', + 'rharul' => '⥬', + 'Rho' => 'Ρ', + 'rho' => 'ρ', + 'rhov' => 'ϱ', + 'RightAngleBracket' => '⟩', + 'RightArrow' => '→', + 'Rightarrow' => '⇒', + 'rightarrow' => '→', + 'RightArrowBar' => '⇥', + 'RightArrowLeftArrow' => '⇄', + 'rightarrowtail' => '↣', + 'RightCeiling' => '⌉', + 'RightDoubleBracket' => '⟧', + 'RightDownTeeVector' => '⥝', + 'RightDownVector' => '⇂', + 'RightDownVectorBar' => '⥕', + 'RightFloor' => '⌋', + 'rightharpoondown' => '⇁', + 'rightharpoonup' => '⇀', + 'rightleftarrows' => '⇄', + 'rightleftharpoons' => '⇌', + 'rightrightarrows' => '⇉', + 'rightsquigarrow' => '↝', + 'RightTee' => '⊢', + 'RightTeeArrow' => '↦', + 'RightTeeVector' => '⥛', + 'rightthreetimes' => '⋌', + 'RightTriangle' => '⊳', + 'RightTriangleBar' => '⧐', + 'RightTriangleEqual' => '⊵', + 'RightUpDownVector' => '⥏', + 'RightUpTeeVector' => '⥜', + 'RightUpVector' => '↾', + 'RightUpVectorBar' => '⥔', + 'RightVector' => '⇀', + 'RightVectorBar' => '⥓', + 'ring' => '˚', + 'risingdotseq' => '≓', + 'rlarr' => '⇄', + 'rlhar' => '⇌', + 'rlm' => '‏', + 'rmoust' => '⎱', + 'rmoustache' => '⎱', + 'rnmid' => '⫮', + 'roang' => '⟭', + 'roarr' => '⇾', + 'robrk' => '⟧', + 'ropar' => '⦆', + 'Ropf' => 'ℝ', + 'ropf' => '𝕣', + 'roplus' => '⨮', + 'rotimes' => '⨵', + 'RoundImplies' => '⥰', + 'rpar' => ')', + 'rpargt' => '⦔', + 'rppolint' => '⨒', + 'rrarr' => '⇉', + 'Rrightarrow' => '⇛', + 'rsaquo' => '›', + 'Rscr' => 'ℛ', + 'rscr' => '𝓇', + 'Rsh' => '↱', + 'rsh' => '↱', + 'rsqb' => ']', + 'rsquo' => '’', + 'rsquor' => '’', + 'rthree' => '⋌', + 'rtimes' => '⋊', + 'rtri' => '▹', + 'rtrie' => '⊵', + 'rtrif' => '▸', + 'rtriltri' => '⧎', + 'RuleDelayed' => '⧴', + 'ruluhar' => '⥨', + 'rx' => '℞', + 'Sacute' => 'Ś', + 'sacute' => 'ś', + 'sbquo' => '‚', + 'Sc' => '⪼', + 'sc' => '≻', + 'scap' => '⪸', + 'Scaron' => 'Š', + 'scaron' => 'š', + 'sccue' => '≽', + 'scE' => '⪴', + 'sce' => '⪰', + 'Scedil' => 'Ş', + 'scedil' => 'ş', + 'Scirc' => 'Ŝ', + 'scirc' => 'ŝ', + 'scnap' => '⪺', + 'scnE' => '⪶', + 'scnsim' => '⋩', + 'scpolint' => '⨓', + 'scsim' => '≿', + 'Scy' => 'С', + 'scy' => 'с', + 'sdot' => '⋅', + 'sdotb' => '⊡', + 'sdote' => '⩦', + 'searhk' => '⤥', + 'seArr' => '⇘', + 'searr' => '↘', + 'searrow' => '↘', + 'sect' => '§', + 'sec' => '§', + 'semi' => ';', + 'seswar' => '⤩', + 'setminus' => '∖', + 'setmn' => '∖', + 'sext' => '✶', + 'Sfr' => '𝔖', + 'sfr' => '𝔰', + 'sfrown' => '⌢', + 'sharp' => '♯', + 'SHCHcy' => 'Щ', + 'shchcy' => 'щ', + 'SHcy' => 'Ш', + 'shcy' => 'ш', + 'ShortDownArrow' => '↓', + 'ShortLeftArrow' => '←', + 'shortmid' => '∣', + 'shortparallel' => '∥', + 'ShortRightArrow' => '→', + 'ShortUpArrow' => '↑', + 'shy' => '­', + 'sh' => '­', + 'Sigma' => 'Σ', + 'sigma' => 'σ', + 'sigmaf' => 'ς', + 'sigmav' => 'ς', + 'sim' => '∼', + 'simdot' => '⩪', + 'sime' => '≃', + 'simeq' => '≃', + 'simg' => '⪞', + 'simgE' => '⪠', + 'siml' => '⪝', + 'simlE' => '⪟', + 'simne' => '≆', + 'simplus' => '⨤', + 'simrarr' => '⥲', + 'slarr' => '←', + 'SmallCircle' => '∘', + 'smallsetminus' => '∖', + 'smashp' => '⨳', + 'smeparsl' => '⧤', + 'smid' => '∣', + 'smile' => '⌣', + 'smt' => '⪪', + 'smte' => '⪬', + 'smtes' => '⪬︀', + 'SOFTcy' => 'Ь', + 'softcy' => 'ь', + 'sol' => '/', + 'solb' => '⧄', + 'solbar' => '⌿', + 'Sopf' => '𝕊', + 'sopf' => '𝕤', + 'spades' => '♠', + 'spadesuit' => '♠', + 'spar' => '∥', + 'sqcap' => '⊓', + 'sqcaps' => '⊓︀', + 'sqcup' => '⊔', + 'sqcups' => '⊔︀', + 'Sqrt' => '√', + 'sqsub' => '⊏', + 'sqsube' => '⊑', + 'sqsubset' => '⊏', + 'sqsubseteq' => '⊑', + 'sqsup' => '⊐', + 'sqsupe' => '⊒', + 'sqsupset' => '⊐', + 'sqsupseteq' => '⊒', + 'squ' => '□', + 'Square' => '□', + 'square' => '□', + 'SquareIntersection' => '⊓', + 'SquareSubset' => '⊏', + 'SquareSubsetEqual' => '⊑', + 'SquareSuperset' => '⊐', + 'SquareSupersetEqual' => '⊒', + 'SquareUnion' => '⊔', + 'squarf' => '▪', + 'squf' => '▪', + 'srarr' => '→', + 'Sscr' => '𝒮', + 'sscr' => '𝓈', + 'ssetmn' => '∖', + 'ssmile' => '⌣', + 'sstarf' => '⋆', + 'Star' => '⋆', + 'star' => '☆', + 'starf' => '★', + 'straightepsilon' => 'ϵ', + 'straightphi' => 'ϕ', + 'strns' => '¯', + 'Sub' => '⋐', + 'sub' => '⊂', + 'subdot' => '⪽', + 'subE' => '⫅', + 'sube' => '⊆', + 'subedot' => '⫃', + 'submult' => '⫁', + 'subnE' => '⫋', + 'subne' => '⊊', + 'subplus' => '⪿', + 'subrarr' => '⥹', + 'Subset' => '⋐', + 'subset' => '⊂', + 'subseteq' => '⊆', + 'subseteqq' => '⫅', + 'SubsetEqual' => '⊆', + 'subsetneq' => '⊊', + 'subsetneqq' => '⫋', + 'subsim' => '⫇', + 'subsub' => '⫕', + 'subsup' => '⫓', + 'succ' => '≻', + 'succapprox' => '⪸', + 'succcurlyeq' => '≽', + 'Succeeds' => '≻', + 'SucceedsEqual' => '⪰', + 'SucceedsSlantEqual' => '≽', + 'SucceedsTilde' => '≿', + 'succeq' => '⪰', + 'succnapprox' => '⪺', + 'succneqq' => '⪶', + 'succnsim' => '⋩', + 'succsim' => '≿', + 'SuchThat' => '∋', + 'Sum' => '∑', + 'sum' => '∑', + 'sung' => '♪', + 'Sup' => '⋑', + 'sup' => '³', + 'sup1' => '¹', + 'sup2' => '²', + 'sup3' => '³', + 'supdot' => '⪾', + 'supdsub' => '⫘', + 'supE' => '⫆', + 'supe' => '⊇', + 'supedot' => '⫄', + 'Superset' => '⊃', + 'SupersetEqual' => '⊇', + 'suphsol' => '⟉', + 'suphsub' => '⫗', + 'suplarr' => '⥻', + 'supmult' => '⫂', + 'supnE' => '⫌', + 'supne' => '⊋', + 'supplus' => '⫀', + 'Supset' => '⋑', + 'supset' => '⊃', + 'supseteq' => '⊇', + 'supseteqq' => '⫆', + 'supsetneq' => '⊋', + 'supsetneqq' => '⫌', + 'supsim' => '⫈', + 'supsub' => '⫔', + 'supsup' => '⫖', + 'swarhk' => '⤦', + 'swArr' => '⇙', + 'swarr' => '↙', + 'swarrow' => '↙', + 'swnwar' => '⤪', + 'szlig' => 'ß', + 'szli' => 'ß', + 'Tab' => ' ', + 'target' => '⌖', + 'Tau' => 'Τ', + 'tau' => 'τ', + 'tbrk' => '⎴', + 'Tcaron' => 'Ť', + 'tcaron' => 'ť', + 'Tcedil' => 'Ţ', + 'tcedil' => 'ţ', + 'Tcy' => 'Т', + 'tcy' => 'т', + 'tdot' => '⃛', + 'telrec' => '⌕', + 'Tfr' => '𝔗', + 'tfr' => '𝔱', + 'there4' => '∴', + 'Therefore' => '∴', + 'therefore' => '∴', + 'Theta' => 'Θ', + 'theta' => 'θ', + 'thetasym' => 'ϑ', + 'thetav' => 'ϑ', + 'thickapprox' => '≈', + 'thicksim' => '∼', + 'ThickSpace' => '  ', + 'thinsp' => ' ', + 'ThinSpace' => ' ', + 'thkap' => '≈', + 'thksim' => '∼', + 'THORN' => 'Þ', + 'THOR' => 'Þ', + 'thorn' => 'þ', + 'thor' => 'þ', + 'Tilde' => '∼', + 'tilde' => '˜', + 'TildeEqual' => '≃', + 'TildeFullEqual' => '≅', + 'TildeTilde' => '≈', + 'times' => '×', + 'time' => '×', + 'timesb' => '⊠', + 'timesbar' => '⨱', + 'timesd' => '⨰', + 'tint' => '∭', + 'toea' => '⤨', + 'top' => '⊤', + 'topbot' => '⌶', + 'topcir' => '⫱', + 'Topf' => '𝕋', + 'topf' => '𝕥', + 'topfork' => '⫚', + 'tosa' => '⤩', + 'tprime' => '‴', + 'TRADE' => '™', + 'trade' => '™', + 'triangle' => '▵', + 'triangledown' => '▿', + 'triangleleft' => '◃', + 'trianglelefteq' => '⊴', + 'triangleq' => '≜', + 'triangleright' => '▹', + 'trianglerighteq' => '⊵', + 'tridot' => '◬', + 'trie' => '≜', + 'triminus' => '⨺', + 'TripleDot' => '⃛', + 'triplus' => '⨹', + 'trisb' => '⧍', + 'tritime' => '⨻', + 'trpezium' => '⏢', + 'Tscr' => '𝒯', + 'tscr' => '𝓉', + 'TScy' => 'Ц', + 'tscy' => 'ц', + 'TSHcy' => 'Ћ', + 'tshcy' => 'ћ', + 'Tstrok' => 'Ŧ', + 'tstrok' => 'ŧ', + 'twixt' => '≬', + 'twoheadleftarrow' => '↞', + 'twoheadrightarrow' => '↠', + 'Uacute' => 'Ú', + 'Uacut' => 'Ú', + 'uacute' => 'ú', + 'uacut' => 'ú', + 'Uarr' => '↟', + 'uArr' => '⇑', + 'uarr' => '↑', + 'Uarrocir' => '⥉', + 'Ubrcy' => 'Ў', + 'ubrcy' => 'ў', + 'Ubreve' => 'Ŭ', + 'ubreve' => 'ŭ', + 'Ucirc' => 'Û', + 'Ucir' => 'Û', + 'ucirc' => 'û', + 'ucir' => 'û', + 'Ucy' => 'У', + 'ucy' => 'у', + 'udarr' => '⇅', + 'Udblac' => 'Ű', + 'udblac' => 'ű', + 'udhar' => '⥮', + 'ufisht' => '⥾', + 'Ufr' => '𝔘', + 'ufr' => '𝔲', + 'Ugrave' => 'Ù', + 'Ugrav' => 'Ù', + 'ugrave' => 'ù', + 'ugrav' => 'ù', + 'uHar' => '⥣', + 'uharl' => '↿', + 'uharr' => '↾', + 'uhblk' => '▀', + 'ulcorn' => '⌜', + 'ulcorner' => '⌜', + 'ulcrop' => '⌏', + 'ultri' => '◸', + 'Umacr' => 'Ū', + 'umacr' => 'ū', + 'uml' => '¨', + 'um' => '¨', + 'UnderBar' => '_', + 'UnderBrace' => '⏟', + 'UnderBracket' => '⎵', + 'UnderParenthesis' => '⏝', + 'Union' => '⋃', + 'UnionPlus' => '⊎', + 'Uogon' => 'Ų', + 'uogon' => 'ų', + 'Uopf' => '𝕌', + 'uopf' => '𝕦', + 'UpArrow' => '↑', + 'Uparrow' => '⇑', + 'uparrow' => '↑', + 'UpArrowBar' => '⤒', + 'UpArrowDownArrow' => '⇅', + 'UpDownArrow' => '↕', + 'Updownarrow' => '⇕', + 'updownarrow' => '↕', + 'UpEquilibrium' => '⥮', + 'upharpoonleft' => '↿', + 'upharpoonright' => '↾', + 'uplus' => '⊎', + 'UpperLeftArrow' => '↖', + 'UpperRightArrow' => '↗', + 'Upsi' => 'ϒ', + 'upsi' => 'υ', + 'upsih' => 'ϒ', + 'Upsilon' => 'Υ', + 'upsilon' => 'υ', + 'UpTee' => '⊥', + 'UpTeeArrow' => '↥', + 'upuparrows' => '⇈', + 'urcorn' => '⌝', + 'urcorner' => '⌝', + 'urcrop' => '⌎', + 'Uring' => 'Ů', + 'uring' => 'ů', + 'urtri' => '◹', + 'Uscr' => '𝒰', + 'uscr' => '𝓊', + 'utdot' => '⋰', + 'Utilde' => 'Ũ', + 'utilde' => 'ũ', + 'utri' => '▵', + 'utrif' => '▴', + 'uuarr' => '⇈', + 'Uuml' => 'Ü', + 'Uum' => 'Ü', + 'uuml' => 'ü', + 'uum' => 'ü', + 'uwangle' => '⦧', + 'vangrt' => '⦜', + 'varepsilon' => 'ϵ', + 'varkappa' => 'ϰ', + 'varnothing' => '∅', + 'varphi' => 'ϕ', + 'varpi' => 'ϖ', + 'varpropto' => '∝', + 'vArr' => '⇕', + 'varr' => '↕', + 'varrho' => 'ϱ', + 'varsigma' => 'ς', + 'varsubsetneq' => '⊊︀', + 'varsubsetneqq' => '⫋︀', + 'varsupsetneq' => '⊋︀', + 'varsupsetneqq' => '⫌︀', + 'vartheta' => 'ϑ', + 'vartriangleleft' => '⊲', + 'vartriangleright' => '⊳', + 'Vbar' => '⫫', + 'vBar' => '⫨', + 'vBarv' => '⫩', + 'Vcy' => 'В', + 'vcy' => 'в', + 'VDash' => '⊫', + 'Vdash' => '⊩', + 'vDash' => '⊨', + 'vdash' => '⊢', + 'Vdashl' => '⫦', + 'Vee' => '⋁', + 'vee' => '∨', + 'veebar' => '⊻', + 'veeeq' => '≚', + 'vellip' => '⋮', + 'Verbar' => '‖', + 'verbar' => '|', + 'Vert' => '‖', + 'vert' => '|', + 'VerticalBar' => '∣', + 'VerticalLine' => '|', + 'VerticalSeparator' => '❘', + 'VerticalTilde' => '≀', + 'VeryThinSpace' => ' ', + 'Vfr' => '𝔙', + 'vfr' => '𝔳', + 'vltri' => '⊲', + 'vnsub' => '⊂⃒', + 'vnsup' => '⊃⃒', + 'Vopf' => '𝕍', + 'vopf' => '𝕧', + 'vprop' => '∝', + 'vrtri' => '⊳', + 'Vscr' => '𝒱', + 'vscr' => '𝓋', + 'vsubnE' => '⫋︀', + 'vsubne' => '⊊︀', + 'vsupnE' => '⫌︀', + 'vsupne' => '⊋︀', + 'Vvdash' => '⊪', + 'vzigzag' => '⦚', + 'Wcirc' => 'Ŵ', + 'wcirc' => 'ŵ', + 'wedbar' => '⩟', + 'Wedge' => '⋀', + 'wedge' => '∧', + 'wedgeq' => '≙', + 'weierp' => '℘', + 'Wfr' => '𝔚', + 'wfr' => '𝔴', + 'Wopf' => '𝕎', + 'wopf' => '𝕨', + 'wp' => '℘', + 'wr' => '≀', + 'wreath' => '≀', + 'Wscr' => '𝒲', + 'wscr' => '𝓌', + 'xcap' => '⋂', + 'xcirc' => '◯', + 'xcup' => '⋃', + 'xdtri' => '▽', + 'Xfr' => '𝔛', + 'xfr' => '𝔵', + 'xhArr' => '⟺', + 'xharr' => '⟷', + 'Xi' => 'Ξ', + 'xi' => 'ξ', + 'xlArr' => '⟸', + 'xlarr' => '⟵', + 'xmap' => '⟼', + 'xnis' => '⋻', + 'xodot' => '⨀', + 'Xopf' => '𝕏', + 'xopf' => '𝕩', + 'xoplus' => '⨁', + 'xotime' => '⨂', + 'xrArr' => '⟹', + 'xrarr' => '⟶', + 'Xscr' => '𝒳', + 'xscr' => '𝓍', + 'xsqcup' => '⨆', + 'xuplus' => '⨄', + 'xutri' => '△', + 'xvee' => '⋁', + 'xwedge' => '⋀', + 'Yacute' => 'Ý', + 'Yacut' => 'Ý', + 'yacute' => 'ý', + 'yacut' => 'ý', + 'YAcy' => 'Я', + 'yacy' => 'я', + 'Ycirc' => 'Ŷ', + 'ycirc' => 'ŷ', + 'Ycy' => 'Ы', + 'ycy' => 'ы', + 'yen' => '¥', + 'ye' => '¥', + 'Yfr' => '𝔜', + 'yfr' => '𝔶', + 'YIcy' => 'Ї', + 'yicy' => 'ї', + 'Yopf' => '𝕐', + 'yopf' => '𝕪', + 'Yscr' => '𝒴', + 'yscr' => '𝓎', + 'YUcy' => 'Ю', + 'yucy' => 'ю', + 'Yuml' => 'Ÿ', + 'yuml' => 'ÿ', + 'yum' => 'ÿ', + 'Zacute' => 'Ź', + 'zacute' => 'ź', + 'Zcaron' => 'Ž', + 'zcaron' => 'ž', + 'Zcy' => 'З', + 'zcy' => 'з', + 'Zdot' => 'Ż', + 'zdot' => 'ż', + 'zeetrf' => 'ℨ', + 'ZeroWidthSpace' => '​', + 'Zeta' => 'Ζ', + 'zeta' => 'ζ', + 'Zfr' => 'ℨ', + 'zfr' => '𝔷', + 'ZHcy' => 'Ж', + 'zhcy' => 'ж', + 'zigrarr' => '⇝', + 'Zopf' => 'ℤ', + 'zopf' => '𝕫', + 'Zscr' => '𝒵', + 'zscr' => '𝓏', + 'zwj' => '‍', + 'zwnj' => '‌', + ); +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Exception.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Exception.php new file mode 100644 index 000000000..64e97e6ff --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Exception.php @@ -0,0 +1,10 @@ + self::NAMESPACE_HTML, + 'svg' => self::NAMESPACE_SVG, + 'math' => self::NAMESPACE_MATHML, + ); + + /** + * Holds the always available namespaces (which does not require the XMLNS declaration). + * + * @var array + */ + protected $implicitNamespaces = array( + 'xml' => self::NAMESPACE_XML, + 'xmlns' => self::NAMESPACE_XMLNS, + 'xlink' => self::NAMESPACE_XLINK, + ); + + /** + * Holds a stack of currently active namespaces. + * + * @var array + */ + protected $nsStack = array(); + + /** + * Holds the number of namespaces declared by a node. + * + * @var array + */ + protected $pushes = array(); + + /** + * Defined in 8.2.5. + */ + const IM_INITIAL = 0; + + const IM_BEFORE_HTML = 1; + + const IM_BEFORE_HEAD = 2; + + const IM_IN_HEAD = 3; + + const IM_IN_HEAD_NOSCRIPT = 4; + + const IM_AFTER_HEAD = 5; + + const IM_IN_BODY = 6; + + const IM_TEXT = 7; + + const IM_IN_TABLE = 8; + + const IM_IN_TABLE_TEXT = 9; + + const IM_IN_CAPTION = 10; + + const IM_IN_COLUMN_GROUP = 11; + + const IM_IN_TABLE_BODY = 12; + + const IM_IN_ROW = 13; + + const IM_IN_CELL = 14; + + const IM_IN_SELECT = 15; + + const IM_IN_SELECT_IN_TABLE = 16; + + const IM_AFTER_BODY = 17; + + const IM_IN_FRAMESET = 18; + + const IM_AFTER_FRAMESET = 19; + + const IM_AFTER_AFTER_BODY = 20; + + const IM_AFTER_AFTER_FRAMESET = 21; + + const IM_IN_SVG = 22; + + const IM_IN_MATHML = 23; + + protected $options = array(); + + protected $stack = array(); + + protected $current; // Pointer in the tag hierarchy. + protected $rules; + protected $doc; + + protected $frag; + + protected $processor; + + protected $insertMode = 0; + + /** + * Track if we are in an element that allows only inline child nodes. + * + * @var string|null + */ + protected $onlyInline; + + /** + * Quirks mode is enabled by default. + * Any document that is missing the DT will be considered to be in quirks mode. + */ + protected $quirks = true; + + protected $errors = array(); + + public function __construct($isFragment = false, array $options = array()) + { + $this->options = $options; + + if (isset($options[self::OPT_TARGET_DOC])) { + $this->doc = $options[self::OPT_TARGET_DOC]; + } else { + $impl = new \DOMImplementation(); + // XXX: + // Create the doctype. For now, we are always creating HTML5 + // documents, and attempting to up-convert any older DTDs to HTML5. + $dt = $impl->createDocumentType('html'); + // $this->doc = \DOMImplementation::createDocument(NULL, 'html', $dt); + $this->doc = $impl->createDocument(null, '', $dt); + $this->doc->encoding = !empty($options['encoding']) ? $options['encoding'] : 'UTF-8'; + } + + $this->errors = array(); + + $this->current = $this->doc; // ->documentElement; + + // Create a rules engine for tags. + $this->rules = new TreeBuildingRules(); + + $implicitNS = array(); + if (isset($this->options[self::OPT_IMPLICIT_NS])) { + $implicitNS = $this->options[self::OPT_IMPLICIT_NS]; + } elseif (isset($this->options['implicitNamespaces'])) { + $implicitNS = $this->options['implicitNamespaces']; + } + + // Fill $nsStack with the defalut HTML5 namespaces, plus the "implicitNamespaces" array taken form $options + array_unshift($this->nsStack, $implicitNS + array('' => self::NAMESPACE_HTML) + $this->implicitNamespaces); + + if ($isFragment) { + $this->insertMode = static::IM_IN_BODY; + $this->frag = $this->doc->createDocumentFragment(); + $this->current = $this->frag; + } + } + + /** + * Get the document. + */ + public function document() + { + return $this->doc; + } + + /** + * Get the DOM fragment for the body. + * + * This returns a DOMNodeList because a fragment may have zero or more + * DOMNodes at its root. + * + * @see http://www.w3.org/TR/2012/CR-html5-20121217/syntax.html#concept-frag-parse-context + * + * @return \DOMDocumentFragment + */ + public function fragment() + { + return $this->frag; + } + + /** + * Provide an instruction processor. + * + * This is used for handling Processor Instructions as they are + * inserted. If omitted, PI's are inserted directly into the DOM tree. + * + * @param InstructionProcessor $proc + */ + public function setInstructionProcessor(InstructionProcessor $proc) + { + $this->processor = $proc; + } + + public function doctype($name, $idType = 0, $id = null, $quirks = false) + { + // This is used solely for setting quirks mode. Currently we don't + // try to preserve the inbound DT. We convert it to HTML5. + $this->quirks = $quirks; + + if ($this->insertMode > static::IM_INITIAL) { + $this->parseError('Illegal placement of DOCTYPE tag. Ignoring: ' . $name); + + return; + } + + $this->insertMode = static::IM_BEFORE_HTML; + } + + /** + * Process the start tag. + * + * @todo - XMLNS namespace handling (we need to parse, even if it's not valid) + * - XLink, MathML and SVG namespace handling + * - Omission rules: 8.1.2.4 Optional tags + * + * @param string $name + * @param array $attributes + * @param bool $selfClosing + * + * @return int + */ + public function startTag($name, $attributes = array(), $selfClosing = false) + { + $lname = $this->normalizeTagName($name); + + // Make sure we have an html element. + if (!$this->doc->documentElement && 'html' !== $name && !$this->frag) { + $this->startTag('html'); + } + + // Set quirks mode if we're at IM_INITIAL with no doctype. + if ($this->insertMode === static::IM_INITIAL) { + $this->quirks = true; + $this->parseError('No DOCTYPE specified.'); + } + + // SPECIAL TAG HANDLING: + // Spec says do this, and "don't ask." + // find the spec where this is defined... looks problematic + if ('image' === $name && !($this->insertMode === static::IM_IN_SVG || $this->insertMode === static::IM_IN_MATHML)) { + $name = 'img'; + } + + // Autoclose p tags where appropriate. + if ($this->insertMode >= static::IM_IN_BODY && Elements::isA($name, Elements::AUTOCLOSE_P)) { + $this->autoclose('p'); + } + + // Set insert mode: + switch ($name) { + case 'html': + $this->insertMode = static::IM_BEFORE_HEAD; + break; + case 'head': + if ($this->insertMode > static::IM_BEFORE_HEAD) { + $this->parseError('Unexpected head tag outside of head context.'); + } else { + $this->insertMode = static::IM_IN_HEAD; + } + break; + case 'body': + $this->insertMode = static::IM_IN_BODY; + break; + case 'svg': + $this->insertMode = static::IM_IN_SVG; + break; + case 'math': + $this->insertMode = static::IM_IN_MATHML; + break; + case 'noscript': + if ($this->insertMode === static::IM_IN_HEAD) { + $this->insertMode = static::IM_IN_HEAD_NOSCRIPT; + } + break; + } + + // Special case handling for SVG. + if ($this->insertMode === static::IM_IN_SVG) { + $lname = Elements::normalizeSvgElement($lname); + } + + $pushes = 0; + // when we found a tag thats appears inside $nsRoots, we have to switch the defalut namespace + if (isset($this->nsRoots[$lname]) && $this->nsStack[0][''] !== $this->nsRoots[$lname]) { + array_unshift($this->nsStack, array( + '' => $this->nsRoots[$lname], + ) + $this->nsStack[0]); + ++$pushes; + } + $needsWorkaround = false; + if (isset($this->options['xmlNamespaces']) && $this->options['xmlNamespaces']) { + // when xmlNamespaces is true a and we found a 'xmlns' or 'xmlns:*' attribute, we should add a new item to the $nsStack + foreach ($attributes as $aName => $aVal) { + if ('xmlns' === $aName) { + $needsWorkaround = $aVal; + array_unshift($this->nsStack, array( + '' => $aVal, + ) + $this->nsStack[0]); + ++$pushes; + } elseif ('xmlns' === (($pos = strpos($aName, ':')) ? substr($aName, 0, $pos) : '')) { + array_unshift($this->nsStack, array( + substr($aName, $pos + 1) => $aVal, + ) + $this->nsStack[0]); + ++$pushes; + } + } + } + + if ($this->onlyInline && Elements::isA($lname, Elements::BLOCK_TAG)) { + $this->autoclose($this->onlyInline); + $this->onlyInline = null; + } + + try { + $prefix = ($pos = strpos($lname, ':')) ? substr($lname, 0, $pos) : ''; + + if (false !== $needsWorkaround) { + $xml = "<$lname xmlns=\"$needsWorkaround\" " . (strlen($prefix) && isset($this->nsStack[0][$prefix]) ? ("xmlns:$prefix=\"" . $this->nsStack[0][$prefix] . '"') : '') . '/>'; + + $frag = new \DOMDocument('1.0', 'UTF-8'); + $frag->loadXML($xml); + + $ele = $this->doc->importNode($frag->documentElement, true); + } else { + if (!isset($this->nsStack[0][$prefix]) || ('' === $prefix && isset($this->options[self::OPT_DISABLE_HTML_NS]) && $this->options[self::OPT_DISABLE_HTML_NS])) { + $ele = $this->doc->createElement($lname); + } else { + $ele = $this->doc->createElementNS($this->nsStack[0][$prefix], $lname); + } + } + } catch (\DOMException $e) { + $this->parseError("Illegal tag name: <$lname>. Replaced with ."); + $ele = $this->doc->createElement('invalid'); + } + + if (Elements::isA($lname, Elements::BLOCK_ONLY_INLINE)) { + $this->onlyInline = $lname; + } + + // When we add some namespacess, we have to track them. Later, when "endElement" is invoked, we have to remove them. + // When we are on a void tag, we do not need to care about namesapce nesting. + if ($pushes > 0 && !Elements::isA($name, Elements::VOID_TAG)) { + // PHP tends to free the memory used by DOM, + // to avoid spl_object_hash collisions whe have to avoid garbage collection of $ele storing it into $pushes + // see https://bugs.php.net/bug.php?id=67459 + $this->pushes[spl_object_hash($ele)] = array($pushes, $ele); + } + + foreach ($attributes as $aName => $aVal) { + // xmlns attributes can't be set + if ('xmlns' === $aName) { + continue; + } + + if ($this->insertMode === static::IM_IN_SVG) { + $aName = Elements::normalizeSvgAttribute($aName); + } elseif ($this->insertMode === static::IM_IN_MATHML) { + $aName = Elements::normalizeMathMlAttribute($aName); + } + + $aVal = (string) $aVal; + + try { + $prefix = ($pos = strpos($aName, ':')) ? substr($aName, 0, $pos) : false; + + if ('xmlns' === $prefix) { + $ele->setAttributeNS(self::NAMESPACE_XMLNS, $aName, $aVal); + } elseif (false !== $prefix && isset($this->nsStack[0][$prefix])) { + $ele->setAttributeNS($this->nsStack[0][$prefix], $aName, $aVal); + } else { + $ele->setAttribute($aName, $aVal); + } + } catch (\DOMException $e) { + $this->parseError("Illegal attribute name for tag $name. Ignoring: $aName"); + continue; + } + + // This is necessary on a non-DTD schema, like HTML5. + if ('id' === $aName) { + $ele->setIdAttribute('id', true); + } + } + + if ($this->frag !== $this->current && $this->rules->hasRules($name)) { + // Some elements have special processing rules. Handle those separately. + $this->current = $this->rules->evaluate($ele, $this->current); + } else { + // Otherwise, it's a standard element. + $this->current->appendChild($ele); + + if (!Elements::isA($name, Elements::VOID_TAG)) { + $this->current = $ele; + } + + // Self-closing tags should only be respected on foreign elements + // (and are implied on void elements) + // See: https://www.w3.org/TR/html5/syntax.html#start-tags + if (Elements::isHtml5Element($name)) { + $selfClosing = false; + } + } + + // This is sort of a last-ditch attempt to correct for cases where no head/body + // elements are provided. + if ($this->insertMode <= static::IM_BEFORE_HEAD && 'head' !== $name && 'html' !== $name) { + $this->insertMode = static::IM_IN_BODY; + } + + // When we are on a void tag, we do not need to care about namesapce nesting, + // but we have to remove the namespaces pushed to $nsStack. + if ($pushes > 0 && Elements::isA($name, Elements::VOID_TAG)) { + // remove the namespaced definded by current node + for ($i = 0; $i < $pushes; ++$i) { + array_shift($this->nsStack); + } + } + + if ($selfClosing) { + $this->endTag($name); + } + + // Return the element mask, which the tokenizer can then use to set + // various processing rules. + return Elements::element($name); + } + + public function endTag($name) + { + $lname = $this->normalizeTagName($name); + + // Special case within 12.2.6.4.7: An end tag whose tag name is "br" should be treated as an opening tag + if ('br' === $name) { + $this->parseError('Closing tag encountered for void element br.'); + + $this->startTag('br'); + } + // Ignore closing tags for other unary elements. + elseif (Elements::isA($name, Elements::VOID_TAG)) { + return; + } + + if ($this->insertMode <= static::IM_BEFORE_HTML) { + // 8.2.5.4.2 + if (in_array($name, array( + 'html', + 'br', + 'head', + 'title', + ))) { + $this->startTag('html'); + $this->endTag($name); + $this->insertMode = static::IM_BEFORE_HEAD; + + return; + } + + // Ignore the tag. + $this->parseError('Illegal closing tag at global scope.'); + + return; + } + + // Special case handling for SVG. + if ($this->insertMode === static::IM_IN_SVG) { + $lname = Elements::normalizeSvgElement($lname); + } + + $cid = spl_object_hash($this->current); + + // XXX: HTML has no parent. What do we do, though, + // if this element appears in the wrong place? + if ('html' === $lname) { + return; + } + + // remove the namespaced definded by current node + if (isset($this->pushes[$cid])) { + for ($i = 0; $i < $this->pushes[$cid][0]; ++$i) { + array_shift($this->nsStack); + } + unset($this->pushes[$cid]); + } + + if (!$this->autoclose($lname)) { + $this->parseError('Could not find closing tag for ' . $lname); + } + + switch ($lname) { + case 'head': + $this->insertMode = static::IM_AFTER_HEAD; + break; + case 'body': + $this->insertMode = static::IM_AFTER_BODY; + break; + case 'svg': + case 'mathml': + $this->insertMode = static::IM_IN_BODY; + break; + } + } + + public function comment($cdata) + { + // TODO: Need to handle case where comment appears outside of the HTML tag. + $node = $this->doc->createComment($cdata); + $this->current->appendChild($node); + } + + public function text($data) + { + // XXX: Hmmm.... should we really be this strict? + if ($this->insertMode < static::IM_IN_HEAD) { + // Per '8.2.5.4.3 The "before head" insertion mode' the characters + // " \t\n\r\f" should be ignored but no mention of a parse error. This is + // practical as most documents contain these characters. Other text is not + // expected here so recording a parse error is necessary. + $dataTmp = trim($data, " \t\n\r\f"); + if (!empty($dataTmp)) { + // fprintf(STDOUT, "Unexpected insert mode: %d", $this->insertMode); + $this->parseError('Unexpected text. Ignoring: ' . $dataTmp); + } + + return; + } + // fprintf(STDOUT, "Appending text %s.", $data); + $node = $this->doc->createTextNode($data); + $this->current->appendChild($node); + } + + public function eof() + { + // If the $current isn't the $root, do we need to do anything? + } + + public function parseError($msg, $line = 0, $col = 0) + { + $this->errors[] = sprintf('Line %d, Col %d: %s', $line, $col, $msg); + } + + public function getErrors() + { + return $this->errors; + } + + public function cdata($data) + { + $node = $this->doc->createCDATASection($data); + $this->current->appendChild($node); + } + + public function processingInstruction($name, $data = null) + { + // XXX: Ignore initial XML declaration, per the spec. + if ($this->insertMode === static::IM_INITIAL && 'xml' === strtolower($name)) { + return; + } + + // Important: The processor may modify the current DOM tree however it sees fit. + if ($this->processor instanceof InstructionProcessor) { + $res = $this->processor->process($this->current, $name, $data); + if (!empty($res)) { + $this->current = $res; + } + + return; + } + + // Otherwise, this is just a dumb PI element. + $node = $this->doc->createProcessingInstruction($name, $data); + + $this->current->appendChild($node); + } + + // ========================================================================== + // UTILITIES + // ========================================================================== + + /** + * Apply normalization rules to a tag name. + * See sections 2.9 and 8.1.2. + * + * @param string $tagName + * + * @return string The normalized tag name. + */ + protected function normalizeTagName($tagName) + { + /* + * Section 2.9 suggests that we should not do this. if (strpos($name, ':') !== false) { // We know from the grammar that there must be at least one other // char besides :, since : is not a legal tag start. $parts = explode(':', $name); return array_pop($parts); } + */ + return $tagName; + } + + protected function quirksTreeResolver($name) + { + throw new \Exception('Not implemented.'); + } + + /** + * Automatically climb the tree and close the closest node with the matching $tag. + * + * @param string $tagName + * + * @return bool + */ + protected function autoclose($tagName) + { + $working = $this->current; + do { + if (XML_ELEMENT_NODE !== $working->nodeType) { + return false; + } + if ($working->tagName === $tagName) { + $this->current = $working->parentNode; + + return true; + } + } while ($working = $working->parentNode); + + return false; + } + + /** + * Checks if the given tagname is an ancestor of the present candidate. + * + * If $this->current or anything above $this->current matches the given tag + * name, this returns true. + * + * @param string $tagName + * + * @return bool + */ + protected function isAncestor($tagName) + { + $candidate = $this->current; + while (XML_ELEMENT_NODE === $candidate->nodeType) { + if ($candidate->tagName === $tagName) { + return true; + } + $candidate = $candidate->parentNode; + } + + return false; + } + + /** + * Returns true if the immediate parent element is of the given tagname. + * + * @param string $tagName + * + * @return bool + */ + protected function isParent($tagName) + { + return $this->current->tagName === $tagName; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php new file mode 100644 index 000000000..9893a718b --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/EventHandler.php @@ -0,0 +1,114 @@ +). + * + * @return int one of the Tokenizer::TEXTMODE_* constants + */ + public function startTag($name, $attributes = array(), $selfClosing = false); + + /** + * An end-tag. + */ + public function endTag($name); + + /** + * A comment section (unparsed character data). + */ + public function comment($cdata); + + /** + * A unit of parsed character data. + * + * Entities in this text are *already decoded*. + */ + public function text($cdata); + + /** + * Indicates that the document has been entirely processed. + */ + public function eof(); + + /** + * Emitted when the parser encounters an error condition. + */ + public function parseError($msg, $line, $col); + + /** + * A CDATA section. + * + * @param string $data + * The unparsed character data + */ + public function cdata($data); + + /** + * This is a holdover from the XML spec. + * + * While user agents don't get PIs, server-side does. + * + * @param string $name The name of the processor (e.g. 'php'). + * @param string $data The unparsed data. + */ + public function processingInstruction($name, $data = null); +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php new file mode 100644 index 000000000..b081ed96b --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/FileInputStream.php @@ -0,0 +1,33 @@ +errors = UTF8Utils::checkForIllegalCodepoints($data); + + $data = $this->replaceLinefeeds($data); + + $this->data = $data; + $this->char = 0; + $this->EOF = strlen($data); + } + + /** + * Check if upcomming chars match the given sequence. + * + * This will read the stream for the $sequence. If it's + * found, this will return true. If not, return false. + * Since this unconsumes any chars it reads, the caller + * will still need to read the next sequence, even if + * this returns true. + * + * Example: $this->scanner->sequenceMatches('') will + * see if the input stream is at the start of a + * '' string. + * + * @param string $sequence + * @param bool $caseSensitive + * + * @return bool + */ + public function sequenceMatches($sequence, $caseSensitive = true) + { + $portion = substr($this->data, $this->char, strlen($sequence)); + + return $caseSensitive ? $portion === $sequence : 0 === strcasecmp($portion, $sequence); + } + + /** + * Get the current position. + * + * @return int The current intiger byte position. + */ + public function position() + { + return $this->char; + } + + /** + * Take a peek at the next character in the data. + * + * @return string The next character. + */ + public function peek() + { + if (($this->char + 1) < $this->EOF) { + return $this->data[$this->char + 1]; + } + + return false; + } + + /** + * Get the next character. + * Note: This advances the pointer. + * + * @return string The next character. + */ + public function next() + { + ++$this->char; + + if ($this->char < $this->EOF) { + return $this->data[$this->char]; + } + + return false; + } + + /** + * Get the current character. + * Note, this does not advance the pointer. + * + * @return string The current character. + */ + public function current() + { + if ($this->char < $this->EOF) { + return $this->data[$this->char]; + } + + return false; + } + + /** + * Silently consume N chars. + * + * @param int $count + */ + public function consume($count = 1) + { + $this->char += $count; + } + + /** + * Unconsume some of the data. + * This moves the data pointer backwards. + * + * @param int $howMany The number of characters to move the pointer back. + */ + public function unconsume($howMany = 1) + { + if (($this->char - $howMany) >= 0) { + $this->char -= $howMany; + } + } + + /** + * Get the next group of that contains hex characters. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group that is hex characters. + */ + public function getHex() + { + return $this->doCharsWhile(static::CHARS_HEX); + } + + /** + * Get the next group of characters that are ASCII Alpha characters. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group of ASCII alpha characters. + */ + public function getAsciiAlpha() + { + return $this->doCharsWhile(static::CHARS_ALPHA); + } + + /** + * Get the next group of characters that are ASCII Alpha characters and numbers. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group of ASCII alpha characters and numbers. + */ + public function getAsciiAlphaNum() + { + return $this->doCharsWhile(static::CHARS_ALNUM); + } + + /** + * Get the next group of numbers. + * Note, along with getting the characters the pointer in the data will be + * moved as well. + * + * @return string The next group of numbers. + */ + public function getNumeric() + { + return $this->doCharsWhile('0123456789'); + } + + /** + * Consume whitespace. + * Whitespace in HTML5 is: formfeed, tab, newline, space. + * + * @return int The length of the matched whitespaces. + */ + public function whitespace() + { + if ($this->char >= $this->EOF) { + return false; + } + + $len = strspn($this->data, "\n\t\f ", $this->char); + + $this->char += $len; + + return $len; + } + + /** + * Returns the current line that is being consumed. + * + * @return int The current line number. + */ + public function currentLine() + { + if (empty($this->EOF) || 0 === $this->char) { + return 1; + } + + // Add one to $this->char because we want the number for the next + // byte to be processed. + return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; + } + + /** + * Read chars until something in the mask is encountered. + * + * @param string $mask + * + * @return mixed + */ + public function charsUntil($mask) + { + return $this->doCharsUntil($mask); + } + + /** + * Read chars as long as the mask matches. + * + * @param string $mask + * + * @return int + */ + public function charsWhile($mask) + { + return $this->doCharsWhile($mask); + } + + /** + * Returns the current column of the current line that the tokenizer is at. + * + * Newlines are column 0. The first char after a newline is column 1. + * + * @return int The column number. + */ + public function columnOffset() + { + // Short circuit for the first char. + if (0 === $this->char) { + return 0; + } + + // strrpos is weird, and the offset needs to be negative for what we + // want (i.e., the last \n before $this->char). This needs to not have + // one (to make it point to the next character, the one we want the + // position of) added to it because strrpos's behaviour includes the + // final offset byte. + $backwardFrom = $this->char - 1 - strlen($this->data); + $lastLine = strrpos($this->data, "\n", $backwardFrom); + + // However, for here we want the length up until the next byte to be + // processed, so add one to the current byte ($this->char). + if (false !== $lastLine) { + $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); + } else { + // After a newline. + $findLengthOf = substr($this->data, 0, $this->char); + } + + return UTF8Utils::countChars($findLengthOf); + } + + /** + * Get all characters until EOF. + * + * This consumes characters until the EOF. + * + * @return int The number of characters remaining. + */ + public function remainingChars() + { + if ($this->char < $this->EOF) { + $data = substr($this->data, $this->char); + $this->char = $this->EOF; + + return $data; + } + + return ''; // false; + } + + /** + * Replace linefeed characters according to the spec. + * + * @param $data + * + * @return string + */ + private function replaceLinefeeds($data) + { + /* + * U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially. + * Any CR characters that are followed by LF characters must be removed, and any CR characters not + * followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are + * represented by LF characters, and there are never any CR characters in the input to the tokenization + * stage. + */ + $crlfTable = array( + "\0" => "\xEF\xBF\xBD", + "\r\n" => "\n", + "\r" => "\n", + ); + + return strtr($data, $crlfTable); + } + + /** + * Read to a particular match (or until $max bytes are consumed). + * + * This operates on byte sequences, not characters. + * + * Matches as far as possible until we reach a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes Bytes to match. + * @param int $max Maximum number of bytes to scan. + * + * @return mixed Index or false if no match is found. You should use strong + * equality when checking the result, since index could be 0. + */ + private function doCharsUntil($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strcspn($this->data, $bytes, $this->char, $max); + } else { + $len = strcspn($this->data, $bytes, $this->char); + } + + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } + + /** + * Returns the string so long as $bytes matches. + * + * Matches as far as possible with a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the + * current char, the pointer advances and the char is part of the + * substring. + * @param int $max The max number of chars to read. + * + * @return string + */ + private function doCharsWhile($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strspn($this->data, $bytes, $this->char, $max); + } else { + $len = strspn($this->data, $bytes, $this->char); + } + + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php new file mode 100644 index 000000000..0c213feb6 --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/StringInputStream.php @@ -0,0 +1,331 @@ + + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +// Some conventions: +// - /* */ indicates verbatim text from the HTML 5 specification +// MPB: Not sure which version of the spec. Moving from HTML5lib to +// HTML5-PHP, I have been using this version: +// http://www.w3.org/TR/2012/CR-html5-20121217/Overview.html#contents +// +// - // indicates regular comments + +/** + * @deprecated since 2.4, to remove in 3.0. Use a string in the scanner instead. + */ +class StringInputStream implements InputStream +{ + /** + * The string data we're parsing. + */ + private $data; + + /** + * The current integer byte position we are in $data. + */ + private $char; + + /** + * Length of $data; when $char === $data, we are at the end-of-file. + */ + private $EOF; + + /** + * Parse errors. + */ + public $errors = array(); + + /** + * Create a new InputStream wrapper. + * + * @param string $data Data to parse. + * @param string $encoding The encoding to use for the data. + * @param string $debug A fprintf format to use to echo the data on stdout. + */ + public function __construct($data, $encoding = 'UTF-8', $debug = '') + { + $data = UTF8Utils::convertToUTF8($data, $encoding); + if ($debug) { + fprintf(STDOUT, $debug, $data, strlen($data)); + } + + // There is good reason to question whether it makes sense to + // do this here, since most of these checks are done during + // parsing, and since this check doesn't actually *do* anything. + $this->errors = UTF8Utils::checkForIllegalCodepoints($data); + + $data = $this->replaceLinefeeds($data); + + $this->data = $data; + $this->char = 0; + $this->EOF = strlen($data); + } + + public function __toString() + { + return $this->data; + } + + /** + * Replace linefeed characters according to the spec. + */ + protected function replaceLinefeeds($data) + { + /* + * U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED (LF) characters are treated specially. + * Any CR characters that are followed by LF characters must be removed, and any CR characters not + * followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are + * represented by LF characters, and there are never any CR characters in the input to the tokenization + * stage. + */ + $crlfTable = array( + "\0" => "\xEF\xBF\xBD", + "\r\n" => "\n", + "\r" => "\n", + ); + + return strtr($data, $crlfTable); + } + + /** + * Returns the current line that the tokenizer is at. + */ + public function currentLine() + { + if (empty($this->EOF) || 0 === $this->char) { + return 1; + } + // Add one to $this->char because we want the number for the next + // byte to be processed. + return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; + } + + /** + * @deprecated + */ + public function getCurrentLine() + { + return $this->currentLine(); + } + + /** + * Returns the current column of the current line that the tokenizer is at. + * Newlines are column 0. The first char after a newline is column 1. + * + * @return int The column number. + */ + public function columnOffset() + { + // Short circuit for the first char. + if (0 === $this->char) { + return 0; + } + // strrpos is weird, and the offset needs to be negative for what we + // want (i.e., the last \n before $this->char). This needs to not have + // one (to make it point to the next character, the one we want the + // position of) added to it because strrpos's behaviour includes the + // final offset byte. + $backwardFrom = $this->char - 1 - strlen($this->data); + $lastLine = strrpos($this->data, "\n", $backwardFrom); + + // However, for here we want the length up until the next byte to be + // processed, so add one to the current byte ($this->char). + if (false !== $lastLine) { + $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); + } else { + // After a newline. + $findLengthOf = substr($this->data, 0, $this->char); + } + + return UTF8Utils::countChars($findLengthOf); + } + + /** + * @deprecated + */ + public function getColumnOffset() + { + return $this->columnOffset(); + } + + /** + * Get the current character. + * + * @return string The current character. + */ + public function current() + { + return $this->data[$this->char]; + } + + /** + * Advance the pointer. + * This is part of the Iterator interface. + */ + public function next() + { + ++$this->char; + } + + /** + * Rewind to the start of the string. + */ + public function rewind() + { + $this->char = 0; + } + + /** + * Is the current pointer location valid. + * + * @return bool Whether the current pointer location is valid. + */ + public function valid() + { + return $this->char < $this->EOF; + } + + /** + * Get all characters until EOF. + * + * This reads to the end of the file, and sets the read marker at the + * end of the file. + * + * Note this performs bounds checking. + * + * @return string Returns the remaining text. If called when the InputStream is + * already exhausted, it returns an empty string. + */ + public function remainingChars() + { + if ($this->char < $this->EOF) { + $data = substr($this->data, $this->char); + $this->char = $this->EOF; + + return $data; + } + + return ''; // false; + } + + /** + * Read to a particular match (or until $max bytes are consumed). + * + * This operates on byte sequences, not characters. + * + * Matches as far as possible until we reach a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes Bytes to match. + * @param int $max Maximum number of bytes to scan. + * + * @return mixed Index or false if no match is found. You should use strong + * equality when checking the result, since index could be 0. + */ + public function charsUntil($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strcspn($this->data, $bytes, $this->char, $max); + } else { + $len = strcspn($this->data, $bytes, $this->char); + } + + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } + + /** + * Returns the string so long as $bytes matches. + * + * Matches as far as possible with a certain set of bytes + * and returns the matched substring. + * + * @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the + * current char, the pointer advances and the char is part of the + * substring. + * @param int $max The max number of chars to read. + * + * @return string + */ + public function charsWhile($bytes, $max = null) + { + if ($this->char >= $this->EOF) { + return false; + } + + if (0 === $max || $max) { + $len = strspn($this->data, $bytes, $this->char, $max); + } else { + $len = strspn($this->data, $bytes, $this->char); + } + $string = (string) substr($this->data, $this->char, $len); + $this->char += $len; + + return $string; + } + + /** + * Unconsume characters. + * + * @param int $howMany The number of characters to unconsume. + */ + public function unconsume($howMany = 1) + { + if (($this->char - $howMany) >= 0) { + $this->char -= $howMany; + } + } + + /** + * Look ahead without moving cursor. + */ + public function peek() + { + if (($this->char + 1) <= $this->EOF) { + return $this->data[$this->char + 1]; + } + + return false; + } + + public function key() + { + return $this->char; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php new file mode 100644 index 000000000..016919ae2 --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/Tokenizer.php @@ -0,0 +1,1197 @@ +scanner = $scanner; + $this->events = $eventHandler; + $this->mode = $mode; + } + + /** + * Begin parsing. + * + * This will begin scanning the document, tokenizing as it goes. + * Tokens are emitted into the event handler. + * + * Tokenizing will continue until the document is completely + * read. Errors are emitted into the event handler, but + * the parser will attempt to continue parsing until the + * entire input stream is read. + */ + public function parse() + { + do { + $this->consumeData(); + // FIXME: Add infinite loop protection. + } while ($this->carryOn); + } + + /** + * Set the text mode for the character data reader. + * + * HTML5 defines three different modes for reading text: + * - Normal: Read until a tag is encountered. + * - RCDATA: Read until a tag is encountered, but skip a few otherwise- + * special characters. + * - Raw: Read until a special closing tag is encountered (viz. pre, script) + * + * This allows those modes to be set. + * + * Normally, setting is done by the event handler via a special return code on + * startTag(), but it can also be set manually using this function. + * + * @param int $textmode One of Elements::TEXT_*. + * @param string $untilTag The tag that should stop RAW or RCDATA mode. Normal mode does not + * use this indicator. + */ + public function setTextMode($textmode, $untilTag = null) + { + $this->textMode = $textmode & (Elements::TEXT_RAW | Elements::TEXT_RCDATA); + $this->untilTag = $untilTag; + } + + /** + * Consume a character and make a move. + * HTML5 8.2.4.1. + */ + protected function consumeData() + { + $tok = $this->scanner->current(); + + if ('&' === $tok) { + // Character reference + $ref = $this->decodeCharacterReference(); + $this->buffer($ref); + + $tok = $this->scanner->current(); + } + + // Parse tag + if ('<' === $tok) { + // Any buffered text data can go out now. + $this->flushBuffer(); + + $tok = $this->scanner->next(); + + if ('!' === $tok) { + $this->markupDeclaration(); + } elseif ('/' === $tok) { + $this->endTag(); + } elseif ('?' === $tok) { + $this->processingInstruction(); + } elseif (ctype_alpha($tok)) { + $this->tagName(); + } else { + $this->parseError('Illegal tag opening'); + // TODO is this necessary ? + $this->characterData(); + } + + $tok = $this->scanner->current(); + } + + if (false === $tok) { + // Handle end of document + $this->eof(); + } else { + // Parse character + switch ($this->textMode) { + case Elements::TEXT_RAW: + $this->rawText($tok); + break; + + case Elements::TEXT_RCDATA: + $this->rcdata($tok); + break; + + default: + if ('<' === $tok || '&' === $tok) { + break; + } + + // NULL character + if ("\00" === $tok) { + $this->parseError('Received null character.'); + + $this->text .= $tok; + $this->scanner->consume(); + + break; + } + + $this->text .= $this->scanner->charsUntil("<&\0"); + } + } + + return $this->carryOn; + } + + /** + * Parse anything that looks like character data. + * + * Different rules apply based on the current text mode. + * + * @see Elements::TEXT_RAW Elements::TEXT_RCDATA. + */ + protected function characterData() + { + $tok = $this->scanner->current(); + if (false === $tok) { + return false; + } + switch ($this->textMode) { + case Elements::TEXT_RAW: + return $this->rawText($tok); + case Elements::TEXT_RCDATA: + return $this->rcdata($tok); + default: + if ('<' === $tok || '&' === $tok) { + return false; + } + + return $this->text($tok); + } + } + + /** + * This buffers the current token as character data. + * + * @param string $tok The current token. + * + * @return bool + */ + protected function text($tok) + { + // This should never happen... + if (false === $tok) { + return false; + } + + // NULL character + if ("\00" === $tok) { + $this->parseError('Received null character.'); + } + + $this->buffer($tok); + $this->scanner->consume(); + + return true; + } + + /** + * Read text in RAW mode. + * + * @param string $tok The current token. + * + * @return bool + */ + protected function rawText($tok) + { + if (is_null($this->untilTag)) { + return $this->text($tok); + } + + $sequence = 'untilTag . '>'; + $txt = $this->readUntilSequence($sequence); + $this->events->text($txt); + $this->setTextMode(0); + + return $this->endTag(); + } + + /** + * Read text in RCDATA mode. + * + * @param string $tok The current token. + * + * @return bool + */ + protected function rcdata($tok) + { + if (is_null($this->untilTag)) { + return $this->text($tok); + } + + $sequence = 'untilTag; + $txt = ''; + + $caseSensitive = !Elements::isHtml5Element($this->untilTag); + while (false !== $tok && !('<' == $tok && ($this->scanner->sequenceMatches($sequence, $caseSensitive)))) { + if ('&' == $tok) { + $txt .= $this->decodeCharacterReference(); + $tok = $this->scanner->current(); + } else { + $txt .= $tok; + $tok = $this->scanner->next(); + } + } + $len = strlen($sequence); + $this->scanner->consume($len); + $len += $this->scanner->whitespace(); + if ('>' !== $this->scanner->current()) { + $this->parseError('Unclosed RCDATA end tag'); + } + + $this->scanner->unconsume($len); + $this->events->text($txt); + $this->setTextMode(0); + + return $this->endTag(); + } + + /** + * If the document is read, emit an EOF event. + */ + protected function eof() + { + // fprintf(STDOUT, "EOF"); + $this->flushBuffer(); + $this->events->eof(); + $this->carryOn = false; + } + + /** + * Look for markup. + */ + protected function markupDeclaration() + { + $tok = $this->scanner->next(); + + // Comment: + if ('-' == $tok && '-' == $this->scanner->peek()) { + $this->scanner->consume(2); + + return $this->comment(); + } elseif ('D' == $tok || 'd' == $tok) { // Doctype + return $this->doctype(); + } elseif ('[' == $tok) { // CDATA section + return $this->cdataSection(); + } + + // FINISH + $this->parseError('Expected . Emit an empty comment because 8.2.4.46 says to. + if ('>' == $tok) { + // Parse error. Emit the comment token. + $this->parseError("Expected comment data, got '>'"); + $this->events->comment(''); + $this->scanner->consume(); + + return true; + } + + // Replace NULL with the replacement char. + if ("\0" == $tok) { + $tok = UTF8Utils::FFFD; + } + while (!$this->isCommentEnd()) { + $comment .= $tok; + $tok = $this->scanner->next(); + } + + $this->events->comment($comment); + $this->scanner->consume(); + + return true; + } + + /** + * Check if the scanner has reached the end of a comment. + * + * @return bool + */ + protected function isCommentEnd() + { + $tok = $this->scanner->current(); + + // EOF + if (false === $tok) { + // Hit the end. + $this->parseError('Unexpected EOF in a comment.'); + + return true; + } + + // If next two tokens are not '--', not the end. + if ('-' != $tok || '-' != $this->scanner->peek()) { + return false; + } + + $this->scanner->consume(2); // Consume '-' and one of '!' or '>' + + // Test for '>' + if ('>' == $this->scanner->current()) { + return true; + } + // Test for '!>' + if ('!' == $this->scanner->current() && '>' == $this->scanner->peek()) { + $this->scanner->consume(); // Consume the last '>' + return true; + } + // Unread '-' and one of '!' or '>'; + $this->scanner->unconsume(2); + + return false; + } + + /** + * Parse a DOCTYPE. + * + * Parse a DOCTYPE declaration. This method has strong bearing on whether or + * not Quirksmode is enabled on the event handler. + * + * @todo This method is a little long. Should probably refactor. + * + * @return bool + */ + protected function doctype() + { + // Check that string is DOCTYPE. + if ($this->scanner->sequenceMatches('DOCTYPE', false)) { + $this->scanner->consume(7); + } else { + $chars = $this->scanner->charsWhile('DOCTYPEdoctype'); + $this->parseError('Expected DOCTYPE, got %s', $chars); + + return $this->bogusComment('scanner->whitespace(); + $tok = $this->scanner->current(); + + // EOF: die. + if (false === $tok) { + $this->events->doctype('html5', EventHandler::DOCTYPE_NONE, '', true); + $this->eof(); + + return true; + } + + // NULL char: convert. + if ("\0" === $tok) { + $this->parseError('Unexpected null character in DOCTYPE.'); + } + + $stop = " \n\f>"; + $doctypeName = $this->scanner->charsUntil($stop); + // Lowercase ASCII, replace \0 with FFFD + $doctypeName = strtolower(strtr($doctypeName, "\0", UTF8Utils::FFFD)); + + $tok = $this->scanner->current(); + + // If false, emit a parse error, DOCTYPE, and return. + if (false === $tok) { + $this->parseError('Unexpected EOF in DOCTYPE declaration.'); + $this->events->doctype($doctypeName, EventHandler::DOCTYPE_NONE, null, true); + + return true; + } + + // Short DOCTYPE, like + if ('>' == $tok) { + // DOCTYPE without a name. + if (0 == strlen($doctypeName)) { + $this->parseError('Expected a DOCTYPE name. Got nothing.'); + $this->events->doctype($doctypeName, 0, null, true); + $this->scanner->consume(); + + return true; + } + $this->events->doctype($doctypeName); + $this->scanner->consume(); + + return true; + } + $this->scanner->whitespace(); + + $pub = strtoupper($this->scanner->getAsciiAlpha()); + $white = $this->scanner->whitespace(); + + // Get ID, and flag it as pub or system. + if (('PUBLIC' == $pub || 'SYSTEM' == $pub) && $white > 0) { + // Get the sys ID. + $type = 'PUBLIC' == $pub ? EventHandler::DOCTYPE_PUBLIC : EventHandler::DOCTYPE_SYSTEM; + $id = $this->quotedString("\0>"); + if (false === $id) { + $this->events->doctype($doctypeName, $type, $pub, false); + + return true; + } + + // Premature EOF. + if (false === $this->scanner->current()) { + $this->parseError('Unexpected EOF in DOCTYPE'); + $this->events->doctype($doctypeName, $type, $id, true); + + return true; + } + + // Well-formed complete DOCTYPE. + $this->scanner->whitespace(); + if ('>' == $this->scanner->current()) { + $this->events->doctype($doctypeName, $type, $id, false); + $this->scanner->consume(); + + return true; + } + + // If we get here, we have scanner->charsUntil('>'); + $this->parseError('Malformed DOCTYPE.'); + $this->events->doctype($doctypeName, $type, $id, true); + $this->scanner->consume(); + + return true; + } + + // Else it's a bogus DOCTYPE. + // Consume to > and trash. + $this->scanner->charsUntil('>'); + + $this->parseError('Expected PUBLIC or SYSTEM. Got %s.', $pub); + $this->events->doctype($doctypeName, 0, null, true); + $this->scanner->consume(); + + return true; + } + + /** + * Utility for reading a quoted string. + * + * @param string $stopchars Characters (in addition to a close-quote) that should stop the string. + * E.g. sometimes '>' is higher precedence than '"' or "'". + * + * @return mixed String if one is found (quotations omitted). + */ + protected function quotedString($stopchars) + { + $tok = $this->scanner->current(); + if ('"' == $tok || "'" == $tok) { + $this->scanner->consume(); + $ret = $this->scanner->charsUntil($tok . $stopchars); + if ($this->scanner->current() == $tok) { + $this->scanner->consume(); + } else { + // Parse error because no close quote. + $this->parseError('Expected %s, got %s', $tok, $this->scanner->current()); + } + + return $ret; + } + + return false; + } + + /** + * Handle a CDATA section. + * + * @return bool + */ + protected function cdataSection() + { + $cdata = ''; + $this->scanner->consume(); + + $chars = $this->scanner->charsWhile('CDAT'); + if ('CDATA' != $chars || '[' != $this->scanner->current()) { + $this->parseError('Expected [CDATA[, got %s', $chars); + + return $this->bogusComment('scanner->next(); + do { + if (false === $tok) { + $this->parseError('Unexpected EOF inside CDATA.'); + $this->bogusComment('scanner->next(); + } while (!$this->scanner->sequenceMatches(']]>')); + + // Consume ]]> + $this->scanner->consume(3); + + $this->events->cdata($cdata); + + return true; + } + + // ================================================================ + // Non-HTML5 + // ================================================================ + + /** + * Handle a processing instruction. + * + * XML processing instructions are supposed to be ignored in HTML5, + * treated as "bogus comments". However, since we're not a user + * agent, we allow them. We consume until ?> and then issue a + * EventListener::processingInstruction() event. + * + * @return bool + */ + protected function processingInstruction() + { + if ('?' != $this->scanner->current()) { + return false; + } + + $tok = $this->scanner->next(); + $procName = $this->scanner->getAsciiAlpha(); + $white = $this->scanner->whitespace(); + + // If not a PI, send to bogusComment. + if (0 == strlen($procName) || 0 == $white || false == $this->scanner->current()) { + $this->parseError("Expected processing instruction name, got $tok"); + $this->bogusComment('. + while (!('?' == $this->scanner->current() && '>' == $this->scanner->peek())) { + $data .= $this->scanner->current(); + + $tok = $this->scanner->next(); + if (false === $tok) { + $this->parseError('Unexpected EOF in processing instruction.'); + $this->events->processingInstruction($procName, $data); + + return true; + } + } + + $this->scanner->consume(2); // Consume the closing tag + $this->events->processingInstruction($procName, $data); + + return true; + } + + // ================================================================ + // UTILITY FUNCTIONS + // ================================================================ + + /** + * Read from the input stream until we get to the desired sequene + * or hit the end of the input stream. + * + * @param string $sequence + * + * @return string + */ + protected function readUntilSequence($sequence) + { + $buffer = ''; + + // Optimization for reading larger blocks faster. + $first = substr($sequence, 0, 1); + while (false !== $this->scanner->current()) { + $buffer .= $this->scanner->charsUntil($first); + + // Stop as soon as we hit the stopping condition. + if ($this->scanner->sequenceMatches($sequence, false)) { + return $buffer; + } + $buffer .= $this->scanner->current(); + $this->scanner->consume(); + } + + // If we get here, we hit the EOF. + $this->parseError('Unexpected EOF during text read.'); + + return $buffer; + } + + /** + * Check if upcomming chars match the given sequence. + * + * This will read the stream for the $sequence. If it's + * found, this will return true. If not, return false. + * Since this unconsumes any chars it reads, the caller + * will still need to read the next sequence, even if + * this returns true. + * + * Example: $this->scanner->sequenceMatches('') will + * see if the input stream is at the start of a + * '' string. + * + * @param string $sequence + * @param bool $caseSensitive + * + * @return bool + */ + protected function sequenceMatches($sequence, $caseSensitive = true) + { + @trigger_error(__METHOD__ . ' method is deprecated since version 2.4 and will be removed in 3.0. Use Scanner::sequenceMatches() instead.', E_USER_DEPRECATED); + + return $this->scanner->sequenceMatches($sequence, $caseSensitive); + } + + /** + * Send a TEXT event with the contents of the text buffer. + * + * This emits an EventHandler::text() event with the current contents of the + * temporary text buffer. (The buffer is used to group as much PCDATA + * as we can instead of emitting lots and lots of TEXT events.) + */ + protected function flushBuffer() + { + if ('' === $this->text) { + return; + } + $this->events->text($this->text); + $this->text = ''; + } + + /** + * Add text to the temporary buffer. + * + * @see flushBuffer() + * + * @param string $str + */ + protected function buffer($str) + { + $this->text .= $str; + } + + /** + * Emit a parse error. + * + * A parse error always returns false because it never consumes any + * characters. + * + * @param string $msg + * + * @return string + */ + protected function parseError($msg) + { + $args = func_get_args(); + + if (count($args) > 1) { + array_shift($args); + $msg = vsprintf($msg, $args); + } + + $line = $this->scanner->currentLine(); + $col = $this->scanner->columnOffset(); + $this->events->parseError($msg, $line, $col); + + return false; + } + + /** + * Decode a character reference and return the string. + * + * If $inAttribute is set to true, a bare & will be returned as-is. + * + * @param bool $inAttribute Set to true if the text is inside of an attribute value. + * false otherwise. + * + * @return string + */ + protected function decodeCharacterReference($inAttribute = false) + { + // Next char after &. + $tok = $this->scanner->next(); + $start = $this->scanner->position(); + + if (false === $tok) { + return '&'; + } + + // These indicate not an entity. We return just + // the &. + if ("\t" === $tok || "\n" === $tok || "\f" === $tok || ' ' === $tok || '&' === $tok || '<' === $tok) { + // $this->scanner->next(); + return '&'; + } + + // Numeric entity + if ('#' === $tok) { + $tok = $this->scanner->next(); + + if (false === $tok) { + $this->parseError('Expected &#DEC; &#HEX;, got EOF'); + $this->scanner->unconsume(1); + + return '&'; + } + + // Hexidecimal encoding. + // X[0-9a-fA-F]+; + // x[0-9a-fA-F]+; + if ('x' === $tok || 'X' === $tok) { + $tok = $this->scanner->next(); // Consume x + + // Convert from hex code to char. + $hex = $this->scanner->getHex(); + if (empty($hex)) { + $this->parseError('Expected &#xHEX;, got &#x%s', $tok); + // We unconsume because we don't know what parser rules might + // be in effect for the remaining chars. For example. '&#>' + // might result in a specific parsing rule inside of tag + // contexts, while not inside of pcdata context. + $this->scanner->unconsume(2); + + return '&'; + } + $entity = CharacterReference::lookupHex($hex); + } // Decimal encoding. + // [0-9]+; + else { + // Convert from decimal to char. + $numeric = $this->scanner->getNumeric(); + if (false === $numeric) { + $this->parseError('Expected &#DIGITS;, got &#%s', $tok); + $this->scanner->unconsume(2); + + return '&'; + } + $entity = CharacterReference::lookupDecimal($numeric); + } + } elseif ('=' === $tok && $inAttribute) { + return '&'; + } else { // String entity. + // Attempt to consume a string up to a ';'. + // [a-zA-Z0-9]+; + $cname = $this->scanner->getAsciiAlphaNum(); + $entity = CharacterReference::lookupName($cname); + + // When no entity is found provide the name of the unmatched string + // and continue on as the & is not part of an entity. The & will + // be converted to & elsewhere. + if (null === $entity) { + if (!$inAttribute || '' === $cname) { + $this->parseError("No match in entity table for '%s'", $cname); + } + $this->scanner->unconsume($this->scanner->position() - $start); + + return '&'; + } + } + + // The scanner has advanced the cursor for us. + $tok = $this->scanner->current(); + + // We have an entity. We're done here. + if (';' === $tok) { + $this->scanner->consume(); + + return $entity; + } + + // Failing to match ; means unconsume the entire string. + $this->scanner->unconsume($this->scanner->position() - $start); + + $this->parseError('Expected &ENTITY;, got &ENTITY%s (no trailing ;) ', $tok); + + return '&'; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php new file mode 100644 index 000000000..00d3951fd --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php @@ -0,0 +1,127 @@ + 1, + 'dd' => 1, + 'dt' => 1, + 'rt' => 1, + 'rp' => 1, + 'tr' => 1, + 'th' => 1, + 'td' => 1, + 'thead' => 1, + 'tfoot' => 1, + 'tbody' => 1, + 'table' => 1, + 'optgroup' => 1, + 'option' => 1, + ); + + /** + * Returns true if the given tagname has special processing rules. + */ + public function hasRules($tagname) + { + return isset(static::$tags[$tagname]); + } + + /** + * Evaluate the rule for the current tag name. + * + * This may modify the existing DOM. + * + * @return \DOMElement The new Current DOM element. + */ + public function evaluate($new, $current) + { + switch ($new->tagName) { + case 'li': + return $this->handleLI($new, $current); + case 'dt': + case 'dd': + return $this->handleDT($new, $current); + case 'rt': + case 'rp': + return $this->handleRT($new, $current); + case 'optgroup': + return $this->closeIfCurrentMatches($new, $current, array( + 'optgroup', + )); + case 'option': + return $this->closeIfCurrentMatches($new, $current, array( + 'option', + )); + case 'tr': + return $this->closeIfCurrentMatches($new, $current, array( + 'tr', + )); + case 'td': + case 'th': + return $this->closeIfCurrentMatches($new, $current, array( + 'th', + 'td', + )); + case 'tbody': + case 'thead': + case 'tfoot': + case 'table': // Spec isn't explicit about this, but it's necessary. + + return $this->closeIfCurrentMatches($new, $current, array( + 'thead', + 'tfoot', + 'tbody', + )); + } + + return $current; + } + + protected function handleLI($ele, $current) + { + return $this->closeIfCurrentMatches($ele, $current, array( + 'li', + )); + } + + protected function handleDT($ele, $current) + { + return $this->closeIfCurrentMatches($ele, $current, array( + 'dt', + 'dd', + )); + } + + protected function handleRT($ele, $current) + { + return $this->closeIfCurrentMatches($ele, $current, array( + 'rt', + 'rp', + )); + } + + protected function closeIfCurrentMatches($ele, $current, $match) + { + if (in_array($current->tagName, $match, true)) { + $current->parentNode->appendChild($ele); + } else { + $current->appendChild($ele); + } + + return $ele; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php new file mode 100644 index 000000000..f6a70bfac --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Parser/UTF8Utils.php @@ -0,0 +1,183 @@ + + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +use Masterminds\HTML5\Exception; + +class UTF8Utils +{ + /** + * The Unicode replacement character. + */ + const FFFD = "\xEF\xBF\xBD"; + + /** + * Count the number of characters in a string. + * UTF-8 aware. This will try (in order) iconv, MB, libxml, and finally a custom counter. + * + * @param string $string + * + * @return int + */ + public static function countChars($string) + { + // Get the length for the string we need. + if (function_exists('mb_strlen')) { + return mb_strlen($string, 'utf-8'); + } + + if (function_exists('iconv_strlen')) { + return iconv_strlen($string, 'utf-8'); + } + + if (function_exists('utf8_decode')) { + // MPB: Will this work? Won't certain decodes lead to two chars + // extrapolated out of 2-byte chars? + return strlen(utf8_decode($string)); + } + + $count = count_chars($string); + + // 0x80 = 0x7F - 0 + 1 (one added to get inclusive range) + // 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range) + return array_sum(array_slice($count, 0, 0x80)) + array_sum(array_slice($count, 0xC2, 0x33)); + } + + /** + * Convert data from the given encoding to UTF-8. + * + * This has not yet been tested with charactersets other than UTF-8. + * It should work with ISO-8859-1/-13 and standard Latin Win charsets. + * + * @param string $data The data to convert + * @param string $encoding A valid encoding. Examples: http://www.php.net/manual/en/mbstring.supported-encodings.php + * + * @return string + */ + public static function convertToUTF8($data, $encoding = 'UTF-8') + { + /* + * From the HTML5 spec: Given an encoding, the bytes in the input stream must be converted + * to Unicode characters for the tokeniser, as described by the rules for that encoding, + * except that the leading U+FEFF BYTE ORDER MARK character, if any, must not be stripped + * by the encoding layer (it is stripped by the rule below). Bytes or sequences of bytes + * in the original byte stream that could not be converted to Unicode characters must be + * converted to U+FFFD REPLACEMENT CHARACTER code points. + */ + + // mb_convert_encoding is chosen over iconv because of a bug. The best + // details for the bug are on http://us1.php.net/manual/en/function.iconv.php#108643 + // which contains links to the actual but reports as well as work around + // details. + if (function_exists('mb_convert_encoding')) { + // mb library has the following behaviors: + // - UTF-16 surrogates result in false. + // - Overlongs and outside Plane 16 result in empty strings. + + // Before we run mb_convert_encoding we need to tell it what to do with + // characters it does not know. This could be different than the parent + // application executing this library so we store the value, change it + // to our needs, and then change it back when we are done. This feels + // a little excessive and it would be great if there was a better way. + $save = mb_substitute_character(); + mb_substitute_character('none'); + $data = mb_convert_encoding($data, 'UTF-8', $encoding); + mb_substitute_character($save); + } + // @todo Get iconv running in at least some environments if that is possible. + elseif (function_exists('iconv') && 'auto' !== $encoding) { + // fprintf(STDOUT, "iconv found\n"); + // iconv has the following behaviors: + // - Overlong representations are ignored. + // - Beyond Plane 16 is replaced with a lower char. + // - Incomplete sequences generate a warning. + $data = @iconv($encoding, 'UTF-8//IGNORE', $data); + } else { + throw new Exception('Not implemented, please install mbstring or iconv'); + } + + /* + * One leading U+FEFF BYTE ORDER MARK character must be ignored if any are present. + */ + if ("\xEF\xBB\xBF" === substr($data, 0, 3)) { + $data = substr($data, 3); + } + + return $data; + } + + /** + * Checks for Unicode code points that are not valid in a document. + * + * @param string $data A string to analyze + * + * @return array An array of (string) error messages produced by the scanning + */ + public static function checkForIllegalCodepoints($data) + { + // Vestigal error handling. + $errors = array(); + + /* + * All U+0000 null characters in the input must be replaced by U+FFFD REPLACEMENT CHARACTERs. + * Any occurrences of such characters is a parse error. + */ + for ($i = 0, $count = substr_count($data, "\0"); $i < $count; ++$i) { + $errors[] = 'null-character'; + } + + /* + * Any occurrences of any characters in the ranges U+0001 to U+0008, U+000B, U+000E to U+001F, U+007F + * to U+009F, U+D800 to U+DFFF , U+FDD0 to U+FDEF, and characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, + * U+2FFFE, U+2FFFF, U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, U+6FFFF, U+7FFFE, + * U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, + * U+DFFFE, U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and U+10FFFF are parse errors. + * (These are all control characters or permanently undefined Unicode characters.) + */ + // Check PCRE is loaded. + $count = preg_match_all( + '/(?: + [\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F + | + \xC2[\x80-\x9F] # U+0080 to U+009F + | + \xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF + | + \xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF + | + \xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF + | + [\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16}) + )/x', $data, $matches); + for ($i = 0; $i < $count; ++$i) { + $errors[] = 'invalid-codepoint'; + } + + return $errors; + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php new file mode 100644 index 000000000..e9421a12d --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/HTML5Entities.php @@ -0,0 +1,1533 @@ + ' ', + "\n" => ' ', + '!' => '!', + '"' => '"', + '#' => '#', + '$' => '$', + '%' => '%', + '&' => '&', + '\'' => ''', + '(' => '(', + ')' => ')', + '*' => '*', + '+' => '+', + ',' => ',', + '.' => '.', + '/' => '/', + ':' => ':', + ';' => ';', + '<' => '<', + '<⃒' => '&nvlt', + '=' => '=', + '=⃥' => '&bne', + '>' => '>', + '>⃒' => '&nvgt', + '?' => '?', + '@' => '@', + '[' => '[', + '\\' => '\', + ']' => ']', + '^' => '^', + '_' => '_', + '`' => '`', + 'fj' => '&fjlig', + '{' => '{', + '|' => '|', + '}' => '}', + ' ' => ' ', + '¡' => '¡', + '¢' => '¢', + '£' => '£', + '¤' => '¤', + '¥' => '¥', + '¦' => '¦', + '§' => '§', + '¨' => '¨', + '©' => '©', + 'ª' => 'ª', + '«' => '«', + '¬' => '¬', + '­' => '­', + '®' => '®', + '¯' => '¯', + '°' => '°', + '±' => '±', + '²' => '²', + '³' => '³', + '´' => '´', + 'µ' => 'µ', + '¶' => '¶', + '·' => '·', + '¸' => '¸', + '¹' => '¹', + 'º' => 'º', + '»' => '»', + '¼' => '¼', + '½' => '½', + '¾' => '¾', + '¿' => '¿', + 'À' => 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Æ' => 'Æ', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ð' => 'Ð', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + '×' => '×', + 'Ø' => 'Ø', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'Þ' => 'Þ', + 'ß' => 'ß', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'æ' => 'æ', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ð' => 'ð', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + '÷' => '÷', + 'ø' => 'ø', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'þ' => 'þ', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Đ' => 'Đ', + 'đ' => 'đ', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ħ' => 'Ħ', + 'ħ' => 'ħ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'ı' => 'ı', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'ĸ' => 'ĸ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ŀ' => 'Ŀ', + 'ŀ' => 'ŀ', + 'Ł' => 'Ł', + 'ł' => 'ł', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'ʼn' => 'ʼn', + 'Ŋ' => 'Ŋ', + 'ŋ' => 'ŋ', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Œ' => 'Œ', + 'œ' => 'œ', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ŧ' => 'Ŧ', + 'ŧ' => 'ŧ', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'ƒ' => 'ƒ', + 'Ƶ' => 'Ƶ', + 'ǵ' => 'ǵ', + 'ȷ' => 'ȷ', + 'ˆ' => 'ˆ', + 'ˇ' => 'ˇ', + '˘' => '˘', + '˙' => '˙', + '˚' => '˚', + '˛' => '˛', + '˜' => '˜', + '˝' => '˝', + '̑' => '̑', + 'Α' => 'Α', + 'Β' => 'Β', + 'Γ' => 'Γ', + 'Δ' => 'Δ', + 'Ε' => 'Ε', + 'Ζ' => 'Ζ', + 'Η' => 'Η', + 'Θ' => 'Θ', + 'Ι' => 'Ι', + 'Κ' => 'Κ', + 'Λ' => 'Λ', + 'Μ' => 'Μ', + 'Ν' => 'Ν', + 'Ξ' => 'Ξ', + 'Ο' => 'Ο', + 'Π' => 'Π', + 'Ρ' => 'Ρ', + 'Σ' => 'Σ', + 'Τ' => 'Τ', + 'Υ' => 'Υ', + 'Φ' => 'Φ', + 'Χ' => 'Χ', + 'Ψ' => 'Ψ', + 'Ω' => 'Ω', + 'α' => 'α', + 'β' => 'β', + 'γ' => 'γ', + 'δ' => 'δ', + 'ε' => 'ε', + 'ζ' => 'ζ', + 'η' => 'η', + 'θ' => 'θ', + 'ι' => 'ι', + 'κ' => 'κ', + 'λ' => 'λ', + 'μ' => 'μ', + 'ν' => 'ν', + 'ξ' => 'ξ', + 'ο' => 'ο', + 'π' => 'π', + 'ρ' => 'ρ', + 'ς' => 'ς', + 'σ' => 'σ', + 'τ' => 'τ', + 'υ' => 'υ', + 'φ' => 'φ', + 'χ' => 'χ', + 'ψ' => 'ψ', + 'ω' => 'ω', + 'ϑ' => 'ϑ', + 'ϒ' => 'ϒ', + 'ϕ' => 'ϕ', + 'ϖ' => 'ϖ', + 'Ϝ' => 'Ϝ', + 'ϝ' => 'ϝ', + 'ϰ' => 'ϰ', + 'ϱ' => 'ϱ', + 'ϵ' => 'ϵ', + '϶' => '϶', + 'Ё' => 'Ё', + 'Ђ' => 'Ђ', + 'Ѓ' => 'Ѓ', + 'Є' => 'Є', + 'Ѕ' => 'Ѕ', + 'І' => 'І', + 'Ї' => 'Ї', + 'Ј' => 'Ј', + 'Љ' => 'Љ', + 'Њ' => 'Њ', + 'Ћ' => 'Ћ', + 'Ќ' => 'Ќ', + 'Ў' => 'Ў', + 'Џ' => 'Џ', + 'А' => 'А', + 'Б' => 'Б', + 'В' => 'В', + 'Г' => 'Г', + 'Д' => 'Д', + 'Е' => 'Е', + 'Ж' => 'Ж', + 'З' => 'З', + 'И' => 'И', + 'Й' => 'Й', + 'К' => 'К', + 'Л' => 'Л', + 'М' => 'М', + 'Н' => 'Н', + 'О' => 'О', + 'П' => 'П', + 'Р' => 'Р', + 'С' => 'С', + 'Т' => 'Т', + 'У' => 'У', + 'Ф' => 'Ф', + 'Х' => 'Х', + 'Ц' => 'Ц', + 'Ч' => 'Ч', + 'Ш' => 'Ш', + 'Щ' => 'Щ', + 'Ъ' => 'Ъ', + 'Ы' => 'Ы', + 'Ь' => 'Ь', + 'Э' => 'Э', + 'Ю' => 'Ю', + 'Я' => 'Я', + 'а' => 'а', + 'б' => 'б', + 'в' => 'в', + 'г' => 'г', + 'д' => 'д', + 'е' => 'е', + 'ж' => 'ж', + 'з' => 'з', + 'и' => 'и', + 'й' => 'й', + 'к' => 'к', + 'л' => 'л', + 'м' => 'м', + 'н' => 'н', + 'о' => 'о', + 'п' => 'п', + 'р' => 'р', + 'с' => 'с', + 'т' => 'т', + 'у' => 'у', + 'ф' => 'ф', + 'х' => 'х', + 'ц' => 'ц', + 'ч' => 'ч', + 'ш' => 'ш', + 'щ' => 'щ', + 'ъ' => 'ъ', + 'ы' => 'ы', + 'ь' => 'ь', + 'э' => 'э', + 'ю' => 'ю', + 'я' => 'я', + 'ё' => 'ё', + 'ђ' => 'ђ', + 'ѓ' => 'ѓ', + 'є' => 'є', + 'ѕ' => 'ѕ', + 'і' => 'і', + 'ї' => 'ї', + 'ј' => 'ј', + 'љ' => 'љ', + 'њ' => 'њ', + 'ћ' => 'ћ', + 'ќ' => 'ќ', + 'ў' => 'ў', + 'џ' => 'џ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + '​' => '​', + '‌' => '‌', + '‍' => '‍', + '‎' => '‎', + '‏' => '‏', + '‐' => '‐', + '–' => '–', + '—' => '—', + '―' => '―', + '‖' => '‖', + '‘' => '‘', + '’' => '’', + '‚' => '‚', + '“' => '“', + '”' => '”', + '„' => '„', + '†' => '†', + '‡' => '‡', + '•' => '•', + '‥' => '‥', + '…' => '…', + '‰' => '‰', + '‱' => '‱', + '′' => '′', + '″' => '″', + '‴' => '‴', + '‵' => '‵', + '‹' => '‹', + '›' => '›', + '‾' => '‾', + '⁁' => '⁁', + '⁃' => '⁃', + '⁄' => '⁄', + '⁏' => '⁏', + '⁗' => '⁗', + ' ' => ' ', + '  ' => '&ThickSpace', + '⁠' => '⁠', + '⁡' => '⁡', + '⁢' => '⁢', + '⁣' => '⁣', + '€' => '€', + '⃛' => '⃛', + '⃜' => '⃜', + 'ℂ' => 'ℂ', + '℅' => '℅', + 'ℊ' => 'ℊ', + 'ℋ' => 'ℋ', + 'ℌ' => 'ℌ', + 'ℍ' => 'ℍ', + 'ℎ' => 'ℎ', + 'ℏ' => 'ℏ', + 'ℐ' => 'ℐ', + 'ℑ' => 'ℑ', + 'ℒ' => 'ℒ', + 'ℓ' => 'ℓ', + 'ℕ' => 'ℕ', + '№' => '№', + '℗' => '℗', + '℘' => '℘', + 'ℙ' => 'ℙ', + 'ℚ' => 'ℚ', + 'ℛ' => 'ℛ', + 'ℜ' => 'ℜ', + 'ℝ' => 'ℝ', + '℞' => '℞', + '™' => '™', + 'ℤ' => 'ℤ', + '℧' => '℧', + 'ℨ' => 'ℨ', + '℩' => '℩', + 'ℬ' => 'ℬ', + 'ℭ' => 'ℭ', + 'ℯ' => 'ℯ', + 'ℰ' => 'ℰ', + 'ℱ' => 'ℱ', + 'ℳ' => 'ℳ', + 'ℴ' => 'ℴ', + 'ℵ' => 'ℵ', + 'ℶ' => 'ℶ', + 'ℷ' => 'ℷ', + 'ℸ' => 'ℸ', + 'ⅅ' => 'ⅅ', + 'ⅆ' => 'ⅆ', + 'ⅇ' => 'ⅇ', + 'ⅈ' => 'ⅈ', + '⅓' => '⅓', + '⅔' => '⅔', + '⅕' => '⅕', + '⅖' => '⅖', + '⅗' => '⅗', + '⅘' => '⅘', + '⅙' => '⅙', + '⅚' => '⅚', + '⅛' => '⅛', + '⅜' => '⅜', + '⅝' => '⅝', + '⅞' => '⅞', + '←' => '←', + '↑' => '↑', + '→' => '→', + '↓' => '↓', + '↔' => '↔', + '↕' => '↕', + '↖' => '↖', + '↗' => '↗', + '↘' => '↘', + '↙' => '↙', + '↚' => '↚', + '↛' => '↛', + '↝' => '↝', + '↝̸' => '&nrarrw', + '↞' => '↞', + '↟' => '↟', + '↠' => '↠', + '↡' => '↡', + '↢' => '↢', + '↣' => '↣', + '↤' => '↤', + '↥' => '↥', + '↦' => '↦', + '↧' => '↧', + '↩' => '↩', + '↪' => '↪', + '↫' => '↫', + '↬' => '↬', + '↭' => '↭', + '↮' => '↮', + '↰' => '↰', + '↱' => '↱', + '↲' => '↲', + '↳' => '↳', + '↵' => '↵', + '↶' => '↶', + '↷' => '↷', + '↺' => '↺', + '↻' => '↻', + '↼' => '↼', + '↽' => '↽', + '↾' => '↾', + '↿' => '↿', + '⇀' => '⇀', + '⇁' => '⇁', + '⇂' => '⇂', + '⇃' => '⇃', + '⇄' => '⇄', + '⇅' => '⇅', + '⇆' => '⇆', + '⇇' => '⇇', + '⇈' => '⇈', + '⇉' => '⇉', + '⇊' => '⇊', + '⇋' => '⇋', + '⇌' => '⇌', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '⇐' => '⇐', + '⇑' => '⇑', + '⇒' => '⇒', + '⇓' => '⇓', + '⇔' => '⇔', + '⇕' => '⇕', + '⇖' => '⇖', + '⇗' => '⇗', + '⇘' => '⇘', + '⇙' => '⇙', + '⇚' => '⇚', + '⇛' => '⇛', + '⇝' => '⇝', + '⇤' => '⇤', + '⇥' => '⇥', + '⇵' => '⇵', + '⇽' => '⇽', + '⇾' => '⇾', + '⇿' => '⇿', + '∀' => '∀', + '∁' => '∁', + '∂' => '∂', + '∂̸' => '&npart', + '∃' => '∃', + '∄' => '∄', + '∅' => '∅', + '∇' => '∇', + '∈' => '∈', + '∉' => '∉', + '∋' => '∋', + '∌' => '∌', + '∏' => '∏', + '∐' => '∐', + '∑' => '∑', + '−' => '−', + '∓' => '∓', + '∔' => '∔', + '∖' => '∖', + '∗' => '∗', + '∘' => '∘', + '√' => '√', + '∝' => '∝', + '∞' => '∞', + '∟' => '∟', + '∠' => '∠', + '∠⃒' => '&nang', + '∡' => '∡', + '∢' => '∢', + '∣' => '∣', + '∤' => '∤', + '∥' => '∥', + '∦' => '∦', + '∧' => '∧', + '∨' => '∨', + '∩' => '∩', + '∩︀' => '&caps', + '∪' => '∪', + '∪︀' => '&cups', + '∫' => '∫', + '∬' => '∬', + '∭' => '∭', + '∮' => '∮', + '∯' => '∯', + '∰' => '∰', + '∱' => '∱', + '∲' => '∲', + '∳' => '∳', + '∴' => '∴', + '∵' => '∵', + '∶' => '∶', + '∷' => '∷', + '∸' => '∸', + '∺' => '∺', + '∻' => '∻', + '∼' => '∼', + '∼⃒' => '&nvsim', + '∽' => '∽', + '∽̱' => '&race', + '∾' => '∾', + '∾̳' => '&acE', + '∿' => '∿', + '≀' => '≀', + '≁' => '≁', + '≂' => '≂', + '≂̸' => '&nesim', + '≃' => '≃', + '≄' => '≄', + '≅' => '≅', + '≆' => '≆', + '≇' => '≇', + '≈' => '≈', + '≉' => '≉', + '≊' => '≊', + '≋' => '≋', + '≋̸' => '&napid', + '≌' => '≌', + '≍' => '≍', + '≍⃒' => '&nvap', + '≎' => '≎', + '≎̸' => '&nbump', + '≏' => '≏', + '≏̸' => '&nbumpe', + '≐' => '≐', + '≐̸' => '&nedot', + '≑' => '≑', + '≒' => '≒', + '≓' => '≓', + '≔' => '≔', + '≕' => '≕', + '≖' => '≖', + '≗' => '≗', + '≙' => '≙', + '≚' => '≚', + '≜' => '≜', + '≟' => '≟', + '≠' => '≠', + '≡' => '≡', + '≡⃥' => '&bnequiv', + '≢' => '≢', + '≤' => '≤', + '≤⃒' => '&nvle', + '≥' => '≥', + '≥⃒' => '&nvge', + '≦' => '≦', + '≦̸' => '&nlE', + '≧' => '≧', + '≧̸' => '&NotGreaterFullEqual', + '≨' => '≨', + '≨︀' => '&lvertneqq', + '≩' => '≩', + '≩︀' => '&gvertneqq', + '≪' => '≪', + '≪̸' => '&nLtv', + '≪⃒' => '&nLt', + '≫' => '≫', + '≫̸' => '&NotGreaterGreater', + '≫⃒' => '&nGt', + '≬' => '≬', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≲' => '≲', + '≳' => '≳', + '≴' => '≴', + '≵' => '≵', + '≶' => '≶', + '≷' => '≷', + '≸' => '≸', + '≹' => '≹', + '≺' => '≺', + '≻' => '≻', + '≼' => '≼', + '≽' => '≽', + '≾' => '≾', + '≿' => '≿', + '≿̸' => '&NotSucceedsTilde', + '⊀' => '⊀', + '⊁' => '⊁', + '⊂' => '⊂', + '⊂⃒' => '&vnsub', + '⊃' => '⊃', + '⊃⃒' => '&nsupset', + '⊄' => '⊄', + '⊅' => '⊅', + '⊆' => '⊆', + '⊇' => '⊇', + '⊈' => '⊈', + '⊉' => '⊉', + '⊊' => '⊊', + '⊊︀' => '&vsubne', + '⊋' => '⊋', + '⊋︀' => '&vsupne', + '⊍' => '⊍', + '⊎' => '⊎', + '⊏' => '⊏', + '⊏̸' => '&NotSquareSubset', + '⊐' => '⊐', + '⊐̸' => '&NotSquareSuperset', + '⊑' => '⊑', + '⊒' => '⊒', + '⊓' => '⊓', + '⊓︀' => '&sqcaps', + '⊔' => '⊔', + '⊔︀' => '&sqcups', + '⊕' => '⊕', + '⊖' => '⊖', + '⊗' => '⊗', + '⊘' => '⊘', + '⊙' => '⊙', + '⊚' => '⊚', + '⊛' => '⊛', + '⊝' => '⊝', + '⊞' => '⊞', + '⊟' => '⊟', + '⊠' => '⊠', + '⊡' => '⊡', + '⊢' => '⊢', + '⊣' => '⊣', + '⊤' => '⊤', + '⊥' => '⊥', + '⊧' => '⊧', + '⊨' => '⊨', + '⊩' => '⊩', + '⊪' => '⊪', + '⊫' => '⊫', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⊰' => '⊰', + '⊲' => '⊲', + '⊳' => '⊳', + '⊴' => '⊴', + '⊴⃒' => '&nvltrie', + '⊵' => '⊵', + '⊵⃒' => '&nvrtrie', + '⊶' => '⊶', + '⊷' => '⊷', + '⊸' => '⊸', + '⊹' => '⊹', + '⊺' => '⊺', + '⊻' => '⊻', + '⊽' => '⊽', + '⊾' => '⊾', + '⊿' => '⊿', + '⋀' => '⋀', + '⋁' => '⋁', + '⋂' => '⋂', + '⋃' => '⋃', + '⋄' => '⋄', + '⋅' => '⋅', + '⋆' => '⋆', + '⋇' => '⋇', + '⋈' => '⋈', + '⋉' => '⋉', + '⋊' => '⋊', + '⋋' => '⋋', + '⋌' => '⋌', + '⋍' => '⋍', + '⋎' => '⋎', + '⋏' => '⋏', + '⋐' => '⋐', + '⋑' => '⋑', + '⋒' => '⋒', + '⋓' => '⋓', + '⋔' => '⋔', + '⋕' => '⋕', + '⋖' => '⋖', + '⋗' => '⋗', + '⋘' => '⋘', + '⋘̸' => '&nLl', + '⋙' => '⋙', + '⋙̸' => '&nGg', + '⋚' => '⋚', + '⋚︀' => '&lesg', + '⋛' => '⋛', + '⋛︀' => '&gesl', + '⋞' => '⋞', + '⋟' => '⋟', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋦' => '⋦', + '⋧' => '⋧', + '⋨' => '⋨', + '⋩' => '⋩', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + '⋮' => '⋮', + '⋯' => '⋯', + '⋰' => '⋰', + '⋱' => '⋱', + '⋲' => '⋲', + '⋳' => '⋳', + '⋴' => '⋴', + '⋵' => '⋵', + '⋵̸' => '¬indot', + '⋶' => '⋶', + '⋷' => '⋷', + '⋹' => '⋹', + '⋹̸' => '¬inE', + '⋺' => '⋺', + '⋻' => '⋻', + '⋼' => '⋼', + '⋽' => '⋽', + '⋾' => '⋾', + '⌅' => '⌅', + '⌆' => '⌆', + '⌈' => '⌈', + '⌉' => '⌉', + '⌊' => '⌊', + '⌋' => '⌋', + '⌌' => '⌌', + '⌍' => '⌍', + '⌎' => '⌎', + '⌏' => '⌏', + '⌐' => '⌐', + '⌒' => '⌒', + '⌓' => '⌓', + '⌕' => '⌕', + '⌖' => '⌖', + '⌜' => '⌜', + '⌝' => '⌝', + '⌞' => '⌞', + '⌟' => '⌟', + '⌢' => '⌢', + '⌣' => '⌣', + '⌭' => '⌭', + '⌮' => '⌮', + '⌶' => '⌶', + '⌽' => '⌽', + '⌿' => '⌿', + '⍼' => '⍼', + '⎰' => '⎰', + '⎱' => '⎱', + '⎴' => '⎴', + '⎵' => '⎵', + '⎶' => '⎶', + '⏜' => '⏜', + '⏝' => '⏝', + '⏞' => '⏞', + '⏟' => '⏟', + '⏢' => '⏢', + '⏧' => '⏧', + '␣' => '␣', + 'Ⓢ' => 'Ⓢ', + '─' => '─', + '│' => '│', + '┌' => '┌', + '┐' => '┐', + '└' => '└', + '┘' => '┘', + '├' => '├', + '┤' => '┤', + '┬' => '┬', + '┴' => '┴', + '┼' => '┼', + '═' => '═', + '║' => '║', + '╒' => '╒', + '╓' => '╓', + '╔' => '╔', + '╕' => '╕', + '╖' => '╖', + '╗' => '╗', + '╘' => '╘', + '╙' => '╙', + '╚' => '╚', + '╛' => '╛', + '╜' => '╜', + '╝' => '╝', + '╞' => '╞', + '╟' => '╟', + '╠' => '╠', + '╡' => '╡', + '╢' => '╢', + '╣' => '╣', + '╤' => '╤', + '╥' => '╥', + '╦' => '╦', + '╧' => '╧', + '╨' => '╨', + '╩' => '╩', + '╪' => '╪', + '╫' => '╫', + '╬' => '╬', + '▀' => '▀', + '▄' => '▄', + '█' => '█', + '░' => '░', + '▒' => '▒', + '▓' => '▓', + '□' => '□', + '▪' => '▪', + '▫' => '▫', + '▭' => '▭', + '▮' => '▮', + '▱' => '▱', + '△' => '△', + '▴' => '▴', + '▵' => '▵', + '▸' => '▸', + '▹' => '▹', + '▽' => '▽', + '▾' => '▾', + '▿' => '▿', + '◂' => '◂', + '◃' => '◃', + '◊' => '◊', + '○' => '○', + '◬' => '◬', + '◯' => '◯', + '◸' => '◸', + '◹' => '◹', + '◺' => '◺', + '◻' => '◻', + '◼' => '◼', + '★' => '★', + '☆' => '☆', + '☎' => '☎', + '♀' => '♀', + '♂' => '♂', + '♠' => '♠', + '♣' => '♣', + '♥' => '♥', + '♦' => '♦', + '♪' => '♪', + '♭' => '♭', + '♮' => '♮', + '♯' => '♯', + '✓' => '✓', + '✗' => '✗', + '✠' => '✠', + '✶' => '✶', + '❘' => '❘', + '❲' => '❲', + '❳' => '❳', + '⟈' => '⟈', + '⟉' => '⟉', + '⟦' => '⟦', + '⟧' => '⟧', + '⟨' => '⟨', + '⟩' => '⟩', + '⟪' => '⟪', + '⟫' => '⟫', + '⟬' => '⟬', + '⟭' => '⟭', + '⟵' => '⟵', + '⟶' => '⟶', + '⟷' => '⟷', + '⟸' => '⟸', + '⟹' => '⟹', + '⟺' => '⟺', + '⟼' => '⟼', + '⟿' => '⟿', + '⤂' => '⤂', + '⤃' => '⤃', + '⤄' => '⤄', + '⤅' => '⤅', + '⤌' => '⤌', + '⤍' => '⤍', + '⤎' => '⤎', + '⤏' => '⤏', + '⤐' => '⤐', + '⤑' => '⤑', + '⤒' => '⤒', + '⤓' => '⤓', + '⤖' => '⤖', + '⤙' => '⤙', + '⤚' => '⤚', + '⤛' => '⤛', + '⤜' => '⤜', + '⤝' => '⤝', + '⤞' => '⤞', + '⤟' => '⤟', + '⤠' => '⤠', + '⤣' => '⤣', + '⤤' => '⤤', + '⤥' => '⤥', + '⤦' => '⤦', + '⤧' => '⤧', + '⤨' => '⤨', + '⤩' => '⤩', + '⤪' => '⤪', + '⤳' => '⤳', + '⤳̸' => '&nrarrc', + '⤵' => '⤵', + '⤶' => '⤶', + '⤷' => '⤷', + '⤸' => '⤸', + '⤹' => '⤹', + '⤼' => '⤼', + '⤽' => '⤽', + '⥅' => '⥅', + '⥈' => '⥈', + '⥉' => '⥉', + '⥊' => '⥊', + '⥋' => '⥋', + '⥎' => '⥎', + '⥏' => '⥏', + '⥐' => '⥐', + '⥑' => '⥑', + '⥒' => '⥒', + '⥓' => '⥓', + '⥔' => '⥔', + '⥕' => '⥕', + '⥖' => '⥖', + '⥗' => '⥗', + '⥘' => '⥘', + '⥙' => '⥙', + '⥚' => '⥚', + '⥛' => '⥛', + '⥜' => '⥜', + '⥝' => '⥝', + '⥞' => '⥞', + '⥟' => '⥟', + '⥠' => '⥠', + '⥡' => '⥡', + '⥢' => '⥢', + '⥣' => '⥣', + '⥤' => '⥤', + '⥥' => '⥥', + '⥦' => '⥦', + '⥧' => '⥧', + '⥨' => '⥨', + '⥩' => '⥩', + '⥪' => '⥪', + '⥫' => '⥫', + '⥬' => '⥬', + '⥭' => '⥭', + '⥮' => '⥮', + '⥯' => '⥯', + '⥰' => '⥰', + '⥱' => '⥱', + '⥲' => '⥲', + '⥳' => '⥳', + '⥴' => '⥴', + '⥵' => '⥵', + '⥶' => '⥶', + '⥸' => '⥸', + '⥹' => '⥹', + '⥻' => '⥻', + '⥼' => '⥼', + '⥽' => '⥽', + '⥾' => '⥾', + '⥿' => '⥿', + '⦅' => '⦅', + '⦆' => '⦆', + '⦋' => '⦋', + '⦌' => '⦌', + '⦍' => '⦍', + '⦎' => '⦎', + '⦏' => '⦏', + '⦐' => '⦐', + '⦑' => '⦑', + '⦒' => '⦒', + '⦓' => '⦓', + '⦔' => '⦔', + '⦕' => '⦕', + '⦖' => '⦖', + '⦚' => '⦚', + '⦜' => '⦜', + '⦝' => '⦝', + '⦤' => '⦤', + '⦥' => '⦥', + '⦦' => '⦦', + '⦧' => '⦧', + '⦨' => '⦨', + '⦩' => '⦩', + '⦪' => '⦪', + '⦫' => '⦫', + '⦬' => '⦬', + '⦭' => '⦭', + '⦮' => '⦮', + '⦯' => '⦯', + '⦰' => '⦰', + '⦱' => '⦱', + '⦲' => '⦲', + '⦳' => '⦳', + '⦴' => '⦴', + '⦵' => '⦵', + '⦶' => '⦶', + '⦷' => '⦷', + '⦹' => '⦹', + '⦻' => '⦻', + '⦼' => '⦼', + '⦾' => '⦾', + '⦿' => '⦿', + '⧀' => '⧀', + '⧁' => '⧁', + '⧂' => '⧂', + '⧃' => '⧃', + '⧄' => '⧄', + '⧅' => '⧅', + '⧉' => '⧉', + '⧍' => '⧍', + '⧎' => '⧎', + '⧏' => '⧏', + '⧏̸' => '&NotLeftTriangleBar', + '⧐' => '⧐', + '⧐̸' => '&NotRightTriangleBar', + '⧜' => '⧜', + '⧝' => '⧝', + '⧞' => '⧞', + '⧣' => '⧣', + '⧤' => '⧤', + '⧥' => '⧥', + '⧫' => '⧫', + '⧴' => '⧴', + '⧶' => '⧶', + '⨀' => '⨀', + '⨁' => '⨁', + '⨂' => '⨂', + '⨄' => '⨄', + '⨆' => '⨆', + '⨌' => '⨌', + '⨍' => '⨍', + '⨐' => '⨐', + '⨑' => '⨑', + '⨒' => '⨒', + '⨓' => '⨓', + '⨔' => '⨔', + '⨕' => '⨕', + '⨖' => '⨖', + '⨗' => '⨗', + '⨢' => '⨢', + '⨣' => '⨣', + '⨤' => '⨤', + '⨥' => '⨥', + '⨦' => '⨦', + '⨧' => '⨧', + '⨩' => '⨩', + '⨪' => '⨪', + '⨭' => '⨭', + '⨮' => '⨮', + '⨯' => '⨯', + '⨰' => '⨰', + '⨱' => '⨱', + '⨳' => '⨳', + '⨴' => '⨴', + '⨵' => '⨵', + '⨶' => '⨶', + '⨷' => '⨷', + '⨸' => '⨸', + '⨹' => '⨹', + '⨺' => '⨺', + '⨻' => '⨻', + '⨼' => '⨼', + '⨿' => '⨿', + '⩀' => '⩀', + '⩂' => '⩂', + '⩃' => '⩃', + '⩄' => '⩄', + '⩅' => '⩅', + '⩆' => '⩆', + '⩇' => '⩇', + '⩈' => '⩈', + '⩉' => '⩉', + '⩊' => '⩊', + '⩋' => '⩋', + '⩌' => '⩌', + '⩍' => '⩍', + '⩐' => '⩐', + '⩓' => '⩓', + '⩔' => '⩔', + '⩕' => '⩕', + '⩖' => '⩖', + '⩗' => '⩗', + '⩘' => '⩘', + '⩚' => '⩚', + '⩛' => '⩛', + '⩜' => '⩜', + '⩝' => '⩝', + '⩟' => '⩟', + '⩦' => '⩦', + '⩪' => '⩪', + '⩭' => '⩭', + '⩭̸' => '&ncongdot', + '⩮' => '⩮', + '⩯' => '⩯', + '⩰' => '⩰', + '⩰̸' => '&napE', + '⩱' => '⩱', + '⩲' => '⩲', + '⩳' => '⩳', + '⩴' => '⩴', + '⩵' => '⩵', + '⩷' => '⩷', + '⩸' => '⩸', + '⩹' => '⩹', + '⩺' => '⩺', + '⩻' => '⩻', + '⩼' => '⩼', + '⩽' => '⩽', + '⩽̸' => '&nles', + '⩾' => '⩾', + '⩾̸' => '&nges', + '⩿' => '⩿', + '⪀' => '⪀', + '⪁' => '⪁', + '⪂' => '⪂', + '⪃' => '⪃', + '⪄' => '⪄', + '⪅' => '⪅', + '⪆' => '⪆', + '⪇' => '⪇', + '⪈' => '⪈', + '⪉' => '⪉', + '⪊' => '⪊', + '⪋' => '⪋', + '⪌' => '⪌', + '⪍' => '⪍', + '⪎' => '⪎', + '⪏' => '⪏', + '⪐' => '⪐', + '⪑' => '⪑', + '⪒' => '⪒', + '⪓' => '⪓', + '⪔' => '⪔', + '⪕' => '⪕', + '⪖' => '⪖', + '⪗' => '⪗', + '⪘' => '⪘', + '⪙' => '⪙', + '⪚' => '⪚', + '⪝' => '⪝', + '⪞' => '⪞', + '⪟' => '⪟', + '⪠' => '⪠', + '⪡' => '⪡', + '⪡̸' => '&NotNestedLessLess', + '⪢' => '⪢', + '⪢̸' => '&NotNestedGreaterGreater', + '⪤' => '⪤', + '⪥' => '⪥', + '⪦' => '⪦', + '⪧' => '⪧', + '⪨' => '⪨', + '⪩' => '⪩', + '⪪' => '⪪', + '⪫' => '⪫', + '⪬' => '⪬', + '⪬︀' => '&smtes', + '⪭' => '⪭', + '⪭︀' => '&lates', + '⪮' => '⪮', + '⪯' => '⪯', + '⪯̸' => '&NotPrecedesEqual', + '⪰' => '⪰', + '⪰̸' => '&NotSucceedsEqual', + '⪳' => '⪳', + '⪴' => '⪴', + '⪵' => '⪵', + '⪶' => '⪶', + '⪷' => '⪷', + '⪸' => '⪸', + '⪹' => '⪹', + '⪺' => '⪺', + '⪻' => '⪻', + '⪼' => '⪼', + '⪽' => '⪽', + '⪾' => '⪾', + '⪿' => '⪿', + '⫀' => '⫀', + '⫁' => '⫁', + '⫂' => '⫂', + '⫃' => '⫃', + '⫄' => '⫄', + '⫅' => '⫅', + '⫅̸' => '&nsubE', + '⫆' => '⫆', + '⫆̸' => '&nsupseteqq', + '⫇' => '⫇', + '⫈' => '⫈', + '⫋' => '⫋', + '⫋︀' => '&vsubnE', + '⫌' => '⫌', + '⫌︀' => '&varsupsetneqq', + '⫏' => '⫏', + '⫐' => '⫐', + '⫑' => '⫑', + '⫒' => '⫒', + '⫓' => '⫓', + '⫔' => '⫔', + '⫕' => '⫕', + '⫖' => '⫖', + '⫗' => '⫗', + '⫘' => '⫘', + '⫙' => '⫙', + '⫚' => '⫚', + '⫛' => '⫛', + '⫤' => '⫤', + '⫦' => '⫦', + '⫧' => '⫧', + '⫨' => '⫨', + '⫩' => '⫩', + '⫫' => '⫫', + '⫬' => '⫬', + '⫭' => '⫭', + '⫮' => '⫮', + '⫯' => '⫯', + '⫰' => '⫰', + '⫱' => '⫱', + '⫲' => '⫲', + '⫳' => '⫳', + '⫽︀' => '&varsupsetneqq', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + '𝒜' => '𝒜', + '𝒞' => '𝒞', + '𝒟' => '𝒟', + '𝒢' => '𝒢', + '𝒥' => '𝒥', + '𝒦' => '𝒦', + '𝒩' => '𝒩', + '𝒪' => '𝒪', + '𝒫' => '𝒫', + '𝒬' => '𝒬', + '𝒮' => '𝒮', + '𝒯' => '𝒯', + '𝒰' => '𝒰', + '𝒱' => '𝒱', + '𝒲' => '𝒲', + '𝒳' => '𝒳', + '𝒴' => '𝒴', + '𝒵' => '𝒵', + '𝒶' => '𝒶', + '𝒷' => '𝒷', + '𝒸' => '𝒸', + '𝒹' => '𝒹', + '𝒻' => '𝒻', + '𝒽' => '𝒽', + '𝒾' => '𝒾', + '𝒿' => '𝒿', + '𝓀' => '𝓀', + '𝓁' => '𝓁', + '𝓂' => '𝓂', + '𝓃' => '𝓃', + '𝓅' => '𝓅', + '𝓆' => '𝓆', + '𝓇' => '𝓇', + '𝓈' => '𝓈', + '𝓉' => '𝓉', + '𝓊' => '𝓊', + '𝓋' => '𝓋', + '𝓌' => '𝓌', + '𝓍' => '𝓍', + '𝓎' => '𝓎', + '𝓏' => '𝓏', + '𝔄' => '𝔄', + '𝔅' => '𝔅', + '𝔇' => '𝔇', + '𝔈' => '𝔈', + '𝔉' => '𝔉', + '𝔊' => '𝔊', + '𝔍' => '𝔍', + '𝔎' => '𝔎', + '𝔏' => '𝔏', + '𝔐' => '𝔐', + '𝔑' => '𝔑', + '𝔒' => '𝔒', + '𝔓' => '𝔓', + '𝔔' => '𝔔', + '𝔖' => '𝔖', + '𝔗' => '𝔗', + '𝔘' => '𝔘', + '𝔙' => '𝔙', + '𝔚' => '𝔚', + '𝔛' => '𝔛', + '𝔜' => '𝔜', + '𝔞' => '𝔞', + '𝔟' => '𝔟', + '𝔠' => '𝔠', + '𝔡' => '𝔡', + '𝔢' => '𝔢', + '𝔣' => '𝔣', + '𝔤' => '𝔤', + '𝔥' => '𝔥', + '𝔦' => '𝔦', + '𝔧' => '𝔧', + '𝔨' => '𝔨', + '𝔩' => '𝔩', + '𝔪' => '𝔪', + '𝔫' => '𝔫', + '𝔬' => '𝔬', + '𝔭' => '𝔭', + '𝔮' => '𝔮', + '𝔯' => '𝔯', + '𝔰' => '𝔰', + '𝔱' => '𝔱', + '𝔲' => '𝔲', + '𝔳' => '𝔳', + '𝔴' => '𝔴', + '𝔵' => '𝔵', + '𝔶' => '𝔶', + '𝔷' => '𝔷', + '𝔸' => '𝔸', + '𝔹' => '𝔹', + '𝔻' => '𝔻', + '𝔼' => '𝔼', + '𝔽' => '𝔽', + '𝔾' => '𝔾', + '𝕀' => '𝕀', + '𝕁' => '𝕁', + '𝕂' => '𝕂', + '𝕃' => '𝕃', + '𝕄' => '𝕄', + '𝕆' => '𝕆', + '𝕊' => '𝕊', + '𝕋' => '𝕋', + '𝕌' => '𝕌', + '𝕍' => '𝕍', + '𝕎' => '𝕎', + '𝕏' => '𝕏', + '𝕐' => '𝕐', + '𝕒' => '𝕒', + '𝕓' => '𝕓', + '𝕔' => '𝕔', + '𝕕' => '𝕕', + '𝕖' => '𝕖', + '𝕗' => '𝕗', + '𝕘' => '𝕘', + '𝕙' => '𝕙', + '𝕚' => '𝕚', + '𝕛' => '𝕛', + '𝕜' => '𝕜', + '𝕝' => '𝕝', + '𝕞' => '𝕞', + '𝕟' => '𝕟', + '𝕠' => '𝕠', + '𝕡' => '𝕡', + '𝕢' => '𝕢', + '𝕣' => '𝕣', + '𝕤' => '𝕤', + '𝕥' => '𝕥', + '𝕦' => '𝕦', + '𝕧' => '𝕧', + '𝕨' => '𝕨', + '𝕩' => '𝕩', + '𝕪' => '𝕪', + '𝕫' => '𝕫', + ); +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php new file mode 100644 index 000000000..ec467f22c --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php @@ -0,0 +1,553 @@ +'http://www.w3.org/1999/xhtml', + 'attrNamespace'=>'http://www.w3.org/1999/xhtml', + + 'nodeName'=>'img', 'nodeName'=>array('img', 'a'), + 'attrName'=>'alt', 'attrName'=>array('title', 'alt'), + ), + */ + array( + 'nodeNamespace' => 'http://www.w3.org/1999/xhtml', + 'attrName' => array('href', + 'hreflang', + 'http-equiv', + 'icon', + 'id', + 'keytype', + 'kind', + 'label', + 'lang', + 'language', + 'list', + 'maxlength', + 'media', + 'method', + 'name', + 'placeholder', + 'rel', + 'rows', + 'rowspan', + 'sandbox', + 'spellcheck', + 'scope', + 'seamless', + 'shape', + 'size', + 'sizes', + 'span', + 'src', + 'srcdoc', + 'srclang', + 'srcset', + 'start', + 'step', + 'style', + 'summary', + 'tabindex', + 'target', + 'title', + 'type', + 'value', + 'width', + 'border', + 'charset', + 'cite', + 'class', + 'code', + 'codebase', + 'color', + 'cols', + 'colspan', + 'content', + 'coords', + 'data', + 'datetime', + 'default', + 'dir', + 'dirname', + 'enctype', + 'for', + 'form', + 'formaction', + 'headers', + 'height', + 'accept', + 'accept-charset', + 'accesskey', + 'action', + 'align', + 'alt', + 'bgcolor', + ), + ), + array( + 'nodeNamespace' => 'http://www.w3.org/1999/xhtml', + 'xpath' => 'starts-with(local-name(), \'data-\')', + ), + ); + + const DOCTYPE = ''; + + public function __construct($output, $options = array()) + { + if (isset($options['encode_entities'])) { + $this->encode = $options['encode_entities']; + } + + $this->outputMode = static::IM_IN_HTML; + $this->out = $output; + $this->hasHTML5 = defined('ENT_HTML5'); + } + + public function addRule(array $rule) + { + $this->nonBooleanAttributes[] = $rule; + } + + public function setTraverser(Traverser $traverser) + { + $this->traverser = $traverser; + + return $this; + } + + public function unsetTraverser() + { + $this->traverser = null; + + return $this; + } + + public function document($dom) + { + $this->doctype(); + if ($dom->documentElement) { + foreach ($dom->childNodes as $node) { + $this->traverser->node($node); + } + $this->nl(); + } + } + + protected function doctype() + { + $this->wr(static::DOCTYPE); + $this->nl(); + } + + public function element($ele) + { + $name = $ele->tagName; + + // Per spec: + // If the element has a declared namespace in the HTML, MathML or + // SVG namespaces, we use the lname instead of the tagName. + if ($this->traverser->isLocalElement($ele)) { + $name = $ele->localName; + } + + // If we are in SVG or MathML there is special handling. + // Using if/elseif instead of switch because it's faster in PHP. + if ('svg' == $name) { + $this->outputMode = static::IM_IN_SVG; + $name = Elements::normalizeSvgElement($name); + } elseif ('math' == $name) { + $this->outputMode = static::IM_IN_MATHML; + } + + $this->openTag($ele); + if (Elements::isA($name, Elements::TEXT_RAW)) { + foreach ($ele->childNodes as $child) { + if ($child instanceof \DOMCharacterData) { + $this->wr($child->data); + } elseif ($child instanceof \DOMElement) { + $this->element($child); + } + } + } else { + // Handle children. + if ($ele->hasChildNodes()) { + $this->traverser->children($ele->childNodes); + } + + // Close out the SVG or MathML special handling. + if ('svg' == $name || 'math' == $name) { + $this->outputMode = static::IM_IN_HTML; + } + } + + // If not unary, add a closing tag. + if (!Elements::isA($name, Elements::VOID_TAG)) { + $this->closeTag($ele); + } + } + + /** + * Write a text node. + * + * @param \DOMText $ele The text node to write. + */ + public function text($ele) + { + if (isset($ele->parentNode) && isset($ele->parentNode->tagName) && Elements::isA($ele->parentNode->localName, Elements::TEXT_RAW)) { + $this->wr($ele->data); + + return; + } + + // FIXME: This probably needs some flags set. + $this->wr($this->enc($ele->data)); + } + + public function cdata($ele) + { + // This encodes CDATA. + $this->wr($ele->ownerDocument->saveXML($ele)); + } + + public function comment($ele) + { + // These produce identical output. + // $this->wr(''); + $this->wr($ele->ownerDocument->saveXML($ele)); + } + + public function processorInstruction($ele) + { + $this->wr('wr($ele->target) + ->wr(' ') + ->wr($ele->data) + ->wr('?>'); + } + + /** + * Write the namespace attributes. + * + * @param \DOMNode $ele The element being written. + */ + protected function namespaceAttrs($ele) + { + if (!$this->xpath || $this->xpath->document !== $ele->ownerDocument) { + $this->xpath = new \DOMXPath($ele->ownerDocument); + } + + foreach ($this->xpath->query('namespace::*[not(.=../../namespace::*)]', $ele) as $nsNode) { + if (!in_array($nsNode->nodeValue, $this->implicitNamespaces)) { + $this->wr(' ')->wr($nsNode->nodeName)->wr('="')->wr($nsNode->nodeValue)->wr('"'); + } + } + } + + /** + * Write the opening tag. + * + * Tags for HTML, MathML, and SVG are in the local name. Otherwise, use the + * qualified name (8.3). + * + * @param \DOMNode $ele The element being written. + */ + protected function openTag($ele) + { + $this->wr('<')->wr($this->traverser->isLocalElement($ele) ? $ele->localName : $ele->tagName); + + $this->attrs($ele); + $this->namespaceAttrs($ele); + + if ($this->outputMode == static::IM_IN_HTML) { + $this->wr('>'); + } // If we are not in html mode we are in SVG, MathML, or XML embedded content. + else { + if ($ele->hasChildNodes()) { + $this->wr('>'); + } // If there are no children this is self closing. + else { + $this->wr(' />'); + } + } + } + + protected function attrs($ele) + { + // FIXME: Needs support for xml, xmlns, xlink, and namespaced elements. + if (!$ele->hasAttributes()) { + return $this; + } + + // TODO: Currently, this always writes name="value", and does not do + // value-less attributes. + $map = $ele->attributes; + $len = $map->length; + for ($i = 0; $i < $len; ++$i) { + $node = $map->item($i); + $val = $this->enc($node->value, true); + + // XXX: The spec says that we need to ensure that anything in + // the XML, XMLNS, or XLink NS's should use the canonical + // prefix. It seems that DOM does this for us already, but there + // may be exceptions. + $name = $node->nodeName; + + // Special handling for attributes in SVG and MathML. + // Using if/elseif instead of switch because it's faster in PHP. + if ($this->outputMode == static::IM_IN_SVG) { + $name = Elements::normalizeSvgAttribute($name); + } elseif ($this->outputMode == static::IM_IN_MATHML) { + $name = Elements::normalizeMathMlAttribute($name); + } + + $this->wr(' ')->wr($name); + + if ((isset($val) && '' !== $val) || $this->nonBooleanAttribute($node)) { + $this->wr('="')->wr($val)->wr('"'); + } + } + } + + protected function nonBooleanAttribute(\DOMAttr $attr) + { + $ele = $attr->ownerElement; + foreach ($this->nonBooleanAttributes as $rule) { + if (isset($rule['nodeNamespace']) && $rule['nodeNamespace'] !== $ele->namespaceURI) { + continue; + } + if (isset($rule['attNamespace']) && $rule['attNamespace'] !== $attr->namespaceURI) { + continue; + } + if (isset($rule['nodeName']) && !is_array($rule['nodeName']) && $rule['nodeName'] !== $ele->localName) { + continue; + } + if (isset($rule['nodeName']) && is_array($rule['nodeName']) && !in_array($ele->localName, $rule['nodeName'], true)) { + continue; + } + if (isset($rule['attrName']) && !is_array($rule['attrName']) && $rule['attrName'] !== $attr->localName) { + continue; + } + if (isset($rule['attrName']) && is_array($rule['attrName']) && !in_array($attr->localName, $rule['attrName'], true)) { + continue; + } + if (isset($rule['xpath'])) { + $xp = $this->getXPath($attr); + if (isset($rule['prefixes'])) { + foreach ($rule['prefixes'] as $nsPrefix => $ns) { + $xp->registerNamespace($nsPrefix, $ns); + } + } + if (!$xp->evaluate($rule['xpath'], $attr)) { + continue; + } + } + + return true; + } + + return false; + } + + private function getXPath(\DOMNode $node) + { + if (!$this->xpath) { + $this->xpath = new \DOMXPath($node->ownerDocument); + } + + return $this->xpath; + } + + /** + * Write the closing tag. + * + * Tags for HTML, MathML, and SVG are in the local name. Otherwise, use the + * qualified name (8.3). + * + * @param \DOMNode $ele The element being written. + */ + protected function closeTag($ele) + { + if ($this->outputMode == static::IM_IN_HTML || $ele->hasChildNodes()) { + $this->wr('wr($this->traverser->isLocalElement($ele) ? $ele->localName : $ele->tagName)->wr('>'); + } + } + + /** + * Write to the output. + * + * @param string $text The string to put into the output + * + * @return $this + */ + protected function wr($text) + { + fwrite($this->out, $text); + + return $this; + } + + /** + * Write a new line character. + * + * @return $this + */ + protected function nl() + { + fwrite($this->out, PHP_EOL); + + return $this; + } + + /** + * Encode text. + * + * When encode is set to false, the default value, the text passed in is + * escaped per section 8.3 of the html5 spec. For details on how text is + * escaped see the escape() method. + * + * When encoding is set to true the text is converted to named character + * references where appropriate. Section 8.1.4 Character references of the + * html5 spec refers to using named character references. This is useful for + * characters that can't otherwise legally be used in the text. + * + * The named character references are listed in section 8.5. + * + * @see http://www.w3.org/TR/2013/CR-html5-20130806/syntax.html#named-character-references True encoding will turn all named character references into their entities. + * This includes such characters as +.# and many other common ones. By default + * encoding here will just escape &'<>". + * + * Note, PHP 5.4+ has better html5 encoding. + * + * @todo Use the Entities class in php 5.3 to have html5 entities. + * + * @param string $text Text to encode. + * @param bool $attribute True if we are encoding an attrubute, false otherwise. + * + * @return string The encoded text. + */ + protected function enc($text, $attribute = false) + { + // Escape the text rather than convert to named character references. + if (!$this->encode) { + return $this->escape($text, $attribute); + } + + // If we are in PHP 5.4+ we can use the native html5 entity functionality to + // convert the named character references. + + if ($this->hasHTML5) { + return htmlentities($text, ENT_HTML5 | ENT_SUBSTITUTE | ENT_QUOTES, 'UTF-8', false); + } // If a version earlier than 5.4 html5 entities are not entirely handled. + // This manually handles them. + else { + return strtr($text, HTML5Entities::$map); + } + } + + /** + * Escape test. + * + * According to the html5 spec section 8.3 Serializing HTML fragments, text + * within tags that are not style, script, xmp, iframe, noembed, and noframes + * need to be properly escaped. + * + * The & should be converted to &, no breaking space unicode characters + * converted to  , when in attribute mode the " should be converted to + * ", and when not in attribute mode the < and > should be converted to + * < and >. + * + * @see http://www.w3.org/TR/2013/CR-html5-20130806/syntax.html#escapingString + * + * @param string $text Text to escape. + * @param bool $attribute True if we are escaping an attrubute, false otherwise. + */ + protected function escape($text, $attribute = false) + { + // Not using htmlspecialchars because, while it does escaping, it doesn't + // match the requirements of section 8.5. For example, it doesn't handle + // non-breaking spaces. + if ($attribute) { + $replace = array( + '"' => '"', + '&' => '&', + "\xc2\xa0" => ' ', + ); + } else { + $replace = array( + '<' => '<', + '>' => '>', + '&' => '&', + "\xc2\xa0" => ' ', + ); + } + + return strtr($text, $replace); + } +} diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/README.md b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/README.md new file mode 100644 index 000000000..849a47f3a --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/README.md @@ -0,0 +1,33 @@ +# The Serializer (Writer) Model + +The serializer roughly follows sections _8.1 Writing HTML documents_ and section +_8.3 Serializing HTML fragments_ by converting DOMDocument, DOMDocumentFragment, +and DOMNodeList into HTML5. + + [ HTML5 ] // Interface for saving. + || + [ Traverser ] // Walk the DOM + || + [ Rules ] // Convert DOM elements into strings. + || + [ HTML5 ] // HTML5 document or fragment in text. + + +## HTML5 Class + +Provides the top level interface for saving. + +## The Traverser + +Walks the DOM finding each element and passing it off to the output rules to +convert to HTML5. + +## Output Rules + +The output rules are defined in the RulesInterface which can have multiple +implementations. Currently, the OutputRules is the default implementation that +converts a DOM as is into HTML5. + +## HTML5 String + +The output of the process it HTML5 as a string or saved to a file. \ No newline at end of file diff --git a/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php new file mode 100644 index 000000000..69a6ecdad --- /dev/null +++ b/library/vendor/dompdf/vendor/masterminds/html5/src/HTML5/Serializer/RulesInterface.php @@ -0,0 +1,99 @@ + 'html', + 'http://www.w3.org/1998/Math/MathML' => 'math', + 'http://www.w3.org/2000/svg' => 'svg', + ); + + protected $dom; + + protected $options; + + protected $encode = false; + + protected $rules; + + protected $out; + + /** + * Create a traverser. + * + * @param \DOMNode|\DOMNodeList $dom The document or node to traverse. + * @param resource $out A stream that allows writing. The traverser will output into this + * stream. + * @param array $options An array of options for the traverser as key/value pairs. These include: + * - encode_entities: A bool to specify if full encding should happen for all named + * charachter references. Defaults to false which escapes &'<>". + * - output_rules: The path to the class handling the output rules. + */ + public function __construct($dom, $out, RulesInterface $rules, $options = array()) + { + $this->dom = $dom; + $this->out = $out; + $this->rules = $rules; + $this->options = $options; + + $this->rules->setTraverser($this); + } + + /** + * Tell the traverser to walk the DOM. + * + * @return resource $out Returns the output stream. + */ + public function walk() + { + if ($this->dom instanceof \DOMDocument) { + $this->rules->document($this->dom); + } elseif ($this->dom instanceof \DOMDocumentFragment) { + // Document fragments are a special case. Only the children need to + // be serialized. + if ($this->dom->hasChildNodes()) { + $this->children($this->dom->childNodes); + } + } // If NodeList, loop + elseif ($this->dom instanceof \DOMNodeList) { + // If this is a NodeList of DOMDocuments this will not work. + $this->children($this->dom); + } // Else assume this is a DOMNode-like datastructure. + else { + $this->node($this->dom); + } + + return $this->out; + } + + /** + * Process a node in the DOM. + * + * @param mixed $node A node implementing \DOMNode. + */ + public function node($node) + { + // A listing of types is at http://php.net/manual/en/dom.constants.php + switch ($node->nodeType) { + case XML_ELEMENT_NODE: + $this->rules->element($node); + break; + case XML_TEXT_NODE: + $this->rules->text($node); + break; + case XML_CDATA_SECTION_NODE: + $this->rules->cdata($node); + break; + case XML_PI_NODE: + $this->rules->processorInstruction($node); + break; + case XML_COMMENT_NODE: + $this->rules->comment($node); + break; + // Currently we don't support embedding DTDs. + default: + //print ''; + break; + } + } + + /** + * Walk through all the nodes on a node list. + * + * @param \DOMNodeList $nl A list of child elements to walk through. + */ + public function children($nl) + { + foreach ($nl as $node) { + $this->node($node); + } + } + + /** + * Is an element local? + * + * @param mixed $ele An element that implement \DOMNode. + * + * @return bool true if local and false otherwise. + */ + public function isLocalElement($ele) + { + $uri = $ele->namespaceURI; + if (empty($uri)) { + return false; + } + + return isset(static::$local_ns[$uri]); + } +} diff --git a/library/vendor/dompdf/lib/php-font-lib/.github/workflows/phpunit.yml b/library/vendor/dompdf/vendor/phenx/php-font-lib/.github/workflows/phpunit.yml similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/.github/workflows/phpunit.yml rename to library/vendor/dompdf/vendor/phenx/php-font-lib/.github/workflows/phpunit.yml diff --git a/library/vendor/dompdf/lib/php-font-lib/LICENSE b/library/vendor/dompdf/vendor/phenx/php-font-lib/LICENSE similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/LICENSE rename to library/vendor/dompdf/vendor/phenx/php-font-lib/LICENSE diff --git a/library/vendor/dompdf/lib/php-font-lib/README.md b/library/vendor/dompdf/vendor/phenx/php-font-lib/README.md similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/README.md rename to library/vendor/dompdf/vendor/phenx/php-font-lib/README.md diff --git a/library/vendor/dompdf/lib/php-font-lib/bower.json b/library/vendor/dompdf/vendor/phenx/php-font-lib/bower.json similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/bower.json rename to library/vendor/dompdf/vendor/phenx/php-font-lib/bower.json diff --git a/library/vendor/dompdf/lib/php-font-lib/composer.json b/library/vendor/dompdf/vendor/phenx/php-font-lib/composer.json similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/composer.json rename to library/vendor/dompdf/vendor/phenx/php-font-lib/composer.json diff --git a/library/vendor/dompdf/lib/php-font-lib/index.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/index.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/index.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/index.php diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/adobe-standard-encoding.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/adobe-standard-encoding.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/adobe-standard-encoding.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/adobe-standard-encoding.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1250.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1250.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1250.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1250.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1251.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1251.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1251.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1251.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1252.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1252.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1252.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1252.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1253.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1253.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1253.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1253.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1254.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1254.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1254.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1254.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1255.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1255.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1255.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1255.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1257.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1257.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1257.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1257.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp1258.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1258.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp1258.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp1258.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/cp874.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp874.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/cp874.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/cp874.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-1.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-1.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-1.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-1.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-11.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-11.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-11.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-11.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-15.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-15.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-15.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-15.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-16.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-16.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-16.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-16.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-2.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-2.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-2.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-2.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-4.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-4.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-4.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-4.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-5.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-5.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-5.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-5.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-7.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-7.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-7.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-7.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-9.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-9.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/iso-8859-9.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/iso-8859-9.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/koi8-r.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/koi8-r.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/koi8-r.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/koi8-r.map diff --git a/library/vendor/dompdf/lib/php-font-lib/maps/koi8-u.map b/library/vendor/dompdf/vendor/phenx/php-font-lib/maps/koi8-u.map similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/maps/koi8-u.map rename to library/vendor/dompdf/vendor/phenx/php-font-lib/maps/koi8-u.map diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/AdobeFontMetrics.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/AdobeFontMetrics.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/AdobeFontMetrics.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/AdobeFontMetrics.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Autoloader.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Autoloader.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Autoloader.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Autoloader.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/BinaryStream.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/BinaryStream.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/BinaryStream.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/BinaryStream.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/EOT/File.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/EOT/File.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/EOT/File.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/EOT/File.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/EOT/Header.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/EOT/Header.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/EOT/Header.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/EOT/Header.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/EncodingMap.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/EncodingMap.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/EncodingMap.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/EncodingMap.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Exception/FontNotFoundException.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Exception/FontNotFoundException.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Exception/FontNotFoundException.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Exception/FontNotFoundException.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Font.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Font.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Font.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Font.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/Outline.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/Outline.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/Outline.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/Outline.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/OutlineComponent.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineComponent.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/OutlineComponent.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineComponent.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/OutlineComposite.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineComposite.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/OutlineComposite.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineComposite.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/OutlineSimple.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineSimple.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Glyph/OutlineSimple.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineSimple.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Header.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Header.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Header.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Header.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/OpenType/File.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/OpenType/File.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/OpenType/File.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/OpenType/File.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/OpenType/TableDirectoryEntry.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/OpenType/TableDirectoryEntry.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/OpenType/TableDirectoryEntry.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/OpenType/TableDirectoryEntry.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/DirectoryEntry.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/DirectoryEntry.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/DirectoryEntry.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/DirectoryEntry.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Table.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Table.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Table.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Table.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/cmap.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/cmap.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/cmap.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/cmap.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/glyf.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/glyf.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/glyf.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/glyf.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/head.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/head.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/head.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/head.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/hhea.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/hhea.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/hhea.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/hhea.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/hmtx.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/hmtx.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/hmtx.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/hmtx.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/kern.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/kern.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/kern.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/kern.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/loca.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/loca.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/loca.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/loca.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/maxp.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/maxp.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/maxp.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/maxp.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/name.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/name.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/name.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/name.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/nameRecord.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/nameRecord.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/nameRecord.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/nameRecord.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/os2.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/os2.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/os2.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/os2.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/post.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/post.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/Table/Type/post.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/Table/Type/post.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/Collection.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/Collection.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/Collection.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/Collection.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/File.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/File.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/File.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/File.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/Header.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/Header.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/Header.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/Header.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/TableDirectoryEntry.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/TableDirectoryEntry.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/TrueType/TableDirectoryEntry.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/TrueType/TableDirectoryEntry.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/WOFF/File.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/WOFF/File.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/WOFF/File.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/WOFF/File.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/WOFF/Header.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/WOFF/Header.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/WOFF/Header.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/WOFF/Header.php diff --git a/library/vendor/dompdf/lib/php-font-lib/src/FontLib/WOFF/TableDirectoryEntry.php b/library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/WOFF/TableDirectoryEntry.php similarity index 100% rename from library/vendor/dompdf/lib/php-font-lib/src/FontLib/WOFF/TableDirectoryEntry.php rename to library/vendor/dompdf/vendor/phenx/php-font-lib/src/FontLib/WOFF/TableDirectoryEntry.php diff --git a/library/vendor/dompdf/vendor/phenx/php-svg-lib/LICENSE b/library/vendor/dompdf/vendor/phenx/php-svg-lib/LICENSE new file mode 100644 index 000000000..0a041280b --- /dev/null +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/library/vendor/dompdf/lib/php-svg-lib/README.md b/library/vendor/dompdf/vendor/phenx/php-svg-lib/README.md similarity index 77% rename from library/vendor/dompdf/lib/php-svg-lib/README.md rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/README.md index f11cde9ea..2b8e6f67e 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/README.md +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/README.md @@ -1,7 +1,6 @@ # SVG file parsing / rendering library -[![Build Status](https://travis-ci.org/PhenX/php-svg-lib.svg?branch=master)](https://travis-ci.org/PhenX/php-svg-lib) -[![Coverage Status](https://coveralls.io/repos/PhenX/php-svg-lib/badge.svg)](https://coveralls.io/r/PhenX/php-svg-lib) +[![Build Status](https://github.com/phenx/php-svg-lib/workflows/test/badge.svg)](https://github.com/phenx/php-svg-lib/actions) [![Latest Stable Version](https://poser.pugx.org/phenx/php-svg-lib/v/stable)](https://packagist.org/packages/phenx/php-svg-lib) @@ -11,4 +10,4 @@ The main purpose of this lib is to rasterize SVG to a surface which can be an image or a PDF for example, through a `\Svg\Surface` PHP interface. -This project was initialized by the need to render SVG documents inside PDF files for the [DomPdf](http://dompdf.github.io) project. \ No newline at end of file +This project was initialized by the need to render SVG documents inside PDF files for the [DomPdf](http://dompdf.github.io) project. diff --git a/library/vendor/dompdf/lib/php-svg-lib/composer.json b/library/vendor/dompdf/vendor/phenx/php-svg-lib/composer.json similarity index 92% rename from library/vendor/dompdf/lib/php-svg-lib/composer.json rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/composer.json index c2568dfbf..a6ed9c541 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/composer.json +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/composer.json @@ -21,7 +21,7 @@ } }, "require": { - "php": "^7.1 || ^7.2 || ^7.3 || ^7.4 || ^8.0", + "php": "^7.1 || ^8.0", "ext-mbstring": "*", "sabberworm/php-css-parser": "^8.4" }, diff --git a/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/CssLength.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/CssLength.php new file mode 100644 index 000000000..88eda8c6f --- /dev/null +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/CssLength.php @@ -0,0 +1,135 @@ + + */ + protected static $inchDivisions = [ + 'in' => 1, + 'cm' => 2.54, + 'mm' => 25.4, + 'q' => 101.6, + 'pc' => 6, + 'pt' => 72, + ]; + + /** + * The CSS length unit indicator. + * Will be lower-case and one of the units listed in the '$units' array or empty. + * + * @var string + */ + protected $unit = ''; + + /** + * The numeric value of the given length. + * + * @var float + */ + protected $value = 0; + + /** + * The original unparsed length provided. + * + * @var string + */ + protected $unparsed; + + public function __construct(string $length) + { + $this->unparsed = $length; + $this->parseLengthComponents($length); + } + + /** + * Parse out the unit and value components from the given string length. + */ + protected function parseLengthComponents(string $length): void + { + $length = strtolower($length); + + foreach (self::$units as $unit) { + $pos = strpos($length, $unit); + if ($pos) { + $this->value = floatval(substr($length, 0, $pos)); + $this->unit = $unit; + return; + } + } + + $this->unit = ''; + $this->value = floatval($length); + } + + /** + * Get the unit type of this css length. + * Units are standardised to be lower-cased. + * + * @return string + */ + public function getUnit(): string + { + return $this->unit; + } + + /** + * Get this CSS length in the equivalent pixel count size. + * + * @param float $referenceSize + * @param float $dpi + * + * @return float + */ + public function toPixels(float $referenceSize = 11.0, float $dpi = 96.0): float + { + // Standard relative units + if (in_array($this->unit, ['em', 'rem', 'ex', 'ch'])) { + return $this->value * $referenceSize; + } + + // Percentage relative units + if (in_array($this->unit, ['%', 'vw', 'vh', 'vmin', 'vmax'])) { + return $this->value * ($referenceSize / 100); + } + + // Inch relative units + if (in_array($this->unit, array_keys(static::$inchDivisions))) { + $inchValue = $this->value * $dpi; + $division = static::$inchDivisions[$this->unit]; + return $inchValue / $division; + } + + return $this->value; + } +} \ No newline at end of file diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/DefaultStyle.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/DefaultStyle.php similarity index 90% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/DefaultStyle.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/DefaultStyle.php index 2fe312b85..4e73d2948 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/DefaultStyle.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/DefaultStyle.php @@ -10,11 +10,11 @@ namespace Svg; class DefaultStyle extends Style { - public $color = ''; + public $color = [0, 0, 0, 1]; public $opacity = 1.0; public $display = 'inline'; - public $fill = 'black'; + public $fill = [0, 0, 0, 1]; public $fillOpacity = 1.0; public $fillRule = 'nonzero'; diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Document.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Document.php similarity index 97% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Document.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Document.php index 2561e3aeb..4de226e70 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Document.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Document.php @@ -101,6 +101,11 @@ class Document extends AbstractTag return $this->height; } + public function getDiagonal() + { + return sqrt(($this->width)**2 + ($this->height)**2) / sqrt(2); + } + public function getDimensions() { $rootAttributes = null; @@ -135,12 +140,12 @@ class Document extends AbstractTag public function handleSizeAttributes($attributes){ if ($this->width === null) { if (isset($attributes["width"])) { - $width = Style::convertSize($attributes["width"], 400); + $width = $this->convertSize($attributes["width"], 400); $this->width = $width; } if (isset($attributes["height"])) { - $height = Style::convertSize($attributes["height"], 300); + $height = $this->convertSize($attributes["height"], 300); $this->height = $height; } diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Gradient/Stop.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Gradient/Stop.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Gradient/Stop.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Gradient/Stop.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Style.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Style.php similarity index 88% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Style.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Style.php index 0c6263303..14b11e902 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Style.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Style.php @@ -18,6 +18,8 @@ class Style const TYPE_ANGLE = 4; const TYPE_NUMBER = 5; + private $_parentStyle; + public $color; public $opacity; public $display; @@ -88,7 +90,7 @@ class Style $group = $tag->getParentGroup(); if ($group) { $parent_style = $group->getStyle(); - + $this->_parentStyle = $parent_style; foreach ($parent_style as $_key => $_value) { if ($_value !== null) { $this->$_key = $_value; @@ -145,13 +147,24 @@ class Style protected function fillStyles($styles) { - foreach ($this->getStyleMap() as $from => $spec) { + $style_map = $this->getStyleMap(); + foreach ($style_map as $from => $spec) { if (isset($styles[$from])) { list($to, $type) = $spec; $value = null; switch ($type) { case self::TYPE_COLOR: $value = self::parseColor($styles[$from]); + if ($value === "currentcolor") { + if ($type === "color") { + $value = $this->_parentStyle->color; + } else { + $value = $this->color; + } + } + if ($value !== null && $value[3] !== 1 && array_key_exists("{$from}-opacity", $style_map) === true) { + $styles["{$from}-opacity"] = $value[3]; + } break; case self::TYPE_NUMBER: @@ -177,8 +190,7 @@ class Style if (count($parts) == 2) { $color = $parts[1]; - } - else { + } else { $color = $parts[0]; } @@ -186,6 +198,10 @@ class Style return "none"; } + if ($color === "currentcolor") { + return "currentcolor"; + } + // SVG color name if (isset(self::$colorNames[$color])) { return self::parseHexColor(self::$colorNames[$color]); @@ -198,18 +214,18 @@ class Style // RGB color if (strpos($color, "rgb") !== false) { - return self::getTriplet($color); + return self::getQuad($color); } // RGB color if (strpos($color, "hsl") !== false) { - $triplet = self::getTriplet($color, true); + $quad = self::getQuad($color, true); - if ($triplet == null) { + if ($quad == null) { return null; } - list($h, $s, $l) = $triplet; + list($h, $s, $l, $a) = $quad; $r = $l; $g = $l; @@ -258,11 +274,13 @@ class Style break; } } + $a = $a * 255; return array( $r * 255.0, $g * 255.0, $b * 255.0, + $a ); } @@ -282,7 +300,7 @@ class Style return null; } - static function getTriplet($color, $percent = false) { + static function getQuad($color, $percent = false) { $i = strpos($color, "("); $j = strpos($color, ")"); @@ -291,46 +309,60 @@ class Style return null; } - $triplet = preg_split("/\\s*,\\s*/", trim(substr($color, $i + 1, $j - $i - 1))); + $quad = preg_split("/\\s*[,\\/]\\s*/", trim(substr($color, $i + 1, $j - $i - 1))); + if (!isset($quad[3])) { + $quad[3] = 1; + } - if (count($triplet) != 3) { + if (count($quad) != 3 && count($quad) != 4) { return null; } - foreach (array_keys($triplet) as $c) { - $triplet[$c] = trim($triplet[$c]); + foreach (array_keys($quad) as $c) { + $quad[$c] = trim($quad[$c]); if ($percent) { - if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") { - $triplet[$c] = floatval($triplet[$c]) / 100; + if ($quad[$c][strlen($quad[$c]) - 1] === "%") { + $quad[$c] = floatval($quad[$c]) / 100; + } else { + $quad[$c] = $quad[$c] / 255; } - else { - $triplet[$c] = $triplet[$c] / 255; - } - } - else { - if ($triplet[$c][strlen($triplet[$c]) - 1] === "%") { - $triplet[$c] = round(floatval($triplet[$c]) * 2.55); + } else { + if ($quad[$c][strlen($quad[$c]) - 1] === "%") { + $quad[$c] = round(floatval($quad[$c]) * 2.55); } } } - return $triplet; + return $quad; } static function parseHexColor($hex) { - $c = array(0, 0, 0); + $c = array(0, 0, 0, 1); // #FFFFFF if (isset($hex[6])) { $c[0] = hexdec(substr($hex, 1, 2)); $c[1] = hexdec(substr($hex, 3, 2)); $c[2] = hexdec(substr($hex, 5, 2)); + + if (isset($hex[7])) { + $alpha = substr($hex, 7, 2); + if (ctype_xdigit($alpha)) { + $c[3] = round(hexdec($alpha)/255, 2); + } + } } else { $c[0] = hexdec($hex[1] . $hex[1]); $c[1] = hexdec($hex[2] . $hex[2]); $c[2] = hexdec($hex[3] . $hex[3]); + + if (isset($hex[4])) { + if (ctype_xdigit($hex[4])) { + $c[3] = round(hexdec($hex[4] . $hex[4])/255, 2); + } + } } return $c; @@ -356,47 +388,6 @@ class Style return $styles; } - /** - * Convert a size to a float - * - * @param string $size SVG size - * @param float $dpi DPI - * @param float $referenceSize Reference size - * - * @return float|null - */ - static function convertSize($size, $referenceSize = 11.0, $dpi = 96.0) { - $size = trim(strtolower($size)); - - if (is_numeric($size)) { - return $size; - } - - if ($pos = strpos($size, "px")) { - return floatval(substr($size, 0, $pos)); - } - - if ($pos = strpos($size, "pt")) { - return floatval(substr($size, 0, $pos)); - } - - if ($pos = strpos($size, "cm")) { - return floatval(substr($size, 0, $pos)) * $dpi; - } - - if ($pos = strpos($size, "%")) { - return $referenceSize * substr($size, 0, $pos) / 100; - } - - if ($pos = strpos($size, "em")) { - return $referenceSize * substr($size, 0, $pos); - } - - // TODO cm, mm, pc, in, etc - - return null; - } - static $colorNames = array( 'antiquewhite' => '#FAEBD7', 'aqua' => '#00FFFF', diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/CPdf.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/CPdf.php similarity index 99% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/CPdf.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/CPdf.php index 32ae8960b..caa28a890 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/CPdf.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/CPdf.php @@ -4174,9 +4174,9 @@ EOT; $this->addContent(sprintf("\n%.3F %.3F %.3F %.3F re", $x1, $y1, $width, $height)); } - function stroke() + function stroke(bool $close = false) { - $this->addContent("\nS"); + $this->addContent("\n" . ($close ? "s" : "S")); } function fill() @@ -4184,9 +4184,9 @@ EOT; $this->addContent("\nf" . ($this->fillRule === "evenodd" ? "*" : "")); } - function fillStroke() + function fillStroke(bool $close = false) { - $this->addContent("\nb" . ($this->fillRule === "evenodd" ? "*" : "")); + $this->addContent("\n" . ($close ? "b" : "B") . ($this->fillRule === "evenodd" ? "*" : "")); } /** diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php similarity index 90% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php index ab661d473..62cc74a1d 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php @@ -122,10 +122,10 @@ class SurfaceCpdf implements SurfaceInterface $this->canvas->closePath(); } - public function fillStroke() + public function fillStroke(bool $close = false) { if (self::DEBUG) echo __FUNCTION__ . "\n"; - $this->canvas->fillStroke(); + $this->canvas->fillStroke($close); } public function clip() @@ -342,10 +342,10 @@ class SurfaceCpdf implements SurfaceInterface $this->stroke(); } - public function stroke() + public function stroke(bool $close = false) { if (self::DEBUG) echo __FUNCTION__ . "\n"; - $this->canvas->stroke(); + $this->canvas->stroke($close); } public function endPath() @@ -435,51 +435,52 @@ class SurfaceCpdf implements SurfaceInterface public function setFont($family, $style, $weight) { - $map = array( - "serif" => "Times", - "sans-serif" => "Helvetica", - "fantasy" => "Symbol", - "cursive" => "Times", - "monospace" => "Courier", + $map = [ + "serif" => "times", + "sans-serif" => "helvetica", + "fantasy" => "symbol", + "cursive" => "times", + "monospace" => "courier" + ]; - "arial" => "Helvetica", - "verdana" => "Helvetica", - ); + $styleMap = [ + "courier" => [ + "" => "Courier", + "b" => "Courier-Bold", + "i" => "Courier-Oblique", + "bi" => "Courier-BoldOblique", + ], + "helvetica" => [ + "" => "Helvetica", + "b" => "Helvetica-Bold", + "i" => "Helvetica-Oblique", + "bi" => "Helvetica-BoldOblique", + ], + "symbol" => [ + "" => "Symbol" + ], + "times" => [ + "" => "Times-Roman", + "b" => "Times-Bold", + "i" => "Times-Italic", + "bi" => "Times-BoldItalic", + ], + ]; - $styleMap = array( - 'Helvetica' => array( - 'b' => 'Helvetica-Bold', - 'i' => 'Helvetica-Oblique', - 'bi' => 'Helvetica-BoldOblique', - ), - 'Courier' => array( - 'b' => 'Courier-Bold', - 'i' => 'Courier-Oblique', - 'bi' => 'Courier-BoldOblique', - ), - 'Times' => array( - '' => 'Times-Roman', - 'b' => 'Times-Bold', - 'i' => 'Times-Italic', - 'bi' => 'Times-BoldItalic', - ), - ); - - $family = strtolower($family); - $style = strtolower($style); - $weight = strtolower($weight); - - if (isset($map[$family])) { - $family = $map[$family]; + $family_lc = strtolower($family); + if (isset($map[$family_lc])) { + $family = $map[$family_lc]; } if (isset($styleMap[$family])) { $key = ""; + $weight = strtolower($weight); if ($weight === "bold" || $weight === "bolder" || (is_numeric($weight) && $weight >= 600)) { $key .= "b"; } + $style = strtolower($style); if ($style === "italic" || $style === "oblique") { $key .= "i"; } diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfaceInterface.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceInterface.php similarity index 95% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfaceInterface.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceInterface.php index e8edcf086..25b30014d 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfaceInterface.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceInterface.php @@ -37,11 +37,11 @@ interface SurfaceInterface public function fill(); - public function stroke(); + public function stroke(bool $close = false); public function endPath(); - public function fillStroke(); + public function fillStroke(bool $close = false); public function clip(); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php similarity index 95% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php index fc5e7143c..3d25aef81 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php @@ -120,10 +120,14 @@ class SurfacePDFLib implements SurfaceInterface $this->canvas->closepath(); } - public function fillStroke() + public function fillStroke(bool $close = false) { if (self::DEBUG) echo __FUNCTION__ . "\n"; - $this->canvas->fill_stroke(); + if ($close) { + $this->canvas->closepath_fill_stroke(); + } else { + $this->canvas->fill_stroke(); + } } public function clip() @@ -281,10 +285,14 @@ class SurfacePDFLib implements SurfaceInterface $this->stroke(); } - public function stroke() + public function stroke(bool $close = false) { if (self::DEBUG) echo __FUNCTION__ . "\n"; - $this->canvas->stroke(); + if ($close) { + $this->canvas->closepath_stroke(); + } else { + $this->canvas->stroke(); + } } public function endPath() @@ -315,7 +323,7 @@ class SurfacePDFLib implements SurfaceInterface $this->style = $style; $canvas = $this->canvas; - if ($stroke = $style->stroke && is_array($style->stroke)) { + if (is_array($style->stroke) && $stroke = $style->stroke) { $canvas->setcolor( "stroke", "rgb", @@ -326,7 +334,7 @@ class SurfacePDFLib implements SurfaceInterface ); } - if ($fill = $style->fill && is_array($style->fill)) { + if (is_array($style->fill) && $fill = $style->fill) { $canvas->setcolor( "fill", "rgb", diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/AbstractTag.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/AbstractTag.php similarity index 64% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/AbstractTag.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/AbstractTag.php index 8c464ddad..9fa679320 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/AbstractTag.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/AbstractTag.php @@ -8,6 +8,7 @@ namespace Svg\Tag; +use Svg\CssLength; use Svg\Document; use Svg\Style; @@ -134,21 +135,19 @@ abstract class AbstractTag $transform = $attributes["transform"]; - $match = array(); + $matches = array(); preg_match_all( - '/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is', + '/(matrix|translate|scale|rotate|skew|skewX|skewY)\((.*?)\)/is', $transform, - $match, + $matches, PREG_SET_ORDER ); $transformations = array(); - if (count($match[0])) { - foreach ($match as $_match) { - $arguments = preg_split('/[ ,]+/', $_match[2]); - array_unshift($arguments, $_match[1]); - $transformations[] = $arguments; - } + foreach ($matches as $match) { + $arguments = preg_split('/[ ,]+/', $match[2]); + array_unshift($arguments, $match[1]); + $transformations[] = $arguments; } foreach ($transformations as $t) { @@ -177,14 +176,61 @@ abstract class AbstractTag break; case "skewX": - $surface->skewX($t[1]); + $tan_x = tan(deg2rad($t[1])); + $surface->transform(1, 0, $tan_x, 1, 0, 0); break; case "skewY": - $surface->skewY($t[1]); + $tan_y = tan(deg2rad($t[1])); + $surface->transform(1, $tan_y, 0, 1, 0, 0); break; } } } } + + /** + * Convert the given size for the context of this current tag. + * Takes a pixel-based reference, which is usually specific to the context of the size, + * but the actual reference size will be decided based upon the unit used. + * + * @param string $size + * @param float $pxReference + * + * @return float + */ + protected function convertSize(string $size, float $pxReference): float + { + $length = new CssLength($size); + $reference = $pxReference; + $defaultFontSize = 12; + + switch ($length->getUnit()) { + case "em": + $reference = $this->style->fontSize ?? $defaultFontSize; + break; + case "rem": + $reference = $this->document->style->fontSize ?? $defaultFontSize; + break; + case "ex": + case "ch": + $emRef = $this->style->fontSize ?? $defaultFontSize; + $reference = $emRef * 0.5; + break; + case "vw": + $reference = $this->getDocument()->getWidth(); + break; + case "vh": + $reference = $this->getDocument()->getHeight(); + break; + case "vmin": + $reference = min($this->getDocument()->getHeight(), $this->getDocument()->getWidth()); + break; + case "vmax": + $reference = max($this->getDocument()->getHeight(), $this->getDocument()->getWidth()); + break; + } + + return (new CssLength($size))->toPixels($reference); + } } diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Anchor.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Anchor.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Anchor.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Anchor.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Circle.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Circle.php similarity index 60% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Circle.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Circle.php index 3f8de2f6a..e504ffe3a 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Circle.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Circle.php @@ -8,6 +8,8 @@ namespace Svg\Tag; +use Svg\Style; + class Circle extends Shape { protected $cx = 0; @@ -17,13 +19,16 @@ class Circle extends Shape public function start($attributes) { if (isset($attributes['cx'])) { - $this->cx = $attributes['cx']; + $width = $this->document->getWidth(); + $this->cx = $this->convertSize($attributes['cx'], $width); } if (isset($attributes['cy'])) { - $this->cy = $attributes['cy']; + $height = $this->document->getHeight(); + $this->cy = $this->convertSize($attributes['cy'], $height); } if (isset($attributes['r'])) { - $this->r = $attributes['r']; + $diagonal = $this->document->getDiagonal(); + $this->r = $this->convertSize($attributes['r'], $diagonal); } $this->document->getSurface()->circle($this->cx, $this->cy, $this->r); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/ClipPath.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/ClipPath.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/ClipPath.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/ClipPath.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Ellipse.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Ellipse.php similarity index 65% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Ellipse.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Ellipse.php index 1f567a00f..42891e031 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Ellipse.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Ellipse.php @@ -8,6 +8,8 @@ namespace Svg\Tag; +use Svg\Style; + class Ellipse extends Shape { protected $cx = 0; @@ -19,17 +21,20 @@ class Ellipse extends Shape { parent::start($attributes); + $width = $this->document->getWidth(); + $height = $this->document->getHeight(); + if (isset($attributes['cx'])) { - $this->cx = $attributes['cx']; + $this->cx = $this->convertSize($attributes['cx'], $width); } if (isset($attributes['cy'])) { - $this->cy = $attributes['cy']; + $this->cy = $this->convertSize($attributes['cy'], $height); } if (isset($attributes['rx'])) { - $this->rx = $attributes['rx']; + $this->rx = $this->convertSize($attributes['rx'], $width); } if (isset($attributes['ry'])) { - $this->ry = $attributes['ry']; + $this->ry = $this->convertSize($attributes['ry'], $height); } $this->document->getSurface()->ellipse($this->cx, $this->cy, $this->rx, $this->ry, 0, 0, 360, false); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Group.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Group.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Group.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Group.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Image.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Image.php similarity index 63% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Image.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Image.php index cce8a5e27..bda17ea31 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Image.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Image.php @@ -8,6 +8,8 @@ namespace Svg\Tag; +use Svg\Style; + class Image extends AbstractTag { protected $x = 0; @@ -28,31 +30,35 @@ class Image extends AbstractTag public function start($attributes) { - $document = $this->document; $height = $this->document->getHeight(); + $width = $this->document->getWidth(); $this->y = $height; if (isset($attributes['x'])) { - $this->x = $attributes['x']; + $this->x = $this->convertSize($attributes['x'], $width); } if (isset($attributes['y'])) { - $this->y = $height - $attributes['y']; + $this->y = $height - $this->convertSize($attributes['y'], $height); } if (isset($attributes['width'])) { - $this->width = $attributes['width']; + $this->width = $this->convertSize($attributes['width'], $width); } if (isset($attributes['height'])) { - $this->height = $attributes['height']; + $this->height = $this->convertSize($attributes['height'], $height); } if (isset($attributes['xlink:href'])) { $this->href = $attributes['xlink:href']; } - $document->getSurface()->transform(1, 0, 0, -1, 0, $height); + if (isset($attributes['href'])) { + $this->href = $attributes['href']; + } - $document->getSurface()->drawImage($this->href, $this->x, $this->y, $this->width, $this->height); + $this->document->getSurface()->transform(1, 0, 0, -1, 0, $height); + + $this->document->getSurface()->drawImage($this->href, $this->x, $this->y, $this->width, $this->height); } protected function after() diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Line.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Line.php similarity index 65% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Line.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Line.php index 80997413c..fb3b64c48 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Line.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Line.php @@ -8,6 +8,8 @@ namespace Svg\Tag; +use Svg\Style; + class Line extends Shape { protected $x1 = 0; @@ -18,17 +20,20 @@ class Line extends Shape public function start($attributes) { + $height = $this->document->getHeight(); + $width = $this->document->getWidth(); + if (isset($attributes['x1'])) { - $this->x1 = $attributes['x1']; + $this->x1 = $this->convertSize($attributes['x1'], $width); } if (isset($attributes['y1'])) { - $this->y1 = $attributes['y1']; + $this->y1 = $this->convertSize($attributes['y1'], $height); } if (isset($attributes['x2'])) { - $this->x2 = $attributes['x2']; + $this->x2 = $this->convertSize($attributes['x2'], $width); } if (isset($attributes['y2'])) { - $this->y2 = $attributes['y2']; + $this->y2 = $this->convertSize($attributes['y2'], $height); } $surface = $this->document->getSurface(); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/LinearGradient.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/LinearGradient.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/LinearGradient.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/LinearGradient.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Path.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Path.php similarity index 94% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Path.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Path.php index c79ba658e..3dce7a619 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Path.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Path.php @@ -61,7 +61,7 @@ class Path extends Shape $commandLower = strtolower($c[1]); // arcs have special flags that apparently don't require spaces. - if ($commandLower === 'a' && preg_match_all(static::ARC_REGEXP, $c[2], $matches)) { + if ($commandLower === 'a' && preg_match_all(static::ARC_REGEXP, $c[2], $matches, PREG_PATTERN_ORDER)) { $numberOfMatches = count($matches[0]); for ($k = 0; $k < $numberOfMatches; ++$k) { $path[] = [ @@ -138,7 +138,6 @@ class Path extends Shape $tempControlY = null; $l = 0; //-((this.width / 2) + $this.pathOffset.x), $t = 0; //-((this.height / 2) + $this.pathOffset.y), - $methodName = null; foreach ($path as $current) { switch ($current[0]) { // first letter @@ -333,23 +332,16 @@ class Path extends Shape $tempX = $x + $current[1]; $tempY = $y + $current[2]; - if (preg_match("/[QqTt]/", $previous[0])) { - // If there is no previous command or if the previous command was not a Q, q, T or t, - // assume the control point is coincident with the current point + // calculate reflection of previous control points + if (preg_match('/[QqT]/', $previous[0])) { + $controlX = 2 * $x - $controlX; + $controlY = 2 * $y - $controlY; + } elseif ($previous[0] === 't') { + $controlX = 2 * $x - $tempControlX; + $controlY = 2 * $y - $tempControlY; + } else { $controlX = $x; $controlY = $y; - } else { - if ($previous[0] === 't') { - // calculate reflection of previous control points for t - $controlX = 2 * $x - $tempControlX; - $controlY = 2 * $y - $tempControlY; - } else { - if ($previous[0] === 'q') { - // calculate reflection of previous control points for q - $controlX = 2 * $x - $controlX; - $controlY = 2 * $y - $controlY; - } - } } $tempControlX = $controlX; @@ -363,8 +355,6 @@ class Path extends Shape ); $x = $tempX; $y = $tempY; - $controlX = $x + $current[1]; - $controlY = $y + $current[2]; break; case 'T': @@ -372,8 +362,14 @@ class Path extends Shape $tempY = $current[2]; // calculate reflection of previous control points - $controlX = 2 * $x - $controlX; - $controlY = 2 * $y - $controlY; + if (preg_match('/[QqTt]/', $previous[0])) { + $controlX = 2 * $x - $controlX; + $controlY = 2 * $y - $controlY; + } else { + $controlX = $x; + $controlY = $y; + } + $surface->quadraticCurveTo( $controlX + $l, $controlY + $t, @@ -385,7 +381,6 @@ class Path extends Shape break; case 'a': - // TODO: optimize this $this->drawArc( $surface, $x + $l, diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Polygon.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Polygon.php similarity index 76% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Polygon.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Polygon.php index 6cef9f62d..e7ca92a1b 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Polygon.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Polygon.php @@ -13,16 +13,25 @@ class Polygon extends Shape public function start($attributes) { $tmp = array(); - preg_match_all('/([\-]*[0-9\.]+)/', $attributes['points'], $tmp); + preg_match_all('/([\-]*[0-9\.]+)/', $attributes['points'], $tmp, PREG_PATTERN_ORDER); $points = $tmp[0]; $count = count($points); + if ($count < 4) { + // nothing to draw + return; + } + $surface = $this->document->getSurface(); list($x, $y) = $points; $surface->moveTo($x, $y); for ($i = 2; $i < $count; $i += 2) { + if ($i + 1 === $count) { + // invalid trailing point + continue; + } $x = $points[$i]; $y = $points[$i + 1]; $surface->lineTo($x, $y); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Polyline.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Polyline.php similarity index 75% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Polyline.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Polyline.php index 68751e1aa..45e2131ec 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Polyline.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Polyline.php @@ -13,16 +13,25 @@ class Polyline extends Shape public function start($attributes) { $tmp = array(); - preg_match_all('/([\-]*[0-9\.]+)/', $attributes['points'], $tmp); + preg_match_all('/([\-]*[0-9\.]+)/', $attributes['points'], $tmp, PREG_PATTERN_ORDER); $points = $tmp[0]; $count = count($points); + if ($count < 4) { + // nothing to draw + return; + } + $surface = $this->document->getSurface(); list($x, $y) = $points; $surface->moveTo($x, $y); for ($i = 2; $i < $count; $i += 2) { + if ($i + 1 === $count) { + // invalid trailing point + continue; + } $x = $points[$i]; $y = $points[$i + 1]; $surface->lineTo($x, $y); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/RadialGradient.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/RadialGradient.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/RadialGradient.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/RadialGradient.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Rect.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Rect.php similarity index 59% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Rect.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Rect.php index 2bff2131b..b5f3f774b 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Rect.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Rect.php @@ -8,6 +8,8 @@ namespace Svg\Tag; +use Svg\Style; + class Rect extends Shape { protected $x = 0; @@ -19,28 +21,21 @@ class Rect extends Shape public function start($attributes) { + $width = $this->document->getWidth(); + $height = $this->document->getHeight(); + if (isset($attributes['x'])) { - $this->x = $attributes['x']; + $this->x = $this->convertSize($attributes['x'], $width); } if (isset($attributes['y'])) { - $this->y = $attributes['y']; + $this->y = $this->convertSize($attributes['y'], $height); } if (isset($attributes['width'])) { - if ('%' === substr($attributes['width'], -1)) { - $factor = substr($attributes['width'], 0, -1) / 100; - $this->width = $this->document->getWidth() * $factor; - } else { - $this->width = $attributes['width']; - } + $this->width = $this->convertSize($attributes['width'], $width); } if (isset($attributes['height'])) { - if ('%' === substr($attributes['height'], -1)) { - $factor = substr($attributes['height'], 0, -1) / 100; - $this->height = $this->document->getHeight() * $factor; - } else { - $this->height = $attributes['height']; - } + $this->height = $this->convertSize($attributes['height'], $height); } if (isset($attributes['rx'])) { diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Shape.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Shape.php similarity index 94% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Shape.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Shape.php index 0a2bfaef5..767e81dbf 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Shape.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Shape.php @@ -38,7 +38,7 @@ class Shape extends AbstractTag if ($fill) { if ($stroke) { - $surface->fillStroke(); + $surface->fillStroke(false); } else { // if (is_string($style->fill)) { // /** @var LinearGradient|RadialGradient $gradient */ @@ -51,7 +51,7 @@ class Shape extends AbstractTag } } elseif ($stroke) { - $surface->stroke(); + $surface->stroke(false); } else { $surface->endPath(); diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Stop.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Stop.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Stop.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Stop.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/StyleTag.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/StyleTag.php similarity index 100% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/StyleTag.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/StyleTag.php diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Text.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Text.php similarity index 83% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Text.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Text.php index 83b5afe6a..80e08a600 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/Text.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/Text.php @@ -8,6 +8,8 @@ namespace Svg\Tag; +use Svg\Style; + class Text extends Shape { protected $x = 0; @@ -16,18 +18,18 @@ class Text extends Shape public function start($attributes) { - $document = $this->document; $height = $this->document->getHeight(); $this->y = $height; if (isset($attributes['x'])) { - $this->x = $attributes['x']; + $width = $this->document->getWidth(); + $this->x = $this->convertSize($attributes['x'], $width); } if (isset($attributes['y'])) { - $this->y = $height - $attributes['y']; + $this->y = $height - $this->convertSize($attributes['y'], $height); } - $document->getSurface()->transform(1, 0, 0, -1, 0, $height); + $this->document->getSurface()->transform(1, 0, 0, -1, 0, $height); } public function end() diff --git a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/UseTag.php b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/UseTag.php similarity index 77% rename from library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/UseTag.php rename to library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/UseTag.php index e5681a13d..c5f00ea9d 100644 --- a/library/vendor/dompdf/lib/php-svg-lib/src/Svg/Tag/UseTag.php +++ b/library/vendor/dompdf/vendor/phenx/php-svg-lib/src/Svg/Tag/UseTag.php @@ -38,7 +38,7 @@ class UseTag extends AbstractTag $document = $this->getDocument(); - $link = $attributes["xlink:href"]; + $link = $attributes["href"] ?? $attributes["xlink:href"]; $this->reference = $document->getDef($link); if ($this->reference) { @@ -69,12 +69,18 @@ class UseTag extends AbstractTag return; } - $attributes = array_merge($this->reference->attributes, $attributes); + $mergedAttributes = $this->reference->attributes; + $attributesToNotMerge = ['x', 'y', 'width', 'height']; + foreach ($attributes as $attrKey => $attrVal) { + if (!in_array($attrKey, $attributesToNotMerge) && !isset($mergedAttributes[$attrKey])) { + $mergedAttributes[$attrKey] = $attrVal; + } + } - $this->reference->handle($attributes); + $this->reference->handle($mergedAttributes); foreach ($this->reference->children as $_child) { - $_attributes = array_merge($_child->attributes, $attributes); + $_attributes = array_merge($_child->attributes, $mergedAttributes); $_child->handle($_attributes); } } diff --git a/library/vendor/dompdf/lib/php-css-parser/CHANGELOG.md b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/CHANGELOG.md similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/CHANGELOG.md rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/CHANGELOG.md diff --git a/library/vendor/dompdf/lib/php-css-parser/LICENSE b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/LICENSE similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/LICENSE rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/LICENSE diff --git a/library/vendor/dompdf/lib/php-css-parser/README.md b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/README.md similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/README.md rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/README.md diff --git a/library/vendor/dompdf/lib/php-css-parser/composer.json b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/composer.json similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/composer.json rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/composer.json diff --git a/library/vendor/dompdf/lib/php-css-parser/src/CSSList/AtRuleBlockList.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/AtRuleBlockList.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/CSSList/AtRuleBlockList.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/AtRuleBlockList.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/CSSList/CSSBlockList.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/CSSBlockList.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/CSSList/CSSBlockList.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/CSSBlockList.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/CSSList/CSSList.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/CSSList.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/CSSList/CSSList.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/CSSList.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/CSSList/Document.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/Document.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/CSSList/Document.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/Document.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/CSSList/KeyFrame.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/KeyFrame.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/CSSList/KeyFrame.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/CSSList/KeyFrame.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Comment/Comment.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Comment/Comment.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Comment/Comment.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Comment/Comment.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Comment/Commentable.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Comment/Commentable.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Comment/Commentable.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Comment/Commentable.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/OutputFormat.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/OutputFormat.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/OutputFormat.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/OutputFormat.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/OutputFormatter.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/OutputFormatter.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/OutputFormatter.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/OutputFormatter.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Parser.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parser.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Parser.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parser.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Parsing/OutputException.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/OutputException.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Parsing/OutputException.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/OutputException.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Parsing/ParserState.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/ParserState.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Parsing/ParserState.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/ParserState.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Parsing/SourceException.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/SourceException.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Parsing/SourceException.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/SourceException.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Parsing/UnexpectedEOFException.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/UnexpectedEOFException.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Parsing/UnexpectedEOFException.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/UnexpectedEOFException.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Parsing/UnexpectedTokenException.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/UnexpectedTokenException.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Parsing/UnexpectedTokenException.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Parsing/UnexpectedTokenException.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Property/AtRule.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/AtRule.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Property/AtRule.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/AtRule.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Property/CSSNamespace.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/CSSNamespace.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Property/CSSNamespace.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/CSSNamespace.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Property/Charset.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/Charset.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Property/Charset.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/Charset.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Property/Import.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/Import.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Property/Import.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/Import.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Property/KeyframeSelector.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/KeyframeSelector.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Property/KeyframeSelector.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/KeyframeSelector.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Property/Selector.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/Selector.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Property/Selector.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Property/Selector.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Renderable.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Renderable.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Renderable.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Renderable.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Rule/Rule.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Rule/Rule.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Rule/Rule.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Rule/Rule.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/RuleSet/AtRuleSet.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/RuleSet/AtRuleSet.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/RuleSet/AtRuleSet.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/RuleSet/AtRuleSet.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/RuleSet/DeclarationBlock.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/RuleSet/DeclarationBlock.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/RuleSet/DeclarationBlock.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/RuleSet/DeclarationBlock.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/RuleSet/RuleSet.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/RuleSet/RuleSet.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/RuleSet/RuleSet.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/RuleSet/RuleSet.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Settings.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Settings.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Settings.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Settings.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/CSSFunction.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CSSFunction.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/CSSFunction.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CSSFunction.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/CSSString.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CSSString.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/CSSString.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CSSString.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/CalcFunction.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CalcFunction.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/CalcFunction.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CalcFunction.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/CalcRuleValueList.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CalcRuleValueList.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/CalcRuleValueList.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/CalcRuleValueList.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/Color.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/Color.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/Color.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/Color.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/LineName.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/LineName.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/LineName.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/LineName.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/PrimitiveValue.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/PrimitiveValue.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/PrimitiveValue.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/PrimitiveValue.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/RuleValueList.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/RuleValueList.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/RuleValueList.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/RuleValueList.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/Size.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/Size.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/Size.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/Size.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/URL.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/URL.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/URL.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/URL.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/Value.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/Value.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/Value.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/Value.php diff --git a/library/vendor/dompdf/lib/php-css-parser/src/Value/ValueList.php b/library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/ValueList.php similarity index 100% rename from library/vendor/dompdf/lib/php-css-parser/src/Value/ValueList.php rename to library/vendor/dompdf/vendor/sabberworm/php-css-parser/src/Value/ValueList.php