aboutsummaryrefslogtreecommitdiffhomepage
path: root/inc/3rdparty/libraries
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas.loeuillet@gmail.com>2013-12-23 02:28:56 -0800
committerNicolas Lœuillet <nicolas.loeuillet@gmail.com>2013-12-23 02:28:56 -0800
commit60fc4f4b1ab37fbfe9021f3fa1395d66a4424ed2 (patch)
tree515c4b9c8286ae363f77722c91acb878151dc386 /inc/3rdparty/libraries
parentcbfd5a1019f47fadefd8490dae9f039ae894298d (diff)
parentda5fc42f615eeb45a702604970f94967507fb432 (diff)
downloadwallabag-1.3.0.tar.gz
wallabag-1.3.0.tar.zst
wallabag-1.3.0.zip
Merge pull request #363 from inthepoche/dev1.3.0
poche 1.3.0
Diffstat (limited to 'inc/3rdparty/libraries')
-rw-r--r--inc/3rdparty/libraries/Zend/Cache.php250
-rw-r--r--inc/3rdparty/libraries/Zend/Cache/Backend.php290
-rw-r--r--inc/3rdparty/libraries/Zend/Cache/Backend/ExtendedInterface.php127
-rw-r--r--inc/3rdparty/libraries/Zend/Cache/Backend/File.php1034
-rw-r--r--inc/3rdparty/libraries/Zend/Cache/Backend/Interface.php99
-rw-r--r--inc/3rdparty/libraries/Zend/Cache/Core.php765
-rw-r--r--inc/3rdparty/libraries/Zend/Cache/Exception.php32
-rw-r--r--inc/3rdparty/libraries/Zend/Exception.php96
-rw-r--r--inc/3rdparty/libraries/content-extractor/ContentExtractor.php728
-rw-r--r--inc/3rdparty/libraries/content-extractor/SiteConfig.php338
-rw-r--r--inc/3rdparty/libraries/feedwriter/FeedItem.php185
-rw-r--r--inc/3rdparty/libraries/feedwriter/FeedWriter.php441
-rw-r--r--inc/3rdparty/libraries/htmLawed/htmLawed.php728
-rw-r--r--inc/3rdparty/libraries/html5/Data.php114
-rw-r--r--inc/3rdparty/libraries/html5/InputStream.php284
-rw-r--r--inc/3rdparty/libraries/html5/Parser.php36
-rw-r--r--inc/3rdparty/libraries/html5/Tokenizer.php2422
-rw-r--r--inc/3rdparty/libraries/html5/TreeBuilder.php3840
-rw-r--r--inc/3rdparty/libraries/html5/named-character-references.ser1
-rw-r--r--inc/3rdparty/libraries/humble-http-agent/CookieJar.php404
-rw-r--r--inc/3rdparty/libraries/humble-http-agent/HumbleHttpAgent.php779
-rw-r--r--inc/3rdparty/libraries/humble-http-agent/RollingCurl.php402
-rw-r--r--inc/3rdparty/libraries/humble-http-agent/SimplePie_HumbleHttpAgent.php79
-rw-r--r--inc/3rdparty/libraries/language-detect/LanguageDetect.php1635
-rw-r--r--inc/3rdparty/libraries/language-detect/Parser.php354
-rw-r--r--inc/3rdparty/libraries/language-detect/lang.dat1
-rw-r--r--inc/3rdparty/libraries/language-detect/unicode_blocks.dat1
-rw-r--r--inc/3rdparty/libraries/readability/JSLikeHTMLElement.php110
-rw-r--r--inc/3rdparty/libraries/readability/Readability.php1138
-rw-r--r--inc/3rdparty/libraries/simplepie/LICENSE.txt26
-rw-r--r--inc/3rdparty/libraries/simplepie/autoloader.php86
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie.php3058
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Author.php157
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Cache.php133
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Base.php114
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/DB.php137
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/File.php173
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Memcache.php183
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/MySQL.php438
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Caption.php210
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Category.php157
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Content/Type/Sniffer.php332
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Copyright.php130
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Core.php57
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Credit.php156
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Decode/HTML/Entities.php617
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Enclosure.php1380
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Exception.php52
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/File.php292
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/HTTP/Parser.php500
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/IRI.php1238
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Item.php2964
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Locator.php372
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Misc.php2247
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Net/IPv6.php276
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Parse/Date.php983
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Parser.php407
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Rating.php129
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Registry.php225
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Restriction.php155
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Sanitize.php549
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/Source.php611
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/XML/Declaration/Parser.php362
-rw-r--r--inc/3rdparty/libraries/simplepie/library/SimplePie/gzdecode.php371
64 files changed, 35990 insertions, 0 deletions
diff --git a/inc/3rdparty/libraries/Zend/Cache.php b/inc/3rdparty/libraries/Zend/Cache.php
new file mode 100644
index 00000000..d28cb559
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache.php
@@ -0,0 +1,250 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Cache.php 24656 2012-02-26 06:02:53Z adamlundrigan $
20 */
21
22
23/**
24 * @package Zend_Cache
25 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
26 * @license http://framework.zend.com/license/new-bsd New BSD License
27 */
28abstract class Zend_Cache
29{
30
31 /**
32 * Standard frontends
33 *
34 * @var array
35 */
36 public static $standardFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
37
38 /**
39 * Standard backends
40 *
41 * @var array
42 */
43 public static $standardBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform',
44 'Xcache', 'TwoLevels', 'WinCache', 'ZendServer_Disk', 'ZendServer_ShMem');
45
46 /**
47 * Standard backends which implement the ExtendedInterface
48 *
49 * @var array
50 */
51 public static $standardExtendedBackends = array('File', 'Apc', 'TwoLevels', 'Memcached', 'Libmemcached', 'Sqlite', 'WinCache');
52
53 /**
54 * Only for backward compatibility (may be removed in next major release)
55 *
56 * @var array
57 * @deprecated
58 */
59 public static $availableFrontends = array('Core', 'Output', 'Class', 'File', 'Function', 'Page');
60
61 /**
62 * Only for backward compatibility (may be removed in next major release)
63 *
64 * @var array
65 * @deprecated
66 */
67 public static $availableBackends = array('File', 'Sqlite', 'Memcached', 'Libmemcached', 'Apc', 'ZendPlatform', 'Xcache', 'WinCache', 'TwoLevels');
68
69 /**
70 * Consts for clean() method
71 */
72 const CLEANING_MODE_ALL = 'all';
73 const CLEANING_MODE_OLD = 'old';
74 const CLEANING_MODE_MATCHING_TAG = 'matchingTag';
75 const CLEANING_MODE_NOT_MATCHING_TAG = 'notMatchingTag';
76 const CLEANING_MODE_MATCHING_ANY_TAG = 'matchingAnyTag';
77
78 /**
79 * Factory
80 *
81 * @param mixed $frontend frontend name (string) or Zend_Cache_Frontend_ object
82 * @param mixed $backend backend name (string) or Zend_Cache_Backend_ object
83 * @param array $frontendOptions associative array of options for the corresponding frontend constructor
84 * @param array $backendOptions associative array of options for the corresponding backend constructor
85 * @param boolean $customFrontendNaming if true, the frontend argument is used as a complete class name ; if false, the frontend argument is used as the end of "Zend_Cache_Frontend_[...]" class name
86 * @param boolean $customBackendNaming if true, the backend argument is used as a complete class name ; if false, the backend argument is used as the end of "Zend_Cache_Backend_[...]" class name
87 * @param boolean $autoload if true, there will no require_once for backend and frontend (useful only for custom backends/frontends)
88 * @throws Zend_Cache_Exception
89 * @return Zend_Cache_Core|Zend_Cache_Frontend
90 */
91 public static function factory($frontend, $backend, $frontendOptions = array(), $backendOptions = array(), $customFrontendNaming = false, $customBackendNaming = false, $autoload = false)
92 {
93 if (is_string($backend)) {
94 $backendObject = self::_makeBackend($backend, $backendOptions, $customBackendNaming, $autoload);
95 } else {
96 if ((is_object($backend)) && (in_array('Zend_Cache_Backend_Interface', class_implements($backend)))) {
97 $backendObject = $backend;
98 } else {
99 self::throwException('backend must be a backend name (string) or an object which implements Zend_Cache_Backend_Interface');
100 }
101 }
102 if (is_string($frontend)) {
103 $frontendObject = self::_makeFrontend($frontend, $frontendOptions, $customFrontendNaming, $autoload);
104 } else {
105 if (is_object($frontend)) {
106 $frontendObject = $frontend;
107 } else {
108 self::throwException('frontend must be a frontend name (string) or an object');
109 }
110 }
111 $frontendObject->setBackend($backendObject);
112 return $frontendObject;
113 }
114
115 /**
116 * Backend Constructor
117 *
118 * @param string $backend
119 * @param array $backendOptions
120 * @param boolean $customBackendNaming
121 * @param boolean $autoload
122 * @return Zend_Cache_Backend
123 */
124 public static function _makeBackend($backend, $backendOptions, $customBackendNaming = false, $autoload = false)
125 {
126 if (!$customBackendNaming) {
127 $backend = self::_normalizeName($backend);
128 }
129 if (in_array($backend, Zend_Cache::$standardBackends)) {
130 // we use a standard backend
131 $backendClass = 'Zend_Cache_Backend_' . $backend;
132 // security controls are explicit
133 require_once realpath(dirname(__FILE__).'/..').DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
134 } else {
135 // we use a custom backend
136 if (!preg_match('~^[\w\\\\]+$~D', $backend)) {
137 Zend_Cache::throwException("Invalid backend name [$backend]");
138 }
139 if (!$customBackendNaming) {
140 // we use this boolean to avoid an API break
141 $backendClass = 'Zend_Cache_Backend_' . $backend;
142 } else {
143 $backendClass = $backend;
144 }
145 if (!$autoload) {
146 $file = str_replace('_', DIRECTORY_SEPARATOR, $backendClass) . '.php';
147 if (!(self::_isReadable($file))) {
148 self::throwException("file $file not found in include_path");
149 }
150 require_once $file;
151 }
152 }
153 return new $backendClass($backendOptions);
154 }
155
156 /**
157 * Frontend Constructor
158 *
159 * @param string $frontend
160 * @param array $frontendOptions
161 * @param boolean $customFrontendNaming
162 * @param boolean $autoload
163 * @return Zend_Cache_Core|Zend_Cache_Frontend
164 */
165 public static function _makeFrontend($frontend, $frontendOptions = array(), $customFrontendNaming = false, $autoload = false)
166 {
167 if (!$customFrontendNaming) {
168 $frontend = self::_normalizeName($frontend);
169 }
170 if (in_array($frontend, self::$standardFrontends)) {
171 // we use a standard frontend
172 // For perfs reasons, with frontend == 'Core', we can interact with the Core itself
173 $frontendClass = 'Zend_Cache_' . ($frontend != 'Core' ? 'Frontend_' : '') . $frontend;
174 // security controls are explicit
175 require_once realpath(dirname(__FILE__).'/..').DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
176 } else {
177 // we use a custom frontend
178 if (!preg_match('~^[\w\\\\]+$~D', $frontend)) {
179 Zend_Cache::throwException("Invalid frontend name [$frontend]");
180 }
181 if (!$customFrontendNaming) {
182 // we use this boolean to avoid an API break
183 $frontendClass = 'Zend_Cache_Frontend_' . $frontend;
184 } else {
185 $frontendClass = $frontend;
186 }
187 if (!$autoload) {
188 $file = str_replace('_', DIRECTORY_SEPARATOR, $frontendClass) . '.php';
189 if (!(self::_isReadable($file))) {
190 self::throwException("file $file not found in include_path");
191 }
192 require_once $file;
193 }
194 }
195 return new $frontendClass($frontendOptions);
196 }
197
198 /**
199 * Throw an exception
200 *
201 * Note : for perf reasons, the "load" of Zend/Cache/Exception is dynamic
202 * @param string $msg Message for the exception
203 * @throws Zend_Cache_Exception
204 */
205 public static function throwException($msg, Exception $e = null)
206 {
207 // For perfs reasons, we use this dynamic inclusion
208 require_once 'Zend/Cache/Exception.php';
209 throw new Zend_Cache_Exception($msg, 0, $e);
210 }
211
212 /**
213 * Normalize frontend and backend names to allow multiple words TitleCased
214 *
215 * @param string $name Name to normalize
216 * @return string
217 */
218 protected static function _normalizeName($name)
219 {
220 $name = ucfirst(strtolower($name));
221 $name = str_replace(array('-', '_', '.'), ' ', $name);
222 $name = ucwords($name);
223 $name = str_replace(' ', '', $name);
224 if (stripos($name, 'ZendServer') === 0) {
225 $name = 'ZendServer_' . substr($name, strlen('ZendServer'));
226 }
227
228 return $name;
229 }
230
231 /**
232 * Returns TRUE if the $filename is readable, or FALSE otherwise.
233 * This function uses the PHP include_path, where PHP's is_readable()
234 * does not.
235 *
236 * Note : this method comes from Zend_Loader (see #ZF-2891 for details)
237 *
238 * @param string $filename
239 * @return boolean
240 */
241 private static function _isReadable($filename)
242 {
243 if (!$fh = @fopen($filename, 'r', true)) {
244 return false;
245 }
246 @fclose($fh);
247 return true;
248 }
249
250}
diff --git a/inc/3rdparty/libraries/Zend/Cache/Backend.php b/inc/3rdparty/libraries/Zend/Cache/Backend.php
new file mode 100644
index 00000000..803fd446
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache/Backend.php
@@ -0,0 +1,290 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @subpackage Zend_Cache_Backend
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: Backend.php 24989 2012-06-21 07:24:13Z mabe $
21 */
22
23
24/**
25 * @package Zend_Cache
26 * @subpackage Zend_Cache_Backend
27 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
28 * @license http://framework.zend.com/license/new-bsd New BSD License
29 */
30class Zend_Cache_Backend
31{
32 /**
33 * Frontend or Core directives
34 *
35 * =====> (int) lifetime :
36 * - Cache lifetime (in seconds)
37 * - If null, the cache is valid forever
38 *
39 * =====> (int) logging :
40 * - if set to true, a logging is activated throw Zend_Log
41 *
42 * @var array directives
43 */
44 protected $_directives = array(
45 'lifetime' => 3600,
46 'logging' => false,
47 'logger' => null
48 );
49
50 /**
51 * Available options
52 *
53 * @var array available options
54 */
55 protected $_options = array();
56
57 /**
58 * Constructor
59 *
60 * @param array $options Associative array of options
61 * @throws Zend_Cache_Exception
62 * @return void
63 */
64 public function __construct(array $options = array())
65 {
66 while (list($name, $value) = each($options)) {
67 $this->setOption($name, $value);
68 }
69 }
70
71 /**
72 * Set the frontend directives
73 *
74 * @param array $directives Assoc of directives
75 * @throws Zend_Cache_Exception
76 * @return void
77 */
78 public function setDirectives($directives)
79 {
80 if (!is_array($directives)) Zend_Cache::throwException('Directives parameter must be an array');
81 while (list($name, $value) = each($directives)) {
82 if (!is_string($name)) {
83 Zend_Cache::throwException("Incorrect option name : $name");
84 }
85 $name = strtolower($name);
86 if (array_key_exists($name, $this->_directives)) {
87 $this->_directives[$name] = $value;
88 }
89
90 }
91
92 $this->_loggerSanity();
93 }
94
95 /**
96 * Set an option
97 *
98 * @param string $name
99 * @param mixed $value
100 * @throws Zend_Cache_Exception
101 * @return void
102 */
103 public function setOption($name, $value)
104 {
105 if (!is_string($name)) {
106 Zend_Cache::throwException("Incorrect option name : $name");
107 }
108 $name = strtolower($name);
109 if (array_key_exists($name, $this->_options)) {
110 $this->_options[$name] = $value;
111 }
112 }
113
114 /**
115 * Returns an option
116 *
117 * @param string $name Optional, the options name to return
118 * @throws Zend_Cache_Exceptions
119 * @return mixed
120 */
121 public function getOption($name)
122 {
123 $name = strtolower($name);
124
125 if (array_key_exists($name, $this->_options)) {
126 return $this->_options[$name];
127 }
128
129 if (array_key_exists($name, $this->_directives)) {
130 return $this->_directives[$name];
131 }
132
133 Zend_Cache::throwException("Incorrect option name : {$name}");
134 }
135
136 /**
137 * Get the life time
138 *
139 * if $specificLifetime is not false, the given specific life time is used
140 * else, the global lifetime is used
141 *
142 * @param int $specificLifetime
143 * @return int Cache life time
144 */
145 public function getLifetime($specificLifetime)
146 {
147 if ($specificLifetime === false) {
148 return $this->_directives['lifetime'];
149 }
150 return $specificLifetime;
151 }
152
153 /**
154 * Return true if the automatic cleaning is available for the backend
155 *
156 * DEPRECATED : use getCapabilities() instead
157 *
158 * @deprecated
159 * @return boolean
160 */
161 public function isAutomaticCleaningAvailable()
162 {
163 return true;
164 }
165
166 /**
167 * Determine system TMP directory and detect if we have read access
168 *
169 * inspired from Zend_File_Transfer_Adapter_Abstract
170 *
171 * @return string
172 * @throws Zend_Cache_Exception if unable to determine directory
173 */
174 public function getTmpDir()
175 {
176 $tmpdir = array();
177 foreach (array($_ENV, $_SERVER) as $tab) {
178 foreach (array('TMPDIR', 'TEMP', 'TMP', 'windir', 'SystemRoot') as $key) {
179 if (isset($tab[$key]) && is_string($tab[$key])) {
180 if (($key == 'windir') or ($key == 'SystemRoot')) {
181 $dir = realpath($tab[$key] . '\\temp');
182 } else {
183 $dir = realpath($tab[$key]);
184 }
185 if ($this->_isGoodTmpDir($dir)) {
186 return $dir;
187 }
188 }
189 }
190 }
191 $upload = ini_get('upload_tmp_dir');
192 if ($upload) {
193 $dir = realpath($upload);
194 if ($this->_isGoodTmpDir($dir)) {
195 return $dir;
196 }
197 }
198 if (function_exists('sys_get_temp_dir')) {
199 $dir = sys_get_temp_dir();
200 if ($this->_isGoodTmpDir($dir)) {
201 return $dir;
202 }
203 }
204 // Attemp to detect by creating a temporary file
205 $tempFile = tempnam(md5(uniqid(rand(), TRUE)), '');
206 if ($tempFile) {
207 $dir = realpath(dirname($tempFile));
208 unlink($tempFile);
209 if ($this->_isGoodTmpDir($dir)) {
210 return $dir;
211 }
212 }
213 if ($this->_isGoodTmpDir('/tmp')) {
214 return '/tmp';
215 }
216 if ($this->_isGoodTmpDir('\\temp')) {
217 return '\\temp';
218 }
219 Zend_Cache::throwException('Could not determine temp directory, please specify a cache_dir manually');
220 }
221
222 /**
223 * Verify if the given temporary directory is readable and writable
224 *
225 * @param string $dir temporary directory
226 * @return boolean true if the directory is ok
227 */
228 protected function _isGoodTmpDir($dir)
229 {
230 if (is_readable($dir)) {
231 if (is_writable($dir)) {
232 return true;
233 }
234 }
235 return false;
236 }
237
238 /**
239 * Make sure if we enable logging that the Zend_Log class
240 * is available.
241 * Create a default log object if none is set.
242 *
243 * @throws Zend_Cache_Exception
244 * @return void
245 */
246 protected function _loggerSanity()
247 {
248 if (!isset($this->_directives['logging']) || !$this->_directives['logging']) {
249 return;
250 }
251
252 if (isset($this->_directives['logger'])) {
253 if ($this->_directives['logger'] instanceof Zend_Log) {
254 return;
255 }
256 Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
257 }
258
259 // Create a default logger to the standard output stream
260 require_once 'Zend/Log.php';
261 require_once 'Zend/Log/Writer/Stream.php';
262 require_once 'Zend/Log/Filter/Priority.php';
263 $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
264 $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<='));
265 $this->_directives['logger'] = $logger;
266 }
267
268 /**
269 * Log a message at the WARN (4) priority.
270 *
271 * @param string $message
272 * @throws Zend_Cache_Exception
273 * @return void
274 */
275 protected function _log($message, $priority = 4)
276 {
277 if (!$this->_directives['logging']) {
278 return;
279 }
280
281 if (!isset($this->_directives['logger'])) {
282 Zend_Cache::throwException('Logging is enabled but logger is not set.');
283 }
284 $logger = $this->_directives['logger'];
285 if (!$logger instanceof Zend_Log) {
286 Zend_Cache::throwException('Logger object is not an instance of Zend_Log class.');
287 }
288 $logger->log($message, $priority);
289 }
290}
diff --git a/inc/3rdparty/libraries/Zend/Cache/Backend/ExtendedInterface.php b/inc/3rdparty/libraries/Zend/Cache/Backend/ExtendedInterface.php
new file mode 100644
index 00000000..c192baaf
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache/Backend/ExtendedInterface.php
@@ -0,0 +1,127 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @subpackage Zend_Cache_Backend
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: ExtendedInterface.php 24593 2012-01-05 20:35:02Z matthew $
21 */
22
23/**
24 * @see Zend_Cache_Backend_Interface
25 */
26//require_once 'Zend/Cache/Backend/Interface.php';
27require_once dirname(__FILE__).'/Interface.php';
28
29/**
30 * @package Zend_Cache
31 * @subpackage Zend_Cache_Backend
32 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
33 * @license http://framework.zend.com/license/new-bsd New BSD License
34 */
35interface Zend_Cache_Backend_ExtendedInterface extends Zend_Cache_Backend_Interface
36{
37
38 /**
39 * Return an array of stored cache ids
40 *
41 * @return array array of stored cache ids (string)
42 */
43 public function getIds();
44
45 /**
46 * Return an array of stored tags
47 *
48 * @return array array of stored tags (string)
49 */
50 public function getTags();
51
52 /**
53 * Return an array of stored cache ids which match given tags
54 *
55 * In case of multiple tags, a logical AND is made between tags
56 *
57 * @param array $tags array of tags
58 * @return array array of matching cache ids (string)
59 */
60 public function getIdsMatchingTags($tags = array());
61
62 /**
63 * Return an array of stored cache ids which don't match given tags
64 *
65 * In case of multiple tags, a logical OR is made between tags
66 *
67 * @param array $tags array of tags
68 * @return array array of not matching cache ids (string)
69 */
70 public function getIdsNotMatchingTags($tags = array());
71
72 /**
73 * Return an array of stored cache ids which match any given tags
74 *
75 * In case of multiple tags, a logical AND is made between tags
76 *
77 * @param array $tags array of tags
78 * @return array array of any matching cache ids (string)
79 */
80 public function getIdsMatchingAnyTags($tags = array());
81
82 /**
83 * Return the filling percentage of the backend storage
84 *
85 * @return int integer between 0 and 100
86 */
87 public function getFillingPercentage();
88
89 /**
90 * Return an array of metadatas for the given cache id
91 *
92 * The array must include these keys :
93 * - expire : the expire timestamp
94 * - tags : a string array of tags
95 * - mtime : timestamp of last modification time
96 *
97 * @param string $id cache id
98 * @return array array of metadatas (false if the cache id is not found)
99 */
100 public function getMetadatas($id);
101
102 /**
103 * Give (if possible) an extra lifetime to the given cache id
104 *
105 * @param string $id cache id
106 * @param int $extraLifetime
107 * @return boolean true if ok
108 */
109 public function touch($id, $extraLifetime);
110
111 /**
112 * Return an associative array of capabilities (booleans) of the backend
113 *
114 * The array must include these keys :
115 * - automatic_cleaning (is automating cleaning necessary)
116 * - tags (are tags supported)
117 * - expired_read (is it possible to read expired cache records
118 * (for doNotTestCacheValidity option for example))
119 * - priority does the backend deal with priority when saving
120 * - infinite_lifetime (is infinite lifetime can work with this backend)
121 * - get_list (is it possible to get the list of cache ids and the complete list of tags)
122 *
123 * @return array associative of with capabilities
124 */
125 public function getCapabilities();
126
127}
diff --git a/inc/3rdparty/libraries/Zend/Cache/Backend/File.php b/inc/3rdparty/libraries/Zend/Cache/Backend/File.php
new file mode 100644
index 00000000..5affbcb3
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache/Backend/File.php
@@ -0,0 +1,1034 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @subpackage Zend_Cache_Backend
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: File.php 24844 2012-05-31 19:01:36Z rob $
21 */
22
23/**
24 * @see Zend_Cache_Backend_Interface
25 */
26//require_once 'Zend/Cache/Backend/ExtendedInterface.php';
27require_once dirname(__FILE__).'/ExtendedInterface.php';
28
29/**
30 * @see Zend_Cache_Backend
31 */
32//require_once 'Zend/Cache/Backend.php';
33require_once realpath(dirname(__FILE__).'/..').DIRECTORY_SEPARATOR.'Backend.php';
34
35
36
37/**
38 * @package Zend_Cache
39 * @subpackage Zend_Cache_Backend
40 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
41 * @license http://framework.zend.com/license/new-bsd New BSD License
42 */
43class Zend_Cache_Backend_File extends Zend_Cache_Backend implements Zend_Cache_Backend_ExtendedInterface
44{
45 /**
46 * Available options
47 *
48 * =====> (string) cache_dir :
49 * - Directory where to put the cache files
50 *
51 * =====> (boolean) file_locking :
52 * - Enable / disable file_locking
53 * - Can avoid cache corruption under bad circumstances but it doesn't work on multithread
54 * webservers and on NFS filesystems for example
55 *
56 * =====> (boolean) read_control :
57 * - Enable / disable read control
58 * - If enabled, a control key is embeded in cache file and this key is compared with the one
59 * calculated after the reading.
60 *
61 * =====> (string) read_control_type :
62 * - Type of read control (only if read control is enabled). Available values are :
63 * 'md5' for a md5 hash control (best but slowest)
64 * 'crc32' for a crc32 hash control (lightly less safe but faster, better choice)
65 * 'adler32' for an adler32 hash control (excellent choice too, faster than crc32)
66 * 'strlen' for a length only test (fastest)
67 *
68 * =====> (int) hashed_directory_level :
69 * - Hashed directory level
70 * - Set the hashed directory structure level. 0 means "no hashed directory
71 * structure", 1 means "one level of directory", 2 means "two levels"...
72 * This option can speed up the cache only when you have many thousands of
73 * cache file. Only specific benchs can help you to choose the perfect value
74 * for you. Maybe, 1 or 2 is a good start.
75 *
76 * =====> (int) hashed_directory_umask :
77 * - deprecated
78 * - Permissions for hashed directory structure
79 *
80 * =====> (int) hashed_directory_perm :
81 * - Permissions for hashed directory structure
82 *
83 * =====> (string) file_name_prefix :
84 * - prefix for cache files
85 * - be really carefull with this option because a too generic value in a system cache dir
86 * (like /tmp) can cause disasters when cleaning the cache
87 *
88 * =====> (int) cache_file_umask :
89 * - deprecated
90 * - Permissions for cache files
91 *
92 * =====> (int) cache_file_perm :
93 * - Permissions for cache files
94 *
95 * =====> (int) metatadatas_array_max_size :
96 * - max size for the metadatas array (don't change this value unless you
97 * know what you are doing)
98 *
99 * @var array available options
100 */
101 protected $_options = array(
102 'cache_dir' => null,
103 'file_locking' => true,
104 'read_control' => true,
105 'read_control_type' => 'crc32',
106 'hashed_directory_level' => 0,
107 'hashed_directory_perm' => 0700,
108 'file_name_prefix' => 'zend_cache',
109 'cache_file_perm' => 0600,
110 'metadatas_array_max_size' => 100
111 );
112
113 /**
114 * Array of metadatas (each item is an associative array)
115 *
116 * @var array
117 */
118 protected $_metadatasArray = array();
119
120
121 /**
122 * Constructor
123 *
124 * @param array $options associative array of options
125 * @throws Zend_Cache_Exception
126 * @return void
127 */
128 public function __construct(array $options = array())
129 {
130 parent::__construct($options);
131 if ($this->_options['cache_dir'] !== null) { // particular case for this option
132 $this->setCacheDir($this->_options['cache_dir']);
133 } else {
134 $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
135 }
136 if (isset($this->_options['file_name_prefix'])) { // particular case for this option
137 if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) {
138 Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]');
139 }
140 }
141 if ($this->_options['metadatas_array_max_size'] < 10) {
142 Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
143 }
144
145 if (isset($options['hashed_directory_umask'])) {
146 // See #ZF-12047
147 trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE);
148 if (!isset($options['hashed_directory_perm'])) {
149 $options['hashed_directory_perm'] = $options['hashed_directory_umask'];
150 }
151 }
152 if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) {
153 // See #ZF-4422
154 $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']);
155 }
156
157 if (isset($options['cache_file_umask'])) {
158 // See #ZF-12047
159 trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE);
160 if (!isset($options['cache_file_perm'])) {
161 $options['cache_file_perm'] = $options['cache_file_umask'];
162 }
163 }
164 if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) {
165 // See #ZF-4422
166 $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']);
167 }
168 }
169
170 /**
171 * Set the cache_dir (particular case of setOption() method)
172 *
173 * @param string $value
174 * @param boolean $trailingSeparator If true, add a trailing separator is necessary
175 * @throws Zend_Cache_Exception
176 * @return void
177 */
178 public function setCacheDir($value, $trailingSeparator = true)
179 {
180 if (!is_dir($value)) {
181 Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value));
182 }
183 if (!is_writable($value)) {
184 Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value));
185 }
186 if ($trailingSeparator) {
187 // add a trailing DIRECTORY_SEPARATOR if necessary
188 $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR;
189 }
190 $this->_options['cache_dir'] = $value;
191 }
192
193 /**
194 * Test if a cache is available for the given id and (if yes) return it (false else)
195 *
196 * @param string $id cache id
197 * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
198 * @return string|false cached datas
199 */
200 public function load($id, $doNotTestCacheValidity = false)
201 {
202 if (!($this->_test($id, $doNotTestCacheValidity))) {
203 // The cache is not hit !
204 return false;
205 }
206 $metadatas = $this->_getMetadatas($id);
207 $file = $this->_file($id);
208 $data = $this->_fileGetContents($file);
209 if ($this->_options['read_control']) {
210 $hashData = $this->_hash($data, $this->_options['read_control_type']);
211 $hashControl = $metadatas['hash'];
212 if ($hashData != $hashControl) {
213 // Problem detected by the read control !
214 $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
215 $this->remove($id);
216 return false;
217 }
218 }
219 return $data;
220 }
221
222 /**
223 * Test if a cache is available or not (for the given id)
224 *
225 * @param string $id cache id
226 * @return mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
227 */
228 public function test($id)
229 {
230 clearstatcache();
231 return $this->_test($id, false);
232 }
233
234 /**
235 * Save some string datas into a cache record
236 *
237 * Note : $data is always "string" (serialization is done by the
238 * core not by the backend)
239 *
240 * @param string $data Datas to cache
241 * @param string $id Cache id
242 * @param array $tags Array of strings, the cache record will be tagged by each string entry
243 * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
244 * @return boolean true if no problem
245 */
246 public function save($data, $id, $tags = array(), $specificLifetime = false)
247 {
248 clearstatcache();
249 $file = $this->_file($id);
250 $path = $this->_path($id);
251 if ($this->_options['hashed_directory_level'] > 0) {
252 if (!is_writable($path)) {
253 // maybe, we just have to build the directory structure
254 $this->_recursiveMkdirAndChmod($id);
255 }
256 if (!is_writable($path)) {
257 return false;
258 }
259 }
260 if ($this->_options['read_control']) {
261 $hash = $this->_hash($data, $this->_options['read_control_type']);
262 } else {
263 $hash = '';
264 }
265 $metadatas = array(
266 'hash' => $hash,
267 'mtime' => time(),
268 'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
269 'tags' => $tags
270 );
271 $res = $this->_setMetadatas($id, $metadatas);
272 if (!$res) {
273 $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
274 return false;
275 }
276 $res = $this->_filePutContents($file, $data);
277 return $res;
278 }
279
280 /**
281 * Remove a cache record
282 *
283 * @param string $id cache id
284 * @return boolean true if no problem
285 */
286 public function remove($id)
287 {
288 $file = $this->_file($id);
289 $boolRemove = $this->_remove($file);
290 $boolMetadata = $this->_delMetadatas($id);
291 return $boolMetadata && $boolRemove;
292 }
293
294 /**
295 * Clean some cache records
296 *
297 * Available modes are :
298 *
299 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
300 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
301 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
302 * ($tags can be an array of strings or a single string)
303 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
304 * ($tags can be an array of strings or a single string)
305 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
306 * ($tags can be an array of strings or a single string)
307 *
308 * @param string $mode clean mode
309 * @param tags array $tags array of tags
310 * @return boolean true if no problem
311 */
312 public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
313 {
314 // We use this protected method to hide the recursive stuff
315 clearstatcache();
316 return $this->_clean($this->_options['cache_dir'], $mode, $tags);
317 }
318
319 /**
320 * Return an array of stored cache ids
321 *
322 * @return array array of stored cache ids (string)
323 */
324 public function getIds()
325 {
326 return $this->_get($this->_options['cache_dir'], 'ids', array());
327 }
328
329 /**
330 * Return an array of stored tags
331 *
332 * @return array array of stored tags (string)
333 */
334 public function getTags()
335 {
336 return $this->_get($this->_options['cache_dir'], 'tags', array());
337 }
338
339 /**
340 * Return an array of stored cache ids which match given tags
341 *
342 * In case of multiple tags, a logical AND is made between tags
343 *
344 * @param array $tags array of tags
345 * @return array array of matching cache ids (string)
346 */
347 public function getIdsMatchingTags($tags = array())
348 {
349 return $this->_get($this->_options['cache_dir'], 'matching', $tags);
350 }
351
352 /**
353 * Return an array of stored cache ids which don't match given tags
354 *
355 * In case of multiple tags, a logical OR is made between tags
356 *
357 * @param array $tags array of tags
358 * @return array array of not matching cache ids (string)
359 */
360 public function getIdsNotMatchingTags($tags = array())
361 {
362 return $this->_get($this->_options['cache_dir'], 'notMatching', $tags);
363 }
364
365 /**
366 * Return an array of stored cache ids which match any given tags
367 *
368 * In case of multiple tags, a logical AND is made between tags
369 *
370 * @param array $tags array of tags
371 * @return array array of any matching cache ids (string)
372 */
373 public function getIdsMatchingAnyTags($tags = array())
374 {
375 return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags);
376 }
377
378 /**
379 * Return the filling percentage of the backend storage
380 *
381 * @throws Zend_Cache_Exception
382 * @return int integer between 0 and 100
383 */
384 public function getFillingPercentage()
385 {
386 $free = disk_free_space($this->_options['cache_dir']);
387 $total = disk_total_space($this->_options['cache_dir']);
388 if ($total == 0) {
389 Zend_Cache::throwException('can\'t get disk_total_space');
390 } else {
391 if ($free >= $total) {
392 return 100;
393 }
394 return ((int) (100. * ($total - $free) / $total));
395 }
396 }
397
398 /**
399 * Return an array of metadatas for the given cache id
400 *
401 * The array must include these keys :
402 * - expire : the expire timestamp
403 * - tags : a string array of tags
404 * - mtime : timestamp of last modification time
405 *
406 * @param string $id cache id
407 * @return array array of metadatas (false if the cache id is not found)
408 */
409 public function getMetadatas($id)
410 {
411 $metadatas = $this->_getMetadatas($id);
412 if (!$metadatas) {
413 return false;
414 }
415 if (time() > $metadatas['expire']) {
416 return false;
417 }
418 return array(
419 'expire' => $metadatas['expire'],
420 'tags' => $metadatas['tags'],
421 'mtime' => $metadatas['mtime']
422 );
423 }
424
425 /**
426 * Give (if possible) an extra lifetime to the given cache id
427 *
428 * @param string $id cache id
429 * @param int $extraLifetime
430 * @return boolean true if ok
431 */
432 public function touch($id, $extraLifetime)
433 {
434 $metadatas = $this->_getMetadatas($id);
435 if (!$metadatas) {
436 return false;
437 }
438 if (time() > $metadatas['expire']) {
439 return false;
440 }
441 $newMetadatas = array(
442 'hash' => $metadatas['hash'],
443 'mtime' => time(),
444 'expire' => $metadatas['expire'] + $extraLifetime,
445 'tags' => $metadatas['tags']
446 );
447 $res = $this->_setMetadatas($id, $newMetadatas);
448 if (!$res) {
449 return false;
450 }
451 return true;
452 }
453
454 /**
455 * Return an associative array of capabilities (booleans) of the backend
456 *
457 * The array must include these keys :
458 * - automatic_cleaning (is automating cleaning necessary)
459 * - tags (are tags supported)
460 * - expired_read (is it possible to read expired cache records
461 * (for doNotTestCacheValidity option for example))
462 * - priority does the backend deal with priority when saving
463 * - infinite_lifetime (is infinite lifetime can work with this backend)
464 * - get_list (is it possible to get the list of cache ids and the complete list of tags)
465 *
466 * @return array associative of with capabilities
467 */
468 public function getCapabilities()
469 {
470 return array(
471 'automatic_cleaning' => true,
472 'tags' => true,
473 'expired_read' => true,
474 'priority' => false,
475 'infinite_lifetime' => true,
476 'get_list' => true
477 );
478 }
479
480 /**
481 * PUBLIC METHOD FOR UNIT TESTING ONLY !
482 *
483 * Force a cache record to expire
484 *
485 * @param string $id cache id
486 */
487 public function ___expire($id)
488 {
489 $metadatas = $this->_getMetadatas($id);
490 if ($metadatas) {
491 $metadatas['expire'] = 1;
492 $this->_setMetadatas($id, $metadatas);
493 }
494 }
495
496 /**
497 * Get a metadatas record
498 *
499 * @param string $id Cache id
500 * @return array|false Associative array of metadatas
501 */
502 protected function _getMetadatas($id)
503 {
504 if (isset($this->_metadatasArray[$id])) {
505 return $this->_metadatasArray[$id];
506 } else {
507 $metadatas = $this->_loadMetadatas($id);
508 if (!$metadatas) {
509 return false;
510 }
511 $this->_setMetadatas($id, $metadatas, false);
512 return $metadatas;
513 }
514 }
515
516 /**
517 * Set a metadatas record
518 *
519 * @param string $id Cache id
520 * @param array $metadatas Associative array of metadatas
521 * @param boolean $save optional pass false to disable saving to file
522 * @return boolean True if no problem
523 */
524 protected function _setMetadatas($id, $metadatas, $save = true)
525 {
526 if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
527 $n = (int) ($this->_options['metadatas_array_max_size'] / 10);
528 $this->_metadatasArray = array_slice($this->_metadatasArray, $n);
529 }
530 if ($save) {
531 $result = $this->_saveMetadatas($id, $metadatas);
532 if (!$result) {
533 return false;
534 }
535 }
536 $this->_metadatasArray[$id] = $metadatas;
537 return true;
538 }
539
540 /**
541 * Drop a metadata record
542 *
543 * @param string $id Cache id
544 * @return boolean True if no problem
545 */
546 protected function _delMetadatas($id)
547 {
548 if (isset($this->_metadatasArray[$id])) {
549 unset($this->_metadatasArray[$id]);
550 }
551 $file = $this->_metadatasFile($id);
552 return $this->_remove($file);
553 }
554
555 /**
556 * Clear the metadatas array
557 *
558 * @return void
559 */
560 protected function _cleanMetadatas()
561 {
562 $this->_metadatasArray = array();
563 }
564
565 /**
566 * Load metadatas from disk
567 *
568 * @param string $id Cache id
569 * @return array|false Metadatas associative array
570 */
571 protected function _loadMetadatas($id)
572 {
573 $file = $this->_metadatasFile($id);
574 $result = $this->_fileGetContents($file);
575 if (!$result) {
576 return false;
577 }
578 $tmp = @unserialize($result);
579 return $tmp;
580 }
581
582 /**
583 * Save metadatas to disk
584 *
585 * @param string $id Cache id
586 * @param array $metadatas Associative array
587 * @return boolean True if no problem
588 */
589 protected function _saveMetadatas($id, $metadatas)
590 {
591 $file = $this->_metadatasFile($id);
592 $result = $this->_filePutContents($file, serialize($metadatas));
593 if (!$result) {
594 return false;
595 }
596 return true;
597 }
598
599 /**
600 * Make and return a file name (with path) for metadatas
601 *
602 * @param string $id Cache id
603 * @return string Metadatas file name (with path)
604 */
605 protected function _metadatasFile($id)
606 {
607 $path = $this->_path($id);
608 $fileName = $this->_idToFileName('internal-metadatas---' . $id);
609 return $path . $fileName;
610 }
611
612 /**
613 * Check if the given filename is a metadatas one
614 *
615 * @param string $fileName File name
616 * @return boolean True if it's a metadatas one
617 */
618 protected function _isMetadatasFile($fileName)
619 {
620 $id = $this->_fileNameToId($fileName);
621 if (substr($id, 0, 21) == 'internal-metadatas---') {
622 return true;
623 } else {
624 return false;
625 }
626 }
627
628 /**
629 * Remove a file
630 *
631 * If we can't remove the file (because of locks or any problem), we will touch
632 * the file to invalidate it
633 *
634 * @param string $file Complete file path
635 * @return boolean True if ok
636 */
637 protected function _remove($file)
638 {
639 if (!is_file($file)) {
640 return false;
641 }
642 if (!@unlink($file)) {
643 # we can't remove the file (because of locks or any problem)
644 $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
645 return false;
646 }
647 return true;
648 }
649
650 /**
651 * Clean some cache records (protected method used for recursive stuff)
652 *
653 * Available modes are :
654 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
655 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
656 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
657 * ($tags can be an array of strings or a single string)
658 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
659 * ($tags can be an array of strings or a single string)
660 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
661 * ($tags can be an array of strings or a single string)
662 *
663 * @param string $dir Directory to clean
664 * @param string $mode Clean mode
665 * @param array $tags Array of tags
666 * @throws Zend_Cache_Exception
667 * @return boolean True if no problem
668 */
669 protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
670 {
671 if (!is_dir($dir)) {
672 return false;
673 }
674 $result = true;
675 $prefix = $this->_options['file_name_prefix'];
676 $glob = @glob($dir . $prefix . '--*');
677 if ($glob === false) {
678 // On some systems it is impossible to distinguish between empty match and an error.
679 return true;
680 }
681 foreach ($glob as $file) {
682 if (is_file($file)) {
683 $fileName = basename($file);
684 if ($this->_isMetadatasFile($fileName)) {
685 // in CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files
686 if ($mode != Zend_Cache::CLEANING_MODE_ALL) {
687 continue;
688 }
689 }
690 $id = $this->_fileNameToId($fileName);
691 $metadatas = $this->_getMetadatas($id);
692 if ($metadatas === FALSE) {
693 $metadatas = array('expire' => 1, 'tags' => array());
694 }
695 switch ($mode) {
696 case Zend_Cache::CLEANING_MODE_ALL:
697 $res = $this->remove($id);
698 if (!$res) {
699 // in this case only, we accept a problem with the metadatas file drop
700 $res = $this->_remove($file);
701 }
702 $result = $result && $res;
703 break;
704 case Zend_Cache::CLEANING_MODE_OLD:
705 if (time() > $metadatas['expire']) {
706 $result = $this->remove($id) && $result;
707 }
708 break;
709 case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
710 $matching = true;
711 foreach ($tags as $tag) {
712 if (!in_array($tag, $metadatas['tags'])) {
713 $matching = false;
714 break;
715 }
716 }
717 if ($matching) {
718 $result = $this->remove($id) && $result;
719 }
720 break;
721 case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
722 $matching = false;
723 foreach ($tags as $tag) {
724 if (in_array($tag, $metadatas['tags'])) {
725 $matching = true;
726 break;
727 }
728 }
729 if (!$matching) {
730 $result = $this->remove($id) && $result;
731 }
732 break;
733 case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
734 $matching = false;
735 foreach ($tags as $tag) {
736 if (in_array($tag, $metadatas['tags'])) {
737 $matching = true;
738 break;
739 }
740 }
741 if ($matching) {
742 $result = $this->remove($id) && $result;
743 }
744 break;
745 default:
746 Zend_Cache::throwException('Invalid mode for clean() method');
747 break;
748 }
749 }
750 if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
751 // Recursive call
752 $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result;
753 if ($mode == Zend_Cache::CLEANING_MODE_ALL) {
754 // we try to drop the structure too
755 @rmdir($file);
756 }
757 }
758 }
759 return $result;
760 }
761
762 protected function _get($dir, $mode, $tags = array())
763 {
764 if (!is_dir($dir)) {
765 return false;
766 }
767 $result = array();
768 $prefix = $this->_options['file_name_prefix'];
769 $glob = @glob($dir . $prefix . '--*');
770 if ($glob === false) {
771 // On some systems it is impossible to distinguish between empty match and an error.
772 return array();
773 }
774 foreach ($glob as $file) {
775 if (is_file($file)) {
776 $fileName = basename($file);
777 $id = $this->_fileNameToId($fileName);
778 $metadatas = $this->_getMetadatas($id);
779 if ($metadatas === FALSE) {
780 continue;
781 }
782 if (time() > $metadatas['expire']) {
783 continue;
784 }
785 switch ($mode) {
786 case 'ids':
787 $result[] = $id;
788 break;
789 case 'tags':
790 $result = array_unique(array_merge($result, $metadatas['tags']));
791 break;
792 case 'matching':
793 $matching = true;
794 foreach ($tags as $tag) {
795 if (!in_array($tag, $metadatas['tags'])) {
796 $matching = false;
797 break;
798 }
799 }
800 if ($matching) {
801 $result[] = $id;
802 }
803 break;
804 case 'notMatching':
805 $matching = false;
806 foreach ($tags as $tag) {
807 if (in_array($tag, $metadatas['tags'])) {
808 $matching = true;
809 break;
810 }
811 }
812 if (!$matching) {
813 $result[] = $id;
814 }
815 break;
816 case 'matchingAny':
817 $matching = false;
818 foreach ($tags as $tag) {
819 if (in_array($tag, $metadatas['tags'])) {
820 $matching = true;
821 break;
822 }
823 }
824 if ($matching) {
825 $result[] = $id;
826 }
827 break;
828 default:
829 Zend_Cache::throwException('Invalid mode for _get() method');
830 break;
831 }
832 }
833 if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
834 // Recursive call
835 $recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags);
836 if ($recursiveRs === false) {
837 $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"');
838 } else {
839 $result = array_unique(array_merge($result, $recursiveRs));
840 }
841 }
842 }
843 return array_unique($result);
844 }
845
846 /**
847 * Compute & return the expire time
848 *
849 * @return int expire time (unix timestamp)
850 */
851 protected function _expireTime($lifetime)
852 {
853 if ($lifetime === null) {
854 return 9999999999;
855 }
856 return time() + $lifetime;
857 }
858
859 /**
860 * Make a control key with the string containing datas
861 *
862 * @param string $data Data
863 * @param string $controlType Type of control 'md5', 'crc32' or 'strlen'
864 * @throws Zend_Cache_Exception
865 * @return string Control key
866 */
867 protected function _hash($data, $controlType)
868 {
869 switch ($controlType) {
870 case 'md5':
871 return md5($data);
872 case 'crc32':
873 return crc32($data);
874 case 'strlen':
875 return strlen($data);
876 case 'adler32':
877 return hash('adler32', $data);
878 default:
879 Zend_Cache::throwException("Incorrect hash function : $controlType");
880 }
881 }
882
883 /**
884 * Transform a cache id into a file name and return it
885 *
886 * @param string $id Cache id
887 * @return string File name
888 */
889 protected function _idToFileName($id)
890 {
891 $prefix = $this->_options['file_name_prefix'];
892 $result = $prefix . '---' . $id;
893 return $result;
894 }
895
896 /**
897 * Make and return a file name (with path)
898 *
899 * @param string $id Cache id
900 * @return string File name (with path)
901 */
902 protected function _file($id)
903 {
904 $path = $this->_path($id);
905 $fileName = $this->_idToFileName($id);
906 return $path . $fileName;
907 }
908
909 /**
910 * Return the complete directory path of a filename (including hashedDirectoryStructure)
911 *
912 * @param string $id Cache id
913 * @param boolean $parts if true, returns array of directory parts instead of single string
914 * @return string Complete directory path
915 */
916 protected function _path($id, $parts = false)
917 {
918 $partsArray = array();
919 $root = $this->_options['cache_dir'];
920 $prefix = $this->_options['file_name_prefix'];
921 if ($this->_options['hashed_directory_level']>0) {
922 $hash = hash('adler32', $id);
923 for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) {
924 $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR;
925 $partsArray[] = $root;
926 }
927 }
928 if ($parts) {
929 return $partsArray;
930 } else {
931 return $root;
932 }
933 }
934
935 /**
936 * Make the directory strucuture for the given id
937 *
938 * @param string $id cache id
939 * @return boolean true
940 */
941 protected function _recursiveMkdirAndChmod($id)
942 {
943 if ($this->_options['hashed_directory_level'] <=0) {
944 return true;
945 }
946 $partsArray = $this->_path($id, true);
947 foreach ($partsArray as $part) {
948 if (!is_dir($part)) {
949 @mkdir($part, $this->_options['hashed_directory_perm']);
950 @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations)
951 }
952 }
953 return true;
954 }
955
956 /**
957 * Test if the given cache id is available (and still valid as a cache record)
958 *
959 * @param string $id Cache id
960 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
961 * @return boolean|mixed false (a cache is not available) or "last modified" timestamp (int) of the available cache record
962 */
963 protected function _test($id, $doNotTestCacheValidity)
964 {
965 $metadatas = $this->_getMetadatas($id);
966 if (!$metadatas) {
967 return false;
968 }
969 if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
970 return $metadatas['mtime'];
971 }
972 return false;
973 }
974
975 /**
976 * Return the file content of the given file
977 *
978 * @param string $file File complete path
979 * @return string File content (or false if problem)
980 */
981 protected function _fileGetContents($file)
982 {
983 $result = false;
984 if (!is_file($file)) {
985 return false;
986 }
987 $f = @fopen($file, 'rb');
988 if ($f) {
989 if ($this->_options['file_locking']) @flock($f, LOCK_SH);
990 $result = stream_get_contents($f);
991 if ($this->_options['file_locking']) @flock($f, LOCK_UN);
992 @fclose($f);
993 }
994 return $result;
995 }
996
997 /**
998 * Put the given string into the given file
999 *
1000 * @param string $file File complete path
1001 * @param string $string String to put in file
1002 * @return boolean true if no problem
1003 */
1004 protected function _filePutContents($file, $string)
1005 {
1006 $result = false;
1007 $f = @fopen($file, 'ab+');
1008 if ($f) {
1009 if ($this->_options['file_locking']) @flock($f, LOCK_EX);
1010 fseek($f, 0);
1011 ftruncate($f, 0);
1012 $tmp = @fwrite($f, $string);
1013 if (!($tmp === FALSE)) {
1014 $result = true;
1015 }
1016 @fclose($f);
1017 }
1018 @chmod($file, $this->_options['cache_file_perm']);
1019 return $result;
1020 }
1021
1022 /**
1023 * Transform a file name into cache id and return it
1024 *
1025 * @param string $fileName File name
1026 * @return string Cache id
1027 */
1028 protected function _fileNameToId($fileName)
1029 {
1030 $prefix = $this->_options['file_name_prefix'];
1031 return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);
1032 }
1033
1034}
diff --git a/inc/3rdparty/libraries/Zend/Cache/Backend/Interface.php b/inc/3rdparty/libraries/Zend/Cache/Backend/Interface.php
new file mode 100644
index 00000000..3f44e2e1
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache/Backend/Interface.php
@@ -0,0 +1,99 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @subpackage Zend_Cache_Backend
18 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $
21 */
22
23
24/**
25 * @package Zend_Cache
26 * @subpackage Zend_Cache_Backend
27 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
28 * @license http://framework.zend.com/license/new-bsd New BSD License
29 */
30interface Zend_Cache_Backend_Interface
31{
32 /**
33 * Set the frontend directives
34 *
35 * @param array $directives assoc of directives
36 */
37 public function setDirectives($directives);
38
39 /**
40 * Test if a cache is available for the given id and (if yes) return it (false else)
41 *
42 * Note : return value is always "string" (unserialization is done by the core not by the backend)
43 *
44 * @param string $id Cache id
45 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
46 * @return string|false cached datas
47 */
48 public function load($id, $doNotTestCacheValidity = false);
49
50 /**
51 * Test if a cache is available or not (for the given id)
52 *
53 * @param string $id cache id
54 * @return mixed|false (a cache is not available) or "last modified" timestamp (int) of the available cache record
55 */
56 public function test($id);
57
58 /**
59 * Save some string datas into a cache record
60 *
61 * Note : $data is always "string" (serialization is done by the
62 * core not by the backend)
63 *
64 * @param string $data Datas to cache
65 * @param string $id Cache id
66 * @param array $tags Array of strings, the cache record will be tagged by each string entry
67 * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
68 * @return boolean true if no problem
69 */
70 public function save($data, $id, $tags = array(), $specificLifetime = false);
71
72 /**
73 * Remove a cache record
74 *
75 * @param string $id Cache id
76 * @return boolean True if no problem
77 */
78 public function remove($id);
79
80 /**
81 * Clean some cache records
82 *
83 * Available modes are :
84 * Zend_Cache::CLEANING_MODE_ALL (default) => remove all cache entries ($tags is not used)
85 * Zend_Cache::CLEANING_MODE_OLD => remove too old cache entries ($tags is not used)
86 * Zend_Cache::CLEANING_MODE_MATCHING_TAG => remove cache entries matching all given tags
87 * ($tags can be an array of strings or a single string)
88 * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
89 * ($tags can be an array of strings or a single string)
90 * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
91 * ($tags can be an array of strings or a single string)
92 *
93 * @param string $mode Clean mode
94 * @param array $tags Array of tags
95 * @return boolean true if no problem
96 */
97 public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array());
98
99}
diff --git a/inc/3rdparty/libraries/Zend/Cache/Core.php b/inc/3rdparty/libraries/Zend/Cache/Core.php
new file mode 100644
index 00000000..e3588636
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache/Core.php
@@ -0,0 +1,765 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Core.php 24989 2012-06-21 07:24:13Z mabe $
20 */
21
22
23/**
24 * @package Zend_Cache
25 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
26 * @license http://framework.zend.com/license/new-bsd New BSD License
27 */
28class Zend_Cache_Core
29{
30 /**
31 * Messages
32 */
33 const BACKEND_NOT_SUPPORTS_TAG = 'tags are not supported by the current backend';
34 const BACKEND_NOT_IMPLEMENTS_EXTENDED_IF = 'Current backend doesn\'t implement the Zend_Cache_Backend_ExtendedInterface, so this method is not available';
35
36 /**
37 * Backend Object
38 *
39 * @var Zend_Cache_Backend_Interface $_backend
40 */
41 protected $_backend = null;
42
43 /**
44 * Available options
45 *
46 * ====> (boolean) write_control :
47 * - Enable / disable write control (the cache is read just after writing to detect corrupt entries)
48 * - Enable write control will lightly slow the cache writing but not the cache reading
49 * Write control can detect some corrupt cache files but maybe it's not a perfect control
50 *
51 * ====> (boolean) caching :
52 * - Enable / disable caching
53 * (can be very useful for the debug of cached scripts)
54 *
55 * =====> (string) cache_id_prefix :
56 * - prefix for cache ids (namespace)
57 *
58 * ====> (boolean) automatic_serialization :
59 * - Enable / disable automatic serialization
60 * - It can be used to save directly datas which aren't strings (but it's slower)
61 *
62 * ====> (int) automatic_cleaning_factor :
63 * - Disable / Tune the automatic cleaning process
64 * - The automatic cleaning process destroy too old (for the given life time)
65 * cache files when a new cache file is written :
66 * 0 => no automatic cache cleaning
67 * 1 => systematic cache cleaning
68 * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
69 *
70 * ====> (int) lifetime :
71 * - Cache lifetime (in seconds)
72 * - If null, the cache is valid forever.
73 *
74 * ====> (boolean) logging :
75 * - If set to true, logging is activated (but the system is slower)
76 *
77 * ====> (boolean) ignore_user_abort
78 * - If set to true, the core will set the ignore_user_abort PHP flag inside the
79 * save() method to avoid cache corruptions in some cases (default false)
80 *
81 * @var array $_options available options
82 */
83 protected $_options = array(
84 'write_control' => true,
85 'caching' => true,
86 'cache_id_prefix' => null,
87 'automatic_serialization' => false,
88 'automatic_cleaning_factor' => 10,
89 'lifetime' => 3600,
90 'logging' => false,
91 'logger' => null,
92 'ignore_user_abort' => false
93 );
94
95 /**
96 * Array of options which have to be transfered to backend
97 *
98 * @var array $_directivesList
99 */
100 protected static $_directivesList = array('lifetime', 'logging', 'logger');
101
102 /**
103 * Not used for the core, just a sort a hint to get a common setOption() method (for the core and for frontends)
104 *
105 * @var array $_specificOptions
106 */
107 protected $_specificOptions = array();
108
109 /**
110 * Last used cache id
111 *
112 * @var string $_lastId
113 */
114 private $_lastId = null;
115
116 /**
117 * True if the backend implements Zend_Cache_Backend_ExtendedInterface
118 *
119 * @var boolean $_extendedBackend
120 */
121 protected $_extendedBackend = false;
122
123 /**
124 * Array of capabilities of the backend (only if it implements Zend_Cache_Backend_ExtendedInterface)
125 *
126 * @var array
127 */
128 protected $_backendCapabilities = array();
129
130 /**
131 * Constructor
132 *
133 * @param array|Zend_Config $options Associative array of options or Zend_Config instance
134 * @throws Zend_Cache_Exception
135 * @return void
136 */
137 public function __construct($options = array())
138 {
139 if ($options instanceof Zend_Config) {
140 $options = $options->toArray();
141 }
142 if (!is_array($options)) {
143 Zend_Cache::throwException("Options passed were not an array"
144 . " or Zend_Config instance.");
145 }
146 while (list($name, $value) = each($options)) {
147 $this->setOption($name, $value);
148 }
149 $this->_loggerSanity();
150 }
151
152 /**
153 * Set options using an instance of type Zend_Config
154 *
155 * @param Zend_Config $config
156 * @return Zend_Cache_Core
157 */
158 public function setConfig(Zend_Config $config)
159 {
160 $options = $config->toArray();
161 while (list($name, $value) = each($options)) {
162 $this->setOption($name, $value);
163 }
164 return $this;
165 }
166
167 /**
168 * Set the backend
169 *
170 * @param Zend_Cache_Backend $backendObject
171 * @throws Zend_Cache_Exception
172 * @return void
173 */
174 public function setBackend(Zend_Cache_Backend $backendObject)
175 {
176 $this->_backend= $backendObject;
177 // some options (listed in $_directivesList) have to be given
178 // to the backend too (even if they are not "backend specific")
179 $directives = array();
180 foreach (Zend_Cache_Core::$_directivesList as $directive) {
181 $directives[$directive] = $this->_options[$directive];
182 }
183 $this->_backend->setDirectives($directives);
184 if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) {
185 $this->_extendedBackend = true;
186 $this->_backendCapabilities = $this->_backend->getCapabilities();
187 }
188
189 }
190
191 /**
192 * Returns the backend
193 *
194 * @return Zend_Cache_Backend backend object
195 */
196 public function getBackend()
197 {
198 return $this->_backend;
199 }
200
201 /**
202 * Public frontend to set an option
203 *
204 * There is an additional validation (relatively to the protected _setOption method)
205 *
206 * @param string $name Name of the option
207 * @param mixed $value Value of the option
208 * @throws Zend_Cache_Exception
209 * @return void
210 */
211 public function setOption($name, $value)
212 {
213 if (!is_string($name)) {
214 Zend_Cache::throwException("Incorrect option name!");
215 }
216 $name = strtolower($name);
217 if (array_key_exists($name, $this->_options)) {
218 // This is a Core option
219 $this->_setOption($name, $value);
220 return;
221 }
222 if (array_key_exists($name, $this->_specificOptions)) {
223 // This a specic option of this frontend
224 $this->_specificOptions[$name] = $value;
225 return;
226 }
227 }
228
229 /**
230 * Public frontend to get an option value
231 *
232 * @param string $name Name of the option
233 * @throws Zend_Cache_Exception
234 * @return mixed option value
235 */
236 public function getOption($name)
237 {
238 $name = strtolower($name);
239
240 if (array_key_exists($name, $this->_options)) {
241 // This is a Core option
242 return $this->_options[$name];
243 }
244
245 if (array_key_exists($name, $this->_specificOptions)) {
246 // This a specic option of this frontend
247 return $this->_specificOptions[$name];
248 }
249
250 Zend_Cache::throwException("Incorrect option name : $name");
251 }
252
253 /**
254 * Set an option
255 *
256 * @param string $name Name of the option
257 * @param mixed $value Value of the option
258 * @throws Zend_Cache_Exception
259 * @return void
260 */
261 private function _setOption($name, $value)
262 {
263 if (!is_string($name) || !array_key_exists($name, $this->_options)) {
264 Zend_Cache::throwException("Incorrect option name : $name");
265 }
266 if ($name == 'lifetime' && empty($value)) {
267 $value = null;
268 }
269 $this->_options[$name] = $value;
270 }
271
272 /**
273 * Force a new lifetime
274 *
275 * The new value is set for the core/frontend but for the backend too (directive)
276 *
277 * @param int $newLifetime New lifetime (in seconds)
278 * @return void
279 */
280 public function setLifetime($newLifetime)
281 {
282 $this->_options['lifetime'] = $newLifetime;
283 $this->_backend->setDirectives(array(
284 'lifetime' => $newLifetime
285 ));
286 }
287
288 /**
289 * Test if a cache is available for the given id and (if yes) return it (false else)
290 *
291 * @param string $id Cache id
292 * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
293 * @param boolean $doNotUnserialize Do not serialize (even if automatic_serialization is true) => for internal use
294 * @return mixed|false Cached datas
295 */
296 public function load($id, $doNotTestCacheValidity = false, $doNotUnserialize = false)
297 {
298 if (!$this->_options['caching']) {
299 return false;
300 }
301 $id = $this->_id($id); // cache id may need prefix
302 $this->_lastId = $id;
303 self::_validateIdOrTag($id);
304
305 $this->_log("Zend_Cache_Core: load item '{$id}'", 7);
306 $data = $this->_backend->load($id, $doNotTestCacheValidity);
307 if ($data===false) {
308 // no cache available
309 return false;
310 }
311 if ((!$doNotUnserialize) && $this->_options['automatic_serialization']) {
312 // we need to unserialize before sending the result
313 return unserialize($data);
314 }
315 return $data;
316 }
317
318 /**
319 * Test if a cache is available for the given id
320 *
321 * @param string $id Cache id
322 * @return int|false Last modified time of cache entry if it is available, false otherwise
323 */
324 public function test($id)
325 {
326 if (!$this->_options['caching']) {
327 return false;
328 }
329 $id = $this->_id($id); // cache id may need prefix
330 self::_validateIdOrTag($id);
331 $this->_lastId = $id;
332
333 $this->_log("Zend_Cache_Core: test item '{$id}'", 7);
334 return $this->_backend->test($id);
335 }
336
337 /**
338 * Save some data in a cache
339 *
340 * @param mixed $data Data to put in cache (can be another type than string if automatic_serialization is on)
341 * @param string $id Cache id (if not set, the last cache id will be used)
342 * @param array $tags Cache tags
343 * @param int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
344 * @param int $priority integer between 0 (very low priority) and 10 (maximum priority) used by some particular backends
345 * @throws Zend_Cache_Exception
346 * @return boolean True if no problem
347 */
348 public function save($data, $id = null, $tags = array(), $specificLifetime = false, $priority = 8)
349 {
350 if (!$this->_options['caching']) {
351 return true;
352 }
353 if ($id === null) {
354 $id = $this->_lastId;
355 } else {
356 $id = $this->_id($id);
357 }
358 self::_validateIdOrTag($id);
359 self::_validateTagsArray($tags);
360 if ($this->_options['automatic_serialization']) {
361 // we need to serialize datas before storing them
362 $data = serialize($data);
363 } else {
364 if (!is_string($data)) {
365 Zend_Cache::throwException("Datas must be string or set automatic_serialization = true");
366 }
367 }
368
369 // automatic cleaning
370 if ($this->_options['automatic_cleaning_factor'] > 0) {
371 $rand = rand(1, $this->_options['automatic_cleaning_factor']);
372 if ($rand==1) {
373 // new way || deprecated way
374 if ($this->_extendedBackend || method_exists($this->_backend, 'isAutomaticCleaningAvailable')) {
375 $this->_log("Zend_Cache_Core::save(): automatic cleaning running", 7);
376 $this->clean(Zend_Cache::CLEANING_MODE_OLD);
377 } else {
378 $this->_log("Zend_Cache_Core::save(): automatic cleaning is not available/necessary with current backend", 4);
379 }
380 }
381 }
382
383 $this->_log("Zend_Cache_Core: save item '{$id}'", 7);
384 if ($this->_options['ignore_user_abort']) {
385 $abort = ignore_user_abort(true);
386 }
387 if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) {
388 $result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority);
389 } else {
390 $result = $this->_backend->save($data, $id, $tags, $specificLifetime);
391 }
392 if ($this->_options['ignore_user_abort']) {
393 ignore_user_abort($abort);
394 }
395
396 if (!$result) {
397 // maybe the cache is corrupted, so we remove it !
398 $this->_log("Zend_Cache_Core::save(): failed to save item '{$id}' -> removing it", 4);
399 $this->_backend->remove($id);
400 return false;
401 }
402
403 if ($this->_options['write_control']) {
404 $data2 = $this->_backend->load($id, true);
405 if ($data!=$data2) {
406 $this->_log("Zend_Cache_Core::save(): write control of item '{$id}' failed -> removing it", 4);
407 $this->_backend->remove($id);
408 return false;
409 }
410 }
411
412 return true;
413 }
414
415 /**
416 * Remove a cache
417 *
418 * @param string $id Cache id to remove
419 * @return boolean True if ok
420 */
421 public function remove($id)
422 {
423 if (!$this->_options['caching']) {
424 return true;
425 }
426 $id = $this->_id($id); // cache id may need prefix
427 self::_validateIdOrTag($id);
428
429 $this->_log("Zend_Cache_Core: remove item '{$id}'", 7);
430 return $this->_backend->remove($id);
431 }
432
433 /**
434 * Clean cache entries
435 *
436 * Available modes are :
437 * 'all' (default) => remove all cache entries ($tags is not used)
438 * 'old' => remove too old cache entries ($tags is not used)
439 * 'matchingTag' => remove cache entries matching all given tags
440 * ($tags can be an array of strings or a single string)
441 * 'notMatchingTag' => remove cache entries not matching one of the given tags
442 * ($tags can be an array of strings or a single string)
443 * 'matchingAnyTag' => remove cache entries matching any given tags
444 * ($tags can be an array of strings or a single string)
445 *
446 * @param string $mode
447 * @param array|string $tags
448 * @throws Zend_Cache_Exception
449 * @return boolean True if ok
450 */
451 public function clean($mode = 'all', $tags = array())
452 {
453 if (!$this->_options['caching']) {
454 return true;
455 }
456 if (!in_array($mode, array(Zend_Cache::CLEANING_MODE_ALL,
457 Zend_Cache::CLEANING_MODE_OLD,
458 Zend_Cache::CLEANING_MODE_MATCHING_TAG,
459 Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG,
460 Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG))) {
461 Zend_Cache::throwException('Invalid cleaning mode');
462 }
463 self::_validateTagsArray($tags);
464
465 return $this->_backend->clean($mode, $tags);
466 }
467
468 /**
469 * Return an array of stored cache ids which match given tags
470 *
471 * In case of multiple tags, a logical AND is made between tags
472 *
473 * @param array $tags array of tags
474 * @return array array of matching cache ids (string)
475 */
476 public function getIdsMatchingTags($tags = array())
477 {
478 if (!$this->_extendedBackend) {
479 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
480 }
481 if (!($this->_backendCapabilities['tags'])) {
482 Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
483 }
484
485 $ids = $this->_backend->getIdsMatchingTags($tags);
486
487 // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
488 if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
489 $prefix = & $this->_options['cache_id_prefix'];
490 $prefixLen = strlen($prefix);
491 foreach ($ids as &$id) {
492 if (strpos($id, $prefix) === 0) {
493 $id = substr($id, $prefixLen);
494 }
495 }
496 }
497
498 return $ids;
499 }
500
501 /**
502 * Return an array of stored cache ids which don't match given tags
503 *
504 * In case of multiple tags, a logical OR is made between tags
505 *
506 * @param array $tags array of tags
507 * @return array array of not matching cache ids (string)
508 */
509 public function getIdsNotMatchingTags($tags = array())
510 {
511 if (!$this->_extendedBackend) {
512 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
513 }
514 if (!($this->_backendCapabilities['tags'])) {
515 Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
516 }
517
518 $ids = $this->_backend->getIdsNotMatchingTags($tags);
519
520 // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
521 if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
522 $prefix = & $this->_options['cache_id_prefix'];
523 $prefixLen = strlen($prefix);
524 foreach ($ids as &$id) {
525 if (strpos($id, $prefix) === 0) {
526 $id = substr($id, $prefixLen);
527 }
528 }
529 }
530
531 return $ids;
532 }
533
534 /**
535 * Return an array of stored cache ids which match any given tags
536 *
537 * In case of multiple tags, a logical OR is made between tags
538 *
539 * @param array $tags array of tags
540 * @return array array of matching any cache ids (string)
541 */
542 public function getIdsMatchingAnyTags($tags = array())
543 {
544 if (!$this->_extendedBackend) {
545 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
546 }
547 if (!($this->_backendCapabilities['tags'])) {
548 Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
549 }
550
551 $ids = $this->_backend->getIdsMatchingAnyTags($tags);
552
553 // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
554 if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
555 $prefix = & $this->_options['cache_id_prefix'];
556 $prefixLen = strlen($prefix);
557 foreach ($ids as &$id) {
558 if (strpos($id, $prefix) === 0) {
559 $id = substr($id, $prefixLen);
560 }
561 }
562 }
563
564 return $ids;
565 }
566
567 /**
568 * Return an array of stored cache ids
569 *
570 * @return array array of stored cache ids (string)
571 */
572 public function getIds()
573 {
574 if (!$this->_extendedBackend) {
575 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
576 }
577
578 $ids = $this->_backend->getIds();
579
580 // we need to remove cache_id_prefix from ids (see #ZF-6178, #ZF-7600)
581 if (isset($this->_options['cache_id_prefix']) && $this->_options['cache_id_prefix'] !== '') {
582 $prefix = & $this->_options['cache_id_prefix'];
583 $prefixLen = strlen($prefix);
584 foreach ($ids as &$id) {
585 if (strpos($id, $prefix) === 0) {
586 $id = substr($id, $prefixLen);
587 }
588 }
589 }
590
591 return $ids;
592 }
593
594 /**
595 * Return an array of stored tags
596 *
597 * @return array array of stored tags (string)
598 */
599 public function getTags()
600 {
601 if (!$this->_extendedBackend) {
602 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
603 }
604 if (!($this->_backendCapabilities['tags'])) {
605 Zend_Cache::throwException(self::BACKEND_NOT_SUPPORTS_TAG);
606 }
607 return $this->_backend->getTags();
608 }
609
610 /**
611 * Return the filling percentage of the backend storage
612 *
613 * @return int integer between 0 and 100
614 */
615 public function getFillingPercentage()
616 {
617 if (!$this->_extendedBackend) {
618 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
619 }
620 return $this->_backend->getFillingPercentage();
621 }
622
623 /**
624 * Return an array of metadatas for the given cache id
625 *
626 * The array will include these keys :
627 * - expire : the expire timestamp
628 * - tags : a string array of tags
629 * - mtime : timestamp of last modification time
630 *
631 * @param string $id cache id
632 * @return array array of metadatas (false if the cache id is not found)
633 */
634 public function getMetadatas($id)
635 {
636 if (!$this->_extendedBackend) {
637 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
638 }
639 $id = $this->_id($id); // cache id may need prefix
640 return $this->_backend->getMetadatas($id);
641 }
642
643 /**
644 * Give (if possible) an extra lifetime to the given cache id
645 *
646 * @param string $id cache id
647 * @param int $extraLifetime
648 * @return boolean true if ok
649 */
650 public function touch($id, $extraLifetime)
651 {
652 if (!$this->_extendedBackend) {
653 Zend_Cache::throwException(self::BACKEND_NOT_IMPLEMENTS_EXTENDED_IF);
654 }
655 $id = $this->_id($id); // cache id may need prefix
656
657 $this->_log("Zend_Cache_Core: touch item '{$id}'", 7);
658 return $this->_backend->touch($id, $extraLifetime);
659 }
660
661 /**
662 * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...)
663 *
664 * Throw an exception if a problem is found
665 *
666 * @param string $string Cache id or tag
667 * @throws Zend_Cache_Exception
668 * @return void
669 */
670 protected static function _validateIdOrTag($string)
671 {
672 if (!is_string($string)) {
673 Zend_Cache::throwException('Invalid id or tag : must be a string');
674 }
675 if (substr($string, 0, 9) == 'internal-') {
676 Zend_Cache::throwException('"internal-*" ids or tags are reserved');
677 }
678 if (!preg_match('~^[a-zA-Z0-9_]+$~D', $string)) {
679 Zend_Cache::throwException("Invalid id or tag '$string' : must use only [a-zA-Z0-9_]");
680 }
681 }
682
683 /**
684 * Validate a tags array (security, reliable filenames, reserved prefixes...)
685 *
686 * Throw an exception if a problem is found
687 *
688 * @param array $tags Array of tags
689 * @throws Zend_Cache_Exception
690 * @return void
691 */
692 protected static function _validateTagsArray($tags)
693 {
694 if (!is_array($tags)) {
695 Zend_Cache::throwException('Invalid tags array : must be an array');
696 }
697 foreach($tags as $tag) {
698 self::_validateIdOrTag($tag);
699 }
700 reset($tags);
701 }
702
703 /**
704 * Make sure if we enable logging that the Zend_Log class
705 * is available.
706 * Create a default log object if none is set.
707 *
708 * @throws Zend_Cache_Exception
709 * @return void
710 */
711 protected function _loggerSanity()
712 {
713 if (!isset($this->_options['logging']) || !$this->_options['logging']) {
714 return;
715 }
716
717 if (isset($this->_options['logger']) && $this->_options['logger'] instanceof Zend_Log) {
718 return;
719 }
720
721 // Create a default logger to the standard output stream
722 require_once 'Zend/Log.php';
723 require_once 'Zend/Log/Writer/Stream.php';
724 require_once 'Zend/Log/Filter/Priority.php';
725 $logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
726 $logger->addFilter(new Zend_Log_Filter_Priority(Zend_Log::WARN, '<='));
727 $this->_options['logger'] = $logger;
728 }
729
730 /**
731 * Log a message at the WARN (4) priority.
732 *
733 * @param string $message
734 * @throws Zend_Cache_Exception
735 * @return void
736 */
737 protected function _log($message, $priority = 4)
738 {
739 if (!$this->_options['logging']) {
740 return;
741 }
742 if (!(isset($this->_options['logger']) || $this->_options['logger'] instanceof Zend_Log)) {
743 Zend_Cache::throwException('Logging is enabled but logger is not set');
744 }
745 $logger = $this->_options['logger'];
746 $logger->log($message, $priority);
747 }
748
749 /**
750 * Make and return a cache id
751 *
752 * Checks 'cache_id_prefix' and returns new id with prefix or simply the id if null
753 *
754 * @param string $id Cache id
755 * @return string Cache id (with or without prefix)
756 */
757 protected function _id($id)
758 {
759 if (($id !== null) && isset($this->_options['cache_id_prefix'])) {
760 return $this->_options['cache_id_prefix'] . $id; // return with prefix
761 }
762 return $id; // no prefix, just return the $id passed
763 }
764
765}
diff --git a/inc/3rdparty/libraries/Zend/Cache/Exception.php b/inc/3rdparty/libraries/Zend/Cache/Exception.php
new file mode 100644
index 00000000..44884515
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Cache/Exception.php
@@ -0,0 +1,32 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Cache
17 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
20 */
21
22/**
23 * @see Zend_Exception
24 */
25require_once 'Zend/Exception.php';
26
27/**
28 * @package Zend_Cache
29 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
30 * @license http://framework.zend.com/license/new-bsd New BSD License
31 */
32class Zend_Cache_Exception extends Zend_Exception {}
diff --git a/inc/3rdparty/libraries/Zend/Exception.php b/inc/3rdparty/libraries/Zend/Exception.php
new file mode 100644
index 00000000..92b2e460
--- /dev/null
+++ b/inc/3rdparty/libraries/Zend/Exception.php
@@ -0,0 +1,96 @@
1<?php
2/**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend
17 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $
20 */
21
22/**
23* @category Zend
24* @package Zend
25* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
26* @license http://framework.zend.com/license/new-bsd New BSD License
27*/
28class Zend_Exception extends Exception
29{
30 /**
31 * @var null|Exception
32 */
33 private $_previous = null;
34
35 /**
36 * Construct the exception
37 *
38 * @param string $msg
39 * @param int $code
40 * @param Exception $previous
41 * @return void
42 */
43 public function __construct($msg = '', $code = 0, Exception $previous = null)
44 {
45 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
46 parent::__construct($msg, (int) $code);
47 $this->_previous = $previous;
48 } else {
49 parent::__construct($msg, (int) $code, $previous);
50 }
51 }
52
53 /**
54 * Overloading
55 *
56 * For PHP < 5.3.0, provides access to the getPrevious() method.
57 *
58 * @param string $method
59 * @param array $args
60 * @return mixed
61 */
62 public function __call($method, array $args)
63 {
64 if ('getprevious' == strtolower($method)) {
65 return $this->_getPrevious();
66 }
67 return null;
68 }
69
70 /**
71 * String representation of the exception
72 *
73 * @return string
74 */
75 public function __toString()
76 {
77 if (version_compare(PHP_VERSION, '5.3.0', '<')) {
78 if (null !== ($e = $this->getPrevious())) {
79 return $e->__toString()
80 . "\n\nNext "
81 . parent::__toString();
82 }
83 }
84 return parent::__toString();
85 }
86
87 /**
88 * Returns previous Exception
89 *
90 * @return Exception|null
91 */
92 protected function _getPrevious()
93 {
94 return $this->_previous;
95 }
96}
diff --git a/inc/3rdparty/libraries/content-extractor/ContentExtractor.php b/inc/3rdparty/libraries/content-extractor/ContentExtractor.php
new file mode 100644
index 00000000..ddd33bb5
--- /dev/null
+++ b/inc/3rdparty/libraries/content-extractor/ContentExtractor.php
@@ -0,0 +1,728 @@
1<?php
2/**
3 * Content Extractor
4 *
5 * Uses patterns specified in site config files and auto detection (hNews/PHP Readability)
6 * to extract content from HTML files.
7 *
8 * @version 1.0
9 * @date 2013-02-05
10 * @author Keyvan Minoukadeh
11 * @copyright 2013 Keyvan Minoukadeh
12 * @license http://www.gnu.org/licenses/agpl-3.0.html AGPL v3
13 */
14
15class ContentExtractor
16{
17 protected static $tidy_config = array(
18 'clean' => true,
19 'output-xhtml' => true,
20 'logical-emphasis' => true,
21 'show-body-only' => false,
22 'new-blocklevel-tags' => 'article, aside, footer, header, hgroup, menu, nav, section, details, datagrid',
23 'new-inline-tags' => 'mark, time, meter, progress, data',
24 'wrap' => 0,
25 'drop-empty-paras' => true,
26 'drop-proprietary-attributes' => false,
27 'enclose-text' => true,
28 'enclose-block-text' => true,
29 'merge-divs' => true,
30 'merge-spans' => true,
31 'char-encoding' => 'utf8',
32 'hide-comments' => true
33 );
34 protected $html;
35 protected $config;
36 protected $title;
37 protected $author = array();
38 protected $language;
39 protected $date;
40 protected $body;
41 protected $success = false;
42 protected $nextPageUrl;
43 public $allowedParsers = array('libxml', 'html5lib');
44 public $fingerprints = array();
45 public $readability;
46 public $debug = false;
47 public $debugVerbose = false;
48
49 function __construct($path, $fallback=null) {
50 SiteConfig::set_config_path($path, $fallback);
51 }
52
53 protected function debug($msg) {
54 if ($this->debug) {
55 $mem = round(memory_get_usage()/1024, 2);
56 $memPeak = round(memory_get_peak_usage()/1024, 2);
57 echo '* ',$msg;
58 if ($this->debugVerbose) echo ' - mem used: ',$mem," (peak: $memPeak)";
59 echo "\n";
60 ob_flush();
61 flush();
62 }
63 }
64
65 public function reset() {
66 $this->html = null;
67 $this->readability = null;
68 $this->config = null;
69 $this->title = null;
70 $this->body = null;
71 $this->author = array();
72 $this->language = null;
73 $this->date = null;
74 $this->nextPageUrl = null;
75 $this->success = false;
76 }
77
78 public function findHostUsingFingerprints($html) {
79 $this->debug('Checking fingerprints...');
80 $head = substr($html, 0, 8000);
81 foreach ($this->fingerprints as $_fp => $_fphost) {
82 $lookin = 'html';
83 if (is_array($_fphost)) {
84 if (isset($_fphost['head']) && $_fphost['head']) {
85 $lookin = 'head';
86 }
87 $_fphost = $_fphost['hostname'];
88 }
89 if (strpos($$lookin, $_fp) !== false) {
90 $this->debug("Found match: $_fphost");
91 return $_fphost;
92 }
93 }
94 $this->debug('No fingerprint matches');
95 return false;
96 }
97
98 // returns SiteConfig instance (joined in order: exact match, wildcard, fingerprint, global, default)
99 public function buildSiteConfig($url, $html='', $add_to_cache=true) {
100 // extract host name
101 $host = @parse_url($url, PHP_URL_HOST);
102 $host = strtolower($host);
103 if (substr($host, 0, 4) == 'www.') $host = substr($host, 4);
104 // is merged version already cached?
105 if (SiteConfig::is_cached("$host.merged")) {
106 $this->debug("Returning cached and merged site config for $host");
107 return SiteConfig::build("$host.merged");
108 }
109 // let's build from site_config/custom/ and standard/
110 $config = SiteConfig::build($host);
111 if ($add_to_cache && $config && !SiteConfig::is_cached("$host")) {
112 SiteConfig::add_to_cache($host, $config);
113 }
114 // if no match, use defaults
115 if (!$config) $config = new SiteConfig();
116 // load fingerprint config?
117 if ($config->autodetect_on_failure()) {
118 // check HTML for fingerprints
119 if (!empty($this->fingerprints) && ($_fphost = $this->findHostUsingFingerprints($html))) {
120 if ($config_fingerprint = SiteConfig::build($_fphost)) {
121 $this->debug("Appending site config settings from $_fphost (fingerprint match)");
122 $config->append($config_fingerprint);
123 if ($add_to_cache && !SiteConfig::is_cached($_fphost)) {
124 //$config_fingerprint->cache_in_apc = true;
125 SiteConfig::add_to_cache($_fphost, $config_fingerprint);
126 }
127 }
128 }
129 }
130 // load global config?
131 if ($config->autodetect_on_failure()) {
132 if ($config_global = SiteConfig::build('global', true)) {
133 $this->debug('Appending site config settings from global.txt');
134 $config->append($config_global);
135 if ($add_to_cache && !SiteConfig::is_cached('global')) {
136 //$config_global->cache_in_apc = true;
137 SiteConfig::add_to_cache('global', $config_global);
138 }
139 }
140 }
141 // store copy of merged config
142 if ($add_to_cache) {
143 // do not store in APC if wildcard match
144 $use_apc = ($host == $config->cache_key);
145 $config->cache_key = null;
146 SiteConfig::add_to_cache("$host.merged", $config, $use_apc);
147 }
148 return $config;
149 }
150
151 // returns true on success, false on failure
152 // $smart_tidy indicates that if tidy is used and no results are produced, we will
153 // try again without it. Tidy helps us deal with PHP's patchy HTML parsing most of the time
154 // but it has problems of its own which we try to avoid with this option.
155 public function process($html, $url, $smart_tidy=true) {
156 $this->reset();
157 $this->config = $this->buildSiteConfig($url, $html);
158
159 // do string replacements
160 if (!empty($this->config->find_string)) {
161 if (count($this->config->find_string) == count($this->config->replace_string)) {
162 $html = str_replace($this->config->find_string, $this->config->replace_string, $html, $_count);
163 $this->debug("Strings replaced: $_count (find_string and/or replace_string)");
164 } else {
165 $this->debug('Skipped string replacement - incorrect number of find-replace strings in site config');
166 }
167 unset($_count);
168 }
169
170 // use tidy (if it exists)?
171 // This fixes problems with some sites which would otherwise
172 // trouble DOMDocument's HTML parsing. (Although sometimes it
173 // makes matters worse, which is why you can override it in site config files.)
174 $tidied = false;
175 if ($this->config->tidy() && function_exists('tidy_parse_string') && $smart_tidy) {
176 $this->debug('Using Tidy');
177 $tidy = tidy_parse_string($html, self::$tidy_config, 'UTF8');
178 if (tidy_clean_repair($tidy)) {
179 $original_html = $html;
180 $tidied = true;
181 $html = $tidy->value;
182 }
183 unset($tidy);
184 }
185
186 // load and parse html
187 $_parser = $this->config->parser();
188 if (!in_array($_parser, $this->allowedParsers)) {
189 $this->debug("HTML parser $_parser not listed, using libxml instead");
190 $_parser = 'libxml';
191 }
192 $this->debug("Attempting to parse HTML with $_parser");
193 $this->readability = new Readability($html, $url, $_parser);
194
195 // we use xpath to find elements in the given HTML document
196 // see http://en.wikipedia.org/wiki/XPath_1.0
197 $xpath = new DOMXPath($this->readability->dom);
198
199 // try to get next page link
200 foreach ($this->config->next_page_link as $pattern) {
201 $elems = @$xpath->evaluate($pattern, $this->readability->dom);
202 if (is_string($elems)) {
203 $this->nextPageUrl = trim($elems);
204 break;
205 } elseif ($elems instanceof DOMNodeList && $elems->length > 0) {
206 foreach ($elems as $item) {
207 if ($item instanceof DOMElement && $item->hasAttribute('href')) {
208 $this->nextPageUrl = $item->getAttribute('href');
209 break 2;
210 } elseif ($item instanceof DOMAttr && $item->value) {
211 $this->nextPageUrl = $item->value;
212 break 2;
213 }
214 }
215 }
216 }
217
218 // try to get title
219 foreach ($this->config->title as $pattern) {
220 // $this->debug("Trying $pattern");
221 $elems = @$xpath->evaluate($pattern, $this->readability->dom);
222 if (is_string($elems)) {
223 $this->title = trim($elems);
224 $this->debug('Title expression evaluated as string: '.$this->title);
225 $this->debug("...XPath match: $pattern");
226 break;
227 } elseif ($elems instanceof DOMNodeList && $elems->length > 0) {
228 $this->title = $elems->item(0)->textContent;
229 $this->debug('Title matched: '.$this->title);
230 $this->debug("...XPath match: $pattern");
231 // remove title from document
232 try {
233 $elems->item(0)->parentNode->removeChild($elems->item(0));
234 } catch (DOMException $e) {
235 // do nothing
236 }
237 break;
238 }
239 }
240
241 // try to get author (if it hasn't already been set)
242 if (empty($this->author)) {
243 foreach ($this->config->author as $pattern) {
244 $elems = @$xpath->evaluate($pattern, $this->readability->dom);
245 if (is_string($elems)) {
246 if (trim($elems) != '') {
247 $this->author[] = trim($elems);
248 $this->debug('Author expression evaluated as string: '.trim($elems));
249 $this->debug("...XPath match: $pattern");
250 break;
251 }
252 } elseif ($elems instanceof DOMNodeList && $elems->length > 0) {
253 foreach ($elems as $elem) {
254 if (!isset($elem->parentNode)) continue;
255 $this->author[] = trim($elem->textContent);
256 $this->debug('Author matched: '.trim($elem->textContent));
257 }
258 if (!empty($this->author)) {
259 $this->debug("...XPath match: $pattern");
260 break;
261 }
262 }
263 }
264 }
265
266 // try to get language
267 $_lang_xpath = array('//html[@lang]/@lang', '//meta[@name="DC.language"]/@content');
268 foreach ($_lang_xpath as $pattern) {
269 $elems = @$xpath->evaluate($pattern, $this->readability->dom);
270 if (is_string($elems)) {
271 if (trim($elems) != '') {
272 $this->language = trim($elems);
273 $this->debug('Language matched: '.$this->language);
274 break;
275 }
276 } elseif ($elems instanceof DOMNodeList && $elems->length > 0) {
277 foreach ($elems as $elem) {
278 if (!isset($elem->parentNode)) continue;
279 $this->language = trim($elem->textContent);
280 $this->debug('Language matched: '.$this->language);
281 }
282 if ($this->language) break;
283 }
284 }
285
286 // try to get date
287 foreach ($this->config->date as $pattern) {
288 $elems = @$xpath->evaluate($pattern, $this->readability->dom);
289 if (is_string($elems)) {
290 $this->date = strtotime(trim($elems, "; \t\n\r\0\x0B"));
291 } elseif ($elems instanceof DOMNodeList && $elems->length > 0) {
292 $this->date = $elems->item(0)->textContent;
293 $this->date = strtotime(trim($this->date, "; \t\n\r\0\x0B"));
294 // remove date from document
295 // $elems->item(0)->parentNode->removeChild($elems->item(0));
296 }
297 if (!$this->date) {
298 $this->date = null;
299 } else {
300 $this->debug('Date matched: '.date('Y-m-d H:i:s', $this->date));
301 $this->debug("...XPath match: $pattern");
302 break;
303 }
304 }
305
306 // strip elements (using xpath expressions)
307 foreach ($this->config->strip as $pattern) {
308 $elems = @$xpath->query($pattern, $this->readability->dom);
309 // check for matches
310 if ($elems && $elems->length > 0) {
311 $this->debug('Stripping '.$elems->length.' elements (strip)');
312 for ($i=$elems->length-1; $i >= 0; $i--) {
313 $elems->item($i)->parentNode->removeChild($elems->item($i));
314 }
315 }
316 }
317
318 // strip elements (using id and class attribute values)
319 foreach ($this->config->strip_id_or_class as $string) {
320 $string = strtr($string, array("'"=>'', '"'=>''));
321 $elems = @$xpath->query("//*[contains(@class, '$string') or contains(@id, '$string')]", $this->readability->dom);
322 // check for matches
323 if ($elems && $elems->length > 0) {
324 $this->debug('Stripping '.$elems->length.' elements (strip_id_or_class)');
325 for ($i=$elems->length-1; $i >= 0; $i--) {
326 $elems->item($i)->parentNode->removeChild($elems->item($i));
327 }
328 }
329 }
330
331 // strip images (using src attribute values)
332 foreach ($this->config->strip_image_src as $string) {
333 $string = strtr($string, array("'"=>'', '"'=>''));
334 $elems = @$xpath->query("//img[contains(@src, '$string')]", $this->readability->dom);
335 // check for matches
336 if ($elems && $elems->length > 0) {
337 $this->debug('Stripping '.$elems->length.' image elements');
338 for ($i=$elems->length-1; $i >= 0; $i--) {
339 $elems->item($i)->parentNode->removeChild($elems->item($i));
340 }
341 }
342 }
343 // strip elements using Readability.com and Instapaper.com ignore class names
344 // .entry-unrelated and .instapaper_ignore
345 // See https://www.readability.com/publishers/guidelines/#view-plainGuidelines
346 // and http://blog.instapaper.com/post/730281947
347 $elems = @$xpath->query("//*[contains(concat(' ',normalize-space(@class),' '),' entry-unrelated ') or contains(concat(' ',normalize-space(@class),' '),' instapaper_ignore ')]", $this->readability->dom);
348 // check for matches
349 if ($elems && $elems->length > 0) {
350 $this->debug('Stripping '.$elems->length.' .entry-unrelated,.instapaper_ignore elements');
351 for ($i=$elems->length-1; $i >= 0; $i--) {
352 $elems->item($i)->parentNode->removeChild($elems->item($i));
353 }
354 }
355
356 // strip elements that contain style="display: none;"
357 $elems = @$xpath->query("//*[contains(@style,'display:none')]", $this->readability->dom);
358 // check for matches
359 if ($elems && $elems->length > 0) {
360 $this->debug('Stripping '.$elems->length.' elements with inline display:none style');
361 for ($i=$elems->length-1; $i >= 0; $i--) {
362 $elems->item($i)->parentNode->removeChild($elems->item($i));
363 }
364 }
365
366 // try to get body
367 foreach ($this->config->body as $pattern) {
368 $elems = @$xpath->query($pattern, $this->readability->dom);
369 // check for matches
370 if ($elems && $elems->length > 0) {
371 $this->debug('Body matched');
372 $this->debug("...XPath match: $pattern");
373 if ($elems->length == 1) {
374 $this->body = $elems->item(0);
375 // prune (clean up elements that may not be content)
376 if ($this->config->prune()) {
377 $this->debug('...pruning content');
378 $this->readability->prepArticle($this->body);
379 }
380 break;
381 } else {
382 $this->body = $this->readability->dom->createElement('div');
383 $this->debug($elems->length.' body elems found');
384 foreach ($elems as $elem) {
385 if (!isset($elem->parentNode)) continue;
386 $isDescendant = false;
387 foreach ($this->body->childNodes as $parent) {
388 if ($this->isDescendant($parent, $elem)) {
389 $isDescendant = true;
390 break;
391 }
392 }
393 if ($isDescendant) {
394 $this->debug('...element is child of another body element, skipping.');
395 } else {
396 // prune (clean up elements that may not be content)
397 if ($this->config->prune()) {
398 $this->debug('Pruning content');
399 $this->readability->prepArticle($elem);
400 }
401 $this->debug('...element added to body');
402 $this->body->appendChild($elem);
403 }
404 }
405 if ($this->body->hasChildNodes()) break;
406 }
407 }
408 }
409
410 // auto detect?
411 $detect_title = $detect_body = $detect_author = $detect_date = false;
412 // detect title?
413 if (!isset($this->title)) {
414 if (empty($this->config->title) || $this->config->autodetect_on_failure()) {
415 $detect_title = true;
416 }
417 }
418 // detect body?
419 if (!isset($this->body)) {
420 if (empty($this->config->body) || $this->config->autodetect_on_failure()) {
421 $detect_body = true;
422 }
423 }
424 // detect author?
425 if (empty($this->author)) {
426 if (empty($this->config->author) || $this->config->autodetect_on_failure()) {
427 $detect_author = true;
428 }
429 }
430 // detect date?
431 if (!isset($this->date)) {
432 if (empty($this->config->date) || $this->config->autodetect_on_failure()) {
433 $detect_date = true;
434 }
435 }
436
437 // check for hNews
438 if ($detect_title || $detect_body) {
439 // check for hentry
440 $elems = @$xpath->query("//*[contains(concat(' ',normalize-space(@class),' '),' hentry ')]", $this->readability->dom);
441 if ($elems && $elems->length > 0) {
442 $this->debug('hNews: found hentry');
443 $hentry = $elems->item(0);
444
445 if ($detect_title) {
446 // check for entry-title
447 $elems = @$xpath->query(".//*[contains(concat(' ',normalize-space(@class),' '),' entry-title ')]", $hentry);
448 if ($elems && $elems->length > 0) {
449 $this->title = $elems->item(0)->textContent;
450 $this->debug('hNews: found entry-title: '.$this->title);
451 // remove title from document
452 $elems->item(0)->parentNode->removeChild($elems->item(0));
453 $detect_title = false;
454 }
455 }
456
457 if ($detect_date) {
458 // check for time element with pubdate attribute
459 $elems = @$xpath->query(".//time[@pubdate] | .//abbr[contains(concat(' ',normalize-space(@class),' '),' published ')]", $hentry);
460 if ($elems && $elems->length > 0) {
461 $this->date = strtotime(trim($elems->item(0)->textContent));
462 // remove date from document
463 //$elems->item(0)->parentNode->removeChild($elems->item(0));
464 if ($this->date) {
465 $this->debug('hNews: found publication date: '.date('Y-m-d H:i:s', $this->date));
466 $detect_date = false;
467 } else {
468 $this->date = null;
469 }
470 }
471 }
472
473 if ($detect_author) {
474 // check for time element with pubdate attribute
475 $elems = @$xpath->query(".//*[contains(concat(' ',normalize-space(@class),' '),' vcard ') and (contains(concat(' ',normalize-space(@class),' '),' author ') or contains(concat(' ',normalize-space(@class),' '),' byline '))]", $hentry);
476 if ($elems && $elems->length > 0) {
477 $author = $elems->item(0);
478 $fn = @$xpath->query(".//*[contains(concat(' ',normalize-space(@class),' '),' fn ')]", $author);
479 if ($fn && $fn->length > 0) {
480 foreach ($fn as $_fn) {
481 if (trim($_fn->textContent) != '') {
482 $this->author[] = trim($_fn->textContent);
483 $this->debug('hNews: found author: '.trim($_fn->textContent));
484 }
485 }
486 } else {
487 if (trim($author->textContent) != '') {
488 $this->author[] = trim($author->textContent);
489 $this->debug('hNews: found author: '.trim($author->textContent));
490 }
491 }
492 $detect_author = empty($this->author);
493 }
494 }
495
496 // check for entry-content.
497 // according to hAtom spec, if there are multiple elements marked entry-content,
498 // we include all of these in the order they appear - see http://microformats.org/wiki/hatom#Entry_Content
499 if ($detect_body) {
500 $elems = @$xpath->query(".//*[contains(concat(' ',normalize-space(@class),' '),' entry-content ')]", $hentry);
501 if ($elems && $elems->length > 0) {
502 $this->debug('hNews: found entry-content');
503 if ($elems->length == 1) {
504 // what if it's empty? (some sites misuse hNews - place their content outside an empty entry-content element)
505 $e = $elems->item(0);
506 if (($e->tagName == 'img') || (trim($e->textContent) != '')) {
507 $this->body = $elems->item(0);
508 // prune (clean up elements that may not be content)
509 if ($this->config->prune()) {
510 $this->debug('Pruning content');
511 $this->readability->prepArticle($this->body);
512 }
513 $detect_body = false;
514 } else {
515 $this->debug('hNews: skipping entry-content - appears not to contain content');
516 }
517 unset($e);
518 } else {
519 $this->body = $this->readability->dom->createElement('div');
520 $this->debug($elems->length.' entry-content elems found');
521 foreach ($elems as $elem) {
522 if (!isset($elem->parentNode)) continue;
523 $isDescendant = false;
524 foreach ($this->body->childNodes as $parent) {
525 if ($this->isDescendant($parent, $elem)) {
526 $isDescendant = true;
527 break;
528 }
529 }
530 if ($isDescendant) {
531 $this->debug('Element is child of another body element, skipping.');
532 } else {
533 // prune (clean up elements that may not be content)
534 if ($this->config->prune()) {
535 $this->debug('Pruning content');
536 $this->readability->prepArticle($elem);
537 }
538 $this->debug('Element added to body');
539 $this->body->appendChild($elem);
540 }
541 }
542 $detect_body = false;
543 }
544 }
545 }
546 }
547 }
548
549 // check for elements marked with instapaper_title
550 if ($detect_title) {
551 // check for instapaper_title
552 $elems = @$xpath->query("//*[contains(concat(' ',normalize-space(@class),' '),' instapaper_title ')]", $this->readability->dom);
553 if ($elems && $elems->length > 0) {
554 $this->title = $elems->item(0)->textContent;
555 $this->debug('Title found (.instapaper_title): '.$this->title);
556 // remove title from document
557 $elems->item(0)->parentNode->removeChild($elems->item(0));
558 $detect_title = false;
559 }
560 }
561 // check for elements marked with instapaper_body
562 if ($detect_body) {
563 $elems = @$xpath->query("//*[contains(concat(' ',normalize-space(@class),' '),' instapaper_body ')]", $this->readability->dom);
564 if ($elems && $elems->length > 0) {
565 $this->debug('body found (.instapaper_body)');
566 $this->body = $elems->item(0);
567 // prune (clean up elements that may not be content)
568 if ($this->config->prune()) {
569 $this->debug('Pruning content');
570 $this->readability->prepArticle($this->body);
571 }
572 $detect_body = false;
573 }
574 }
575
576 // Find author in rel="author" marked element
577 // We only use this if there's exactly one.
578 // If there's more than one, it could indicate more than
579 // one author, but it could also indicate that we're processing
580 // a page listing different articles with different authors.
581 if ($detect_author) {
582 $elems = @$xpath->query("//a[contains(concat(' ',normalize-space(@rel),' '),' author ')]", $this->readability->dom);
583 if ($elems && $elems->length == 1) {
584 $author = trim($elems->item(0)->textContent);
585 if ($author != '') {
586 $this->debug("Author found (rel=\"author\"): $author");
587 $this->author[] = $author;
588 $detect_author = false;
589 }
590 }
591 }
592
593 // Find date in pubdate marked time element
594 // For the same reason given above, we only use this
595 // if there's exactly one element.
596 if ($detect_date) {
597 $elems = @$xpath->query("//time[@pubdate]", $this->readability->dom);
598 if ($elems && $elems->length == 1) {
599 $this->date = strtotime(trim($elems->item(0)->textContent));
600 // remove date from document
601 //$elems->item(0)->parentNode->removeChild($elems->item(0));
602 if ($this->date) {
603 $this->debug('Date found (pubdate marked time element): '.date('Y-m-d H:i:s', $this->date));
604 $detect_date = false;
605 } else {
606 $this->date = null;
607 }
608 }
609 }
610
611 // still missing title or body, so we detect using Readability
612 if ($detect_title || $detect_body) {
613 $this->debug('Using Readability');
614 // clone body if we're only using Readability for title (otherwise it may interfere with body element)
615 if (isset($this->body)) $this->body = $this->body->cloneNode(true);
616 $success = $this->readability->init();
617 }
618 if ($detect_title) {
619 $this->debug('Detecting title');
620 $this->title = $this->readability->getTitle()->textContent;
621 }
622 if ($detect_body && $success) {
623 $this->debug('Detecting body');
624 $this->body = $this->readability->getContent();
625 if ($this->body->childNodes->length == 1 && $this->body->firstChild->nodeType === XML_ELEMENT_NODE) {
626 $this->body = $this->body->firstChild;
627 }
628 // prune (clean up elements that may not be content)
629 if ($this->config->prune()) {
630 $this->debug('Pruning content');
631 $this->readability->prepArticle($this->body);
632 }
633 }
634 if (isset($this->body)) {
635 // remove scripts
636 $this->readability->removeScripts($this->body);
637 // remove any h1-h6 elements that appear as first thing in the body
638 // and which match our title
639 if (isset($this->title) && ($this->title != '')) {
640 $firstChild = $this->body->firstChild;
641 while ($firstChild->nodeType && ($firstChild->nodeType !== XML_ELEMENT_NODE)) {
642 $firstChild = $firstChild->nextSibling;
643 }
644 if (($firstChild->nodeType === XML_ELEMENT_NODE)
645 && in_array(strtolower($firstChild->tagName), array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))
646 && (strtolower(trim($firstChild->textContent)) == strtolower(trim($this->title)))) {
647 $this->body->removeChild($firstChild);
648 }
649 }
650 // prevent self-closing iframes
651 $elems = $this->body->getElementsByTagName('iframe');
652 for ($i = $elems->length-1; $i >= 0; $i--) {
653 $e = $elems->item($i);
654 if (!$e->hasChildNodes()) {
655 $e->appendChild($this->body->ownerDocument->createTextNode('[embedded content]'));
656 }
657 }
658 // remove image lazy loading - WordPress plugin http://wordpress.org/extend/plugins/lazy-load/
659 // the plugin replaces the src attribute to point to a 1x1 gif and puts the original src
660 // inside the data-lazy-src attribute. It also places the original image inside a noscript element
661 // next to the amended one.
662 $elems = @$xpath->query("//img[@data-lazy-src]", $this->body);
663 for ($i = $elems->length-1; $i >= 0; $i--) {
664 $e = $elems->item($i);
665 // let's see if we can grab image from noscript
666 if ($e->nextSibling !== null && $e->nextSibling->nodeName === 'noscript') {
667 $_new_elem = $e->ownerDocument->createDocumentFragment();
668 @$_new_elem->appendXML($e->nextSibling->innerHTML);
669 $e->nextSibling->parentNode->replaceChild($_new_elem, $e->nextSibling);
670 $e->parentNode->removeChild($e);
671 } else {
672 // Use data-lazy-src as src value
673 $e->setAttribute('src', $e->getAttribute('data-lazy-src'));
674 $e->removeAttribute('data-lazy-src');
675 }
676 }
677
678 $this->success = true;
679 }
680
681 // if we've had no success and we've used tidy, there's a chance
682 // that tidy has messed up. So let's try again without tidy...
683 if (!$this->success && $tidied && $smart_tidy) {
684 $this->debug('Trying again without tidy');
685 $this->process($original_html, $url, false);
686 }
687
688 return $this->success;
689 }
690
691 private function isDescendant(DOMElement $parent, DOMElement $child) {
692 $node = $child->parentNode;
693 while ($node != null) {
694 if ($node->isSameNode($parent)) return true;
695 $node = $node->parentNode;
696 }
697 return false;
698 }
699
700 public function getContent() {
701 return $this->body;
702 }
703
704 public function getTitle() {
705 return $this->title;
706 }
707
708 public function getAuthors() {
709 return $this->author;
710 }
711
712 public function getLanguage() {
713 return $this->language;
714 }
715
716 public function getDate() {
717 return $this->date;
718 }
719
720 public function getSiteConfig() {
721 return $this->config;
722 }
723
724 public function getNextPageUrl() {
725 return $this->nextPageUrl;
726 }
727}
728?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/content-extractor/SiteConfig.php b/inc/3rdparty/libraries/content-extractor/SiteConfig.php
new file mode 100644
index 00000000..c5e300d7
--- /dev/null
+++ b/inc/3rdparty/libraries/content-extractor/SiteConfig.php
@@ -0,0 +1,338 @@
1<?php
2/**
3 * Site Config
4 *
5 * Each instance of this class should hold extraction patterns and other directives
6 * for a website. See ContentExtractor class to see how it's used.
7 *
8 * @version 0.7
9 * @date 2012-08-27
10 * @author Keyvan Minoukadeh
11 * @copyright 2012 Keyvan Minoukadeh
12 * @license http://www.gnu.org/licenses/agpl-3.0.html AGPL v3
13 */
14
15class SiteConfig
16{
17 // Use first matching element as title (0 or more xpath expressions)
18 public $title = array();
19
20 // Use first matching element as body (0 or more xpath expressions)
21 public $body = array();
22
23 // Use first matching element as author (0 or more xpath expressions)
24 public $author = array();
25
26 // Use first matching element as date (0 or more xpath expressions)
27 public $date = array();
28
29 // Strip elements matching these xpath expressions (0 or more)
30 public $strip = array();
31
32 // Strip elements which contain these strings (0 or more) in the id or class attribute
33 public $strip_id_or_class = array();
34
35 // Strip images which contain these strings (0 or more) in the src attribute
36 public $strip_image_src = array();
37
38 // Additional HTTP headers to send
39 // NOT YET USED
40 public $http_header = array();
41
42 // Process HTML with tidy before creating DOM (bool or null if undeclared)
43 public $tidy = null;
44
45 protected $default_tidy = true; // used if undeclared
46
47 // Autodetect title/body if xpath expressions fail to produce results.
48 // Note that this applies to title and body separately, ie.
49 // * if we get a body match but no title match, this option will determine whether we autodetect title
50 // * if neither match, this determines whether we autodetect title and body.
51 // Also note that this only applies when there is at least one xpath expression in title or body, ie.
52 // * if title and body are both empty (no xpath expressions), this option has no effect (both title and body will be auto-detected)
53 // * if there's an xpath expression for title and none for body, body will be auto-detected and this option will determine whether we auto-detect title if the xpath expression for it fails to produce results.
54 // Usage scenario: you want to extract something specific from a set of URLs, e.g. a table, and if the table is not found, you want to ignore the entry completely. Auto-detection is unlikely to succeed here, so you construct your patterns and set this option to false. Another scenario may be a site where auto-detection has proven to fail (or worse, picked up the wrong content).
55 // bool or null if undeclared
56 public $autodetect_on_failure = null;
57 protected $default_autodetect_on_failure = true; // used if undeclared
58
59 // Clean up content block - attempt to remove elements that appear to be superfluous
60 // bool or null if undeclared
61 public $prune = null;
62 protected $default_prune = true; // used if undeclared
63
64 // Test URL - if present, can be used to test the config above
65 public $test_url = array();
66
67 // Single-page link - should identify a link element or URL pointing to the page holding the entire article
68 // This is useful for sites which split their articles across multiple pages. Links to such pages tend to
69 // display the first page with links to the other pages at the bottom. Often there is also a link to a page
70 // which displays the entire article on one page (e.g. 'print view').
71 // This should be an XPath expression identifying the link to that page. If present and we find a match,
72 // we will retrieve that page and the rest of the options in this config will be applied to the new page.
73 public $single_page_link = array();
74
75 public $next_page_link = array();
76
77 // Single-page link in feed? - same as above, but patterns applied to item description HTML taken from feed
78 public $single_page_link_in_feed = array();
79
80 // Which parser to use for turning raw HTML into a DOMDocument (either 'libxml' or 'html5lib')
81 // string or null if undeclared
82 public $parser = null;
83 protected $default_parser = 'libxml'; // used if undeclared
84
85 // Strings to search for in HTML before processing begins (used with $replace_string)
86 public $find_string = array();
87 // Strings to replace those found in $find_string before HTML processing begins
88 public $replace_string = array();
89
90 // the options below cannot be set in the config files which this class represents
91
92 //public $cache_in_apc = false; // used to decide if we should cache in apc or not
93 public $cache_key = null;
94 public static $debug = false;
95 protected static $apc = false;
96 protected static $config_path;
97 protected static $config_path_fallback;
98 protected static $config_cache = array();
99 const HOSTNAME_REGEX = '/^(([a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9-]*[A-Za-z0-9])$/';
100
101 protected static function debug($msg) {
102 if (self::$debug) {
103 //$mem = round(memory_get_usage()/1024, 2);
104 //$memPeak = round(memory_get_peak_usage()/1024, 2);
105 echo '* ',$msg;
106 //echo ' - mem used: ',$mem," (peak: $memPeak)\n";
107 echo "\n";
108 ob_flush();
109 flush();
110 }
111 }
112
113 // enable APC caching of certain site config files?
114 // If enabled the following site config files will be
115 // cached in APC cache (when requested for first time):
116 // * anything in site_config/custom/ and its corresponding file in site_config/standard/
117 // * the site config files associated with HTML fingerprints
118 // * the global site config file
119 // returns true if enabled, false otherwise
120 public static function use_apc($apc=true) {
121 if (!function_exists('apc_add')) {
122 if ($apc) self::debug('APC will not be used (function apc_add does not exist)');
123 return false;
124 }
125 self::$apc = $apc;
126 return $apc;
127 }
128
129 // return bool or null
130 public function tidy($use_default=true) {
131 if ($use_default) return (isset($this->tidy)) ? $this->tidy : $this->default_tidy;
132 return $this->tidy;
133 }
134
135 // return bool or null
136 public function prune($use_default=true) {
137 if ($use_default) return (isset($this->prune)) ? $this->prune : $this->default_prune;
138 return $this->prune;
139 }
140
141 // return string or null
142 public function parser($use_default=true) {
143 if ($use_default) return (isset($this->parser)) ? $this->parser : $this->default_parser;
144 return $this->parser;
145 }
146
147 // return bool or null
148 public function autodetect_on_failure($use_default=true) {
149 if ($use_default) return (isset($this->autodetect_on_failure)) ? $this->autodetect_on_failure : $this->default_autodetect_on_failure;
150 return $this->autodetect_on_failure;
151 }
152
153 public static function set_config_path($path, $fallback=null) {
154 self::$config_path = $path;
155 self::$config_path_fallback = $fallback;
156 }
157
158 public static function add_to_cache($key, SiteConfig $config, $use_apc=true) {
159 $key = strtolower($key);
160 if (substr($key, 0, 4) == 'www.') $key = substr($key, 4);
161 if ($config->cache_key) $key = $config->cache_key;
162 self::$config_cache[$key] = $config;
163 if (self::$apc && $use_apc) {
164 self::debug("Adding site config to APC cache with key sc.$key");
165 apc_add("sc.$key", $config);
166 }
167 self::debug("Cached site config with key $key");
168 }
169
170 public static function is_cached($key) {
171 $key = strtolower($key);
172 if (substr($key, 0, 4) == 'www.') $key = substr($key, 4);
173 if (array_key_exists($key, self::$config_cache)) {
174 return true;
175 } elseif (self::$apc && (bool)apc_fetch("sc.$key")) {
176 return true;
177 }
178 return false;
179 }
180
181 public function append(SiteConfig $newconfig) {
182 // check for commands where we accept multiple statements (no test_url)
183 foreach (array('title', 'body', 'author', 'date', 'strip', 'strip_id_or_class', 'strip_image_src', 'single_page_link', 'single_page_link_in_feed', 'next_page_link', 'http_header', 'find_string', 'replace_string') as $var) {
184 // append array elements for this config variable from $newconfig to this config
185 //$this->$var = $this->$var + $newconfig->$var;
186 $this->$var = array_unique(array_merge($this->$var, $newconfig->$var));
187 }
188 // check for single statement commands
189 // we do not overwrite existing non null values
190 foreach (array('tidy', 'prune', 'parser', 'autodetect_on_failure') as $var) {
191 if ($this->$var === null) $this->$var = $newconfig->$var;
192 }
193 }
194
195 // returns SiteConfig instance if an appropriate one is found, false otherwise
196 // if $exact_host_match is true, we will not look for wildcard config matches
197 // by default if host is 'test.example.org' we will look for and load '.example.org.txt' if it exists
198 public static function build($host, $exact_host_match=false) {
199 $host = strtolower($host);
200 if (substr($host, 0, 4) == 'www.') $host = substr($host, 4);
201 if (!$host || (strlen($host) > 200) || !preg_match(self::HOSTNAME_REGEX, ltrim($host, '.'))) return false;
202 // check for site configuration
203 $try = array($host);
204 // should we look for wildcard matches
205 if (!$exact_host_match) {
206 $split = explode('.', $host);
207 if (count($split) > 1) {
208 array_shift($split);
209 $try[] = '.'.implode('.', $split);
210 }
211 }
212
213 // look for site config file in primary folder
214 self::debug(". looking for site config for $host in primary folder");
215 foreach ($try as $h) {
216 if (array_key_exists($h, self::$config_cache)) {
217 self::debug("... site config for $h already loaded in this request");
218 return self::$config_cache[$h];
219 } elseif (self::$apc && ($sconfig = apc_fetch("sc.$h"))) {
220 self::debug("... site config for $h in APC cache");
221 return $sconfig;
222 } elseif (file_exists(self::$config_path."/$h.txt")) {
223 self::debug("... found site config ($h.txt)");
224 $file_primary = self::$config_path."/$h.txt";
225 $matched_name = $h;
226 break;
227 }
228 }
229
230 // if we found site config, process it
231 if (isset($file_primary)) {
232 $config_lines = file($file_primary, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
233 if (!$config_lines || !is_array($config_lines)) return false;
234 $config = self::build_from_array($config_lines);
235 // if APC caching is available and enabled, mark this for cache
236 //$config->cache_in_apc = true;
237 $config->cache_key = $matched_name;
238
239 // if autodetec on failure is off (on by default) we do not need to look
240 // in secondary folder
241 if (!$config->autodetect_on_failure()) {
242 self::debug('... autodetect on failure is disabled (no other site config files will be loaded)');
243 return $config;
244 }
245 }
246
247 // look for site config file in secondary folder
248 if (isset(self::$config_path_fallback)) {
249 self::debug(". looking for site config for $host in secondary folder");
250 foreach ($try as $h) {
251 if (file_exists(self::$config_path_fallback."/$h.txt")) {
252 self::debug("... found site config in secondary folder ($h.txt)");
253 $file_secondary = self::$config_path_fallback."/$h.txt";
254 $matched_name = $h;
255 break;
256 }
257 }
258 if (!isset($file_secondary)) {
259 self::debug("... no site config match in secondary folder");
260 }
261 }
262
263 // return false if no config file found
264 if (!isset($file_primary) && !isset($file_secondary)) {
265 self::debug("... no site config match for $host");
266 return false;
267 }
268
269 // return primary config if secondary not found
270 if (!isset($file_secondary) && isset($config)) {
271 return $config;
272 }
273
274 // process secondary config file
275 $config_lines = file($file_secondary, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
276 if (!$config_lines || !is_array($config_lines)) {
277 // failed to process secondary
278 if (isset($config)) {
279 // return primary config
280 return $config;
281 } else {
282 return false;
283 }
284 }
285
286 // merge with primary and return
287 if (isset($config)) {
288 self::debug('. merging config files');
289 $config->append(self::build_from_array($config_lines));
290 return $config;
291 } else {
292 // return just secondary
293 $config = self::build_from_array($config_lines);
294 // if APC caching is available and enabled, mark this for cache
295 //$config->cache_in_apc = true;
296 $config->cache_key = $matched_name;
297 return $config;
298 }
299 }
300
301 public static function build_from_array(array $lines) {
302 $config = new SiteConfig();
303 foreach ($lines as $line) {
304 $line = trim($line);
305
306 // skip comments, empty lines
307 if ($line == '' || $line[0] == '#') continue;
308
309 // get command
310 $command = explode(':', $line, 2);
311 // if there's no colon ':', skip this line
312 if (count($command) != 2) continue;
313 $val = trim($command[1]);
314 $command = trim($command[0]);
315 if ($command == '' || $val == '') continue;
316
317 // check for commands where we accept multiple statements
318 if (in_array($command, array('title', 'body', 'author', 'date', 'strip', 'strip_id_or_class', 'strip_image_src', 'single_page_link', 'single_page_link_in_feed', 'next_page_link', 'http_header', 'test_url', 'find_string', 'replace_string'))) {
319 array_push($config->$command, $val);
320 // check for single statement commands that evaluate to true or false
321 } elseif (in_array($command, array('tidy', 'prune', 'autodetect_on_failure'))) {
322 $config->$command = ($val == 'yes');
323 // check for single statement commands stored as strings
324 } elseif (in_array($command, array('parser'))) {
325 $config->$command = $val;
326 // check for replace_string(find): replace
327 } elseif ((substr($command, -1) == ')') && preg_match('!^([a-z0-9_]+)\((.*?)\)$!i', $command, $match)) {
328 if (in_array($match[1], array('replace_string'))) {
329 $command = $match[1];
330 array_push($config->find_string, $match[2]);
331 array_push($config->$command, $val);
332 }
333 }
334 }
335 return $config;
336 }
337}
338?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/feedwriter/FeedItem.php b/inc/3rdparty/libraries/feedwriter/FeedItem.php
new file mode 100644
index 00000000..9373deeb
--- /dev/null
+++ b/inc/3rdparty/libraries/feedwriter/FeedItem.php
@@ -0,0 +1,185 @@
1<?php
2 /**
3 * Univarsel Feed Writer
4 *
5 * FeedItem class - Used as feed element in FeedWriter class
6 *
7 * @package UnivarselFeedWriter
8 * @author Anis uddin Ahmad <anisniit@gmail.com>
9 * @link http://www.ajaxray.com/projects/rss
10 */
11 class FeedItem
12 {
13 private $elements = array(); //Collection of feed elements
14 private $version;
15
16 /**
17 * Constructor
18 *
19 * @param contant (RSS1/RSS2/ATOM) RSS2 is default.
20 */
21 function __construct($version = RSS2)
22 {
23 $this->version = $version;
24 }
25
26 /**
27 * Set element (overwrites existing elements with $elementName)
28 *
29 * @access public
30 * @param srting The tag name of an element
31 * @param srting The content of tag
32 * @param array Attributes(if any) in 'attrName' => 'attrValue' format
33 * @return void
34 */
35 public function setElement($elementName, $content, $attributes = null)
36 {
37 if (isset($this->elements[$elementName])) {
38 unset($this->elements[$elementName]);
39 }
40 $this->addElement($elementName, $content, $attributes);
41 }
42
43 /**
44 * Add an element to elements array
45 *
46 * @access public
47 * @param srting The tag name of an element
48 * @param srting The content of tag
49 * @param array Attributes(if any) in 'attrName' => 'attrValue' format
50 * @return void
51 */
52 public function addElement($elementName, $content, $attributes = null)
53 {
54 $i = 0;
55 if (isset($this->elements[$elementName])) {
56 $i = count($this->elements[$elementName]);
57 } else {
58 $this->elements[$elementName] = array();
59 }
60 $this->elements[$elementName][$i]['name'] = $elementName;
61 $this->elements[$elementName][$i]['content'] = $content;
62 $this->elements[$elementName][$i]['attributes'] = $attributes;
63 }
64
65 /**
66 * Set multiple feed elements from an array.
67 * Elements which have attributes cannot be added by this method
68 *
69 * @access public
70 * @param array array of elements in 'tagName' => 'tagContent' format.
71 * @return void
72 */
73 public function addElementArray($elementArray)
74 {
75 if(! is_array($elementArray)) return;
76 foreach ($elementArray as $elementName => $content)
77 {
78 $this->addElement($elementName, $content);
79 }
80 }
81
82 /**
83 * Return the collection of elements in this feed item
84 *
85 * @access public
86 * @return array
87 */
88 public function getElements()
89 {
90 return $this->elements;
91 }
92
93 // Wrapper functions ------------------------------------------------------
94
95 /**
96 * Set the 'dscription' element of feed item
97 *
98 * @access public
99 * @param string The content of 'description' element
100 * @return void
101 */
102 public function setDescription($description)
103 {
104 $tag = 'description';
105 $this->setElement($tag, $description);
106 }
107
108 /**
109 * @desc Set the 'title' element of feed item
110 * @access public
111 * @param string The content of 'title' element
112 * @return void
113 */
114 public function setTitle($title)
115 {
116 $this->setElement('title', $title);
117 }
118
119 /**
120 * Set the 'date' element of feed item
121 *
122 * @access public
123 * @param string The content of 'date' element
124 * @return void
125 */
126 public function setDate($date)
127 {
128 if(! is_numeric($date))
129 {
130 $date = strtotime($date);
131 }
132
133 if($this->version == RSS2)
134 {
135 $tag = 'pubDate';
136 $value = date(DATE_RSS, $date);
137 }
138 else
139 {
140 $tag = 'dc:date';
141 $value = date("Y-m-d", $date);
142 }
143
144 $this->setElement($tag, $value);
145 }
146
147 /**
148 * Set the 'link' element of feed item
149 *
150 * @access public
151 * @param string The content of 'link' element
152 * @return void
153 */
154 public function setLink($link)
155 {
156 if($this->version == RSS2 || $this->version == RSS1)
157 {
158 $this->setElement('link', $link);
159 }
160 else
161 {
162 $this->setElement('link','',array('href'=>$link));
163 $this->setElement('id', FeedWriter::uuid($link,'urn:uuid:'));
164 }
165
166 }
167
168 /**
169 * Set the 'encloser' element of feed item
170 * For RSS 2.0 only
171 *
172 * @access public
173 * @param string The url attribute of encloser tag
174 * @param string The length attribute of encloser tag
175 * @param string The type attribute of encloser tag
176 * @return void
177 */
178 public function setEncloser($url, $length, $type)
179 {
180 $attributes = array('url'=>$url, 'length'=>$length, 'type'=>$type);
181 $this->setElement('enclosure','',$attributes);
182 }
183
184 } // end of class FeedItem
185?>
diff --git a/inc/3rdparty/libraries/feedwriter/FeedWriter.php b/inc/3rdparty/libraries/feedwriter/FeedWriter.php
new file mode 100644
index 00000000..adb2526c
--- /dev/null
+++ b/inc/3rdparty/libraries/feedwriter/FeedWriter.php
@@ -0,0 +1,441 @@
1<?php
2define('RSS2', 1, true);
3define('JSON', 2, true);
4define('JSONP', 3, true);
5
6 /**
7 * Univarsel Feed Writer class
8 *
9 * Genarate RSS2 or JSON (original: RSS 1.0, RSS2.0 and ATOM Feed)
10 *
11 * Modified for FiveFilters.org's Full-Text RSS project
12 * to allow for inclusion of hubs, JSON output.
13 * Stripped RSS1 and ATOM support.
14 *
15 * @package UnivarselFeedWriter
16 * @author Anis uddin Ahmad <anisniit@gmail.com>
17 * @link http://www.ajaxray.com/projects/rss
18 */
19 class FeedWriter
20 {
21 private $self = null; // self URL - http://feed2.w3.org/docs/warning/MissingAtomSelfLink.html
22 private $hubs = array(); // PubSubHubbub hubs
23 private $channels = array(); // Collection of channel elements
24 private $items = array(); // Collection of items as object of FeedItem class.
25 private $data = array(); // Store some other version wise data
26 private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA
27 private $xsl = null; // stylesheet to render RSS (used by Chrome)
28 private $json = null; // JSON object
29
30 private $version = null;
31
32 /**
33 * Constructor
34 *
35 * @param constant the version constant (RSS2 or JSON).
36 */
37 function __construct($version = RSS2)
38 {
39 $this->version = $version;
40
41 // Setting default value for assential channel elements
42 $this->channels['title'] = $version . ' Feed';
43 $this->channels['link'] = 'http://www.ajaxray.com/blog';
44
45 //Tag names to encode in CDATA
46 $this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary');
47 }
48
49 public function setFormat($format) {
50 $this->version = $format;
51 }
52
53 // Start # public functions ---------------------------------------------
54
55 /**
56 * Set a channel element
57 * @access public
58 * @param srting name of the channel tag
59 * @param string content of the channel tag
60 * @return void
61 */
62 public function setChannelElement($elementName, $content)
63 {
64 $this->channels[$elementName] = $content ;
65 }
66
67 /**
68 * Set multiple channel elements from an array. Array elements
69 * should be 'channelName' => 'channelContent' format.
70 *
71 * @access public
72 * @param array array of channels
73 * @return void
74 */
75 public function setChannelElementsFromArray($elementArray)
76 {
77 if(! is_array($elementArray)) return;
78 foreach ($elementArray as $elementName => $content)
79 {
80 $this->setChannelElement($elementName, $content);
81 }
82 }
83
84 /**
85 * Genarate the actual RSS/JSON file
86 *
87 * @access public
88 * @return void
89 */
90 public function genarateFeed()
91 {
92 if ($this->version == RSS2) {
93 header('Content-type: text/xml; charset=UTF-8');
94 // this line prevents Chrome 20 from prompting download
95 // used by Google: https://news.google.com/news/feeds?ned=us&topic=b&output=rss
96 header('X-content-type-options: nosniff');
97 } elseif ($this->version == JSON) {
98 header('Content-type: application/json; charset=UTF-8');
99 $this->json = new stdClass();
100 } elseif ($this->version == JSONP) {
101 header('Content-type: application/javascript; charset=UTF-8');
102 $this->json = new stdClass();
103 }
104 $this->printHead();
105 $this->printChannels();
106 $this->printItems();
107 $this->printTale();
108 if ($this->version == JSON || $this->version == JSONP) {
109 echo json_encode($this->json);
110 }
111 }
112
113 /**
114 * Create a new FeedItem.
115 *
116 * @access public
117 * @return object instance of FeedItem class
118 */
119 public function createNewItem()
120 {
121 $Item = new FeedItem($this->version);
122 return $Item;
123 }
124
125 /**
126 * Add a FeedItem to the main class
127 *
128 * @access public
129 * @param object instance of FeedItem class
130 * @return void
131 */
132 public function addItem($feedItem)
133 {
134 $this->items[] = $feedItem;
135 }
136
137 // Wrapper functions -------------------------------------------------------------------
138
139 /**
140 * Set the 'title' channel element
141 *
142 * @access public
143 * @param srting value of 'title' channel tag
144 * @return void
145 */
146 public function setTitle($title)
147 {
148 $this->setChannelElement('title', $title);
149 }
150
151 /**
152 * Add a hub to the channel element
153 *
154 * @access public
155 * @param string URL
156 * @return void
157 */
158 public function addHub($hub)
159 {
160 $this->hubs[] = $hub;
161 }
162
163 /**
164 * Set XSL URL
165 *
166 * @access public
167 * @param string URL
168 * @return void
169 */
170 public function setXsl($xsl)
171 {
172 $this->xsl = $xsl;
173 }
174
175 /**
176 * Set self URL
177 *
178 * @access public
179 * @param string URL
180 * @return void
181 */
182 public function setSelf($self)
183 {
184 $this->self = $self;
185 }
186
187 /**
188 * Set the 'description' channel element
189 *
190 * @access public
191 * @param srting value of 'description' channel tag
192 * @return void
193 */
194 public function setDescription($desciption)
195 {
196 $tag = ($this->version == ATOM)? 'subtitle' : 'description';
197 $this->setChannelElement($tag, $desciption);
198 }
199
200 /**
201 * Set the 'link' channel element
202 *
203 * @access public
204 * @param srting value of 'link' channel tag
205 * @return void
206 */
207 public function setLink($link)
208 {
209 $this->setChannelElement('link', $link);
210 }
211
212 /**
213 * Set the 'image' channel element
214 *
215 * @access public
216 * @param srting title of image
217 * @param srting link url of the imahe
218 * @param srting path url of the image
219 * @return void
220 */
221 public function setImage($title, $link, $url)
222 {
223 $this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url));
224 }
225
226 // End # public functions ----------------------------------------------
227
228 // Start # private functions ----------------------------------------------
229
230 /**
231 * Prints the xml and rss namespace
232 *
233 * @access private
234 * @return void
235 */
236 private function printHead()
237 {
238 if ($this->version == RSS2)
239 {
240 $out = '<?xml version="1.0" encoding="utf-8"?>'."\n";
241 if ($this->xsl) $out .= '<?xml-stylesheet type="text/xsl" href="'.htmlspecialchars($this->xsl).'"?>' . PHP_EOL;
242 $out .= '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">' . PHP_EOL;
243 echo $out;
244 }
245 elseif ($this->version == JSON || $this->version == JSONP)
246 {
247 $this->json->rss = array('@attributes' => array('version' => '2.0'));
248 }
249 }
250
251 /**
252 * Closes the open tags at the end of file
253 *
254 * @access private
255 * @return void
256 */
257 private function printTale()
258 {
259 if ($this->version == RSS2)
260 {
261 echo '</channel>',PHP_EOL,'</rss>';
262 }
263 // do nothing for JSON
264 }
265
266 /**
267 * Creates a single node as xml format
268 *
269 * @access private
270 * @param string name of the tag
271 * @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format
272 * @param array Attributes(if any) in 'attrName' => 'attrValue' format
273 * @return string formatted xml tag
274 */
275 private function makeNode($tagName, $tagContent, $attributes = null)
276 {
277 if ($this->version == RSS2)
278 {
279 $nodeText = '';
280 $attrText = '';
281 if (is_array($attributes))
282 {
283 foreach ($attributes as $key => $value)
284 {
285 $attrText .= " $key=\"$value\" ";
286 }
287 }
288 $nodeText .= "<{$tagName}{$attrText}>";
289 if (is_array($tagContent))
290 {
291 foreach ($tagContent as $key => $value)
292 {
293 $nodeText .= $this->makeNode($key, $value);
294 }
295 }
296 else
297 {
298 //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);
299 $nodeText .= htmlspecialchars($tagContent);
300 }
301 //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>";
302 $nodeText .= "</$tagName>";
303 return $nodeText . PHP_EOL;
304 }
305 elseif ($this->version == JSON || $this->version == JSONP)
306 {
307 $tagName = (string)$tagName;
308 $tagName = strtr($tagName, ':', '_');
309 $node = null;
310 if (!$tagContent && is_array($attributes) && count($attributes))
311 {
312 $node = array('@attributes' => $this->json_keys($attributes));
313 } else {
314 if (is_array($tagContent)) {
315 $node = $this->json_keys($tagContent);
316 } else {
317 $node = $tagContent;
318 }
319 }
320 return $node;
321 }
322 return ''; // should not get here
323 }
324
325 private function json_keys(array $array) {
326 $new = array();
327 foreach ($array as $key => $val) {
328 if (is_string($key)) $key = strtr($key, ':', '_');
329 if (is_array($val)) {
330 $new[$key] = $this->json_keys($val);
331 } else {
332 $new[$key] = $val;
333 }
334 }
335 return $new;
336 }
337
338 /**
339 * @desc Print channels
340 * @access private
341 * @return void
342 */
343 private function printChannels()
344 {
345 //Start channel tag
346 if ($this->version == RSS2) {
347 echo '<channel>' . PHP_EOL;
348 // add hubs
349 foreach ($this->hubs as $hub) {
350 //echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom'));
351 echo '<link rel="hub" href="'.htmlspecialchars($hub).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;
352 }
353 // add self
354 if (isset($this->self)) {
355 //echo $this->makeNode('link', '', array('rel'=>'self', 'href'=>$this->self, 'xmlns'=>'http://www.w3.org/2005/Atom'));
356 echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;
357 }
358 //Print Items of channel
359 foreach ($this->channels as $key => $value)
360 {
361 echo $this->makeNode($key, $value);
362 }
363 } elseif ($this->version == JSON || $this->version == JSONP) {
364 $this->json->rss['channel'] = (object)$this->json_keys($this->channels);
365 }
366 }
367
368 /**
369 * Prints formatted feed items
370 *
371 * @access private
372 * @return void
373 */
374 private function printItems()
375 {
376 foreach ($this->items as $item) {
377 $itemElements = $item->getElements();
378
379 echo $this->startItem();
380
381 if ($this->version == JSON || $this->version == JSONP) {
382 $json_item = array();
383 }
384
385 foreach ($itemElements as $thisElement) {
386 foreach ($thisElement as $instance) {
387 if ($this->version == RSS2) {
388 echo $this->makeNode($instance['name'], $instance['content'], $instance['attributes']);
389 } elseif ($this->version == JSON || $this->version == JSONP) {
390 $_json_node = $this->makeNode($instance['name'], $instance['content'], $instance['attributes']);
391 if (count($thisElement) > 1) {
392 $json_item[strtr($instance['name'], ':', '_')][] = $_json_node;
393 } else {
394 $json_item[strtr($instance['name'], ':', '_')] = $_json_node;
395 }
396 }
397 }
398 }
399 echo $this->endItem();
400 if ($this->version == JSON || $this->version == JSONP) {
401 if (count($this->items) > 1) {
402 $this->json->rss['channel']->item[] = $json_item;
403 } else {
404 $this->json->rss['channel']->item = $json_item;
405 }
406 }
407 }
408 }
409
410 /**
411 * Make the starting tag of channels
412 *
413 * @access private
414 * @return void
415 */
416 private function startItem()
417 {
418 if ($this->version == RSS2)
419 {
420 echo '<item>' . PHP_EOL;
421 }
422 // nothing for JSON
423 }
424
425 /**
426 * Closes feed item tag
427 *
428 * @access private
429 * @return void
430 */
431 private function endItem()
432 {
433 if ($this->version == RSS2)
434 {
435 echo '</item>' . PHP_EOL;
436 }
437 // nothing for JSON
438 }
439
440 // End # private functions ----------------------------------------------
441 } \ No newline at end of file
diff --git a/inc/3rdparty/libraries/htmLawed/htmLawed.php b/inc/3rdparty/libraries/htmLawed/htmLawed.php
new file mode 100644
index 00000000..9a62aca5
--- /dev/null
+++ b/inc/3rdparty/libraries/htmLawed/htmLawed.php
@@ -0,0 +1,728 @@
1<?php
2
3/*
4htmLawed 1.1.14, 8 August 2012
5OOP code, 8 August 2012
6Copyright Santosh Patnaik
7Dual LGPL v3 and GPL v2+ license
8A PHP Labware internal utility; www.bioinformatics.org/phplabware/internal_utilities/htmLawed
9
10See htmLawed_README.txt/htm
11*/
12
13class htmLawed{
14// begin class
15public static function hl($t, $C=1, $S=array()){
16$C = is_array($C) ? $C : array();
17if(!empty($C['valid_xhtml'])){
18 $C['elements'] = empty($C['elements']) ? '*-center-dir-font-isindex-menu-s-strike-u' : $C['elements'];
19 $C['make_tag_strict'] = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 2;
20 $C['xml:lang'] = isset($C['xml:lang']) ? $C['xml:lang'] : 2;
21}
22// config eles
23$e = array('a'=>1, 'abbr'=>1, 'acronym'=>1, 'address'=>1, 'applet'=>1, 'area'=>1, 'b'=>1, 'bdo'=>1, 'big'=>1, 'blockquote'=>1, 'br'=>1, 'button'=>1, 'caption'=>1, 'center'=>1, 'cite'=>1, 'code'=>1, 'col'=>1, 'colgroup'=>1, 'dd'=>1, 'del'=>1, 'dfn'=>1, 'dir'=>1, 'div'=>1, 'dl'=>1, 'dt'=>1, 'em'=>1, 'embed'=>1, 'fieldset'=>1, 'font'=>1, 'form'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'i'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'ins'=>1, 'isindex'=>1, 'kbd'=>1, 'label'=>1, 'legend'=>1, 'li'=>1, 'map'=>1, 'menu'=>1, 'noscript'=>1, 'object'=>1, 'ol'=>1, 'optgroup'=>1, 'option'=>1, 'p'=>1, 'param'=>1, 'pre'=>1, 'q'=>1, 'rb'=>1, 'rbc'=>1, 'rp'=>1, 'rt'=>1, 'rtc'=>1, 'ruby'=>1, 's'=>1, 'samp'=>1, 'script'=>1, 'select'=>1, 'small'=>1, 'span'=>1, 'strike'=>1, 'strong'=>1, 'sub'=>1, 'sup'=>1, 'table'=>1, 'tbody'=>1, 'td'=>1, 'textarea'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1, 'tt'=>1, 'u'=>1, 'ul'=>1, 'var'=>1); // 86/deprecated+embed+ruby
24if(!empty($C['safe'])){
25 unset($e['applet'], $e['embed'], $e['iframe'], $e['object'], $e['script']);
26}
27$x = !empty($C['elements']) ? str_replace(array("\n", "\r", "\t", ' '), '', $C['elements']) : '*';
28if($x == '-*'){$e = array();}
29elseif(strpos($x, '*') === false){$e = array_flip(explode(',', $x));}
30else{
31 if(isset($x[1])){
32 preg_match_all('`(?:^|-|\+)[^\-+]+?(?=-|\+|$)`', $x, $m, PREG_SET_ORDER);
33 for($i=count($m); --$i>=0;){$m[$i] = $m[$i][0];}
34 foreach($m as $v){
35 if($v[0] == '+'){$e[substr($v, 1)] = 1;}
36 if($v[0] == '-' && isset($e[($v = substr($v, 1))]) && !in_array('+'. $v, $m)){unset($e[$v]);}
37 }
38 }
39}
40$C['elements'] =& $e;
41// config attrs
42$x = !empty($C['deny_attribute']) ? str_replace(array("\n", "\r", "\t", ' '), '', $C['deny_attribute']) : '';
43$x = array_flip((isset($x[0]) && $x[0] == '*') ? explode('-', $x) : explode(',', $x. (!empty($C['safe']) ? ',on*' : '')));
44if(isset($x['on*'])){
45 unset($x['on*']);
46 $x += array('onblur'=>1, 'onchange'=>1, 'onclick'=>1, 'ondblclick'=>1, 'onfocus'=>1, 'onkeydown'=>1, 'onkeypress'=>1, 'onkeyup'=>1, 'onmousedown'=>1, 'onmousemove'=>1, 'onmouseout'=>1, 'onmouseover'=>1, 'onmouseup'=>1, 'onreset'=>1, 'onselect'=>1, 'onsubmit'=>1);
47}
48$C['deny_attribute'] = $x;
49// config URL
50$x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https';
51$C['schemes'] = array();
52foreach(explode(';', str_replace(array(' ', "\t", "\r", "\n"), '', $x)) as $v){
53 $x = $x2 = null; list($x, $x2) = explode(':', $v, 2);
54 if($x2){$C['schemes'][$x] = array_flip(explode(',', $x2));}
55}
56if(!isset($C['schemes']['*'])){$C['schemes']['*'] = array('file'=>1, 'http'=>1, 'https'=>1,);}
57if(!empty($C['safe']) && empty($C['schemes']['style'])){$C['schemes']['style'] = array('!'=>1);}
58$C['abs_url'] = isset($C['abs_url']) ? $C['abs_url'] : 0;
59if(!isset($C['base_url']) or !preg_match('`^[a-zA-Z\d.+\-]+://[^/]+/(.+?/)?$`', $C['base_url'])){
60 $C['base_url'] = $C['abs_url'] = 0;
61}
62// config rest
63$C['and_mark'] = empty($C['and_mark']) ? 0 : 1;
64$C['anti_link_spam'] = (isset($C['anti_link_spam']) && is_array($C['anti_link_spam']) && count($C['anti_link_spam']) == 2 && (empty($C['anti_link_spam'][0]) or htmLawed::hl_regex($C['anti_link_spam'][0])) && (empty($C['anti_link_spam'][1]) or htmLawed::hl_regex($C['anti_link_spam'][1]))) ? $C['anti_link_spam'] : 0;
65$C['anti_mail_spam'] = isset($C['anti_mail_spam']) ? $C['anti_mail_spam'] : 0;
66$C['balance'] = isset($C['balance']) ? (bool)$C['balance'] : 1;
67$C['cdata'] = isset($C['cdata']) ? $C['cdata'] : (empty($C['safe']) ? 3 : 0);
68$C['clean_ms_char'] = empty($C['clean_ms_char']) ? 0 : $C['clean_ms_char'];
69$C['comment'] = isset($C['comment']) ? $C['comment'] : (empty($C['safe']) ? 3 : 0);
70$C['css_expression'] = empty($C['css_expression']) ? 0 : 1;
71$C['direct_list_nest'] = empty($C['direct_list_nest']) ? 0 : 1;
72$C['hexdec_entity'] = isset($C['hexdec_entity']) ? $C['hexdec_entity'] : 1;
73$C['hook'] = (!empty($C['hook']) && function_exists($C['hook'])) ? $C['hook'] : 0;
74$C['hook_tag'] = (!empty($C['hook_tag']) && function_exists($C['hook_tag'])) ? $C['hook_tag'] : 0;
75$C['keep_bad'] = isset($C['keep_bad']) ? $C['keep_bad'] : 6;
76$C['lc_std_val'] = isset($C['lc_std_val']) ? (bool)$C['lc_std_val'] : 1;
77$C['make_tag_strict'] = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 1;
78$C['named_entity'] = isset($C['named_entity']) ? (bool)$C['named_entity'] : 1;
79$C['no_deprecated_attr'] = isset($C['no_deprecated_attr']) ? $C['no_deprecated_attr'] : 1;
80$C['parent'] = isset($C['parent'][0]) ? strtolower($C['parent']) : 'body';
81$C['show_setting'] = !empty($C['show_setting']) ? $C['show_setting'] : 0;
82$C['style_pass'] = empty($C['style_pass']) ? 0 : 1;
83$C['tidy'] = empty($C['tidy']) ? 0 : $C['tidy'];
84$C['unique_ids'] = isset($C['unique_ids']) ? $C['unique_ids'] : 1;
85$C['xml:lang'] = isset($C['xml:lang']) ? $C['xml:lang'] : 0;
86
87if(isset($GLOBALS['C'])){$reC = $GLOBALS['C'];}
88$GLOBALS['C'] = $C;
89$S = is_array($S) ? $S : htmLawed::hl_spec($S);
90if(isset($GLOBALS['S'])){$reS = $GLOBALS['S'];}
91$GLOBALS['S'] = $S;
92
93$t = preg_replace('`[\x00-\x08\x0b-\x0c\x0e-\x1f]`', '', $t);
94if($C['clean_ms_char']){
95 $x = array("\x7f"=>'', "\x80"=>'&#8364;', "\x81"=>'', "\x83"=>'&#402;', "\x85"=>'&#8230;', "\x86"=>'&#8224;', "\x87"=>'&#8225;', "\x88"=>'&#710;', "\x89"=>'&#8240;', "\x8a"=>'&#352;', "\x8b"=>'&#8249;', "\x8c"=>'&#338;', "\x8d"=>'', "\x8e"=>'&#381;', "\x8f"=>'', "\x90"=>'', "\x95"=>'&#8226;', "\x96"=>'&#8211;', "\x97"=>'&#8212;', "\x98"=>'&#732;', "\x99"=>'&#8482;', "\x9a"=>'&#353;', "\x9b"=>'&#8250;', "\x9c"=>'&#339;', "\x9d"=>'', "\x9e"=>'&#382;', "\x9f"=>'&#376;');
96 $x = $x + ($C['clean_ms_char'] == 1 ? array("\x82"=>'&#8218;', "\x84"=>'&#8222;', "\x91"=>'&#8216;', "\x92"=>'&#8217;', "\x93"=>'&#8220;', "\x94"=>'&#8221;') : array("\x82"=>'\'', "\x84"=>'"', "\x91"=>'\'', "\x92"=>'\'', "\x93"=>'"', "\x94"=>'"'));
97 $t = strtr($t, $x);
98}
99if($C['cdata'] or $C['comment']){$t = preg_replace_callback('`<!(?:(?:--.*?--)|(?:\[CDATA\[.*?\]\]))>`sm', 'htmLawed::hl_cmtcd', $t);}
100$t = preg_replace_callback('`&amp;([A-Za-z][A-Za-z0-9]{1,30}|#(?:[0-9]{1,8}|[Xx][0-9A-Fa-f]{1,7}));`', 'htmLawed::hl_ent', str_replace('&', '&amp;', $t));
101if($C['unique_ids'] && !isset($GLOBALS['hl_Ids'])){$GLOBALS['hl_Ids'] = array();}
102if($C['hook']){$t = $C['hook']($t, $C, $S);}
103if($C['show_setting'] && preg_match('`^[a-z][a-z0-9_]*$`i', $C['show_setting'])){
104 $GLOBALS[$C['show_setting']] = array('config'=>$C, 'spec'=>$S, 'time'=>microtime());
105}
106// main
107$t = preg_replace_callback('`<(?:(?:\s|$)|(?:[^>]*(?:>|$)))|>`m', 'htmLawed::hl_tag', $t);
108$t = $C['balance'] ? htmLawed::hl_bal($t, $C['keep_bad'], $C['parent']) : $t;
109$t = (($C['cdata'] or $C['comment']) && strpos($t, "\x01") !== false) ? str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05"), array('', '', '&', '<', '>'), $t) : $t;
110$t = $C['tidy'] ? htmLawed::hl_tidy($t, $C['tidy'], $C['parent']) : $t;
111unset($C, $e);
112if(isset($reC)){$GLOBALS['C'] = $reC;}
113if(isset($reS)){$GLOBALS['S'] = $reS;}
114return $t;
115// eof
116}
117
118public static function hl_attrval($t, $p){
119// check attr val against $S
120$o = 1; $l = strlen($t);
121foreach($p as $k=>$v){
122 switch($k){
123 case 'maxlen':if($l > $v){$o = 0;}
124 break; case 'minlen': if($l < $v){$o = 0;}
125 break; case 'maxval': if((float)($t) > $v){$o = 0;}
126 break; case 'minval': if((float)($t) < $v){$o = 0;}
127 break; case 'match': if(!preg_match($v, $t)){$o = 0;}
128 break; case 'nomatch': if(preg_match($v, $t)){$o = 0;}
129 break; case 'oneof':
130 $m = 0;
131 foreach(explode('|', $v) as $n){if($t == $n){$m = 1; break;}}
132 $o = $m;
133 break; case 'noneof':
134 $m = 1;
135 foreach(explode('|', $v) as $n){if($t == $n){$m = 0; break;}}
136 $o = $m;
137 break; default:
138 break;
139 }
140 if(!$o){break;}
141}
142return ($o ? $t : (isset($p['default']) ? $p['default'] : 0));
143// eof
144}
145
146public static function hl_bal($t, $do=1, $in='div'){
147// balance tags
148// by content
149$cB = array('blockquote'=>1, 'form'=>1, 'map'=>1, 'noscript'=>1); // Block
150$cE = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1); // Empty
151$cF = array('button'=>1, 'del'=>1, 'div'=>1, 'dd'=>1, 'fieldset'=>1, 'iframe'=>1, 'ins'=>1, 'li'=>1, 'noscript'=>1, 'object'=>1, 'td'=>1, 'th'=>1); // Flow; later context-wise dynamic move of ins & del to $cI
152$cI = array('a'=>1, 'abbr'=>1, 'acronym'=>1, 'address'=>1, 'b'=>1, 'bdo'=>1, 'big'=>1, 'caption'=>1, 'cite'=>1, 'code'=>1, 'dfn'=>1, 'dt'=>1, 'em'=>1, 'font'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'i'=>1, 'kbd'=>1, 'label'=>1, 'legend'=>1, 'p'=>1, 'pre'=>1, 'q'=>1, 'rb'=>1, 'rt'=>1, 's'=>1, 'samp'=>1, 'small'=>1, 'span'=>1, 'strike'=>1, 'strong'=>1, 'sub'=>1, 'sup'=>1, 'tt'=>1, 'u'=>1, 'var'=>1); // Inline
153$cN = array('a'=>array('a'=>1), 'button'=>array('a'=>1, 'button'=>1, 'fieldset'=>1, 'form'=>1, 'iframe'=>1, 'input'=>1, 'label'=>1, 'select'=>1, 'textarea'=>1), 'fieldset'=>array('fieldset'=>1), 'form'=>array('form'=>1), 'label'=>array('label'=>1), 'noscript'=>array('script'=>1), 'pre'=>array('big'=>1, 'font'=>1, 'img'=>1, 'object'=>1, 'script'=>1, 'small'=>1, 'sub'=>1, 'sup'=>1), 'rb'=>array('ruby'=>1), 'rt'=>array('ruby'=>1)); // Illegal
154$cN2 = array_keys($cN);
155$cR = array('blockquote'=>1, 'dir'=>1, 'dl'=>1, 'form'=>1, 'map'=>1, 'menu'=>1, 'noscript'=>1, 'ol'=>1, 'optgroup'=>1, 'rbc'=>1, 'rtc'=>1, 'ruby'=>1, 'select'=>1, 'table'=>1, 'tbody'=>1, 'tfoot'=>1, 'thead'=>1, 'tr'=>1, 'ul'=>1);
156$cS = array('colgroup'=>array('col'=>1), 'dir'=>array('li'=>1), 'dl'=>array('dd'=>1, 'dt'=>1), 'menu'=>array('li'=>1), 'ol'=>array('li'=>1), 'optgroup'=>array('option'=>1), 'option'=>array('#pcdata'=>1), 'rbc'=>array('rb'=>1), 'rp'=>array('#pcdata'=>1), 'rtc'=>array('rt'=>1), 'ruby'=>array('rb'=>1, 'rbc'=>1, 'rp'=>1, 'rt'=>1, 'rtc'=>1), 'select'=>array('optgroup'=>1, 'option'=>1), 'script'=>array('#pcdata'=>1), 'table'=>array('caption'=>1, 'col'=>1, 'colgroup'=>1, 'tfoot'=>1, 'tbody'=>1, 'tr'=>1, 'thead'=>1), 'tbody'=>array('tr'=>1), 'tfoot'=>array('tr'=>1), 'textarea'=>array('#pcdata'=>1), 'thead'=>array('tr'=>1), 'tr'=>array('td'=>1, 'th'=>1), 'ul'=>array('li'=>1)); // Specific - immediate parent-child
157if($GLOBALS['C']['direct_list_nest']){$cS['ol'] = $cS['ul'] += array('ol'=>1, 'ul'=>1);}
158$cO = array('address'=>array('p'=>1), 'applet'=>array('param'=>1), 'blockquote'=>array('script'=>1), 'fieldset'=>array('legend'=>1, '#pcdata'=>1), 'form'=>array('script'=>1), 'map'=>array('area'=>1), 'object'=>array('param'=>1, 'embed'=>1)); // Other
159$cT = array('colgroup'=>1, 'dd'=>1, 'dt'=>1, 'li'=>1, 'option'=>1, 'p'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1); // Omitable closing
160// block/inline type; ins & del both type; #pcdata: text
161$eB = array('address'=>1, 'blockquote'=>1, 'center'=>1, 'del'=>1, 'dir'=>1, 'dl'=>1, 'div'=>1, 'fieldset'=>1, 'form'=>1, 'ins'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'isindex'=>1, 'menu'=>1, 'noscript'=>1, 'ol'=>1, 'p'=>1, 'pre'=>1, 'table'=>1, 'ul'=>1);
162$eI = array('#pcdata'=>1, 'a'=>1, 'abbr'=>1, 'acronym'=>1, 'applet'=>1, 'b'=>1, 'bdo'=>1, 'big'=>1, 'br'=>1, 'button'=>1, 'cite'=>1, 'code'=>1, 'del'=>1, 'dfn'=>1, 'em'=>1, 'embed'=>1, 'font'=>1, 'i'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'ins'=>1, 'kbd'=>1, 'label'=>1, 'map'=>1, 'object'=>1, 'q'=>1, 'ruby'=>1, 's'=>1, 'samp'=>1, 'select'=>1, 'script'=>1, 'small'=>1, 'span'=>1, 'strike'=>1, 'strong'=>1, 'sub'=>1, 'sup'=>1, 'textarea'=>1, 'tt'=>1, 'u'=>1, 'var'=>1);
163$eN = array('a'=>1, 'big'=>1, 'button'=>1, 'fieldset'=>1, 'font'=>1, 'form'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'label'=>1, 'object'=>1, 'ruby'=>1, 'script'=>1, 'select'=>1, 'small'=>1, 'sub'=>1, 'sup'=>1, 'textarea'=>1); // Exclude from specific ele; $cN values
164$eO = array('area'=>1, 'caption'=>1, 'col'=>1, 'colgroup'=>1, 'dd'=>1, 'dt'=>1, 'legend'=>1, 'li'=>1, 'optgroup'=>1, 'option'=>1, 'param'=>1, 'rb'=>1, 'rbc'=>1, 'rp'=>1, 'rt'=>1, 'rtc'=>1, 'script'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'thead'=>1, 'th'=>1, 'tr'=>1); // Missing in $eB & $eI
165$eF = $eB + $eI;
166
167// $in sets allowed child
168$in = ((isset($eF[$in]) && $in != '#pcdata') or isset($eO[$in])) ? $in : 'div';
169if(isset($cE[$in])){
170 return (!$do ? '' : str_replace(array('<', '>'), array('&lt;', '&gt;'), $t));
171}
172if(isset($cS[$in])){$inOk = $cS[$in];}
173elseif(isset($cI[$in])){$inOk = $eI; $cI['del'] = 1; $cI['ins'] = 1;}
174elseif(isset($cF[$in])){$inOk = $eF; unset($cI['del'], $cI['ins']);}
175elseif(isset($cB[$in])){$inOk = $eB; unset($cI['del'], $cI['ins']);}
176if(isset($cO[$in])){$inOk = $inOk + $cO[$in];}
177if(isset($cN[$in])){$inOk = array_diff_assoc($inOk, $cN[$in]);}
178
179$t = explode('<', $t);
180$ok = $q = array(); // $q seq list of open non-empty ele
181ob_start();
182
183for($i=-1, $ci=count($t); ++$i<$ci;){
184 // allowed $ok in parent $p
185 if($ql = count($q)){
186 $p = array_pop($q);
187 $q[] = $p;
188 if(isset($cS[$p])){$ok = $cS[$p];}
189 elseif(isset($cI[$p])){$ok = $eI; $cI['del'] = 1; $cI['ins'] = 1;}
190 elseif(isset($cF[$p])){$ok = $eF; unset($cI['del'], $cI['ins']);}
191 elseif(isset($cB[$p])){$ok = $eB; unset($cI['del'], $cI['ins']);}
192 if(isset($cO[$p])){$ok = $ok + $cO[$p];}
193 if(isset($cN[$p])){$ok = array_diff_assoc($ok, $cN[$p]);}
194 }else{$ok = $inOk; unset($cI['del'], $cI['ins']);}
195 // bad tags, & ele content
196 if(isset($e) && ($do == 1 or (isset($ok['#pcdata']) && ($do == 3 or $do == 5)))){
197 echo '&lt;', $s, $e, $a, '&gt;';
198 }
199 if(isset($x[0])){
200 if(strlen(trim($x)) && (($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql))){
201 echo '<div>', $x, '</div>';
202 }
203 elseif($do < 3 or isset($ok['#pcdata'])){echo $x;}
204 elseif(strpos($x, "\x02\x04")){
205 foreach(preg_split('`(\x01\x02[^\x01\x02]+\x02\x01)`', $x, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $v){
206 echo (substr($v, 0, 2) == "\x01\x02" ? $v : ($do > 4 ? preg_replace('`\S`', '', $v) : ''));
207 }
208 }elseif($do > 4){echo preg_replace('`\S`', '', $x);}
209 }
210 // get markup
211 if(!preg_match('`^(/?)([a-z1-6]+)([^>]*)>(.*)`sm', $t[$i], $r)){$x = $t[$i]; continue;}
212 $s = null; $e = null; $a = null; $x = null; list($all, $s, $e, $a, $x) = $r;
213 // close tag
214 if($s){
215 if(isset($cE[$e]) or !in_array($e, $q)){continue;} // Empty/unopen
216 if($p == $e){array_pop($q); echo '</', $e, '>'; unset($e); continue;} // Last open
217 $add = ''; // Nesting - close open tags that need to be
218 for($j=-1, $cj=count($q); ++$j<$cj;){
219 if(($d = array_pop($q)) == $e){break;}
220 else{$add .= "</{$d}>";}
221 }
222 echo $add, '</', $e, '>'; unset($e); continue;
223 }
224 // open tag
225 // $cB ele needs $eB ele as child
226 if(isset($cB[$e]) && strlen(trim($x))){
227 $t[$i] = "{$e}{$a}>";
228 array_splice($t, $i+1, 0, 'div>'. $x); unset($e, $x); ++$ci; --$i; continue;
229 }
230 if((($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql)) && !isset($eB[$e]) && !isset($ok[$e])){
231 array_splice($t, $i, 0, 'div>'); unset($e, $x); ++$ci; --$i; continue;
232 }
233 // if no open ele, $in = parent; mostly immediate parent-child relation should hold
234 if(!$ql or !isset($eN[$e]) or !array_intersect($q, $cN2)){
235 if(!isset($ok[$e])){
236 if($ql && isset($cT[$p])){echo '</', array_pop($q), '>'; unset($e, $x); --$i;}
237 continue;
238 }
239 if(!isset($cE[$e])){$q[] = $e;}
240 echo '<', $e, $a, '>'; unset($e); continue;
241 }
242 // specific parent-child
243 if(isset($cS[$p][$e])){
244 if(!isset($cE[$e])){$q[] = $e;}
245 echo '<', $e, $a, '>'; unset($e); continue;
246 }
247 // nesting
248 $add = '';
249 $q2 = array();
250 for($k=-1, $kc=count($q); ++$k<$kc;){
251 $d = $q[$k];
252 $ok2 = array();
253 if(isset($cS[$d])){$q2[] = $d; continue;}
254 $ok2 = isset($cI[$d]) ? $eI : $eF;
255 if(isset($cO[$d])){$ok2 = $ok2 + $cO[$d];}
256 if(isset($cN[$d])){$ok2 = array_diff_assoc($ok2, $cN[$d]);}
257 if(!isset($ok2[$e])){
258 if(!$k && !isset($inOk[$e])){continue 2;}
259 $add = "</{$d}>";
260 for(;++$k<$kc;){$add = "</{$q[$k]}>{$add}";}
261 break;
262 }
263 else{$q2[] = $d;}
264 }
265 $q = $q2;
266 if(!isset($cE[$e])){$q[] = $e;}
267 echo $add, '<', $e, $a, '>'; unset($e); continue;
268}
269
270// end
271if($ql = count($q)){
272 $p = array_pop($q);
273 $q[] = $p;
274 if(isset($cS[$p])){$ok = $cS[$p];}
275 elseif(isset($cI[$p])){$ok = $eI; $cI['del'] = 1; $cI['ins'] = 1;}
276 elseif(isset($cF[$p])){$ok = $eF; unset($cI['del'], $cI['ins']);}
277 elseif(isset($cB[$p])){$ok = $eB; unset($cI['del'], $cI['ins']);}
278 if(isset($cO[$p])){$ok = $ok + $cO[$p];}
279 if(isset($cN[$p])){$ok = array_diff_assoc($ok, $cN[$p]);}
280}else{$ok = $inOk; unset($cI['del'], $cI['ins']);}
281if(isset($e) && ($do == 1 or (isset($ok['#pcdata']) && ($do == 3 or $do == 5)))){
282 echo '&lt;', $s, $e, $a, '&gt;';
283}
284if(isset($x[0])){
285 if(strlen(trim($x)) && (($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql))){
286 echo '<div>', $x, '</div>';
287 }
288 elseif($do < 3 or isset($ok['#pcdata'])){echo $x;}
289 elseif(strpos($x, "\x02\x04")){
290 foreach(preg_split('`(\x01\x02[^\x01\x02]+\x02\x01)`', $x, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $v){
291 echo (substr($v, 0, 2) == "\x01\x02" ? $v : ($do > 4 ? preg_replace('`\S`', '', $v) : ''));
292 }
293 }elseif($do > 4){echo preg_replace('`\S`', '', $x);}
294}
295while(!empty($q) && ($e = array_pop($q))){echo '</', $e, '>';}
296$o = ob_get_contents();
297ob_end_clean();
298return $o;
299// eof
300}
301
302public static function hl_cmtcd($t){
303// comment/CDATA sec handler
304$t = $t[0];
305global $C;
306if(!($v = $C[$n = $t[3] == '-' ? 'comment' : 'cdata'])){return $t;}
307if($v == 1){return '';}
308if($n == 'comment'){
309 if(substr(($t = preg_replace('`--+`', '-', substr($t, 4, -3))), -1) != ' '){$t .= ' ';}
310}
311else{$t = substr($t, 1, -1);}
312$t = $v == 2 ? str_replace(array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $t) : $t;
313return str_replace(array('&', '<', '>'), array("\x03", "\x04", "\x05"), ($n == 'comment' ? "\x01\x02\x04!--$t--\x05\x02\x01" : "\x01\x01\x04$t\x05\x01\x01"));
314// eof
315}
316
317public static function hl_ent($t){
318// entitity handler
319global $C;
320$t = $t[1];
321static $U = array('quot'=>1,'amp'=>1,'lt'=>1,'gt'=>1);
322static $N = array('fnof'=>'402', 'Alpha'=>'913', 'Beta'=>'914', 'Gamma'=>'915', 'Delta'=>'916', 'Epsilon'=>'917', 'Zeta'=>'918', 'Eta'=>'919', 'Theta'=>'920', 'Iota'=>'921', 'Kappa'=>'922', 'Lambda'=>'923', 'Mu'=>'924', 'Nu'=>'925', 'Xi'=>'926', 'Omicron'=>'927', 'Pi'=>'928', 'Rho'=>'929', 'Sigma'=>'931', 'Tau'=>'932', 'Upsilon'=>'933', 'Phi'=>'934', 'Chi'=>'935', 'Psi'=>'936', 'Omega'=>'937', 'alpha'=>'945', 'beta'=>'946', 'gamma'=>'947', 'delta'=>'948', 'epsilon'=>'949', 'zeta'=>'950', 'eta'=>'951', 'theta'=>'952', 'iota'=>'953', 'kappa'=>'954', 'lambda'=>'955', 'mu'=>'956', 'nu'=>'957', 'xi'=>'958', 'omicron'=>'959', 'pi'=>'960', 'rho'=>'961', 'sigmaf'=>'962', 'sigma'=>'963', 'tau'=>'964', 'upsilon'=>'965', 'phi'=>'966', 'chi'=>'967', 'psi'=>'968', 'omega'=>'969', 'thetasym'=>'977', 'upsih'=>'978', 'piv'=>'982', 'bull'=>'8226', 'hellip'=>'8230', 'prime'=>'8242', 'Prime'=>'8243', 'oline'=>'8254', 'frasl'=>'8260', 'weierp'=>'8472', 'image'=>'8465', 'real'=>'8476', 'trade'=>'8482', 'alefsym'=>'8501', 'larr'=>'8592', 'uarr'=>'8593', 'rarr'=>'8594', 'darr'=>'8595', 'harr'=>'8596', 'crarr'=>'8629', 'lArr'=>'8656', 'uArr'=>'8657', 'rArr'=>'8658', 'dArr'=>'8659', 'hArr'=>'8660', 'forall'=>'8704', 'part'=>'8706', 'exist'=>'8707', 'empty'=>'8709', 'nabla'=>'8711', 'isin'=>'8712', 'notin'=>'8713', 'ni'=>'8715', 'prod'=>'8719', 'sum'=>'8721', 'minus'=>'8722', 'lowast'=>'8727', 'radic'=>'8730', 'prop'=>'8733', 'infin'=>'8734', 'ang'=>'8736', 'and'=>'8743', 'or'=>'8744', 'cap'=>'8745', 'cup'=>'8746', 'int'=>'8747', 'there4'=>'8756', 'sim'=>'8764', 'cong'=>'8773', 'asymp'=>'8776', 'ne'=>'8800', 'equiv'=>'8801', 'le'=>'8804', 'ge'=>'8805', 'sub'=>'8834', 'sup'=>'8835', 'nsub'=>'8836', 'sube'=>'8838', 'supe'=>'8839', 'oplus'=>'8853', 'otimes'=>'8855', 'perp'=>'8869', 'sdot'=>'8901', 'lceil'=>'8968', 'rceil'=>'8969', 'lfloor'=>'8970', 'rfloor'=>'8971', 'lang'=>'9001', 'rang'=>'9002', 'loz'=>'9674', 'spades'=>'9824', 'clubs'=>'9827', 'hearts'=>'9829', 'diams'=>'9830', 'apos'=>'39', 'OElig'=>'338', 'oelig'=>'339', 'Scaron'=>'352', 'scaron'=>'353', 'Yuml'=>'376', 'circ'=>'710', 'tilde'=>'732', 'ensp'=>'8194', 'emsp'=>'8195', 'thinsp'=>'8201', 'zwnj'=>'8204', 'zwj'=>'8205', 'lrm'=>'8206', 'rlm'=>'8207', 'ndash'=>'8211', 'mdash'=>'8212', 'lsquo'=>'8216', 'rsquo'=>'8217', 'sbquo'=>'8218', 'ldquo'=>'8220', 'rdquo'=>'8221', 'bdquo'=>'8222', 'dagger'=>'8224', 'Dagger'=>'8225', 'permil'=>'8240', 'lsaquo'=>'8249', 'rsaquo'=>'8250', 'euro'=>'8364', 'nbsp'=>'160', 'iexcl'=>'161', 'cent'=>'162', 'pound'=>'163', 'curren'=>'164', 'yen'=>'165', 'brvbar'=>'166', 'sect'=>'167', 'uml'=>'168', 'copy'=>'169', 'ordf'=>'170', 'laquo'=>'171', 'not'=>'172', 'shy'=>'173', 'reg'=>'174', 'macr'=>'175', 'deg'=>'176', 'plusmn'=>'177', 'sup2'=>'178', 'sup3'=>'179', 'acute'=>'180', 'micro'=>'181', 'para'=>'182', 'middot'=>'183', 'cedil'=>'184', 'sup1'=>'185', 'ordm'=>'186', 'raquo'=>'187', 'frac14'=>'188', 'frac12'=>'189', 'frac34'=>'190', 'iquest'=>'191', 'Agrave'=>'192', 'Aacute'=>'193', 'Acirc'=>'194', 'Atilde'=>'195', 'Auml'=>'196', 'Aring'=>'197', 'AElig'=>'198', 'Ccedil'=>'199', 'Egrave'=>'200', 'Eacute'=>'201', 'Ecirc'=>'202', 'Euml'=>'203', 'Igrave'=>'204', 'Iacute'=>'205', 'Icirc'=>'206', 'Iuml'=>'207', 'ETH'=>'208', 'Ntilde'=>'209', 'Ograve'=>'210', 'Oacute'=>'211', 'Ocirc'=>'212', 'Otilde'=>'213', 'Ouml'=>'214', 'times'=>'215', 'Oslash'=>'216', 'Ugrave'=>'217', 'Uacute'=>'218', 'Ucirc'=>'219', 'Uuml'=>'220', 'Yacute'=>'221', 'THORN'=>'222', 'szlig'=>'223', 'agrave'=>'224', 'aacute'=>'225', 'acirc'=>'226', 'atilde'=>'227', 'auml'=>'228', 'aring'=>'229', 'aelig'=>'230', 'ccedil'=>'231', 'egrave'=>'232', 'eacute'=>'233', 'ecirc'=>'234', 'euml'=>'235', 'igrave'=>'236', 'iacute'=>'237', 'icirc'=>'238', 'iuml'=>'239', 'eth'=>'240', 'ntilde'=>'241', 'ograve'=>'242', 'oacute'=>'243', 'ocirc'=>'244', 'otilde'=>'245', 'ouml'=>'246', 'divide'=>'247', 'oslash'=>'248', 'ugrave'=>'249', 'uacute'=>'250', 'ucirc'=>'251', 'uuml'=>'252', 'yacute'=>'253', 'thorn'=>'254', 'yuml'=>'255');
323if($t[0] != '#'){
324 return ($C['and_mark'] ? "\x06" : '&'). (isset($U[$t]) ? $t : (isset($N[$t]) ? (!$C['named_entity'] ? '#'. ($C['hexdec_entity'] > 1 ? 'x'. dechex($N[$t]) : $N[$t]) : $t) : 'amp;'. $t)). ';';
325}
326if(($n = ctype_digit($t = substr($t, 1)) ? intval($t) : hexdec(substr($t, 1))) < 9 or ($n > 13 && $n < 32) or $n == 11 or $n == 12 or ($n > 126 && $n < 160 && $n != 133) or ($n > 55295 && ($n < 57344 or ($n > 64975 && $n < 64992) or $n == 65534 or $n == 65535 or $n > 1114111))){
327 return ($C['and_mark'] ? "\x06" : '&'). "amp;#{$t};";
328}
329return ($C['and_mark'] ? "\x06" : '&'). '#'. (((ctype_digit($t) && $C['hexdec_entity'] < 2) or !$C['hexdec_entity']) ? $n : 'x'. dechex($n)). ';';
330// eof
331}
332
333public static function hl_prot($p, $c=null){
334// check URL scheme
335global $C;
336$b = $a = '';
337if($c == null){$c = 'style'; $b = $p[1]; $a = $p[3]; $p = trim($p[2]);}
338$c = isset($C['schemes'][$c]) ? $C['schemes'][$c] : $C['schemes']['*'];
339static $d = 'denied:';
340if(isset($c['!']) && substr($p, 0, 7) != $d){$p = "$d$p";}
341if(isset($c['*']) or !strcspn($p, '#?;') or (substr($p, 0, 7) == $d)){return "{$b}{$p}{$a}";} // All ok, frag, query, param
342if(preg_match('`^([a-z\d\-+.&#; ]+?)(:|&#(58|x3a);|%3a|\\\\0{0,4}3a).`i', $p, $m) && !isset($c[strtolower($m[1])])){ // Denied prot
343 return "{$b}{$d}{$p}{$a}";
344}
345if($C['abs_url']){
346 if($C['abs_url'] == -1 && strpos($p, $C['base_url']) === 0){ // Make url rel
347 $p = substr($p, strlen($C['base_url']));
348 }elseif(empty($m[1])){ // Make URL abs
349 if(substr($p, 0, 2) == '//'){$p = substr($C['base_url'], 0, strpos($C['base_url'], ':')+1). $p;}
350 elseif($p[0] == '/'){$p = preg_replace('`(^.+?://[^/]+)(.*)`', '$1', $C['base_url']). $p;}
351 elseif(strcspn($p, './')){$p = $C['base_url']. $p;}
352 else{
353 preg_match('`^([a-zA-Z\d\-+.]+://[^/]+)(.*)`', $C['base_url'], $m);
354 $p = preg_replace('`(?<=/)\./`', '', $m[2]. $p);
355 while(preg_match('`(?<=/)([^/]{3,}|[^/.]+?|\.[^/.]|[^/.]\.)/\.\./`', $p)){
356 $p = preg_replace('`(?<=/)([^/]{3,}|[^/.]+?|\.[^/.]|[^/.]\.)/\.\./`', '', $p);
357 }
358 $p = $m[1]. $p;
359 }
360 }
361}
362return "{$b}{$p}{$a}";
363// eof
364}
365
366public static function hl_regex($p){
367// ?regex
368if(empty($p)){return 0;}
369if($t = ini_get('track_errors')){$o = isset($php_errormsg) ? $php_errormsg : null;}
370else{ini_set('track_errors', 1);}
371unset($php_errormsg);
372if(($d = ini_get('display_errors'))){ini_set('display_errors', 0);}
373preg_match($p, '');
374if($d){ini_set('display_errors', 1);}
375$r = isset($php_errormsg) ? 0 : 1;
376if($t){$php_errormsg = isset($o) ? $o : null;}
377else{ini_set('track_errors', 0);}
378return $r;
379// eof
380}
381
382public static function hl_spec($t){
383// final $spec
384$s = array();
385$t = str_replace(array("\t", "\r", "\n", ' '), '', preg_replace('/"(?>(`.|[^"])*)"/sme', 'substr(str_replace(array(";", "|", "~", " ", ",", "/", "(", ")", \'`"\'), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\""), "$0"), 1, -1)', trim($t)));
386for($i = count(($t = explode(';', $t))); --$i>=0;){
387 $w = $t[$i];
388 if(empty($w) or ($e = strpos($w, '=')) === false or !strlen(($a = substr($w, $e+1)))){continue;}
389 $y = $n = array();
390 foreach(explode(',', $a) as $v){
391 if(!preg_match('`^([a-z:\-\*]+)(?:\((.*?)\))?`i', $v, $m)){continue;}
392 if(($x = strtolower($m[1])) == '-*'){$n['*'] = 1; continue;}
393 if($x[0] == '-'){$n[substr($x, 1)] = 1; continue;}
394 if(!isset($m[2])){$y[$x] = 1; continue;}
395 foreach(explode('/', $m[2]) as $m){
396 if(empty($m) or ($p = strpos($m, '=')) == 0 or $p < 5){$y[$x] = 1; continue;}
397 $y[$x][strtolower(substr($m, 0, $p))] = str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08"), array(";", "|", "~", " ", ",", "/", "(", ")"), substr($m, $p+1));
398 }
399 if(isset($y[$x]['match']) && !htmLawed::hl_regex($y[$x]['match'])){unset($y[$x]['match']);}
400 if(isset($y[$x]['nomatch']) && !htmLawed::hl_regex($y[$x]['nomatch'])){unset($y[$x]['nomatch']);}
401 }
402 if(!count($y) && !count($n)){continue;}
403 foreach(explode(',', substr($w, 0, $e)) as $v){
404 if(!strlen(($v = strtolower($v)))){continue;}
405 if(count($y)){$s[$v] = $y;}
406 if(count($n)){$s[$v]['n'] = $n;}
407 }
408}
409return $s;
410// eof
411}
412
413public static function hl_tag($t){
414// tag/attribute handler
415global $C;
416$t = $t[0];
417// invalid < >
418if($t == '< '){return '&lt; ';}
419if($t == '>'){return '&gt;';}
420if(!preg_match('`^<(/?)([a-zA-Z][a-zA-Z1-6]*)([^>]*?)\s?>$`m', $t, $m)){
421 return str_replace(array('<', '>'), array('&lt;', '&gt;'), $t);
422}elseif(!isset($C['elements'][($e = strtolower($m[2]))])){
423 return (($C['keep_bad']%2) ? str_replace(array('<', '>'), array('&lt;', '&gt;'), $t) : '');
424}
425// attr string
426$a = str_replace(array("\n", "\r", "\t"), ' ', trim($m[3]));
427// tag transform
428static $eD = array('applet'=>1, 'center'=>1, 'dir'=>1, 'embed'=>1, 'font'=>1, 'isindex'=>1, 'menu'=>1, 's'=>1, 'strike'=>1, 'u'=>1); // Deprecated
429if($C['make_tag_strict'] && isset($eD[$e])){
430 $trt = htmLawed::hl_tag2($e, $a, $C['make_tag_strict']);
431 if(!$e){return (($C['keep_bad']%2) ? str_replace(array('<', '>'), array('&lt;', '&gt;'), $t) : '');}
432}
433// close tag
434static $eE = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1); // Empty ele
435if(!empty($m[1])){
436 return (!isset($eE[$e]) ? (empty($C['hook_tag']) ? "</$e>" : $C['hook_tag']($e)) : (($C['keep_bad'])%2 ? str_replace(array('<', '>'), array('&lt;', '&gt;'), $t) : ''));
437}
438
439// open tag & attr
440static $aN = array('abbr'=>array('td'=>1, 'th'=>1), 'accept-charset'=>array('form'=>1), 'accept'=>array('form'=>1, 'input'=>1), 'accesskey'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'label'=>1, 'legend'=>1, 'textarea'=>1), 'action'=>array('form'=>1), 'align'=>array('caption'=>1, 'embed'=>1, 'applet'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'object'=>1, 'legend'=>1, 'table'=>1, 'hr'=>1, 'div'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'p'=>1, 'col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'alt'=>array('applet'=>1, 'area'=>1, 'img'=>1, 'input'=>1), 'archive'=>array('applet'=>1, 'object'=>1), 'axis'=>array('td'=>1, 'th'=>1), 'bgcolor'=>array('embed'=>1, 'table'=>1, 'tr'=>1, 'td'=>1, 'th'=>1), 'border'=>array('table'=>1, 'img'=>1, 'object'=>1), 'bordercolor'=>array('table'=>1, 'td'=>1, 'tr'=>1), 'cellpadding'=>array('table'=>1), 'cellspacing'=>array('table'=>1), 'char'=>array('col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'charoff'=>array('col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'charset'=>array('a'=>1, 'script'=>1), 'checked'=>array('input'=>1), 'cite'=>array('blockquote'=>1, 'q'=>1, 'del'=>1, 'ins'=>1), 'classid'=>array('object'=>1), 'clear'=>array('br'=>1), 'code'=>array('applet'=>1), 'codebase'=>array('object'=>1, 'applet'=>1), 'codetype'=>array('object'=>1), 'color'=>array('font'=>1), 'cols'=>array('textarea'=>1), 'colspan'=>array('td'=>1, 'th'=>1), 'compact'=>array('dir'=>1, 'dl'=>1, 'menu'=>1, 'ol'=>1, 'ul'=>1), 'coords'=>array('area'=>1, 'a'=>1), 'data'=>array('object'=>1), 'datetime'=>array('del'=>1, 'ins'=>1), 'declare'=>array('object'=>1), 'defer'=>array('script'=>1), 'dir'=>array('bdo'=>1), 'disabled'=>array('button'=>1, 'input'=>1, 'optgroup'=>1, 'option'=>1, 'select'=>1, 'textarea'=>1), 'enctype'=>array('form'=>1), 'face'=>array('font'=>1), 'for'=>array('label'=>1), 'frame'=>array('table'=>1), 'frameborder'=>array('iframe'=>1), 'headers'=>array('td'=>1, 'th'=>1), 'height'=>array('embed'=>1, 'iframe'=>1, 'td'=>1, 'th'=>1, 'img'=>1, 'object'=>1, 'applet'=>1), 'href'=>array('a'=>1, 'area'=>1), 'hreflang'=>array('a'=>1), 'hspace'=>array('applet'=>1, 'img'=>1, 'object'=>1), 'ismap'=>array('img'=>1, 'input'=>1), 'label'=>array('option'=>1, 'optgroup'=>1), 'language'=>array('script'=>1), 'longdesc'=>array('img'=>1, 'iframe'=>1), 'marginheight'=>array('iframe'=>1), 'marginwidth'=>array('iframe'=>1), 'maxlength'=>array('input'=>1), 'method'=>array('form'=>1), 'model'=>array('embed'=>1), 'multiple'=>array('select'=>1), 'name'=>array('button'=>1, 'embed'=>1, 'textarea'=>1, 'applet'=>1, 'select'=>1, 'form'=>1, 'iframe'=>1, 'img'=>1, 'a'=>1, 'input'=>1, 'object'=>1, 'map'=>1, 'param'=>1), 'nohref'=>array('area'=>1), 'noshade'=>array('hr'=>1), 'nowrap'=>array('td'=>1, 'th'=>1), 'object'=>array('applet'=>1), 'onblur'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'label'=>1, 'select'=>1, 'textarea'=>1), 'onchange'=>array('input'=>1, 'select'=>1, 'textarea'=>1), 'onfocus'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'label'=>1, 'select'=>1, 'textarea'=>1), 'onreset'=>array('form'=>1), 'onselect'=>array('input'=>1, 'textarea'=>1), 'onsubmit'=>array('form'=>1), 'pluginspage'=>array('embed'=>1), 'pluginurl'=>array('embed'=>1), 'prompt'=>array('isindex'=>1), 'readonly'=>array('textarea'=>1, 'input'=>1), 'rel'=>array('a'=>1), 'rev'=>array('a'=>1), 'rows'=>array('textarea'=>1), 'rowspan'=>array('td'=>1, 'th'=>1), 'rules'=>array('table'=>1), 'scope'=>array('td'=>1, 'th'=>1), 'scrolling'=>array('iframe'=>1), 'selected'=>array('option'=>1), 'shape'=>array('area'=>1, 'a'=>1), 'size'=>array('hr'=>1, 'font'=>1, 'input'=>1, 'select'=>1), 'span'=>array('col'=>1, 'colgroup'=>1), 'src'=>array('embed'=>1, 'script'=>1, 'input'=>1, 'iframe'=>1, 'img'=>1), 'standby'=>array('object'=>1), 'start'=>array('ol'=>1), 'summary'=>array('table'=>1), 'tabindex'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'object'=>1, 'select'=>1, 'textarea'=>1), 'target'=>array('a'=>1, 'area'=>1, 'form'=>1), 'type'=>array('a'=>1, 'embed'=>1, 'object'=>1, 'param'=>1, 'script'=>1, 'input'=>1, 'li'=>1, 'ol'=>1, 'ul'=>1, 'button'=>1), 'usemap'=>array('img'=>1, 'input'=>1, 'object'=>1), 'valign'=>array('col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'value'=>array('input'=>1, 'option'=>1, 'param'=>1, 'button'=>1, 'li'=>1), 'valuetype'=>array('param'=>1), 'vspace'=>array('applet'=>1, 'img'=>1, 'object'=>1), 'width'=>array('embed'=>1, 'hr'=>1, 'iframe'=>1, 'img'=>1, 'object'=>1, 'table'=>1, 'td'=>1, 'th'=>1, 'applet'=>1, 'col'=>1, 'colgroup'=>1, 'pre'=>1), 'wmode'=>array('embed'=>1), 'xml:space'=>array('pre'=>1, 'script'=>1, 'style'=>1)); // Ele-specific
441static $aNE = array('checked'=>1, 'compact'=>1, 'declare'=>1, 'defer'=>1, 'disabled'=>1, 'ismap'=>1, 'multiple'=>1, 'nohref'=>1, 'noresize'=>1, 'noshade'=>1, 'nowrap'=>1, 'readonly'=>1, 'selected'=>1); // Empty
442static $aNP = array('action'=>1, 'cite'=>1, 'classid'=>1, 'codebase'=>1, 'data'=>1, 'href'=>1, 'longdesc'=>1, 'model'=>1, 'pluginspage'=>1, 'pluginurl'=>1, 'usemap'=>1); // Need scheme check; excludes style, on* & src
443static $aNU = array('class'=>array('param'=>1, 'script'=>1), 'dir'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'iframe'=>1, 'param'=>1, 'script'=>1), 'id'=>array('script'=>1), 'lang'=>array('applet'=>1, 'br'=>1, 'iframe'=>1, 'param'=>1, 'script'=>1), 'xml:lang'=>array('applet'=>1, 'br'=>1, 'iframe'=>1, 'param'=>1, 'script'=>1), 'onclick'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'ondblclick'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onkeydown'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onkeypress'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onkeyup'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmousedown'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmousemove'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmouseout'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmouseover'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmouseup'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'style'=>array('param'=>1, 'script'=>1), 'title'=>array('param'=>1, 'script'=>1)); // Univ & exceptions
444
445if($C['lc_std_val']){
446 // predef attr vals for $eAL & $aNE ele
447 static $aNL = array('all'=>1, 'baseline'=>1, 'bottom'=>1, 'button'=>1, 'center'=>1, 'char'=>1, 'checkbox'=>1, 'circle'=>1, 'col'=>1, 'colgroup'=>1, 'cols'=>1, 'data'=>1, 'default'=>1, 'file'=>1, 'get'=>1, 'groups'=>1, 'hidden'=>1, 'image'=>1, 'justify'=>1, 'left'=>1, 'ltr'=>1, 'middle'=>1, 'none'=>1, 'object'=>1, 'password'=>1, 'poly'=>1, 'post'=>1, 'preserve'=>1, 'radio'=>1, 'rect'=>1, 'ref'=>1, 'reset'=>1, 'right'=>1, 'row'=>1, 'rowgroup'=>1, 'rows'=>1, 'rtl'=>1, 'submit'=>1, 'text'=>1, 'top'=>1);
448 static $eAL = array('a'=>1, 'area'=>1, 'bdo'=>1, 'button'=>1, 'col'=>1, 'form'=>1, 'img'=>1, 'input'=>1, 'object'=>1, 'optgroup'=>1, 'option'=>1, 'param'=>1, 'script'=>1, 'select'=>1, 'table'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1, 'xml:space'=>1);
449 $lcase = isset($eAL[$e]) ? 1 : 0;
450}
451
452$depTr = 0;
453if($C['no_deprecated_attr']){
454 // dep attr:applicable ele
455 static $aND = array('align'=>array('caption'=>1, 'div'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'legend'=>1, 'object'=>1, 'p'=>1, 'table'=>1), 'bgcolor'=>array('table'=>1, 'td'=>1, 'th'=>1, 'tr'=>1), 'border'=>array('img'=>1, 'object'=>1), 'bordercolor'=>array('table'=>1, 'td'=>1, 'tr'=>1), 'clear'=>array('br'=>1), 'compact'=>array('dl'=>1, 'ol'=>1, 'ul'=>1), 'height'=>array('td'=>1, 'th'=>1), 'hspace'=>array('img'=>1, 'object'=>1), 'language'=>array('script'=>1), 'name'=>array('a'=>1, 'form'=>1, 'iframe'=>1, 'img'=>1, 'map'=>1), 'noshade'=>array('hr'=>1), 'nowrap'=>array('td'=>1, 'th'=>1), 'size'=>array('hr'=>1), 'start'=>array('ol'=>1), 'type'=>array('li'=>1, 'ol'=>1, 'ul'=>1), 'value'=>array('li'=>1), 'vspace'=>array('img'=>1, 'object'=>1), 'width'=>array('hr'=>1, 'pre'=>1, 'td'=>1, 'th'=>1));
456 static $eAD = array('a'=>1, 'br'=>1, 'caption'=>1, 'div'=>1, 'dl'=>1, 'form'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'legend'=>1, 'li'=>1, 'map'=>1, 'object'=>1, 'ol'=>1, 'p'=>1, 'pre'=>1, 'script'=>1, 'table'=>1, 'td'=>1, 'th'=>1, 'tr'=>1, 'ul'=>1);
457 $depTr = isset($eAD[$e]) ? 1 : 0;
458}
459
460// attr name-vals
461if(strpos($a, "\x01") !== false){$a = preg_replace('`\x01[^\x01]*\x01`', '', $a);} // No comment/CDATA sec
462$mode = 0; $a = trim($a, ' /'); $aA = array();
463while(strlen($a)){
464 $w = 0;
465 switch($mode){
466 case 0: // Name
467 if(preg_match('`^[a-zA-Z][\-a-zA-Z:]+`', $a, $m)){
468 $nm = strtolower($m[0]);
469 $w = $mode = 1; $a = ltrim(substr_replace($a, '', 0, strlen($m[0])));
470 }
471 break; case 1:
472 if($a[0] == '='){ // =
473 $w = 1; $mode = 2; $a = ltrim($a, '= ');
474 }else{ // No val
475 $w = 1; $mode = 0; $a = ltrim($a);
476 $aA[$nm] = '';
477 }
478 break; case 2: // Val
479 if(preg_match('`^((?:"[^"]*")|(?:\'[^\']*\')|(?:\s*[^\s"\']+))(.*)`', $a, $m)){
480 $a = ltrim($m[2]); $m = $m[1]; $w = 1; $mode = 0;
481 $aA[$nm] = trim(($m[0] == '"' or $m[0] == '\'') ? substr($m, 1, -1) : $m);
482 }
483 break;
484 }
485 if($w == 0){ // Parse errs, deal with space, " & '
486 $a = preg_replace('`^(?:"[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*`', '', $a);
487 $mode = 0;
488 }
489}
490if($mode == 1){$aA[$nm] = '';}
491
492// clean attrs
493global $S;
494$rl = isset($S[$e]) ? $S[$e] : array();
495$a = array(); $nfr = 0;
496foreach($aA as $k=>$v){
497 if(((isset($C['deny_attribute']['*']) ? isset($C['deny_attribute'][$k]) : !isset($C['deny_attribute'][$k])) && (isset($aN[$k][$e]) or (isset($aNU[$k]) && !isset($aNU[$k][$e]))) && !isset($rl['n'][$k]) && !isset($rl['n']['*'])) or isset($rl[$k])){
498 if(isset($aNE[$k])){$v = $k;}
499 elseif(!empty($lcase) && (($e != 'button' or $e != 'input') or $k == 'type')){ // Rather loose but ?not cause issues
500 $v = (isset($aNL[($v2 = strtolower($v))])) ? $v2 : $v;
501 }
502 if($k == 'style' && !$C['style_pass']){
503 if(false !== strpos($v, '&#')){
504 static $sC = array('&#x20;'=>' ', '&#32;'=>' ', '&#x45;'=>'e', '&#69;'=>'e', '&#x65;'=>'e', '&#101;'=>'e', '&#x58;'=>'x', '&#88;'=>'x', '&#x78;'=>'x', '&#120;'=>'x', '&#x50;'=>'p', '&#80;'=>'p', '&#x70;'=>'p', '&#112;'=>'p', '&#x53;'=>'s', '&#83;'=>'s', '&#x73;'=>'s', '&#115;'=>'s', '&#x49;'=>'i', '&#73;'=>'i', '&#x69;'=>'i', '&#105;'=>'i', '&#x4f;'=>'o', '&#79;'=>'o', '&#x6f;'=>'o', '&#111;'=>'o', '&#x4e;'=>'n', '&#78;'=>'n', '&#x6e;'=>'n', '&#110;'=>'n', '&#x55;'=>'u', '&#85;'=>'u', '&#x75;'=>'u', '&#117;'=>'u', '&#x52;'=>'r', '&#82;'=>'r', '&#x72;'=>'r', '&#114;'=>'r', '&#x4c;'=>'l', '&#76;'=>'l', '&#x6c;'=>'l', '&#108;'=>'l', '&#x28;'=>'(', '&#40;'=>'(', '&#x29;'=>')', '&#41;'=>')', '&#x20;'=>':', '&#32;'=>':', '&#x22;'=>'"', '&#34;'=>'"', '&#x27;'=>"'", '&#39;'=>"'", '&#x2f;'=>'/', '&#47;'=>'/', '&#x2a;'=>'*', '&#42;'=>'*', '&#x5c;'=>'\\', '&#92;'=>'\\');
505 $v = strtr($v, $sC);
506 }
507 $v = preg_replace_callback('`(url(?:\()(?: )*(?:\'|"|&(?:quot|apos);)?)(.+?)((?:\'|"|&(?:quot|apos);)?(?: )*(?:\)))`iS', 'htmLawed::hl_prot', $v);
508 $v = !$C['css_expression'] ? preg_replace('`expression`i', ' ', preg_replace('`\\\\\S|(/|(%2f))(\*|(%2a))`i', ' ', $v)) : $v;
509 }elseif(isset($aNP[$k]) or strpos($k, 'src') !== false or $k[0] == 'o'){
510 $v = str_replace("\xad", ' ', (strpos($v, '&') !== false ? str_replace(array('&#xad;', '&#173;', '&shy;'), ' ', $v) : $v));
511 $v = htmLawed::hl_prot($v, $k);
512 if($k == 'href'){ // X-spam
513 if($C['anti_mail_spam'] && strpos($v, 'mailto:') === 0){
514 $v = str_replace('@', htmlspecialchars($C['anti_mail_spam']), $v);
515 }elseif($C['anti_link_spam']){
516 $r1 = $C['anti_link_spam'][1];
517 if(!empty($r1) && preg_match($r1, $v)){continue;}
518 $r0 = $C['anti_link_spam'][0];
519 if(!empty($r0) && preg_match($r0, $v)){
520 if(isset($a['rel'])){
521 if(!preg_match('`\bnofollow\b`i', $a['rel'])){$a['rel'] .= ' nofollow';}
522 }elseif(isset($aA['rel'])){
523 if(!preg_match('`\bnofollow\b`i', $aA['rel'])){$nfr = 1;}
524 }else{$a['rel'] = 'nofollow';}
525 }
526 }
527 }
528 }
529 if(isset($rl[$k]) && is_array($rl[$k]) && ($v = htmLawed::hl_attrval($v, $rl[$k])) === 0){continue;}
530 $a[$k] = str_replace('"', '&quot;', $v);
531 }
532}
533if($nfr){$a['rel'] = isset($a['rel']) ? $a['rel']. ' nofollow' : 'nofollow';}
534
535// rqd attr
536static $eAR = array('area'=>array('alt'=>'area'), 'bdo'=>array('dir'=>'ltr'), 'form'=>array('action'=>''), 'img'=>array('src'=>'', 'alt'=>'image'), 'map'=>array('name'=>''), 'optgroup'=>array('label'=>''), 'param'=>array('name'=>''), 'script'=>array('type'=>'text/javascript'), 'textarea'=>array('rows'=>'10', 'cols'=>'50'));
537if(isset($eAR[$e])){
538 foreach($eAR[$e] as $k=>$v){
539 if(!isset($a[$k])){$a[$k] = isset($v[0]) ? $v : $k;}
540 }
541}
542
543// depr attrs
544if($depTr){
545 $c = array();
546 foreach($a as $k=>$v){
547 if($k == 'style' or !isset($aND[$k][$e])){continue;}
548 if($k == 'align'){
549 unset($a['align']);
550 if($e == 'img' && ($v == 'left' or $v == 'right')){$c[] = 'float: '. $v;}
551 elseif(($e == 'div' or $e == 'table') && $v == 'center'){$c[] = 'margin: auto';}
552 else{$c[] = 'text-align: '. $v;}
553 }elseif($k == 'bgcolor'){
554 unset($a['bgcolor']);
555 $c[] = 'background-color: '. $v;
556 }elseif($k == 'border'){
557 unset($a['border']); $c[] = "border: {$v}px";
558 }elseif($k == 'bordercolor'){
559 unset($a['bordercolor']); $c[] = 'border-color: '. $v;
560 }elseif($k == 'clear'){
561 unset($a['clear']); $c[] = 'clear: '. ($v != 'all' ? $v : 'both');
562 }elseif($k == 'compact'){
563 unset($a['compact']); $c[] = 'font-size: 85%';
564 }elseif($k == 'height' or $k == 'width'){
565 unset($a[$k]); $c[] = $k. ': '. ($v[0] != '*' ? $v. (ctype_digit($v) ? 'px' : '') : 'auto');
566 }elseif($k == 'hspace'){
567 unset($a['hspace']); $c[] = "margin-left: {$v}px; margin-right: {$v}px";
568 }elseif($k == 'language' && !isset($a['type'])){
569 unset($a['language']);
570 $a['type'] = 'text/'. strtolower($v);
571 }elseif($k == 'name'){
572 if($C['no_deprecated_attr'] == 2 or ($e != 'a' && $e != 'map')){unset($a['name']);}
573 if(!isset($a['id']) && preg_match('`[a-zA-Z][a-zA-Z\d.:_\-]*`', $v)){$a['id'] = $v;}
574 }elseif($k == 'noshade'){
575 unset($a['noshade']); $c[] = 'border-style: none; border: 0; background-color: gray; color: gray';
576 }elseif($k == 'nowrap'){
577 unset($a['nowrap']); $c[] = 'white-space: nowrap';
578 }elseif($k == 'size'){
579 unset($a['size']); $c[] = 'size: '. $v. 'px';
580 }elseif($k == 'start' or $k == 'value'){
581 unset($a[$k]);
582 }elseif($k == 'type'){
583 unset($a['type']);
584 static $ol_type = array('i'=>'lower-roman', 'I'=>'upper-roman', 'a'=>'lower-latin', 'A'=>'upper-latin', '1'=>'decimal');
585 $c[] = 'list-style-type: '. (isset($ol_type[$v]) ? $ol_type[$v] : 'decimal');
586 }elseif($k == 'vspace'){
587 unset($a['vspace']); $c[] = "margin-top: {$v}px; margin-bottom: {$v}px";
588 }
589 }
590 if(count($c)){
591 $c = implode('; ', $c);
592 $a['style'] = isset($a['style']) ? rtrim($a['style'], ' ;'). '; '. $c. ';': $c. ';';
593 }
594}
595// unique ID
596if($C['unique_ids'] && isset($a['id'])){
597 if(!preg_match('`^[A-Za-z][A-Za-z0-9_\-.:]*$`', ($id = $a['id'])) or (isset($GLOBALS['hl_Ids'][$id]) && $C['unique_ids'] == 1)){unset($a['id']);
598 }else{
599 while(isset($GLOBALS['hl_Ids'][$id])){$id = $C['unique_ids']. $id;}
600 $GLOBALS['hl_Ids'][($a['id'] = $id)] = 1;
601 }
602}
603// xml:lang
604if($C['xml:lang'] && isset($a['lang'])){
605 $a['xml:lang'] = isset($a['xml:lang']) ? $a['xml:lang'] : $a['lang'];
606 if($C['xml:lang'] == 2){unset($a['lang']);}
607}
608// for transformed tag
609if(!empty($trt)){
610 $a['style'] = isset($a['style']) ? rtrim($a['style'], ' ;'). '; '. $trt : $trt;
611}
612// return with empty ele /
613if(empty($C['hook_tag'])){
614 $aA = '';
615 foreach($a as $k=>$v){$aA .= " {$k}=\"{$v}\"";}
616 return "<{$e}{$aA}". (isset($eE[$e]) ? ' /' : ''). '>';
617}
618else{return $C['hook_tag']($e, $a);}
619// eof
620}
621
622public static function hl_tag2(&$e, &$a, $t=1){
623// transform tag
624if($e == 'center'){$e = 'div'; return 'text-align: center;';}
625if($e == 'dir' or $e == 'menu'){$e = 'ul'; return '';}
626if($e == 's' or $e == 'strike'){$e = 'span'; return 'text-decoration: line-through;';}
627if($e == 'u'){$e = 'span'; return 'text-decoration: underline;';}
628static $fs = array('0'=>'xx-small', '1'=>'xx-small', '2'=>'small', '3'=>'medium', '4'=>'large', '5'=>'x-large', '6'=>'xx-large', '7'=>'300%', '-1'=>'smaller', '-2'=>'60%', '+1'=>'larger', '+2'=>'150%', '+3'=>'200%', '+4'=>'300%');
629if($e == 'font'){
630 $a2 = '';
631 if(preg_match('`face\s*=\s*(\'|")([^=]+?)\\1`i', $a, $m) or preg_match('`face\s*=(\s*)(\S+)`i', $a, $m)){
632 $a2 .= ' font-family: '. str_replace('"', '\'', trim($m[2])). ';';
633 }
634 if(preg_match('`color\s*=\s*(\'|")?(.+?)(\\1|\s|$)`i', $a, $m)){
635 $a2 .= ' color: '. trim($m[2]). ';';
636 }
637 if(preg_match('`size\s*=\s*(\'|")?(.+?)(\\1|\s|$)`i', $a, $m) && isset($fs[($m = trim($m[2]))])){
638 $a2 .= ' font-size: '. $fs[$m]. ';';
639 }
640 $e = 'span'; return ltrim($a2);
641}
642if($t == 2){$e = 0; return 0;}
643return '';
644// eof
645}
646
647public static function hl_tidy($t, $w, $p){
648// Tidy/compact HTM
649if(strpos(' pre,script,textarea', "$p,")){return $t;}
650$t = str_replace(' </', '</', preg_replace(array('`(<\w[^>]*(?<!/)>)\s+`', '`\s+`', '`(<\w[^>]*(?<!/)>) `'), array(' $1', ' ', '$1'), preg_replace_callback(array('`(<(!\[CDATA\[))(.+?)(\]\]>)`sm', '`(<(!--))(.+?)(-->)`sm', '`(<(pre|script|textarea)[^>]*?>)(.+?)(</\2>)`sm'), create_function('$m', 'return $m[1]. str_replace(array("<", ">", "\n", "\r", "\t", " "), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), $m[3]). $m[4];'), $t)));
651if(($w = strtolower($w)) == -1){
652 return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array('<', '>', "\n", "\r", "\t", ' '), $t);
653}
654$s = strpos(" $w", 't') ? "\t" : ' ';
655$s = preg_match('`\d`', $w, $m) ? str_repeat($s, $m[0]) : str_repeat($s, ($s == "\t" ? 1 : 2));
656$N = preg_match('`[ts]([1-9])`', $w, $m) ? $m[1] : 0;
657$a = array('br'=>1);
658$b = array('button'=>1, 'input'=>1, 'option'=>1);
659$c = array('caption'=>1, 'dd'=>1, 'dt'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'isindex'=>1, 'label'=>1, 'legend'=>1, 'li'=>1, 'object'=>1, 'p'=>1, 'pre'=>1, 'td'=>1, 'textarea'=>1, 'th'=>1);
660$d = array('address'=>1, 'blockquote'=>1, 'center'=>1, 'colgroup'=>1, 'dir'=>1, 'div'=>1, 'dl'=>1, 'fieldset'=>1, 'form'=>1, 'hr'=>1, 'iframe'=>1, 'map'=>1, 'menu'=>1, 'noscript'=>1, 'ol'=>1, 'optgroup'=>1, 'rbc'=>1, 'rtc'=>1, 'ruby'=>1, 'script'=>1, 'select'=>1, 'table'=>1, 'tbody'=>1, 'tfoot'=>1, 'thead'=>1, 'tr'=>1, 'ul'=>1);
661$T = explode('<', $t);
662$X = 1;
663while($X){
664 $n = $N;
665 $t = $T;
666 ob_start();
667 if(isset($d[$p])){echo str_repeat($s, ++$n);}
668 echo ltrim(array_shift($t));
669 for($i=-1, $j=count($t); ++$i<$j;){
670 $r = ''; list($e, $r) = explode('>', $t[$i]);
671 $x = $e[0] == '/' ? 0 : (substr($e, -1) == '/' ? 1 : ($e[0] != '!' ? 2 : -1));
672 $y = !$x ? ltrim($e, '/') : ($x > 0 ? substr($e, 0, strcspn($e, ' ')) : 0);
673 $e = "<$e>";
674 if(isset($d[$y])){
675 if(!$x){
676 if($n){echo "\n", str_repeat($s, --$n), "$e\n", str_repeat($s, $n);}
677 else{++$N; ob_end_clean(); continue 2;}
678 }
679 else{echo "\n", str_repeat($s, $n), "$e\n", str_repeat($s, ($x != 1 ? ++$n : $n));}
680 echo ltrim($r); continue;
681 }
682 $f = "\n". str_repeat($s, $n);
683 if(isset($c[$y])){
684 if(!$x){echo $e, $f, ltrim($r);}
685 else{echo $f, $e, $r;}
686 }elseif(isset($b[$y])){echo $f, $e, $r;
687 }elseif(isset($a[$y])){echo $e, $f, ltrim($r);
688 }elseif(!$y){echo $f, $e, $f, ltrim($r);
689 }else{echo $e, $r;}
690 }
691 $X = 0;
692}
693$t = preg_replace('`[\n]\s*?[\n]+`', "\n", ob_get_contents());
694ob_end_clean();
695if(($l = strpos(" $w", 'r') ? (strpos(" $w", 'n') ? "\r\n" : "\r") : 0)){
696 $t = str_replace("\n", $l, $t);
697}
698return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array('<', '>', "\n", "\r", "\t", ' '), $t);
699// eof
700}
701
702public static function hl_version(){
703// rel
704return '1.1.14';
705// eof
706}
707
708public static function kses($t, $h, $p=array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto')){
709// kses compat
710foreach($h as $k=>$v){
711 $h[$k]['n']['*'] = 1;
712}
713$C['cdata'] = $C['comment'] = $C['make_tag_strict'] = $C['no_deprecated_attr'] = $C['unique_ids'] = 0;
714$C['keep_bad'] = 1;
715$C['elements'] = count($h) ? strtolower(implode(',', array_keys($h))) : '-*';
716$C['hook'] = 'htmLawed::kses_hook';
717$C['schemes'] = '*:'. implode(',', $p);
718return htmLawed::hl($t, $C, $h);
719// eof
720}
721
722public static function kses_hook($t, &$C, &$S){
723// kses compat
724return $t;
725// eof
726}
727// end class
728} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/html5/Data.php b/inc/3rdparty/libraries/html5/Data.php
new file mode 100644
index 00000000..497345f4
--- /dev/null
+++ b/inc/3rdparty/libraries/html5/Data.php
@@ -0,0 +1,114 @@
1<?php
2
3// warning: this file is encoded in UTF-8!
4
5class HTML5_Data
6{
7
8 // at some point this should be moved to a .ser file. Another
9 // possible optimization is to give UTF-8 bytes, not Unicode
10 // codepoints
11 // XXX: Not quite sure why it's named this; this is
12 // actually the numeric entity dereference table.
13 protected static $realCodepointTable = array(
14 0x00 => 0xFFFD, // REPLACEMENT CHARACTER
15 0x0D => 0x000A, // LINE FEED (LF)
16 0x80 => 0x20AC, // EURO SIGN ('€')
17 0x81 => 0x0081, // <control>
18 0x82 => 0x201A, // SINGLE LOW-9 QUOTATION MARK ('‚')
19 0x83 => 0x0192, // LATIN SMALL LETTER F WITH HOOK ('ƒ')
20 0x84 => 0x201E, // DOUBLE LOW-9 QUOTATION MARK ('„')
21 0x85 => 0x2026, // HORIZONTAL ELLIPSIS ('…')
22 0x86 => 0x2020, // DAGGER ('†')
23 0x87 => 0x2021, // DOUBLE DAGGER ('‡')
24 0x88 => 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ')
25 0x89 => 0x2030, // PER MILLE SIGN ('‰')
26 0x8A => 0x0160, // LATIN CAPITAL LETTER S WITH CARON ('Š')
27 0x8B => 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('‹')
28 0x8C => 0x0152, // LATIN CAPITAL LIGATURE OE ('Œ')
29 0x8D => 0x008D, // <control>
30 0x8E => 0x017D, // LATIN CAPITAL LETTER Z WITH CARON ('Ž')
31 0x8F => 0x008F, // <control>
32 0x90 => 0x0090, // <control>
33 0x91 => 0x2018, // LEFT SINGLE QUOTATION MARK ('‘')
34 0x92 => 0x2019, // RIGHT SINGLE QUOTATION MARK ('’')
35 0x93 => 0x201C, // LEFT DOUBLE QUOTATION MARK ('“')
36 0x94 => 0x201D, // RIGHT DOUBLE QUOTATION MARK ('”')
37 0x95 => 0x2022, // BULLET ('•')
38 0x96 => 0x2013, // EN DASH ('–')
39 0x97 => 0x2014, // EM DASH ('—')
40 0x98 => 0x02DC, // SMALL TILDE ('˜')
41 0x99 => 0x2122, // TRADE MARK SIGN ('™')
42 0x9A => 0x0161, // LATIN SMALL LETTER S WITH CARON ('š')
43 0x9B => 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('›')
44 0x9C => 0x0153, // LATIN SMALL LIGATURE OE ('œ')
45 0x9D => 0x009D, // <control>
46 0x9E => 0x017E, // LATIN SMALL LETTER Z WITH CARON ('ž')
47 0x9F => 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ')
48 );
49
50 protected static $namedCharacterReferences;
51
52 protected static $namedCharacterReferenceMaxLength;
53
54 /**
55 * Returns the "real" Unicode codepoint of a malformed character
56 * reference.
57 */
58 public static function getRealCodepoint($ref) {
59 if (!isset(self::$realCodepointTable[$ref])) return false;
60 else return self::$realCodepointTable[$ref];
61 }
62
63 public static function getNamedCharacterReferences() {
64 if (!self::$namedCharacterReferences) {
65 self::$namedCharacterReferences = unserialize(
66 file_get_contents(dirname(__FILE__) . '/named-character-references.ser'));
67 }
68 return self::$namedCharacterReferences;
69 }
70
71 /**
72 * Converts a Unicode codepoint to sequence of UTF-8 bytes.
73 * @note Shamelessly stolen from HTML Purifier, which is also
74 * shamelessly stolen from Feyd (which is in public domain).
75 */
76 public static function utf8chr($code) {
77 /* We don't care: we live dangerously
78 * if($code > 0x10FFFF or $code < 0x0 or
79 ($code >= 0xD800 and $code <= 0xDFFF) ) {
80 // bits are set outside the "valid" range as defined
81 // by UNICODE 4.1.0
82 return "\xEF\xBF\xBD";
83 }*/
84
85 $x = $y = $z = $w = 0;
86 if ($code < 0x80) {
87 // regular ASCII character
88 $x = $code;
89 } else {
90 // set up bits for UTF-8
91 $x = ($code & 0x3F) | 0x80;
92 if ($code < 0x800) {
93 $y = (($code & 0x7FF) >> 6) | 0xC0;
94 } else {
95 $y = (($code & 0xFC0) >> 6) | 0x80;
96 if($code < 0x10000) {
97 $z = (($code >> 12) & 0x0F) | 0xE0;
98 } else {
99 $z = (($code >> 12) & 0x3F) | 0x80;
100 $w = (($code >> 18) & 0x07) | 0xF0;
101 }
102 }
103 }
104 // set up the actual character
105 $ret = '';
106 if($w) $ret .= chr($w);
107 if($z) $ret .= chr($z);
108 if($y) $ret .= chr($y);
109 $ret .= chr($x);
110
111 return $ret;
112 }
113
114}
diff --git a/inc/3rdparty/libraries/html5/InputStream.php b/inc/3rdparty/libraries/html5/InputStream.php
new file mode 100644
index 00000000..f98b4272
--- /dev/null
+++ b/inc/3rdparty/libraries/html5/InputStream.php
@@ -0,0 +1,284 @@
1<?php
2
3/*
4
5Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be included
16in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26*/
27
28// Some conventions:
29// /* */ indicates verbatim text from the HTML 5 specification
30// // indicates regular comments
31
32class HTML5_InputStream {
33 /**
34 * The string data we're parsing.
35 */
36 private $data;
37
38 /**
39 * The current integer byte position we are in $data
40 */
41 private $char;
42
43 /**
44 * Length of $data; when $char === $data, we are at the end-of-file.
45 */
46 private $EOF;
47
48 /**
49 * Parse errors.
50 */
51 public $errors = array();
52
53 /**
54 * @param $data Data to parse
55 */
56 public function __construct($data) {
57
58 /* Given an encoding, the bytes in the input stream must be
59 converted to Unicode characters for the tokeniser, as
60 described by the rules for that encoding, except that the
61 leading U+FEFF BYTE ORDER MARK character, if any, must not
62 be stripped by the encoding layer (it is stripped by the rule below).
63
64 Bytes or sequences of bytes in the original byte stream that
65 could not be converted to Unicode characters must be converted
66 to U+FFFD REPLACEMENT CHARACTER code points. */
67
68 // XXX currently assuming input data is UTF-8; once we
69 // build encoding detection this will no longer be the case
70 //
71 // We previously had an mbstring implementation here, but that
72 // implementation is heavily non-conforming, so it's been
73 // omitted.
74 if (extension_loaded('iconv')) {
75 // non-conforming
76 $data = @iconv('UTF-8', 'UTF-8//IGNORE', $data);
77 } else {
78 // we can make a conforming native implementation
79 throw new Exception('Not implemented, please install mbstring or iconv');
80 }
81
82 /* One leading U+FEFF BYTE ORDER MARK character must be
83 ignored if any are present. */
84 if (substr($data, 0, 3) === "\xEF\xBB\xBF") {
85 $data = substr($data, 3);
86 }
87
88 /* All U+0000 NULL characters in the input must be replaced
89 by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such
90 characters is a parse error. */
91 for ($i = 0, $count = substr_count($data, "\0"); $i < $count; $i++) {
92 $this->errors[] = array(
93 'type' => HTML5_Tokenizer::PARSEERROR,
94 'data' => 'null-character'
95 );
96 }
97 /* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED
98 (LF) characters are treated specially. Any CR characters
99 that are followed by LF characters must be removed, and any
100 CR characters not followed by LF characters must be converted
101 to LF characters. Thus, newlines in HTML DOMs are represented
102 by LF characters, and there are never any CR characters in the
103 input to the tokenization stage. */
104 $data = str_replace(
105 array(
106 "\0",
107 "\r\n",
108 "\r"
109 ),
110 array(
111 "\xEF\xBF\xBD",
112 "\n",
113 "\n"
114 ),
115 $data
116 );
117
118 /* Any occurrences of any characters in the ranges U+0001 to
119 U+0008, U+000B, U+000E to U+001F, U+007F to U+009F,
120 U+D800 to U+DFFF , U+FDD0 to U+FDEF, and
121 characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF,
122 U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE,
123 U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF,
124 U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE,
125 U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and
126 U+10FFFF are parse errors. (These are all control characters
127 or permanently undefined Unicode characters.) */
128 // Check PCRE is loaded.
129 if (extension_loaded('pcre')) {
130 $count = preg_match_all(
131 '/(?:
132 [\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F
133 |
134 \xC2[\x80-\x9F] # U+0080 to U+009F
135 |
136 \xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF
137 |
138 \xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF
139 |
140 \xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF
141 |
142 [\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16})
143 )/x',
144 $data,
145 $matches
146 );
147 for ($i = 0; $i < $count; $i++) {
148 $this->errors[] = array(
149 'type' => HTML5_Tokenizer::PARSEERROR,
150 'data' => 'invalid-codepoint'
151 );
152 }
153 } else {
154 // XXX: Need non-PCRE impl, probably using substr_count
155 }
156
157 $this->data = $data;
158 $this->char = 0;
159 $this->EOF = strlen($data);
160 }
161
162 /**
163 * Returns the current line that the tokenizer is at.
164 */
165 public function getCurrentLine() {
166 // Check the string isn't empty
167 if($this->EOF) {
168 // Add one to $this->char because we want the number for the next
169 // byte to be processed.
170 return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
171 } else {
172 // If the string is empty, we are on the first line (sorta).
173 return 1;
174 }
175 }
176
177 /**
178 * Returns the current column of the current line that the tokenizer is at.
179 */
180 public function getColumnOffset() {
181 // strrpos is weird, and the offset needs to be negative for what we
182 // want (i.e., the last \n before $this->char). This needs to not have
183 // one (to make it point to the next character, the one we want the
184 // position of) added to it because strrpos's behaviour includes the
185 // final offset byte.
186 $lastLine = strrpos($this->data, "\n", $this->char - 1 - strlen($this->data));
187
188 // However, for here we want the length up until the next byte to be
189 // processed, so add one to the current byte ($this->char).
190 if($lastLine !== false) {
191 $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
192 } else {
193 $findLengthOf = substr($this->data, 0, $this->char);
194 }
195
196 // Get the length for the string we need.
197 if(extension_loaded('iconv')) {
198 return iconv_strlen($findLengthOf, 'utf-8');
199 } elseif(extension_loaded('mbstring')) {
200 return mb_strlen($findLengthOf, 'utf-8');
201 } elseif(extension_loaded('xml')) {
202 return strlen(utf8_decode($findLengthOf));
203 } else {
204 $count = count_chars($findLengthOf);
205 // 0x80 = 0x7F - 0 + 1 (one added to get inclusive range)
206 // 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range)
207 return array_sum(array_slice($count, 0, 0x80)) +
208 array_sum(array_slice($count, 0xC2, 0x33));
209 }
210 }
211
212 /**
213 * Retrieve the currently consume character.
214 * @note This performs bounds checking
215 */
216 public function char() {
217 return ($this->char++ < $this->EOF)
218 ? $this->data[$this->char - 1]
219 : false;
220 }
221
222 /**
223 * Get all characters until EOF.
224 * @note This performs bounds checking
225 */
226 public function remainingChars() {
227 if($this->char < $this->EOF) {
228 $data = substr($this->data, $this->char);
229 $this->char = $this->EOF;
230 return $data;
231 } else {
232 return false;
233 }
234 }
235
236 /**
237 * Matches as far as possible until we reach a certain set of bytes
238 * and returns the matched substring.
239 * @param $bytes Bytes to match.
240 */
241 public function charsUntil($bytes, $max = null) {
242 if ($this->char < $this->EOF) {
243 if ($max === 0 || $max) {
244 $len = strcspn($this->data, $bytes, $this->char, $max);
245 } else {
246 $len = strcspn($this->data, $bytes, $this->char);
247 }
248 $string = (string) substr($this->data, $this->char, $len);
249 $this->char += $len;
250 return $string;
251 } else {
252 return false;
253 }
254 }
255
256 /**
257 * Matches as far as possible with a certain set of bytes
258 * and returns the matched substring.
259 * @param $bytes Bytes to match.
260 */
261 public function charsWhile($bytes, $max = null) {
262 if ($this->char < $this->EOF) {
263 if ($max === 0 || $max) {
264 $len = strspn($this->data, $bytes, $this->char, $max);
265 } else {
266 $len = strspn($this->data, $bytes, $this->char);
267 }
268 $string = (string) substr($this->data, $this->char, $len);
269 $this->char += $len;
270 return $string;
271 } else {
272 return false;
273 }
274 }
275
276 /**
277 * Unconsume one character.
278 */
279 public function unget() {
280 if ($this->char <= $this->EOF) {
281 $this->char--;
282 }
283 }
284}
diff --git a/inc/3rdparty/libraries/html5/Parser.php b/inc/3rdparty/libraries/html5/Parser.php
new file mode 100644
index 00000000..5f9ca560
--- /dev/null
+++ b/inc/3rdparty/libraries/html5/Parser.php
@@ -0,0 +1,36 @@
1<?php
2
3require_once dirname(__FILE__) . '/Data.php';
4require_once dirname(__FILE__) . '/InputStream.php';
5require_once dirname(__FILE__) . '/TreeBuilder.php';
6require_once dirname(__FILE__) . '/Tokenizer.php';
7
8/**
9 * Outwards facing interface for HTML5.
10 */
11class HTML5_Parser
12{
13 /**
14 * Parses a full HTML document.
15 * @param $text HTML text to parse
16 * @param $builder Custom builder implementation
17 * @return Parsed HTML as DOMDocument
18 */
19 static public function parse($text, $builder = null) {
20 $tokenizer = new HTML5_Tokenizer($text, $builder);
21 $tokenizer->parse();
22 return $tokenizer->save();
23 }
24 /**
25 * Parses an HTML fragment.
26 * @param $text HTML text to parse
27 * @param $context String name of context element to pretend parsing is in.
28 * @param $builder Custom builder implementation
29 * @return Parsed HTML as DOMDocument
30 */
31 static public function parseFragment($text, $context = null, $builder = null) {
32 $tokenizer = new HTML5_Tokenizer($text, $builder);
33 $tokenizer->parseFragment($context);
34 return $tokenizer->save();
35 }
36}
diff --git a/inc/3rdparty/libraries/html5/Tokenizer.php b/inc/3rdparty/libraries/html5/Tokenizer.php
new file mode 100644
index 00000000..0af07164
--- /dev/null
+++ b/inc/3rdparty/libraries/html5/Tokenizer.php
@@ -0,0 +1,2422 @@
1<?php
2
3/*
4
5Copyright 2007 Jeroen van der Meer <http://jero.net/>
6Copyright 2008 Edward Z. Yang <http://htmlpurifier.org/>
7Copyright 2009 Geoffrey Sneddon <http://gsnedders.com/>
8
9Permission is hereby granted, free of charge, to any person obtaining a
10copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be included
18in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28*/
29
30// Some conventions:
31// /* */ indicates verbatim text from the HTML 5 specification
32// // indicates regular comments
33
34// all flags are in hyphenated form
35
36class HTML5_Tokenizer {
37 /**
38 * Points to an InputStream object.
39 */
40 protected $stream;
41
42 /**
43 * Tree builder that the tokenizer emits token to.
44 */
45 private $tree;
46
47 /**
48 * Current content model we are parsing as.
49 */
50 protected $content_model;
51
52 /**
53 * Current token that is being built, but not yet emitted. Also
54 * is the last token emitted, if applicable.
55 */
56 protected $token;
57
58 // These are constants describing the content model
59 const PCDATA = 0;
60 const RCDATA = 1;
61 const CDATA = 2;
62 const PLAINTEXT = 3;
63
64 // These are constants describing tokens
65 // XXX should probably be moved somewhere else, probably the
66 // HTML5 class.
67 const DOCTYPE = 0;
68 const STARTTAG = 1;
69 const ENDTAG = 2;
70 const COMMENT = 3;
71 const CHARACTER = 4;
72 const SPACECHARACTER = 5;
73 const EOF = 6;
74 const PARSEERROR = 7;
75
76 // These are constants representing bunches of characters.
77 const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
78 const UPPER_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
79 const LOWER_ALPHA = 'abcdefghijklmnopqrstuvwxyz';
80 const DIGIT = '0123456789';
81 const HEX = '0123456789ABCDEFabcdef';
82 const WHITESPACE = "\t\n\x0c ";
83
84 /**
85 * @param $data Data to parse
86 */
87 public function __construct($data, $builder = null) {
88 $this->stream = new HTML5_InputStream($data);
89 if (!$builder) $this->tree = new HTML5_TreeBuilder;
90 else $this->tree = $builder;
91 $this->content_model = self::PCDATA;
92 }
93
94 public function parseFragment($context = null) {
95 $this->tree->setupContext($context);
96 if ($this->tree->content_model) {
97 $this->content_model = $this->tree->content_model;
98 $this->tree->content_model = null;
99 }
100 $this->parse();
101 }
102
103 // XXX maybe convert this into an iterator? regardless, this function
104 // and the save function should go into a Parser facade of some sort
105 /**
106 * Performs the actual parsing of the document.
107 */
108 public function parse() {
109 // Current state
110 $state = 'data';
111 // This is used to avoid having to have look-behind in the data state.
112 $lastFourChars = '';
113 /**
114 * Escape flag as specified by the HTML5 specification: "used to
115 * control the behavior of the tokeniser. It is either true or
116 * false, and initially must be set to the false state."
117 */
118 $escape = false;
119 //echo "\n\n";
120 while($state !== null) {
121
122 /*echo $state . ' ';
123 switch ($this->content_model) {
124 case self::PCDATA: echo 'PCDATA'; break;
125 case self::RCDATA: echo 'RCDATA'; break;
126 case self::CDATA: echo 'CDATA'; break;
127 case self::PLAINTEXT: echo 'PLAINTEXT'; break;
128 }
129 if ($escape) echo " escape";
130 echo "\n";*/
131
132 switch($state) {
133 case 'data':
134
135 /* Consume the next input character */
136 $char = $this->stream->char();
137 $lastFourChars .= $char;
138 if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4);
139
140 // see below for meaning
141 $hyp_cond =
142 !$escape &&
143 (
144 $this->content_model === self::RCDATA ||
145 $this->content_model === self::CDATA
146 );
147 $amp_cond =
148 !$escape &&
149 (
150 $this->content_model === self::PCDATA ||
151 $this->content_model === self::RCDATA
152 );
153 $lt_cond =
154 $this->content_model === self::PCDATA ||
155 (
156 (
157 $this->content_model === self::RCDATA ||
158 $this->content_model === self::CDATA
159 ) &&
160 !$escape
161 );
162 $gt_cond =
163 $escape &&
164 (
165 $this->content_model === self::RCDATA ||
166 $this->content_model === self::CDATA
167 );
168
169 if($char === '&' && $amp_cond) {
170 /* U+0026 AMPERSAND (&)
171 When the content model flag is set to one of the PCDATA or RCDATA
172 states and the escape flag is false: switch to the
173 character reference data state. Otherwise: treat it as per
174 the "anything else" entry below. */
175 $state = 'character reference data';
176
177 } elseif(
178 $char === '-' &&
179 $hyp_cond &&
180 $lastFourChars === '<!--'
181 ) {
182 /*
183 U+002D HYPHEN-MINUS (-)
184 If the content model flag is set to either the RCDATA state or
185 the CDATA state, and the escape flag is false, and there are at
186 least three characters before this one in the input stream, and the
187 last four characters in the input stream, including this one, are
188 U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS,
189 and U+002D HYPHEN-MINUS ("<!--"), then set the escape flag to true. */
190 $escape = true;
191
192 /* In any case, emit the input character as a character token. Stay
193 in the data state. */
194 $this->emitToken(array(
195 'type' => self::CHARACTER,
196 'data' => '-'
197 ));
198 // We do the "any case" part as part of "anything else".
199
200 /* U+003C LESS-THAN SIGN (<) */
201 } elseif($char === '<' && $lt_cond) {
202 /* When the content model flag is set to the PCDATA state: switch
203 to the tag open state.
204
205 When the content model flag is set to either the RCDATA state or
206 the CDATA state and the escape flag is false: switch to the tag
207 open state.
208
209 Otherwise: treat it as per the "anything else" entry below. */
210 $state = 'tag open';
211
212 /* U+003E GREATER-THAN SIGN (>) */
213 } elseif(
214 $char === '>' &&
215 $gt_cond &&
216 substr($lastFourChars, 1) === '-->'
217 ) {
218 /* If the content model flag is set to either the RCDATA state or
219 the CDATA state, and the escape flag is true, and the last three
220 characters in the input stream including this one are U+002D
221 HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN ("-->"),
222 set the escape flag to false. */
223 $escape = false;
224
225 /* In any case, emit the input character as a character token.
226 Stay in the data state. */
227 $this->emitToken(array(
228 'type' => self::CHARACTER,
229 'data' => '>'
230 ));
231 // We do the "any case" part as part of "anything else".
232
233 } elseif($char === false) {
234 /* EOF
235 Emit an end-of-file token. */
236 $state = null;
237 $this->tree->emitToken(array(
238 'type' => self::EOF
239 ));
240
241 } elseif($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
242 // Directly after emitting a token you switch back to the "data
243 // state". At that point spaceCharacters are important so they are
244 // emitted separately.
245 $chars = $this->stream->charsWhile(self::WHITESPACE);
246 $this->emitToken(array(
247 'type' => self::SPACECHARACTER,
248 'data' => $char . $chars
249 ));
250 $lastFourChars .= $chars;
251 if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4);
252
253 } else {
254 /* Anything else
255 THIS IS AN OPTIMIZATION: Get as many character that
256 otherwise would also be treated as a character token and emit it
257 as a single character token. Stay in the data state. */
258
259 $mask = '';
260 if ($hyp_cond) $mask .= '-';
261 if ($amp_cond) $mask .= '&';
262 if ($lt_cond) $mask .= '<';
263 if ($gt_cond) $mask .= '>';
264
265 if ($mask === '') {
266 $chars = $this->stream->remainingChars();
267 } else {
268 $chars = $this->stream->charsUntil($mask);
269 }
270
271 $this->emitToken(array(
272 'type' => self::CHARACTER,
273 'data' => $char . $chars
274 ));
275
276 $lastFourChars .= $chars;
277 if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4);
278
279 $state = 'data';
280 }
281 break;
282
283 case 'character reference data':
284 /* (This cannot happen if the content model flag
285 is set to the CDATA state.) */
286
287 /* Attempt to consume a character reference, with no
288 additional allowed character. */
289 $entity = $this->consumeCharacterReference();
290
291 /* If nothing is returned, emit a U+0026 AMPERSAND
292 character token. Otherwise, emit the character token that
293 was returned. */
294 // This is all done when consuming the character reference.
295 $this->emitToken(array(
296 'type' => self::CHARACTER,
297 'data' => $entity
298 ));
299
300 /* Finally, switch to the data state. */
301 $state = 'data';
302 break;
303
304 case 'tag open':
305 $char = $this->stream->char();
306
307 switch($this->content_model) {
308 case self::RCDATA:
309 case self::CDATA:
310 /* Consume the next input character. If it is a
311 U+002F SOLIDUS (/) character, switch to the close
312 tag open state. Otherwise, emit a U+003C LESS-THAN
313 SIGN character token and reconsume the current input
314 character in the data state. */
315 // We consumed above.
316
317 if($char === '/') {
318 $state = 'close tag open';
319
320 } else {
321 $this->emitToken(array(
322 'type' => self::CHARACTER,
323 'data' => '<'
324 ));
325
326 $this->stream->unget();
327
328 $state = 'data';
329 }
330 break;
331
332 case self::PCDATA:
333 /* If the content model flag is set to the PCDATA state
334 Consume the next input character: */
335 // We consumed above.
336
337 if($char === '!') {
338 /* U+0021 EXCLAMATION MARK (!)
339 Switch to the markup declaration open state. */
340 $state = 'markup declaration open';
341
342 } elseif($char === '/') {
343 /* U+002F SOLIDUS (/)
344 Switch to the close tag open state. */
345 $state = 'close tag open';
346
347 } elseif('A' <= $char && $char <= 'Z') {
348 /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z
349 Create a new start tag token, set its tag name to the lowercase
350 version of the input character (add 0x0020 to the character's code
351 point), then switch to the tag name state. (Don't emit the token
352 yet; further details will be filled in before it is emitted.) */
353 $this->token = array(
354 'name' => strtolower($char),
355 'type' => self::STARTTAG,
356 'attr' => array()
357 );
358
359 $state = 'tag name';
360
361 } elseif('a' <= $char && $char <= 'z') {
362 /* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z
363 Create a new start tag token, set its tag name to the input
364 character, then switch to the tag name state. (Don't emit
365 the token yet; further details will be filled in before it
366 is emitted.) */
367 $this->token = array(
368 'name' => $char,
369 'type' => self::STARTTAG,
370 'attr' => array()
371 );
372
373 $state = 'tag name';
374
375 } elseif($char === '>') {
376 /* U+003E GREATER-THAN SIGN (>)
377 Parse error. Emit a U+003C LESS-THAN SIGN character token and a
378 U+003E GREATER-THAN SIGN character token. Switch to the data state. */
379 $this->emitToken(array(
380 'type' => self::PARSEERROR,
381 'data' => 'expected-tag-name-but-got-right-bracket'
382 ));
383 $this->emitToken(array(
384 'type' => self::CHARACTER,
385 'data' => '<>'
386 ));
387
388 $state = 'data';
389
390 } elseif($char === '?') {
391 /* U+003F QUESTION MARK (?)
392 Parse error. Switch to the bogus comment state. */
393 $this->emitToken(array(
394 'type' => self::PARSEERROR,
395 'data' => 'expected-tag-name-but-got-question-mark'
396 ));
397 $this->token = array(
398 'data' => '?',
399 'type' => self::COMMENT
400 );
401 $state = 'bogus comment';
402
403 } else {
404 /* Anything else
405 Parse error. Emit a U+003C LESS-THAN SIGN character token and
406 reconsume the current input character in the data state. */
407 $this->emitToken(array(
408 'type' => self::PARSEERROR,
409 'data' => 'expected-tag-name'
410 ));
411 $this->emitToken(array(
412 'type' => self::CHARACTER,
413 'data' => '<'
414 ));
415
416 $state = 'data';
417 $this->stream->unget();
418 }
419 break;
420 }
421 break;
422
423 case 'close tag open':
424 if (
425 $this->content_model === self::RCDATA ||
426 $this->content_model === self::CDATA
427 ) {
428 /* If the content model flag is set to the RCDATA or CDATA
429 states... */
430 $name = strtolower($this->stream->charsWhile(self::ALPHA));
431 $following = $this->stream->char();
432 $this->stream->unget();
433 if (
434 !$this->token ||
435 $this->token['name'] !== $name ||
436 $this->token['name'] === $name && !in_array($following, array("\x09", "\x0A", "\x0C", "\x20", "\x3E", "\x2F", false))
437 ) {
438 /* if no start tag token has ever been emitted by this instance
439 of the tokenizer (fragment case), or, if the next few
440 characters do not match the tag name of the last start tag
441 token emitted (compared in an ASCII case-insensitive manner),
442 or if they do but they are not immediately followed by one of
443 the following characters:
444
445 * U+0009 CHARACTER TABULATION
446 * U+000A LINE FEED (LF)
447 * U+000C FORM FEED (FF)
448 * U+0020 SPACE
449 * U+003E GREATER-THAN SIGN (>)
450 * U+002F SOLIDUS (/)
451 * EOF
452
453 ...then emit a U+003C LESS-THAN SIGN character token, a
454 U+002F SOLIDUS character token, and switch to the data
455 state to process the next input character. */
456 // XXX: Probably ought to replace in_array with $following === x ||...
457
458 // We also need to emit $name now we've consumed that, as we
459 // know it'll just be emitted as a character token.
460 $this->emitToken(array(
461 'type' => self::CHARACTER,
462 'data' => '</' . $name
463 ));
464
465 $state = 'data';
466 } else {
467 // This matches what would happen if we actually did the
468 // otherwise below (but we can't because we've consumed too
469 // much).
470
471 // Start the end tag token with the name we already have.
472 $this->token = array(
473 'name' => $name,
474 'type' => self::ENDTAG
475 );
476
477 // Change to tag name state.
478 $state = 'tag name';
479 }
480 } elseif ($this->content_model === self::PCDATA) {
481 /* Otherwise, if the content model flag is set to the PCDATA
482 state [...]: */
483 $char = $this->stream->char();
484
485 if ('A' <= $char && $char <= 'Z') {
486 /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z
487 Create a new end tag token, set its tag name to the lowercase version
488 of the input character (add 0x0020 to the character's code point), then
489 switch to the tag name state. (Don't emit the token yet; further details
490 will be filled in before it is emitted.) */
491 $this->token = array(
492 'name' => strtolower($char),
493 'type' => self::ENDTAG
494 );
495
496 $state = 'tag name';
497
498 } elseif ('a' <= $char && $char <= 'z') {
499 /* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z
500 Create a new end tag token, set its tag name to the
501 input character, then switch to the tag name state.
502 (Don't emit the token yet; further details will be
503 filled in before it is emitted.) */
504 $this->token = array(
505 'name' => $char,
506 'type' => self::ENDTAG
507 );
508
509 $state = 'tag name';
510
511 } elseif($char === '>') {
512 /* U+003E GREATER-THAN SIGN (>)
513 Parse error. Switch to the data state. */
514 $this->emitToken(array(
515 'type' => self::PARSEERROR,
516 'data' => 'expected-closing-tag-but-got-right-bracket'
517 ));
518 $state = 'data';
519
520 } elseif($char === false) {
521 /* EOF
522 Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F
523 SOLIDUS character token. Reconsume the EOF character in the data state. */
524 $this->emitToken(array(
525 'type' => self::PARSEERROR,
526 'data' => 'expected-closing-tag-but-got-eof'
527 ));
528 $this->emitToken(array(
529 'type' => self::CHARACTER,
530 'data' => '</'
531 ));
532
533 $this->stream->unget();
534 $state = 'data';
535
536 } else {
537 /* Parse error. Switch to the bogus comment state. */
538 $this->emitToken(array(
539 'type' => self::PARSEERROR,
540 'data' => 'expected-closing-tag-but-got-char'
541 ));
542 $this->token = array(
543 'data' => $char,
544 'type' => self::COMMENT
545 );
546 $state = 'bogus comment';
547 }
548 }
549 break;
550
551 case 'tag name':
552 /* Consume the next input character: */
553 $char = $this->stream->char();
554
555 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
556 /* U+0009 CHARACTER TABULATION
557 U+000A LINE FEED (LF)
558 U+000C FORM FEED (FF)
559 U+0020 SPACE
560 Switch to the before attribute name state. */
561 $state = 'before attribute name';
562
563 } elseif($char === '/') {
564 /* U+002F SOLIDUS (/)
565 Switch to the self-closing start tag state. */
566 $state = 'self-closing start tag';
567
568 } elseif($char === '>') {
569 /* U+003E GREATER-THAN SIGN (>)
570 Emit the current tag token. Switch to the data state. */
571 $this->emitToken($this->token);
572 $state = 'data';
573
574 } elseif('A' <= $char && $char <= 'Z') {
575 /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
576 Append the lowercase version of the current input
577 character (add 0x0020 to the character's code point) to
578 the current tag token's tag name. Stay in the tag name state. */
579 $chars = $this->stream->charsWhile(self::UPPER_ALPHA);
580
581 $this->token['name'] .= strtolower($char . $chars);
582 $state = 'tag name';
583
584 } elseif($char === false) {
585 /* EOF
586 Parse error. Reconsume the EOF character in the data state. */
587 $this->emitToken(array(
588 'type' => self::PARSEERROR,
589 'data' => 'eof-in-tag-name'
590 ));
591
592 $this->stream->unget();
593 $state = 'data';
594
595 } else {
596 /* Anything else
597 Append the current input character to the current tag token's tag name.
598 Stay in the tag name state. */
599 $chars = $this->stream->charsUntil("\t\n\x0C />" . self::UPPER_ALPHA);
600
601 $this->token['name'] .= $char . $chars;
602 $state = 'tag name';
603 }
604 break;
605
606 case 'before attribute name':
607 /* Consume the next input character: */
608 $char = $this->stream->char();
609
610 // this conditional is optimized, check bottom
611 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
612 /* U+0009 CHARACTER TABULATION
613 U+000A LINE FEED (LF)
614 U+000C FORM FEED (FF)
615 U+0020 SPACE
616 Stay in the before attribute name state. */
617 $state = 'before attribute name';
618
619 } elseif($char === '/') {
620 /* U+002F SOLIDUS (/)
621 Switch to the self-closing start tag state. */
622 $state = 'self-closing start tag';
623
624 } elseif($char === '>') {
625 /* U+003E GREATER-THAN SIGN (>)
626 Emit the current tag token. Switch to the data state. */
627 $this->emitToken($this->token);
628 $state = 'data';
629
630 } elseif('A' <= $char && $char <= 'Z') {
631 /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
632 Start a new attribute in the current tag token. Set that
633 attribute's name to the lowercase version of the current
634 input character (add 0x0020 to the character's code
635 point), and its value to the empty string. Switch to the
636 attribute name state.*/
637 $this->token['attr'][] = array(
638 'name' => strtolower($char),
639 'value' => ''
640 );
641
642 $state = 'attribute name';
643
644 } elseif($char === false) {
645 /* EOF
646 Parse error. Reconsume the EOF character in the data state. */
647 $this->emitToken(array(
648 'type' => self::PARSEERROR,
649 'data' => 'expected-attribute-name-but-got-eof'
650 ));
651
652 $this->stream->unget();
653 $state = 'data';
654
655 } else {
656 /* U+0022 QUOTATION MARK (")
657 U+0027 APOSTROPHE (')
658 U+003C LESS-THAN SIGN (<)
659 U+003D EQUALS SIGN (=)
660 Parse error. Treat it as per the "anything else" entry
661 below. */
662 if($char === '"' || $char === "'" || $char === '<' || $char === '=') {
663 $this->emitToken(array(
664 'type' => self::PARSEERROR,
665 'data' => 'invalid-character-in-attribute-name'
666 ));
667 }
668
669 /* Anything else
670 Start a new attribute in the current tag token. Set that attribute's
671 name to the current input character, and its value to the empty string.
672 Switch to the attribute name state. */
673 $this->token['attr'][] = array(
674 'name' => $char,
675 'value' => ''
676 );
677
678 $state = 'attribute name';
679 }
680 break;
681
682 case 'attribute name':
683 // Consume the next input character:
684 $char = $this->stream->char();
685
686 // this conditional is optimized, check bottom
687 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
688 /* U+0009 CHARACTER TABULATION
689 U+000A LINE FEED (LF)
690 U+000C FORM FEED (FF)
691 U+0020 SPACE
692 Switch to the after attribute name state. */
693 $state = 'after attribute name';
694
695 } elseif($char === '/') {
696 /* U+002F SOLIDUS (/)
697 Switch to the self-closing start tag state. */
698 $state = 'self-closing start tag';
699
700 } elseif($char === '=') {
701 /* U+003D EQUALS SIGN (=)
702 Switch to the before attribute value state. */
703 $state = 'before attribute value';
704
705 } elseif($char === '>') {
706 /* U+003E GREATER-THAN SIGN (>)
707 Emit the current tag token. Switch to the data state. */
708 $this->emitToken($this->token);
709 $state = 'data';
710
711 } elseif('A' <= $char && $char <= 'Z') {
712 /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
713 Append the lowercase version of the current input
714 character (add 0x0020 to the character's code point) to
715 the current attribute's name. Stay in the attribute name
716 state. */
717 $chars = $this->stream->charsWhile(self::UPPER_ALPHA);
718
719 $last = count($this->token['attr']) - 1;
720 $this->token['attr'][$last]['name'] .= strtolower($char . $chars);
721
722 $state = 'attribute name';
723
724 } elseif($char === false) {
725 /* EOF
726 Parse error. Reconsume the EOF character in the data state. */
727 $this->emitToken(array(
728 'type' => self::PARSEERROR,
729 'data' => 'eof-in-attribute-name'
730 ));
731
732 $this->stream->unget();
733 $state = 'data';
734
735 } else {
736 /* U+0022 QUOTATION MARK (")
737 U+0027 APOSTROPHE (')
738 U+003C LESS-THAN SIGN (<)
739 Parse error. Treat it as per the "anything else"
740 entry below. */
741 if($char === '"' || $char === "'" || $char === '<') {
742 $this->emitToken(array(
743 'type' => self::PARSEERROR,
744 'data' => 'invalid-character-in-attribute-name'
745 ));
746 }
747
748 /* Anything else
749 Append the current input character to the current attribute's name.
750 Stay in the attribute name state. */
751 $chars = $this->stream->charsUntil("\t\n\x0C /=>\"'" . self::UPPER_ALPHA);
752
753 $last = count($this->token['attr']) - 1;
754 $this->token['attr'][$last]['name'] .= $char . $chars;
755
756 $state = 'attribute name';
757 }
758
759 /* When the user agent leaves the attribute name state
760 (and before emitting the tag token, if appropriate), the
761 complete attribute's name must be compared to the other
762 attributes on the same token; if there is already an
763 attribute on the token with the exact same name, then this
764 is a parse error and the new attribute must be dropped, along
765 with the value that gets associated with it (if any). */
766 // this might be implemented in the emitToken method
767 break;
768
769 case 'after attribute name':
770 // Consume the next input character:
771 $char = $this->stream->char();
772
773 // this is an optimized conditional, check the bottom
774 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
775 /* U+0009 CHARACTER TABULATION
776 U+000A LINE FEED (LF)
777 U+000C FORM FEED (FF)
778 U+0020 SPACE
779 Stay in the after attribute name state. */
780 $state = 'after attribute name';
781
782 } elseif($char === '/') {
783 /* U+002F SOLIDUS (/)
784 Switch to the self-closing start tag state. */
785 $state = 'self-closing start tag';
786
787 } elseif($char === '=') {
788 /* U+003D EQUALS SIGN (=)
789 Switch to the before attribute value state. */
790 $state = 'before attribute value';
791
792 } elseif($char === '>') {
793 /* U+003E GREATER-THAN SIGN (>)
794 Emit the current tag token. Switch to the data state. */
795 $this->emitToken($this->token);
796 $state = 'data';
797
798 } elseif('A' <= $char && $char <= 'Z') {
799 /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
800 Start a new attribute in the current tag token. Set that
801 attribute's name to the lowercase version of the current
802 input character (add 0x0020 to the character's code
803 point), and its value to the empty string. Switch to the
804 attribute name state. */
805 $this->token['attr'][] = array(
806 'name' => strtolower($char),
807 'value' => ''
808 );
809
810 $state = 'attribute name';
811
812 } elseif($char === false) {
813 /* EOF
814 Parse error. Reconsume the EOF character in the data state. */
815 $this->emitToken(array(
816 'type' => self::PARSEERROR,
817 'data' => 'expected-end-of-tag-but-got-eof'
818 ));
819
820 $this->stream->unget();
821 $state = 'data';
822
823 } else {
824 /* U+0022 QUOTATION MARK (")
825 U+0027 APOSTROPHE (')
826 U+003C LESS-THAN SIGN(<)
827 Parse error. Treat it as per the "anything else"
828 entry below. */
829 if($char === '"' || $char === "'" || $char === "<") {
830 $this->emitToken(array(
831 'type' => self::PARSEERROR,
832 'data' => 'invalid-character-after-attribute-name'
833 ));
834 }
835
836 /* Anything else
837 Start a new attribute in the current tag token. Set that attribute's
838 name to the current input character, and its value to the empty string.
839 Switch to the attribute name state. */
840 $this->token['attr'][] = array(
841 'name' => $char,
842 'value' => ''
843 );
844
845 $state = 'attribute name';
846 }
847 break;
848
849 case 'before attribute value':
850 // Consume the next input character:
851 $char = $this->stream->char();
852
853 // this is an optimized conditional
854 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
855 /* U+0009 CHARACTER TABULATION
856 U+000A LINE FEED (LF)
857 U+000C FORM FEED (FF)
858 U+0020 SPACE
859 Stay in the before attribute value state. */
860 $state = 'before attribute value';
861
862 } elseif($char === '"') {
863 /* U+0022 QUOTATION MARK (")
864 Switch to the attribute value (double-quoted) state. */
865 $state = 'attribute value (double-quoted)';
866
867 } elseif($char === '&') {
868 /* U+0026 AMPERSAND (&)
869 Switch to the attribute value (unquoted) state and reconsume
870 this input character. */
871 $this->stream->unget();
872 $state = 'attribute value (unquoted)';
873
874 } elseif($char === '\'') {
875 /* U+0027 APOSTROPHE (')
876 Switch to the attribute value (single-quoted) state. */
877 $state = 'attribute value (single-quoted)';
878
879 } elseif($char === '>') {
880 /* U+003E GREATER-THAN SIGN (>)
881 Parse error. Emit the current tag token. Switch to the data state. */
882 $this->emitToken(array(
883 'type' => self::PARSEERROR,
884 'data' => 'expected-attribute-value-but-got-right-bracket'
885 ));
886 $this->emitToken($this->token);
887 $state = 'data';
888
889 } elseif($char === false) {
890 /* EOF
891 Parse error. Reconsume the EOF character in the data state. */
892 $this->emitToken(array(
893 'type' => self::PARSEERROR,
894 'data' => 'expected-attribute-value-but-got-eof'
895 ));
896 $this->stream->unget();
897 $state = 'data';
898
899 } else {
900 /* U+003D EQUALS SIGN (=)
901 * U+003C LESS-THAN SIGN (<)
902 Parse error. Treat it as per the "anything else" entry below. */
903 if($char === '=' || $char === '<') {
904 $this->emitToken(array(
905 'type' => self::PARSEERROR,
906 'data' => 'equals-in-unquoted-attribute-value'
907 ));
908 }
909
910 /* Anything else
911 Append the current input character to the current attribute's value.
912 Switch to the attribute value (unquoted) state. */
913 $last = count($this->token['attr']) - 1;
914 $this->token['attr'][$last]['value'] .= $char;
915
916 $state = 'attribute value (unquoted)';
917 }
918 break;
919
920 case 'attribute value (double-quoted)':
921 // Consume the next input character:
922 $char = $this->stream->char();
923
924 if($char === '"') {
925 /* U+0022 QUOTATION MARK (")
926 Switch to the after attribute value (quoted) state. */
927 $state = 'after attribute value (quoted)';
928
929 } elseif($char === '&') {
930 /* U+0026 AMPERSAND (&)
931 Switch to the character reference in attribute value
932 state, with the additional allowed character
933 being U+0022 QUOTATION MARK ("). */
934 $this->characterReferenceInAttributeValue('"');
935
936 } elseif($char === false) {
937 /* EOF
938 Parse error. Reconsume the EOF character in the data state. */
939 $this->emitToken(array(
940 'type' => self::PARSEERROR,
941 'data' => 'eof-in-attribute-value-double-quote'
942 ));
943
944 $this->stream->unget();
945 $state = 'data';
946
947 } else {
948 /* Anything else
949 Append the current input character to the current attribute's value.
950 Stay in the attribute value (double-quoted) state. */
951 $chars = $this->stream->charsUntil('"&');
952
953 $last = count($this->token['attr']) - 1;
954 $this->token['attr'][$last]['value'] .= $char . $chars;
955
956 $state = 'attribute value (double-quoted)';
957 }
958 break;
959
960 case 'attribute value (single-quoted)':
961 // Consume the next input character:
962 $char = $this->stream->char();
963
964 if($char === "'") {
965 /* U+0022 QUOTATION MARK (')
966 Switch to the after attribute value state. */
967 $state = 'after attribute value (quoted)';
968
969 } elseif($char === '&') {
970 /* U+0026 AMPERSAND (&)
971 Switch to the entity in attribute value state. */
972 $this->characterReferenceInAttributeValue("'");
973
974 } elseif($char === false) {
975 /* EOF
976 Parse error. Reconsume the EOF character in the data state. */
977 $this->emitToken(array(
978 'type' => self::PARSEERROR,
979 'data' => 'eof-in-attribute-value-single-quote'
980 ));
981
982 $this->stream->unget();
983 $state = 'data';
984
985 } else {
986 /* Anything else
987 Append the current input character to the current attribute's value.
988 Stay in the attribute value (single-quoted) state. */
989 $chars = $this->stream->charsUntil("'&");
990
991 $last = count($this->token['attr']) - 1;
992 $this->token['attr'][$last]['value'] .= $char . $chars;
993
994 $state = 'attribute value (single-quoted)';
995 }
996 break;
997
998 case 'attribute value (unquoted)':
999 // Consume the next input character:
1000 $char = $this->stream->char();
1001
1002 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1003 /* U+0009 CHARACTER TABULATION
1004 U+000A LINE FEED (LF)
1005 U+000C FORM FEED (FF)
1006 U+0020 SPACE
1007 Switch to the before attribute name state. */
1008 $state = 'before attribute name';
1009
1010 } elseif($char === '&') {
1011 /* U+0026 AMPERSAND (&)
1012 Switch to the entity in attribute value state, with the
1013 additional allowed character being U+003E
1014 GREATER-THAN SIGN (>). */
1015 $this->characterReferenceInAttributeValue('>');
1016
1017 } elseif($char === '>') {
1018 /* U+003E GREATER-THAN SIGN (>)
1019 Emit the current tag token. Switch to the data state. */
1020 $this->emitToken($this->token);
1021 $state = 'data';
1022
1023 } elseif ($char === false) {
1024 /* EOF
1025 Parse error. Reconsume the EOF character in the data state. */
1026 $this->emitToken(array(
1027 'type' => self::PARSEERROR,
1028 'data' => 'eof-in-attribute-value-no-quotes'
1029 ));
1030 $this->stream->unget();
1031 $state = 'data';
1032
1033 } else {
1034 /* U+0022 QUOTATION MARK (")
1035 U+0027 APOSTROPHE (')
1036 U+003C LESS-THAN SIGN (<)
1037 U+003D EQUALS SIGN (=)
1038 Parse error. Treat it as per the "anything else"
1039 entry below. */
1040 if($char === '"' || $char === "'" || $char === '=' || $char == '<') {
1041 $this->emitToken(array(
1042 'type' => self::PARSEERROR,
1043 'data' => 'unexpected-character-in-unquoted-attribute-value'
1044 ));
1045 }
1046
1047 /* Anything else
1048 Append the current input character to the current attribute's value.
1049 Stay in the attribute value (unquoted) state. */
1050 $chars = $this->stream->charsUntil("\t\n\x0c &>\"'=");
1051
1052 $last = count($this->token['attr']) - 1;
1053 $this->token['attr'][$last]['value'] .= $char . $chars;
1054
1055 $state = 'attribute value (unquoted)';
1056 }
1057 break;
1058
1059 case 'after attribute value (quoted)':
1060 /* Consume the next input character: */
1061 $char = $this->stream->char();
1062
1063 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1064 /* U+0009 CHARACTER TABULATION
1065 U+000A LINE FEED (LF)
1066 U+000C FORM FEED (FF)
1067 U+0020 SPACE
1068 Switch to the before attribute name state. */
1069 $state = 'before attribute name';
1070
1071 } elseif ($char === '/') {
1072 /* U+002F SOLIDUS (/)
1073 Switch to the self-closing start tag state. */
1074 $state = 'self-closing start tag';
1075
1076 } elseif ($char === '>') {
1077 /* U+003E GREATER-THAN SIGN (>)
1078 Emit the current tag token. Switch to the data state. */
1079 $this->emitToken($this->token);
1080 $state = 'data';
1081
1082 } elseif ($char === false) {
1083 /* EOF
1084 Parse error. Reconsume the EOF character in the data state. */
1085 $this->emitToken(array(
1086 'type' => self::PARSEERROR,
1087 'data' => 'unexpected-EOF-after-attribute-value'
1088 ));
1089 $this->stream->unget();
1090 $state = 'data';
1091
1092 } else {
1093 /* Anything else
1094 Parse error. Reconsume the character in the before attribute
1095 name state. */
1096 $this->emitToken(array(
1097 'type' => self::PARSEERROR,
1098 'data' => 'unexpected-character-after-attribute-value'
1099 ));
1100 $this->stream->unget();
1101 $state = 'before attribute name';
1102 }
1103 break;
1104
1105 case 'self-closing start tag':
1106 /* Consume the next input character: */
1107 $char = $this->stream->char();
1108
1109 if ($char === '>') {
1110 /* U+003E GREATER-THAN SIGN (>)
1111 Set the self-closing flag of the current tag token.
1112 Emit the current tag token. Switch to the data state. */
1113 // not sure if this is the name we want
1114 $this->token['self-closing'] = true;
1115 $this->emitToken($this->token);
1116 $state = 'data';
1117
1118 } elseif ($char === false) {
1119 /* EOF
1120 Parse error. Reconsume the EOF character in the data state. */
1121 $this->emitToken(array(
1122 'type' => self::PARSEERROR,
1123 'data' => 'unexpected-eof-after-self-closing'
1124 ));
1125 $this->stream->unget();
1126 $state = 'data';
1127
1128 } else {
1129 /* Anything else
1130 Parse error. Reconsume the character in the before attribute name state. */
1131 $this->emitToken(array(
1132 'type' => self::PARSEERROR,
1133 'data' => 'unexpected-character-after-self-closing'
1134 ));
1135 $this->stream->unget();
1136 $state = 'before attribute name';
1137 }
1138 break;
1139
1140 case 'bogus comment':
1141 /* (This can only happen if the content model flag is set to the PCDATA state.) */
1142 /* Consume every character up to the first U+003E GREATER-THAN SIGN
1143 character (>) or the end of the file (EOF), whichever comes first. Emit
1144 a comment token whose data is the concatenation of all the characters
1145 starting from and including the character that caused the state machine
1146 to switch into the bogus comment state, up to and including the last
1147 consumed character before the U+003E character, if any, or up to the
1148 end of the file otherwise. (If the comment was started by the end of
1149 the file (EOF), the token is empty.) */
1150 $this->token['data'] .= (string) $this->stream->charsUntil('>');
1151 $this->stream->char();
1152
1153 $this->emitToken($this->token);
1154
1155 /* Switch to the data state. */
1156 $state = 'data';
1157 break;
1158
1159 case 'markup declaration open':
1160 // Consume for below
1161 $hyphens = $this->stream->charsWhile('-', 2);
1162 if ($hyphens === '-') {
1163 $this->stream->unget();
1164 }
1165 if ($hyphens !== '--') {
1166 $alpha = $this->stream->charsWhile(self::ALPHA, 7);
1167 }
1168
1169 /* If the next two characters are both U+002D HYPHEN-MINUS (-)
1170 characters, consume those two characters, create a comment token whose
1171 data is the empty string, and switch to the comment state. */
1172 if($hyphens === '--') {
1173 $state = 'comment start';
1174 $this->token = array(
1175 'data' => '',
1176 'type' => self::COMMENT
1177 );
1178
1179 /* Otherwise if the next seven characters are a case-insensitive match
1180 for the word "DOCTYPE", then consume those characters and switch to the
1181 DOCTYPE state. */
1182 } elseif(strtoupper($alpha) === 'DOCTYPE') {
1183 $state = 'DOCTYPE';
1184
1185 // XXX not implemented
1186 /* Otherwise, if the insertion mode is "in foreign content"
1187 and the current node is not an element in the HTML namespace
1188 and the next seven characters are an ASCII case-sensitive
1189 match for the string "[CDATA[" (the five uppercase letters
1190 "CDATA" with a U+005B LEFT SQUARE BRACKET character before
1191 and after), then consume those characters and switch to the
1192 CDATA section state (which is unrelated to the content model
1193 flag's CDATA state). */
1194
1195 /* Otherwise, is is a parse error. Switch to the bogus comment state.
1196 The next character that is consumed, if any, is the first character
1197 that will be in the comment. */
1198 } else {
1199 $this->emitToken(array(
1200 'type' => self::PARSEERROR,
1201 'data' => 'expected-dashes-or-doctype'
1202 ));
1203 $this->token = array(
1204 'data' => (string) $alpha,
1205 'type' => self::COMMENT
1206 );
1207 $state = 'bogus comment';
1208 }
1209 break;
1210
1211 case 'comment start':
1212 /* Consume the next input character: */
1213 $char = $this->stream->char();
1214
1215 if ($char === '-') {
1216 /* U+002D HYPHEN-MINUS (-)
1217 Switch to the comment start dash state. */
1218 $state = 'comment start dash';
1219 } elseif ($char === '>') {
1220 /* U+003E GREATER-THAN SIGN (>)
1221 Parse error. Emit the comment token. Switch to the
1222 data state. */
1223 $this->emitToken(array(
1224 'type' => self::PARSEERROR,
1225 'data' => 'incorrect-comment'
1226 ));
1227 $this->emitToken($this->token);
1228 $state = 'data';
1229 } elseif ($char === false) {
1230 /* EOF
1231 Parse error. Emit the comment token. Reconsume the
1232 EOF character in the data state. */
1233 $this->emitToken(array(
1234 'type' => self::PARSEERROR,
1235 'data' => 'eof-in-comment'
1236 ));
1237 $this->emitToken($this->token);
1238 $this->stream->unget();
1239 $state = 'data';
1240 } else {
1241 /* Anything else
1242 Append the input character to the comment token's
1243 data. Switch to the comment state. */
1244 $this->token['data'] .= $char;
1245 $state = 'comment';
1246 }
1247 break;
1248
1249 case 'comment start dash':
1250 /* Consume the next input character: */
1251 $char = $this->stream->char();
1252 if ($char === '-') {
1253 /* U+002D HYPHEN-MINUS (-)
1254 Switch to the comment end state */
1255 $state = 'comment end';
1256 } elseif ($char === '>') {
1257 /* U+003E GREATER-THAN SIGN (>)
1258 Parse error. Emit the comment token. Switch to the
1259 data state. */
1260 $this->emitToken(array(
1261 'type' => self::PARSEERROR,
1262 'data' => 'incorrect-comment'
1263 ));
1264 $this->emitToken($this->token);
1265 $state = 'data';
1266 } elseif ($char === false) {
1267 /* Parse error. Emit the comment token. Reconsume the
1268 EOF character in the data state. */
1269 $this->emitToken(array(
1270 'type' => self::PARSEERROR,
1271 'data' => 'eof-in-comment'
1272 ));
1273 $this->emitToken($this->token);
1274 $this->stream->unget();
1275 $state = 'data';
1276 } else {
1277 $this->token['data'] .= '-' . $char;
1278 $state = 'comment';
1279 }
1280 break;
1281
1282 case 'comment':
1283 /* Consume the next input character: */
1284 $char = $this->stream->char();
1285
1286 if($char === '-') {
1287 /* U+002D HYPHEN-MINUS (-)
1288 Switch to the comment end dash state */
1289 $state = 'comment end dash';
1290
1291 } elseif($char === false) {
1292 /* EOF
1293 Parse error. Emit the comment token. Reconsume the EOF character
1294 in the data state. */
1295 $this->emitToken(array(
1296 'type' => self::PARSEERROR,
1297 'data' => 'eof-in-comment'
1298 ));
1299 $this->emitToken($this->token);
1300 $this->stream->unget();
1301 $state = 'data';
1302
1303 } else {
1304 /* Anything else
1305 Append the input character to the comment token's data. Stay in
1306 the comment state. */
1307 $chars = $this->stream->charsUntil('-');
1308
1309 $this->token['data'] .= $char . $chars;
1310 }
1311 break;
1312
1313 case 'comment end dash':
1314 /* Consume the next input character: */
1315 $char = $this->stream->char();
1316
1317 if($char === '-') {
1318 /* U+002D HYPHEN-MINUS (-)
1319 Switch to the comment end state */
1320 $state = 'comment end';
1321
1322 } elseif($char === false) {
1323 /* EOF
1324 Parse error. Emit the comment token. Reconsume the EOF character
1325 in the data state. */
1326 $this->emitToken(array(
1327 'type' => self::PARSEERROR,
1328 'data' => 'eof-in-comment-end-dash'
1329 ));
1330 $this->emitToken($this->token);
1331 $this->stream->unget();
1332 $state = 'data';
1333
1334 } else {
1335 /* Anything else
1336 Append a U+002D HYPHEN-MINUS (-) character and the input
1337 character to the comment token's data. Switch to the comment state. */
1338 $this->token['data'] .= '-'.$char;
1339 $state = 'comment';
1340 }
1341 break;
1342
1343 case 'comment end':
1344 /* Consume the next input character: */
1345 $char = $this->stream->char();
1346
1347 if($char === '>') {
1348 /* U+003E GREATER-THAN SIGN (>)
1349 Emit the comment token. Switch to the data state. */
1350 $this->emitToken($this->token);
1351 $state = 'data';
1352
1353 } elseif($char === '-') {
1354 /* U+002D HYPHEN-MINUS (-)
1355 Parse error. Append a U+002D HYPHEN-MINUS (-) character
1356 to the comment token's data. Stay in the comment end
1357 state. */
1358 $this->emitToken(array(
1359 'type' => self::PARSEERROR,
1360 'data' => 'unexpected-dash-after-double-dash-in-comment'
1361 ));
1362 $this->token['data'] .= '-';
1363
1364 } elseif($char === "\t" || $char === "\n" || $char === "\x0a" || $char === ' ') {
1365 $this->emitToken(array(
1366 'type' => self::PARSEERROR,
1367 'data' => 'unexpected-space-after-double-dash-in-comment'
1368 ));
1369 $this->token['data'] .= '--' . $char;
1370 $state = 'comment end space';
1371
1372 } elseif($char === '!') {
1373 $this->emitToken(array(
1374 'type' => self::PARSEERROR,
1375 'data' => 'unexpected-bang-after-double-dash-in-comment'
1376 ));
1377 $state = 'comment end bang';
1378
1379 } elseif($char === false) {
1380 /* EOF
1381 Parse error. Emit the comment token. Reconsume the
1382 EOF character in the data state. */
1383 $this->emitToken(array(
1384 'type' => self::PARSEERROR,
1385 'data' => 'eof-in-comment-double-dash'
1386 ));
1387 $this->emitToken($this->token);
1388 $this->stream->unget();
1389 $state = 'data';
1390
1391 } else {
1392 /* Anything else
1393 Parse error. Append two U+002D HYPHEN-MINUS (-)
1394 characters and the input character to the comment token's
1395 data. Switch to the comment state. */
1396 $this->emitToken(array(
1397 'type' => self::PARSEERROR,
1398 'data' => 'unexpected-char-in-comment'
1399 ));
1400 $this->token['data'] .= '--'.$char;
1401 $state = 'comment';
1402 }
1403 break;
1404
1405 case 'comment end bang':
1406 $char = $this->stream->char();
1407 if ($char === '>') {
1408 $this->emitToken($this->token);
1409 $state = 'data';
1410 } elseif ($char === "-") {
1411 $this->token['data'] .= '--!';
1412 $state = 'comment end dash';
1413 } elseif ($char === false) {
1414 $this->emitToken(array(
1415 'type' => self::PARSEERROR,
1416 'data' => 'eof-in-comment-end-bang'
1417 ));
1418 $this->emitToken($this->token);
1419 $this->stream->unget();
1420 $state = 'data';
1421 } else {
1422 $this->token['data'] .= '--!' . $char;
1423 $state = 'comment';
1424 }
1425 break;
1426
1427 case 'comment end space':
1428 $char = $this->stream->char();
1429 if ($char === '>') {
1430 $this->emitToken($this->token);
1431 $state = 'data';
1432 } elseif ($char === '-') {
1433 $state = 'comment end dash';
1434 } elseif ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1435 $this->token['data'] .= $char;
1436 } elseif ($char === false) {
1437 $this->emitToken(array(
1438 'type' => self::PARSEERROR,
1439 'data' => 'unexpected-eof-in-comment-end-space',
1440 ));
1441 $this->emitToken($this->token);
1442 $this->stream->unget();
1443 $state = 'data';
1444 } else {
1445 $this->token['data'] .= $char;
1446 $state = 'comment';
1447 }
1448 break;
1449
1450 case 'DOCTYPE':
1451 /* Consume the next input character: */
1452 $char = $this->stream->char();
1453
1454 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1455 /* U+0009 CHARACTER TABULATION
1456 U+000A LINE FEED (LF)
1457 U+000C FORM FEED (FF)
1458 U+0020 SPACE
1459 Switch to the before DOCTYPE name state. */
1460 $state = 'before DOCTYPE name';
1461
1462 } elseif($char === false) {
1463 /* EOF
1464 Parse error. Create a new DOCTYPE token. Set its
1465 force-quirks flag to on. Emit the token. Reconsume the
1466 EOF character in the data state. */
1467 $this->emitToken(array(
1468 'type' => self::PARSEERROR,
1469 'data' => 'need-space-after-doctype-but-got-eof'
1470 ));
1471 $this->emitToken(array(
1472 'name' => '',
1473 'type' => self::DOCTYPE,
1474 'force-quirks' => true,
1475 'error' => true
1476 ));
1477 $this->stream->unget();
1478 $state = 'data';
1479
1480 } else {
1481 /* Anything else
1482 Parse error. Reconsume the current character in the
1483 before DOCTYPE name state. */
1484 $this->emitToken(array(
1485 'type' => self::PARSEERROR,
1486 'data' => 'need-space-after-doctype'
1487 ));
1488 $this->stream->unget();
1489 $state = 'before DOCTYPE name';
1490 }
1491 break;
1492
1493 case 'before DOCTYPE name':
1494 /* Consume the next input character: */
1495 $char = $this->stream->char();
1496
1497 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1498 /* U+0009 CHARACTER TABULATION
1499 U+000A LINE FEED (LF)
1500 U+000C FORM FEED (FF)
1501 U+0020 SPACE
1502 Stay in the before DOCTYPE name state. */
1503
1504 } elseif($char === '>') {
1505 /* U+003E GREATER-THAN SIGN (>)
1506 Parse error. Create a new DOCTYPE token. Set its
1507 force-quirks flag to on. Emit the token. Switch to the
1508 data state. */
1509 $this->emitToken(array(
1510 'type' => self::PARSEERROR,
1511 'data' => 'expected-doctype-name-but-got-right-bracket'
1512 ));
1513 $this->emitToken(array(
1514 'name' => '',
1515 'type' => self::DOCTYPE,
1516 'force-quirks' => true,
1517 'error' => true
1518 ));
1519
1520 $state = 'data';
1521
1522 } elseif('A' <= $char && $char <= 'Z') {
1523 /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
1524 Create a new DOCTYPE token. Set the token's name to the
1525 lowercase version of the input character (add 0x0020 to
1526 the character's code point). Switch to the DOCTYPE name
1527 state. */
1528 $this->token = array(
1529 'name' => strtolower($char),
1530 'type' => self::DOCTYPE,
1531 'error' => true
1532 );
1533
1534 $state = 'DOCTYPE name';
1535
1536 } elseif($char === false) {
1537 /* EOF
1538 Parse error. Create a new DOCTYPE token. Set its
1539 force-quirks flag to on. Emit the token. Reconsume the
1540 EOF character in the data state. */
1541 $this->emitToken(array(
1542 'type' => self::PARSEERROR,
1543 'data' => 'expected-doctype-name-but-got-eof'
1544 ));
1545 $this->emitToken(array(
1546 'name' => '',
1547 'type' => self::DOCTYPE,
1548 'force-quirks' => true,
1549 'error' => true
1550 ));
1551
1552 $this->stream->unget();
1553 $state = 'data';
1554
1555 } else {
1556 /* Anything else
1557 Create a new DOCTYPE token. Set the token's name to the
1558 current input character. Switch to the DOCTYPE name state. */
1559 $this->token = array(
1560 'name' => $char,
1561 'type' => self::DOCTYPE,
1562 'error' => true
1563 );
1564
1565 $state = 'DOCTYPE name';
1566 }
1567 break;
1568
1569 case 'DOCTYPE name':
1570 /* Consume the next input character: */
1571 $char = $this->stream->char();
1572
1573 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1574 /* U+0009 CHARACTER TABULATION
1575 U+000A LINE FEED (LF)
1576 U+000C FORM FEED (FF)
1577 U+0020 SPACE
1578 Switch to the after DOCTYPE name state. */
1579 $state = 'after DOCTYPE name';
1580
1581 } elseif($char === '>') {
1582 /* U+003E GREATER-THAN SIGN (>)
1583 Emit the current DOCTYPE token. Switch to the data state. */
1584 $this->emitToken($this->token);
1585 $state = 'data';
1586
1587 } elseif('A' <= $char && $char <= 'Z') {
1588 /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
1589 Append the lowercase version of the input character
1590 (add 0x0020 to the character's code point) to the current
1591 DOCTYPE token's name. Stay in the DOCTYPE name state. */
1592 $this->token['name'] .= strtolower($char);
1593
1594 } elseif($char === false) {
1595 /* EOF
1596 Parse error. Set the DOCTYPE token's force-quirks flag
1597 to on. Emit that DOCTYPE token. Reconsume the EOF
1598 character in the data state. */
1599 $this->emitToken(array(
1600 'type' => self::PARSEERROR,
1601 'data' => 'eof-in-doctype-name'
1602 ));
1603 $this->token['force-quirks'] = true;
1604 $this->emitToken($this->token);
1605 $this->stream->unget();
1606 $state = 'data';
1607
1608 } else {
1609 /* Anything else
1610 Append the current input character to the current
1611 DOCTYPE token's name. Stay in the DOCTYPE name state. */
1612 $this->token['name'] .= $char;
1613 }
1614
1615 // XXX this is probably some sort of quirks mode designation,
1616 // check tree-builder to be sure. In general 'error' needs
1617 // to be specc'ified, this probably means removing it at the end
1618 $this->token['error'] = ($this->token['name'] === 'HTML')
1619 ? false
1620 : true;
1621 break;
1622
1623 case 'after DOCTYPE name':
1624 /* Consume the next input character: */
1625 $char = $this->stream->char();
1626
1627 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1628 /* U+0009 CHARACTER TABULATION
1629 U+000A LINE FEED (LF)
1630 U+000C FORM FEED (FF)
1631 U+0020 SPACE
1632 Stay in the after DOCTYPE name state. */
1633
1634 } elseif($char === '>') {
1635 /* U+003E GREATER-THAN SIGN (>)
1636 Emit the current DOCTYPE token. Switch to the data state. */
1637 $this->emitToken($this->token);
1638 $state = 'data';
1639
1640 } elseif($char === false) {
1641 /* EOF
1642 Parse error. Set the DOCTYPE token's force-quirks flag
1643 to on. Emit that DOCTYPE token. Reconsume the EOF
1644 character in the data state. */
1645 $this->emitToken(array(
1646 'type' => self::PARSEERROR,
1647 'data' => 'eof-in-doctype'
1648 ));
1649 $this->token['force-quirks'] = true;
1650 $this->emitToken($this->token);
1651 $this->stream->unget();
1652 $state = 'data';
1653
1654 } else {
1655 /* Anything else */
1656
1657 $nextSix = strtoupper($char . $this->stream->charsWhile(self::ALPHA, 5));
1658 if ($nextSix === 'PUBLIC') {
1659 /* If the next six characters are an ASCII
1660 case-insensitive match for the word "PUBLIC", then
1661 consume those characters and switch to the before
1662 DOCTYPE public identifier state. */
1663 $state = 'before DOCTYPE public identifier';
1664
1665 } elseif ($nextSix === 'SYSTEM') {
1666 /* Otherwise, if the next six characters are an ASCII
1667 case-insensitive match for the word "SYSTEM", then
1668 consume those characters and switch to the before
1669 DOCTYPE system identifier state. */
1670 $state = 'before DOCTYPE system identifier';
1671
1672 } else {
1673 /* Otherwise, this is the parse error. Set the DOCTYPE
1674 token's force-quirks flag to on. Switch to the bogus
1675 DOCTYPE state. */
1676 $this->emitToken(array(
1677 'type' => self::PARSEERROR,
1678 'data' => 'expected-space-or-right-bracket-in-doctype'
1679 ));
1680 $this->token['force-quirks'] = true;
1681 $this->token['error'] = true;
1682 $state = 'bogus DOCTYPE';
1683 }
1684 }
1685 break;
1686
1687 case 'before DOCTYPE public identifier':
1688 /* Consume the next input character: */
1689 $char = $this->stream->char();
1690
1691 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1692 /* U+0009 CHARACTER TABULATION
1693 U+000A LINE FEED (LF)
1694 U+000C FORM FEED (FF)
1695 U+0020 SPACE
1696 Stay in the before DOCTYPE public identifier state. */
1697 } elseif ($char === '"') {
1698 /* U+0022 QUOTATION MARK (")
1699 Set the DOCTYPE token's public identifier to the empty
1700 string (not missing), then switch to the DOCTYPE public
1701 identifier (double-quoted) state. */
1702 $this->token['public'] = '';
1703 $state = 'DOCTYPE public identifier (double-quoted)';
1704 } elseif ($char === "'") {
1705 /* U+0027 APOSTROPHE (')
1706 Set the DOCTYPE token's public identifier to the empty
1707 string (not missing), then switch to the DOCTYPE public
1708 identifier (single-quoted) state. */
1709 $this->token['public'] = '';
1710 $state = 'DOCTYPE public identifier (single-quoted)';
1711 } elseif ($char === '>') {
1712 /* Parse error. Set the DOCTYPE token's force-quirks flag
1713 to on. Emit that DOCTYPE token. Switch to the data state. */
1714 $this->emitToken(array(
1715 'type' => self::PARSEERROR,
1716 'data' => 'unexpected-end-of-doctype'
1717 ));
1718 $this->token['force-quirks'] = true;
1719 $this->emitToken($this->token);
1720 $state = 'data';
1721 } elseif ($char === false) {
1722 /* Parse error. Set the DOCTYPE token's force-quirks
1723 flag to on. Emit that DOCTYPE token. Reconsume the EOF
1724 character in the data state. */
1725 $this->emitToken(array(
1726 'type' => self::PARSEERROR,
1727 'data' => 'eof-in-doctype'
1728 ));
1729 $this->token['force-quirks'] = true;
1730 $this->emitToken($this->token);
1731 $this->stream->unget();
1732 $state = 'data';
1733 } else {
1734 /* Parse error. Set the DOCTYPE token's force-quirks flag
1735 to on. Switch to the bogus DOCTYPE state. */
1736 $this->emitToken(array(
1737 'type' => self::PARSEERROR,
1738 'data' => 'unexpected-char-in-doctype'
1739 ));
1740 $this->token['force-quirks'] = true;
1741 $state = 'bogus DOCTYPE';
1742 }
1743 break;
1744
1745 case 'DOCTYPE public identifier (double-quoted)':
1746 /* Consume the next input character: */
1747 $char = $this->stream->char();
1748
1749 if ($char === '"') {
1750 /* U+0022 QUOTATION MARK (")
1751 Switch to the after DOCTYPE public identifier state. */
1752 $state = 'after DOCTYPE public identifier';
1753 } elseif ($char === '>') {
1754 /* U+003E GREATER-THAN SIGN (>)
1755 Parse error. Set the DOCTYPE token's force-quirks flag
1756 to on. Emit that DOCTYPE token. Switch to the data state. */
1757 $this->emitToken(array(
1758 'type' => self::PARSEERROR,
1759 'data' => 'unexpected-end-of-doctype'
1760 ));
1761 $this->token['force-quirks'] = true;
1762 $this->emitToken($this->token);
1763 $state = 'data';
1764 } elseif ($char === false) {
1765 /* EOF
1766 Parse error. Set the DOCTYPE token's force-quirks flag
1767 to on. Emit that DOCTYPE token. Reconsume the EOF
1768 character in the data state. */
1769 $this->emitToken(array(
1770 'type' => self::PARSEERROR,
1771 'data' => 'eof-in-doctype'
1772 ));
1773 $this->token['force-quirks'] = true;
1774 $this->emitToken($this->token);
1775 $this->stream->unget();
1776 $state = 'data';
1777 } else {
1778 /* Anything else
1779 Append the current input character to the current
1780 DOCTYPE token's public identifier. Stay in the DOCTYPE
1781 public identifier (double-quoted) state. */
1782 $this->token['public'] .= $char;
1783 }
1784 break;
1785
1786 case 'DOCTYPE public identifier (single-quoted)':
1787 /* Consume the next input character: */
1788 $char = $this->stream->char();
1789
1790 if ($char === "'") {
1791 /* U+0027 APOSTROPHE (')
1792 Switch to the after DOCTYPE public identifier state. */
1793 $state = 'after DOCTYPE public identifier';
1794 } elseif ($char === '>') {
1795 /* U+003E GREATER-THAN SIGN (>)
1796 Parse error. Set the DOCTYPE token's force-quirks flag
1797 to on. Emit that DOCTYPE token. Switch to the data state. */
1798 $this->emitToken(array(
1799 'type' => self::PARSEERROR,
1800 'data' => 'unexpected-end-of-doctype'
1801 ));
1802 $this->token['force-quirks'] = true;
1803 $this->emitToken($this->token);
1804 $state = 'data';
1805 } elseif ($char === false) {
1806 /* EOF
1807 Parse error. Set the DOCTYPE token's force-quirks flag
1808 to on. Emit that DOCTYPE token. Reconsume the EOF
1809 character in the data state. */
1810 $this->emitToken(array(
1811 'type' => self::PARSEERROR,
1812 'data' => 'eof-in-doctype'
1813 ));
1814 $this->token['force-quirks'] = true;
1815 $this->emitToken($this->token);
1816 $this->stream->unget();
1817 $state = 'data';
1818 } else {
1819 /* Anything else
1820 Append the current input character to the current
1821 DOCTYPE token's public identifier. Stay in the DOCTYPE
1822 public identifier (double-quoted) state. */
1823 $this->token['public'] .= $char;
1824 }
1825 break;
1826
1827 case 'after DOCTYPE public identifier':
1828 /* Consume the next input character: */
1829 $char = $this->stream->char();
1830
1831 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1832 /* U+0009 CHARACTER TABULATION
1833 U+000A LINE FEED (LF)
1834 U+000C FORM FEED (FF)
1835 U+0020 SPACE
1836 Stay in the after DOCTYPE public identifier state. */
1837 } elseif ($char === '"') {
1838 /* U+0022 QUOTATION MARK (")
1839 Set the DOCTYPE token's system identifier to the
1840 empty string (not missing), then switch to the DOCTYPE
1841 system identifier (double-quoted) state. */
1842 $this->token['system'] = '';
1843 $state = 'DOCTYPE system identifier (double-quoted)';
1844 } elseif ($char === "'") {
1845 /* U+0027 APOSTROPHE (')
1846 Set the DOCTYPE token's system identifier to the
1847 empty string (not missing), then switch to the DOCTYPE
1848 system identifier (single-quoted) state. */
1849 $this->token['system'] = '';
1850 $state = 'DOCTYPE system identifier (single-quoted)';
1851 } elseif ($char === '>') {
1852 /* U+003E GREATER-THAN SIGN (>)
1853 Emit the current DOCTYPE token. Switch to the data state. */
1854 $this->emitToken($this->token);
1855 $state = 'data';
1856 } elseif ($char === false) {
1857 /* Parse error. Set the DOCTYPE token's force-quirks
1858 flag to on. Emit that DOCTYPE token. Reconsume the EOF
1859 character in the data state. */
1860 $this->emitToken(array(
1861 'type' => self::PARSEERROR,
1862 'data' => 'eof-in-doctype'
1863 ));
1864 $this->token['force-quirks'] = true;
1865 $this->emitToken($this->token);
1866 $this->stream->unget();
1867 $state = 'data';
1868 } else {
1869 /* Anything else
1870 Parse error. Set the DOCTYPE token's force-quirks flag
1871 to on. Switch to the bogus DOCTYPE state. */
1872 $this->emitToken(array(
1873 'type' => self::PARSEERROR,
1874 'data' => 'unexpected-char-in-doctype'
1875 ));
1876 $this->token['force-quirks'] = true;
1877 $state = 'bogus DOCTYPE';
1878 }
1879 break;
1880
1881 case 'before DOCTYPE system identifier':
1882 /* Consume the next input character: */
1883 $char = $this->stream->char();
1884
1885 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
1886 /* U+0009 CHARACTER TABULATION
1887 U+000A LINE FEED (LF)
1888 U+000C FORM FEED (FF)
1889 U+0020 SPACE
1890 Stay in the before DOCTYPE system identifier state. */
1891 } elseif ($char === '"') {
1892 /* U+0022 QUOTATION MARK (")
1893 Set the DOCTYPE token's system identifier to the empty
1894 string (not missing), then switch to the DOCTYPE system
1895 identifier (double-quoted) state. */
1896 $this->token['system'] = '';
1897 $state = 'DOCTYPE system identifier (double-quoted)';
1898 } elseif ($char === "'") {
1899 /* U+0027 APOSTROPHE (')
1900 Set the DOCTYPE token's system identifier to the empty
1901 string (not missing), then switch to the DOCTYPE system
1902 identifier (single-quoted) state. */
1903 $this->token['system'] = '';
1904 $state = 'DOCTYPE system identifier (single-quoted)';
1905 } elseif ($char === '>') {
1906 /* Parse error. Set the DOCTYPE token's force-quirks flag
1907 to on. Emit that DOCTYPE token. Switch to the data state. */
1908 $this->emitToken(array(
1909 'type' => self::PARSEERROR,
1910 'data' => 'unexpected-char-in-doctype'
1911 ));
1912 $this->token['force-quirks'] = true;
1913 $this->emitToken($this->token);
1914 $state = 'data';
1915 } elseif ($char === false) {
1916 /* Parse error. Set the DOCTYPE token's force-quirks
1917 flag to on. Emit that DOCTYPE token. Reconsume the EOF
1918 character in the data state. */
1919 $this->emitToken(array(
1920 'type' => self::PARSEERROR,
1921 'data' => 'eof-in-doctype'
1922 ));
1923 $this->token['force-quirks'] = true;
1924 $this->emitToken($this->token);
1925 $this->stream->unget();
1926 $state = 'data';
1927 } else {
1928 /* Parse error. Set the DOCTYPE token's force-quirks flag
1929 to on. Switch to the bogus DOCTYPE state. */
1930 $this->emitToken(array(
1931 'type' => self::PARSEERROR,
1932 'data' => 'unexpected-char-in-doctype'
1933 ));
1934 $this->token['force-quirks'] = true;
1935 $state = 'bogus DOCTYPE';
1936 }
1937 break;
1938
1939 case 'DOCTYPE system identifier (double-quoted)':
1940 /* Consume the next input character: */
1941 $char = $this->stream->char();
1942
1943 if ($char === '"') {
1944 /* U+0022 QUOTATION MARK (")
1945 Switch to the after DOCTYPE system identifier state. */
1946 $state = 'after DOCTYPE system identifier';
1947 } elseif ($char === '>') {
1948 /* U+003E GREATER-THAN SIGN (>)
1949 Parse error. Set the DOCTYPE token's force-quirks flag
1950 to on. Emit that DOCTYPE token. Switch to the data state. */
1951 $this->emitToken(array(
1952 'type' => self::PARSEERROR,
1953 'data' => 'unexpected-end-of-doctype'
1954 ));
1955 $this->token['force-quirks'] = true;
1956 $this->emitToken($this->token);
1957 $state = 'data';
1958 } elseif ($char === false) {
1959 /* EOF
1960 Parse error. Set the DOCTYPE token's force-quirks flag
1961 to on. Emit that DOCTYPE token. Reconsume the EOF
1962 character in the data state. */
1963 $this->emitToken(array(
1964 'type' => self::PARSEERROR,
1965 'data' => 'eof-in-doctype'
1966 ));
1967 $this->token['force-quirks'] = true;
1968 $this->emitToken($this->token);
1969 $this->stream->unget();
1970 $state = 'data';
1971 } else {
1972 /* Anything else
1973 Append the current input character to the current
1974 DOCTYPE token's system identifier. Stay in the DOCTYPE
1975 system identifier (double-quoted) state. */
1976 $this->token['system'] .= $char;
1977 }
1978 break;
1979
1980 case 'DOCTYPE system identifier (single-quoted)':
1981 /* Consume the next input character: */
1982 $char = $this->stream->char();
1983
1984 if ($char === "'") {
1985 /* U+0027 APOSTROPHE (')
1986 Switch to the after DOCTYPE system identifier state. */
1987 $state = 'after DOCTYPE system identifier';
1988 } elseif ($char === '>') {
1989 /* U+003E GREATER-THAN SIGN (>)
1990 Parse error. Set the DOCTYPE token's force-quirks flag
1991 to on. Emit that DOCTYPE token. Switch to the data state. */
1992 $this->emitToken(array(
1993 'type' => self::PARSEERROR,
1994 'data' => 'unexpected-end-of-doctype'
1995 ));
1996 $this->token['force-quirks'] = true;
1997 $this->emitToken($this->token);
1998 $state = 'data';
1999 } elseif ($char === false) {
2000 /* EOF
2001 Parse error. Set the DOCTYPE token's force-quirks flag
2002 to on. Emit that DOCTYPE token. Reconsume the EOF
2003 character in the data state. */
2004 $this->emitToken(array(
2005 'type' => self::PARSEERROR,
2006 'data' => 'eof-in-doctype'
2007 ));
2008 $this->token['force-quirks'] = true;
2009 $this->emitToken($this->token);
2010 $this->stream->unget();
2011 $state = 'data';
2012 } else {
2013 /* Anything else
2014 Append the current input character to the current
2015 DOCTYPE token's system identifier. Stay in the DOCTYPE
2016 system identifier (double-quoted) state. */
2017 $this->token['system'] .= $char;
2018 }
2019 break;
2020
2021 case 'after DOCTYPE system identifier':
2022 /* Consume the next input character: */
2023 $char = $this->stream->char();
2024
2025 if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
2026 /* U+0009 CHARACTER TABULATION
2027 U+000A LINE FEED (LF)
2028 U+000C FORM FEED (FF)
2029 U+0020 SPACE
2030 Stay in the after DOCTYPE system identifier state. */
2031 } elseif ($char === '>') {
2032 /* U+003E GREATER-THAN SIGN (>)
2033 Emit the current DOCTYPE token. Switch to the data state. */
2034 $this->emitToken($this->token);
2035 $state = 'data';
2036 } elseif ($char === false) {
2037 /* Parse error. Set the DOCTYPE token's force-quirks
2038 flag to on. Emit that DOCTYPE token. Reconsume the EOF
2039 character in the data state. */
2040 $this->emitToken(array(
2041 'type' => self::PARSEERROR,
2042 'data' => 'eof-in-doctype'
2043 ));
2044 $this->token['force-quirks'] = true;
2045 $this->emitToken($this->token);
2046 $this->stream->unget();
2047 $state = 'data';
2048 } else {
2049 /* Anything else
2050 Parse error. Switch to the bogus DOCTYPE state.
2051 (This does not set the DOCTYPE token's force-quirks
2052 flag to on.) */
2053 $this->emitToken(array(
2054 'type' => self::PARSEERROR,
2055 'data' => 'unexpected-char-in-doctype'
2056 ));
2057 $state = 'bogus DOCTYPE';
2058 }
2059 break;
2060
2061 case 'bogus DOCTYPE':
2062 /* Consume the next input character: */
2063 $char = $this->stream->char();
2064
2065 if ($char === '>') {
2066 /* U+003E GREATER-THAN SIGN (>)
2067 Emit the DOCTYPE token. Switch to the data state. */
2068 $this->emitToken($this->token);
2069 $state = 'data';
2070
2071 } elseif($char === false) {
2072 /* EOF
2073 Emit the DOCTYPE token. Reconsume the EOF character in
2074 the data state. */
2075 $this->emitToken($this->token);
2076 $this->stream->unget();
2077 $state = 'data';
2078
2079 } else {
2080 /* Anything else
2081 Stay in the bogus DOCTYPE state. */
2082 }
2083 break;
2084
2085 // case 'cdataSection':
2086
2087 }
2088 }
2089 }
2090
2091 /**
2092 * Returns a serialized representation of the tree.
2093 */
2094 public function save() {
2095 return $this->tree->save();
2096 }
2097
2098 /**
2099 * Returns the input stream.
2100 */
2101 public function stream() {
2102 return $this->stream;
2103 }
2104
2105 private function consumeCharacterReference($allowed = false, $inattr = false) {
2106 // This goes quite far against spec, and is far closer to the Python
2107 // impl., mainly because we don't do the large unconsuming the spec
2108 // requires.
2109
2110 // All consumed characters.
2111 $chars = $this->stream->char();
2112
2113 /* This section defines how to consume a character
2114 reference. This definition is used when parsing character
2115 references in text and in attributes.
2116
2117 The behavior depends on the identity of the next character
2118 (the one immediately after the U+0026 AMPERSAND character): */
2119
2120 if (
2121 $chars[0] === "\x09" ||
2122 $chars[0] === "\x0A" ||
2123 $chars[0] === "\x0C" ||
2124 $chars[0] === "\x20" ||
2125 $chars[0] === '<' ||
2126 $chars[0] === '&' ||
2127 $chars === false ||
2128 $chars[0] === $allowed
2129 ) {
2130 /* U+0009 CHARACTER TABULATION
2131 U+000A LINE FEED (LF)
2132 U+000C FORM FEED (FF)
2133 U+0020 SPACE
2134 U+003C LESS-THAN SIGN
2135 U+0026 AMPERSAND
2136 EOF
2137 The additional allowed character, if there is one
2138 Not a character reference. No characters are consumed,
2139 and nothing is returned. (This is not an error, either.) */
2140 // We already consumed, so unconsume.
2141 $this->stream->unget();
2142 return '&';
2143 } elseif ($chars[0] === '#') {
2144 /* Consume the U+0023 NUMBER SIGN. */
2145 // Um, yeah, we already did that.
2146 /* The behavior further depends on the character after
2147 the U+0023 NUMBER SIGN: */
2148 $chars .= $this->stream->char();
2149 if (isset($chars[1]) && ($chars[1] === 'x' || $chars[1] === 'X')) {
2150 /* U+0078 LATIN SMALL LETTER X
2151 U+0058 LATIN CAPITAL LETTER X */
2152 /* Consume the X. */
2153 // Um, yeah, we already did that.
2154 /* Follow the steps below, but using the range of
2155 characters U+0030 DIGIT ZERO through to U+0039 DIGIT
2156 NINE, U+0061 LATIN SMALL LETTER A through to U+0066
2157 LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER
2158 A, through to U+0046 LATIN CAPITAL LETTER F (in other
2159 words, 0123456789, ABCDEF, abcdef). */
2160 $char_class = self::HEX;
2161 /* When it comes to interpreting the
2162 number, interpret it as a hexadecimal number. */
2163 $hex = true;
2164 } else {
2165 /* Anything else */
2166 // Unconsume because we shouldn't have consumed this.
2167 $chars = $chars[0];
2168 $this->stream->unget();
2169 /* Follow the steps below, but using the range of
2170 characters U+0030 DIGIT ZERO through to U+0039 DIGIT
2171 NINE (i.e. just 0123456789). */
2172 $char_class = self::DIGIT;
2173 /* When it comes to interpreting the number,
2174 interpret it as a decimal number. */
2175 $hex = false;
2176 }
2177
2178 /* Consume as many characters as match the range of characters given above. */
2179 $consumed = $this->stream->charsWhile($char_class);
2180 if ($consumed === '' || $consumed === false) {
2181 /* If no characters match the range, then don't consume
2182 any characters (and unconsume the U+0023 NUMBER SIGN
2183 character and, if appropriate, the X character). This
2184 is a parse error; nothing is returned. */
2185 $this->emitToken(array(
2186 'type' => self::PARSEERROR,
2187 'data' => 'expected-numeric-entity'
2188 ));
2189 return '&' . $chars;
2190 } else {
2191 /* Otherwise, if the next character is a U+003B SEMICOLON,
2192 consume that too. If it isn't, there is a parse error. */
2193 if ($this->stream->char() !== ';') {
2194 $this->stream->unget();
2195 $this->emitToken(array(
2196 'type' => self::PARSEERROR,
2197 'data' => 'numeric-entity-without-semicolon'
2198 ));
2199 }
2200
2201 /* If one or more characters match the range, then take
2202 them all and interpret the string of characters as a number
2203 (either hexadecimal or decimal as appropriate). */
2204 $codepoint = $hex ? hexdec($consumed) : (int) $consumed;
2205
2206 /* If that number is one of the numbers in the first column
2207 of the following table, then this is a parse error. Find the
2208 row with that number in the first column, and return a
2209 character token for the Unicode character given in the
2210 second column of that row. */
2211 $new_codepoint = HTML5_Data::getRealCodepoint($codepoint);
2212 if ($new_codepoint) {
2213 $this->emitToken(array(
2214 'type' => self::PARSEERROR,
2215 'data' => 'illegal-windows-1252-entity'
2216 ));
2217 return HTML5_Data::utf8chr($new_codepoint);
2218 } else {
2219 /* Otherwise, if the number is greater than 0x10FFFF, then
2220 * this is a parse error. Return a U+FFFD REPLACEMENT
2221 * CHARACTER. */
2222 if ($codepoint > 0x10FFFF) {
2223 $this->emitToken(array(
2224 'type' => self::PARSEERROR,
2225 'data' => 'overlong-character-entity' // XXX probably not correct
2226 ));
2227 return "\xEF\xBF\xBD";
2228 }
2229 /* Otherwise, return a character token for the Unicode
2230 * character whose code point is that number. If the
2231 * number is in the range 0x0001 to 0x0008, 0x000E to
2232 * 0x001F, 0x007F to 0x009F, 0xD800 to 0xDFFF, 0xFDD0 to
2233 * 0xFDEF, or is one of 0x000B, 0xFFFE, 0xFFFF, 0x1FFFE,
2234 * 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE,
2235 * 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,
2236 * 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE,
2237 * 0xAFFFF, 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
2238 * 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE,
2239 * or 0x10FFFF, then this is a parse error. */
2240 // && has higher precedence than ||
2241 if (
2242 $codepoint >= 0x0000 && $codepoint <= 0x0008 ||
2243 $codepoint === 0x000B ||
2244 $codepoint >= 0x000E && $codepoint <= 0x001F ||
2245 $codepoint >= 0x007F && $codepoint <= 0x009F ||
2246 $codepoint >= 0xD800 && $codepoint <= 0xDFFF ||
2247 $codepoint >= 0xFDD0 && $codepoint <= 0xFDEF ||
2248 ($codepoint & 0xFFFE) === 0xFFFE ||
2249 $codepoint == 0x10FFFF || $codepoint == 0x10FFFE
2250 ) {
2251 $this->emitToken(array(
2252 'type' => self::PARSEERROR,
2253 'data' => 'illegal-codepoint-for-numeric-entity'
2254 ));
2255 }
2256 return HTML5_Data::utf8chr($codepoint);
2257 }
2258 }
2259
2260 } else {
2261 /* Anything else */
2262
2263 /* Consume the maximum number of characters possible,
2264 with the consumed characters matching one of the
2265 identifiers in the first column of the named character
2266 references table (in a case-sensitive manner). */
2267 // What we actually do here is consume as much as we can while it
2268 // matches the start of one of the identifiers in the first column.
2269
2270 $refs = HTML5_Data::getNamedCharacterReferences();
2271
2272 // Get the longest string which is the start of an identifier
2273 // ($chars) as well as the longest identifier which matches ($id)
2274 // and its codepoint ($codepoint).
2275 $codepoint = false;
2276 $char = $chars;
2277 while ($char !== false && isset($refs[$char])) {
2278 $refs = $refs[$char];
2279 if (isset($refs['codepoint'])) {
2280 $id = $chars;
2281 $codepoint = $refs['codepoint'];
2282 }
2283 $chars .= $char = $this->stream->char();
2284 }
2285
2286 // Unconsume the one character we just took which caused the while
2287 // statement to fail. This could be anything and could cause state
2288 // changes (as if it matches the while loop it must be
2289 // alphanumeric so we can just concat it to whatever we get later).
2290 $this->stream->unget();
2291 if ($char !== false) {
2292 $chars = substr($chars, 0, -1);
2293 }
2294
2295 /* If no match can be made, then this is a parse error.
2296 No characters are consumed, and nothing is returned. */
2297 if (!$codepoint) {
2298 $this->emitToken(array(
2299 'type' => self::PARSEERROR,
2300 'data' => 'expected-named-entity'
2301 ));
2302 return '&' . $chars;
2303 }
2304
2305 /* If the last character matched is not a U+003B SEMICOLON
2306 (;), there is a parse error. */
2307 $semicolon = true;
2308 if (substr($id, -1) !== ';') {
2309 $this->emitToken(array(
2310 'type' => self::PARSEERROR,
2311 'data' => 'named-entity-without-semicolon'
2312 ));
2313 $semicolon = false;
2314 }
2315
2316 /* If the character reference is being consumed as part of
2317 an attribute, and the last character matched is not a
2318 U+003B SEMICOLON (;), and the next character is in the
2319 range U+0030 DIGIT ZERO to U+0039 DIGIT NINE, U+0041
2320 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z,
2321 or U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z,
2322 then, for historical reasons, all the characters that were
2323 matched after the U+0026 AMPERSAND (&) must be unconsumed,
2324 and nothing is returned. */
2325 if ($inattr && !$semicolon) {
2326 // The next character is either the next character in $chars or in the stream.
2327 if (strlen($chars) > strlen($id)) {
2328 $next = substr($chars, strlen($id), 1);
2329 } else {
2330 $next = $this->stream->char();
2331 $this->stream->unget();
2332 }
2333 if (
2334 '0' <= $next && $next <= '9' ||
2335 'A' <= $next && $next <= 'Z' ||
2336 'a' <= $next && $next <= 'z'
2337 ) {
2338 return '&' . $chars;
2339 }
2340 }
2341
2342 /* Otherwise, return a character token for the character
2343 corresponding to the character reference name (as given
2344 by the second column of the named character references table). */
2345 return HTML5_Data::utf8chr($codepoint) . substr($chars, strlen($id));
2346 }
2347 }
2348
2349 private function characterReferenceInAttributeValue($allowed = false) {
2350 /* Attempt to consume a character reference. */
2351 $entity = $this->consumeCharacterReference($allowed, true);
2352
2353 /* If nothing is returned, append a U+0026 AMPERSAND
2354 character to the current attribute's value.
2355
2356 Otherwise, append the returned character token to the
2357 current attribute's value. */
2358 $char = (!$entity)
2359 ? '&'
2360 : $entity;
2361
2362 $last = count($this->token['attr']) - 1;
2363 $this->token['attr'][$last]['value'] .= $char;
2364
2365 /* Finally, switch back to the attribute value state that you
2366 were in when were switched into this state. */
2367 }
2368
2369 /**
2370 * Emits a token, passing it on to the tree builder.
2371 */
2372 protected function emitToken($token, $checkStream = true, $dry = false) {
2373 if ($checkStream) {
2374 // Emit errors from input stream.
2375 while ($this->stream->errors) {
2376 $this->emitToken(array_shift($this->stream->errors), false);
2377 }
2378 }
2379 if($token['type'] === self::ENDTAG && !empty($token['attr'])) {
2380 for ($i = 0; $i < count($token['attr']); $i++) {
2381 $this->emitToken(array(
2382 'type' => self::PARSEERROR,
2383 'data' => 'attributes-in-end-tag'
2384 ));
2385 }
2386 }
2387 if($token['type'] === self::ENDTAG && !empty($token['self-closing'])) {
2388 $this->emitToken(array(
2389 'type' => self::PARSEERROR,
2390 'data' => 'self-closing-flag-on-end-tag',
2391 ));
2392 }
2393 if($token['type'] === self::STARTTAG) {
2394 // This could be changed to actually pass the tree-builder a hash
2395 $hash = array();
2396 foreach ($token['attr'] as $keypair) {
2397 if (isset($hash[$keypair['name']])) {
2398 $this->emitToken(array(
2399 'type' => self::PARSEERROR,
2400 'data' => 'duplicate-attribute',
2401 ));
2402 } else {
2403 $hash[$keypair['name']] = $keypair['value'];
2404 }
2405 }
2406 }
2407
2408 if(!$dry) {
2409 // the current structure of attributes is not a terribly good one
2410 $this->tree->emitToken($token);
2411 }
2412
2413 if(!$dry && is_int($this->tree->content_model)) {
2414 $this->content_model = $this->tree->content_model;
2415 $this->tree->content_model = null;
2416
2417 } elseif($token['type'] === self::ENDTAG) {
2418 $this->content_model = self::PCDATA;
2419 }
2420 }
2421}
2422
diff --git a/inc/3rdparty/libraries/html5/TreeBuilder.php b/inc/3rdparty/libraries/html5/TreeBuilder.php
new file mode 100644
index 00000000..2f5244f9
--- /dev/null
+++ b/inc/3rdparty/libraries/html5/TreeBuilder.php
@@ -0,0 +1,3840 @@
1<?php
2
3/*
4
5Copyright 2007 Jeroen van der Meer <http://jero.net/>
6Copyright 2009 Edward Z. Yang <edwardzyang@thewritingpot.com>
7
8Permission is hereby granted, free of charge, to any person obtaining a
9copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sublicense, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice shall be included
17in all copies or substantial portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27*/
28
29// Tags for FIX ME!!!: (in order of priority)
30// XXX - should be fixed NAO!
31// XERROR - with regards to parse errors
32// XSCRIPT - with regards to scripting mode
33// XENCODING - with regards to encoding (for reparsing tests)
34// XDOM - DOM specific code (tagName is explicitly not marked).
35// this is not (yet) in helper functions.
36
37class HTML5_TreeBuilder {
38 public $stack = array();
39 public $content_model;
40
41 private $mode;
42 private $original_mode;
43 private $secondary_mode;
44 private $dom;
45 // Whether or not normal insertion of nodes should actually foster
46 // parent (used in one case in spec)
47 private $foster_parent = false;
48 private $a_formatting = array();
49
50 private $head_pointer = null;
51 private $form_pointer = null;
52
53 private $flag_frameset_ok = true;
54 private $flag_force_quirks = false;
55 private $ignored = false;
56 private $quirks_mode = null;
57 // this gets to 2 when we want to ignore the next lf character, and
58 // is decrement at the beginning of each processed token (this way,
59 // code can check for (bool)$ignore_lf_token, but it phases out
60 // appropriately)
61 private $ignore_lf_token = 0;
62 private $fragment = false;
63 private $root;
64
65 private $scoping = array('applet','button','caption','html','marquee','object','table','td','th', 'svg:foreignObject');
66 private $formatting = array('a','b','big','code','em','font','i','nobr','s','small','strike','strong','tt','u');
67 // dl and ds are speculative
68 private $special = array('address','area','article','aside','base','basefont','bgsound',
69 'blockquote','body','br','center','col','colgroup','command','dc','dd','details','dir','div','dl','ds',
70 'dt','embed','fieldset','figure','footer','form','frame','frameset','h1','h2','h3','h4','h5',
71 'h6','head','header','hgroup','hr','iframe','img','input','isindex','li','link',
72 'listing','menu','meta','nav','noembed','noframes','noscript','ol',
73 'p','param','plaintext','pre','script','select','spacer','style',
74 'tbody','textarea','tfoot','thead','title','tr','ul','wbr');
75
76 private $pendingTableCharacters;
77 private $pendingTableCharactersDirty;
78
79 // Tree construction modes
80 const INITIAL = 0;
81 const BEFORE_HTML = 1;
82 const BEFORE_HEAD = 2;
83 const IN_HEAD = 3;
84 const IN_HEAD_NOSCRIPT = 4;
85 const AFTER_HEAD = 5;
86 const IN_BODY = 6;
87 const IN_CDATA_RCDATA = 7;
88 const IN_TABLE = 8;
89 const IN_TABLE_TEXT = 9;
90 const IN_CAPTION = 10;
91 const IN_COLUMN_GROUP = 11;
92 const IN_TABLE_BODY = 12;
93 const IN_ROW = 13;
94 const IN_CELL = 14;
95 const IN_SELECT = 15;
96 const IN_SELECT_IN_TABLE= 16;
97 const IN_FOREIGN_CONTENT= 17;
98 const AFTER_BODY = 18;
99 const IN_FRAMESET = 19;
100 const AFTER_FRAMESET = 20;
101 const AFTER_AFTER_BODY = 21;
102 const AFTER_AFTER_FRAMESET = 22;
103
104 /**
105 * Converts a magic number to a readable name. Use for debugging.
106 */
107 private function strConst($number) {
108 static $lookup;
109 if (!$lookup) {
110 $lookup = array();
111 $r = new ReflectionClass('HTML5_TreeBuilder');
112 $consts = $r->getConstants();
113 foreach ($consts as $const => $num) {
114 if (!is_int($num)) continue;
115 $lookup[$num] = $const;
116 }
117 }
118 return $lookup[$number];
119 }
120
121 // The different types of elements.
122 const SPECIAL = 100;
123 const SCOPING = 101;
124 const FORMATTING = 102;
125 const PHRASING = 103;
126
127 // Quirks modes in $quirks_mode
128 const NO_QUIRKS = 200;
129 const QUIRKS_MODE = 201;
130 const LIMITED_QUIRKS_MODE = 202;
131
132 // Marker to be placed in $a_formatting
133 const MARKER = 300;
134
135 // Namespaces for foreign content
136 const NS_HTML = null; // to prevent DOM from requiring NS on everything
137 const NS_MATHML = 'http://www.w3.org/1998/Math/MathML';
138 const NS_SVG = 'http://www.w3.org/2000/svg';
139 const NS_XLINK = 'http://www.w3.org/1999/xlink';
140 const NS_XML = 'http://www.w3.org/XML/1998/namespace';
141 const NS_XMLNS = 'http://www.w3.org/2000/xmlns/';
142
143 // Different types of scopes to test for elements
144 const SCOPE = 0;
145 const SCOPE_LISTITEM = 1;
146 const SCOPE_TABLE = 2;
147
148 public function __construct() {
149 $this->mode = self::INITIAL;
150 $this->dom = new DOMDocument;
151
152 $this->dom->encoding = 'UTF-8';
153 $this->dom->preserveWhiteSpace = true;
154 $this->dom->substituteEntities = true;
155 $this->dom->strictErrorChecking = false;
156 }
157
158 // Process tag tokens
159 public function emitToken($token, $mode = null) {
160 // XXX: ignore parse errors... why are we emitting them, again?
161 if ($token['type'] === HTML5_Tokenizer::PARSEERROR) return;
162 if ($mode === null) $mode = $this->mode;
163
164 /*
165 $backtrace = debug_backtrace();
166 if ($backtrace[1]['class'] !== 'HTML5_TreeBuilder') echo "--\n";
167 echo $this->strConst($mode);
168 if ($this->original_mode) echo " (originally ".$this->strConst($this->original_mode).")";
169 echo "\n ";
170 token_dump($token);
171 $this->printStack();
172 $this->printActiveFormattingElements();
173 if ($this->foster_parent) echo " -> this is a foster parent mode\n";
174 if ($this->flag_frameset_ok) echo " -> frameset ok\n";
175 */
176
177 if ($this->ignore_lf_token) $this->ignore_lf_token--;
178 $this->ignored = false;
179 // indenting is a little wonky, this can be changed later on
180 switch ($mode) {
181
182 case self::INITIAL:
183
184 /* A character token that is one of U+0009 CHARACTER TABULATION,
185 * U+000A LINE FEED (LF), U+000C FORM FEED (FF), or U+0020 SPACE */
186 if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
187 /* Ignore the token. */
188 $this->ignored = true;
189 } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
190 if (
191 $token['name'] !== 'html' || !empty($token['public']) ||
192 !empty($token['system']) || $token !== 'about:legacy-compat'
193 ) {
194 /* If the DOCTYPE token's name is not a case-sensitive match
195 * for the string "html", or if the token's public identifier
196 * is not missing, or if the token's system identifier is
197 * neither missing nor a case-sensitive match for the string
198 * "about:legacy-compat", then there is a parse error (this
199 * is the DOCTYPE parse error). */
200 // DOCTYPE parse error
201 }
202 /* Append a DocumentType node to the Document node, with the name
203 * attribute set to the name given in the DOCTYPE token, or the
204 * empty string if the name was missing; the publicId attribute
205 * set to the public identifier given in the DOCTYPE token, or
206 * the empty string if the public identifier was missing; the
207 * systemId attribute set to the system identifier given in the
208 * DOCTYPE token, or the empty string if the system identifier
209 * was missing; and the other attributes specific to
210 * DocumentType objects set to null and empty lists as
211 * appropriate. Associate the DocumentType node with the
212 * Document object so that it is returned as the value of the
213 * doctype attribute of the Document object. */
214 if (!isset($token['public'])) $token['public'] = null;
215 if (!isset($token['system'])) $token['system'] = null;
216 // XDOM
217 // Yes this is hacky. I'm kind of annoyed that I can't appendChild
218 // a doctype to DOMDocument. Maybe I haven't chanted the right
219 // syllables.
220 $impl = new DOMImplementation();
221 // This call can fail for particularly pathological cases (namely,
222 // the qualifiedName parameter ($token['name']) could be missing.
223 if ($token['name']) {
224 $doctype = $impl->createDocumentType($token['name'], $token['public'], $token['system']);
225 $this->dom->appendChild($doctype);
226 } else {
227 // It looks like libxml's not actually *able* to express this case.
228 // So... don't.
229 $this->dom->emptyDoctype = true;
230 }
231 $public = is_null($token['public']) ? false : strtolower($token['public']);
232 $system = is_null($token['system']) ? false : strtolower($token['system']);
233 $publicStartsWithForQuirks = array(
234 "+//silmaril//dtd html pro v0r11 19970101//",
235 "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
236 "-//as//dtd html 3.0 aswedit + extensions//",
237 "-//ietf//dtd html 2.0 level 1//",
238 "-//ietf//dtd html 2.0 level 2//",
239 "-//ietf//dtd html 2.0 strict level 1//",
240 "-//ietf//dtd html 2.0 strict level 2//",
241 "-//ietf//dtd html 2.0 strict//",
242 "-//ietf//dtd html 2.0//",
243 "-//ietf//dtd html 2.1e//",
244 "-//ietf//dtd html 3.0//",
245 "-//ietf//dtd html 3.2 final//",
246 "-//ietf//dtd html 3.2//",
247 "-//ietf//dtd html 3//",
248 "-//ietf//dtd html level 0//",
249 "-//ietf//dtd html level 1//",
250 "-//ietf//dtd html level 2//",
251 "-//ietf//dtd html level 3//",
252 "-//ietf//dtd html strict level 0//",
253 "-//ietf//dtd html strict level 1//",
254 "-//ietf//dtd html strict level 2//",
255 "-//ietf//dtd html strict level 3//",
256 "-//ietf//dtd html strict//",
257 "-//ietf//dtd html//",
258 "-//metrius//dtd metrius presentational//",
259 "-//microsoft//dtd internet explorer 2.0 html strict//",
260 "-//microsoft//dtd internet explorer 2.0 html//",
261 "-//microsoft//dtd internet explorer 2.0 tables//",
262 "-//microsoft//dtd internet explorer 3.0 html strict//",
263 "-//microsoft//dtd internet explorer 3.0 html//",
264 "-//microsoft//dtd internet explorer 3.0 tables//",
265 "-//netscape comm. corp.//dtd html//",
266 "-//netscape comm. corp.//dtd strict html//",
267 "-//o'reilly and associates//dtd html 2.0//",
268 "-//o'reilly and associates//dtd html extended 1.0//",
269 "-//o'reilly and associates//dtd html extended relaxed 1.0//",
270 "-//spyglass//dtd html 2.0 extended//",
271 "-//sq//dtd html 2.0 hotmetal + extensions//",
272 "-//sun microsystems corp.//dtd hotjava html//",
273 "-//sun microsystems corp.//dtd hotjava strict html//",
274 "-//w3c//dtd html 3 1995-03-24//",
275 "-//w3c//dtd html 3.2 draft//",
276 "-//w3c//dtd html 3.2 final//",
277 "-//w3c//dtd html 3.2//",
278 "-//w3c//dtd html 3.2s draft//",
279 "-//w3c//dtd html 4.0 frameset//",
280 "-//w3c//dtd html 4.0 transitional//",
281 "-//w3c//dtd html experimental 19960712//",
282 "-//w3c//dtd html experimental 970421//",
283 "-//w3c//dtd w3 html//",
284 "-//w3o//dtd w3 html 3.0//",
285 "-//webtechs//dtd mozilla html 2.0//",
286 "-//webtechs//dtd mozilla html//",
287 );
288 $publicSetToForQuirks = array(
289 "-//w3o//dtd w3 html strict 3.0//",
290 "-/w3c/dtd html 4.0 transitional/en",
291 "html",
292 );
293 $publicStartsWithAndSystemForQuirks = array(
294 "-//w3c//dtd html 4.01 frameset//",
295 "-//w3c//dtd html 4.01 transitional//",
296 );
297 $publicStartsWithForLimitedQuirks = array(
298 "-//w3c//dtd xhtml 1.0 frameset//",
299 "-//w3c//dtd xhtml 1.0 transitional//",
300 );
301 $publicStartsWithAndSystemForLimitedQuirks = array(
302 "-//w3c//dtd html 4.01 frameset//",
303 "-//w3c//dtd html 4.01 transitional//",
304 );
305 // first, do easy checks
306 if (
307 !empty($token['force-quirks']) ||
308 strtolower($token['name']) !== 'html'
309 ) {
310 $this->quirks_mode = self::QUIRKS_MODE;
311 } else {
312 do {
313 if ($system) {
314 foreach ($publicStartsWithAndSystemForQuirks as $x) {
315 if (strncmp($public, $x, strlen($x)) === 0) {
316 $this->quirks_mode = self::QUIRKS_MODE;
317 break;
318 }
319 }
320 if (!is_null($this->quirks_mode)) break;
321 foreach ($publicStartsWithAndSystemForLimitedQuirks as $x) {
322 if (strncmp($public, $x, strlen($x)) === 0) {
323 $this->quirks_mode = self::LIMITED_QUIRKS_MODE;
324 break;
325 }
326 }
327 if (!is_null($this->quirks_mode)) break;
328 }
329 foreach ($publicSetToForQuirks as $x) {
330 if ($public === $x) {
331 $this->quirks_mode = self::QUIRKS_MODE;
332 break;
333 }
334 }
335 if (!is_null($this->quirks_mode)) break;
336 foreach ($publicStartsWithForLimitedQuirks as $x) {
337 if (strncmp($public, $x, strlen($x)) === 0) {
338 $this->quirks_mode = self::LIMITED_QUIRKS_MODE;
339 }
340 }
341 if (!is_null($this->quirks_mode)) break;
342 if ($system === "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
343 $this->quirks_mode = self::QUIRKS_MODE;
344 break;
345 }
346 foreach ($publicStartsWithForQuirks as $x) {
347 if (strncmp($public, $x, strlen($x)) === 0) {
348 $this->quirks_mode = self::QUIRKS_MODE;
349 break;
350 }
351 }
352 if (is_null($this->quirks_mode)) {
353 $this->quirks_mode = self::NO_QUIRKS;
354 }
355 } while (false);
356 }
357 $this->mode = self::BEFORE_HTML;
358 } else {
359 // parse error
360 /* Switch the insertion mode to "before html", then reprocess the
361 * current token. */
362 $this->mode = self::BEFORE_HTML;
363 $this->quirks_mode = self::QUIRKS_MODE;
364 $this->emitToken($token);
365 }
366 break;
367
368 case self::BEFORE_HTML:
369
370 /* A DOCTYPE token */
371 if($token['type'] === HTML5_Tokenizer::DOCTYPE) {
372 // Parse error. Ignore the token.
373 $this->ignored = true;
374
375 /* A comment token */
376 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
377 /* Append a Comment node to the Document object with the data
378 attribute set to the data given in the comment token. */
379 // XDOM
380 $comment = $this->dom->createComment($token['data']);
381 $this->dom->appendChild($comment);
382
383 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
384 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
385 or U+0020 SPACE */
386 } elseif($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
387 /* Ignore the token. */
388 $this->ignored = true;
389
390 /* A start tag whose tag name is "html" */
391 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] == 'html') {
392 /* Create an element for the token in the HTML namespace. Append it
393 * to the Document object. Put this element in the stack of open
394 * elements. */
395 // XDOM
396 $html = $this->insertElement($token, false);
397 $this->dom->appendChild($html);
398 $this->stack[] = $html;
399
400 $this->mode = self::BEFORE_HEAD;
401
402 } else {
403 /* Create an html element. Append it to the Document object. Put
404 * this element in the stack of open elements. */
405 // XDOM
406 $html = $this->dom->createElementNS(self::NS_HTML, 'html');
407 $this->dom->appendChild($html);
408 $this->stack[] = $html;
409
410 /* Switch the insertion mode to "before head", then reprocess the
411 * current token. */
412 $this->mode = self::BEFORE_HEAD;
413 $this->emitToken($token);
414 }
415 break;
416
417 case self::BEFORE_HEAD:
418
419 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
420 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
421 or U+0020 SPACE */
422 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
423 /* Ignore the token. */
424 $this->ignored = true;
425
426 /* A comment token */
427 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
428 /* Append a Comment node to the current node with the data attribute
429 set to the data given in the comment token. */
430 $this->insertComment($token['data']);
431
432 /* A DOCTYPE token */
433 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
434 /* Parse error. Ignore the token */
435 $this->ignored = true;
436 // parse error
437
438 /* A start tag token with the tag name "html" */
439 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
440 /* Process the token using the rules for the "in body"
441 * insertion mode. */
442 $this->processWithRulesFor($token, self::IN_BODY);
443
444 /* A start tag token with the tag name "head" */
445 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') {
446 /* Insert an HTML element for the token. */
447 $element = $this->insertElement($token);
448
449 /* Set the head element pointer to this new element node. */
450 $this->head_pointer = $element;
451
452 /* Change the insertion mode to "in head". */
453 $this->mode = self::IN_HEAD;
454
455 /* An end tag whose tag name is one of: "head", "body", "html", "br" */
456 } elseif(
457 $token['type'] === HTML5_Tokenizer::ENDTAG && (
458 $token['name'] === 'head' || $token['name'] === 'body' ||
459 $token['name'] === 'html' || $token['name'] === 'br'
460 )) {
461 /* Act as if a start tag token with the tag name "head" and no
462 * attributes had been seen, then reprocess the current token. */
463 $this->emitToken(array(
464 'name' => 'head',
465 'type' => HTML5_Tokenizer::STARTTAG,
466 'attr' => array()
467 ));
468 $this->emitToken($token);
469
470 /* Any other end tag */
471 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG) {
472 /* Parse error. Ignore the token. */
473 $this->ignored = true;
474
475 } else {
476 /* Act as if a start tag token with the tag name "head" and no
477 * attributes had been seen, then reprocess the current token.
478 * Note: This will result in an empty head element being
479 * generated, with the current token being reprocessed in the
480 * "after head" insertion mode. */
481 $this->emitToken(array(
482 'name' => 'head',
483 'type' => HTML5_Tokenizer::STARTTAG,
484 'attr' => array()
485 ));
486 $this->emitToken($token);
487 }
488 break;
489
490 case self::IN_HEAD:
491
492 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
493 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
494 or U+0020 SPACE. */
495 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
496 /* Insert the character into the current node. */
497 $this->insertText($token['data']);
498
499 /* A comment token */
500 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
501 /* Append a Comment node to the current node with the data attribute
502 set to the data given in the comment token. */
503 $this->insertComment($token['data']);
504
505 /* A DOCTYPE token */
506 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
507 /* Parse error. Ignore the token. */
508 $this->ignored = true;
509 // parse error
510
511 /* A start tag whose tag name is "html" */
512 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
513 $token['name'] === 'html') {
514 $this->processWithRulesFor($token, self::IN_BODY);
515
516 /* A start tag whose tag name is one of: "base", "command", "link" */
517 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
518 ($token['name'] === 'base' || $token['name'] === 'command' ||
519 $token['name'] === 'link')) {
520 /* Insert an HTML element for the token. Immediately pop the
521 * current node off the stack of open elements. */
522 $this->insertElement($token);
523 array_pop($this->stack);
524
525 // YYY: Acknowledge the token's self-closing flag, if it is set.
526
527 /* A start tag whose tag name is "meta" */
528 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'meta') {
529 /* Insert an HTML element for the token. Immediately pop the
530 * current node off the stack of open elements. */
531 $this->insertElement($token);
532 array_pop($this->stack);
533
534 // XERROR: Acknowledge the token's self-closing flag, if it is set.
535
536 // XENCODING: If the element has a charset attribute, and its value is a
537 // supported encoding, and the confidence is currently tentative,
538 // then change the encoding to the encoding given by the value of
539 // the charset attribute.
540 //
541 // Otherwise, if the element has a content attribute, and applying
542 // the algorithm for extracting an encoding from a Content-Type to
543 // its value returns a supported encoding encoding, and the
544 // confidence is currently tentative, then change the encoding to
545 // the encoding encoding.
546
547 /* A start tag with the tag name "title" */
548 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'title') {
549 $this->insertRCDATAElement($token);
550
551 /* A start tag whose tag name is "noscript", if the scripting flag is enabled, or
552 * A start tag whose tag name is one of: "noframes", "style" */
553 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
554 ($token['name'] === 'noscript' || $token['name'] === 'noframes' || $token['name'] === 'style')) {
555 // XSCRIPT: Scripting flag not respected
556 $this->insertCDATAElement($token);
557
558 // XSCRIPT: Scripting flag disable not implemented
559
560 /* A start tag with the tag name "script" */
561 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'script') {
562 /* 1. Create an element for the token in the HTML namespace. */
563 $node = $this->insertElement($token, false);
564
565 /* 2. Mark the element as being "parser-inserted" */
566 // Uhhh... XSCRIPT
567
568 /* 3. If the parser was originally created for the HTML
569 * fragment parsing algorithm, then mark the script element as
570 * "already executed". (fragment case) */
571 // ditto... XSCRIPT
572
573 /* 4. Append the new element to the current node and push it onto
574 * the stack of open elements. */
575 end($this->stack)->appendChild($node);
576 $this->stack[] = $node;
577 // I guess we could squash these together
578
579 /* 6. Let the original insertion mode be the current insertion mode. */
580 $this->original_mode = $this->mode;
581 /* 7. Switch the insertion mode to "in CDATA/RCDATA" */
582 $this->mode = self::IN_CDATA_RCDATA;
583 /* 5. Switch the tokeniser's content model flag to the CDATA state. */
584 $this->content_model = HTML5_Tokenizer::CDATA;
585
586 /* An end tag with the tag name "head" */
587 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'head') {
588 /* Pop the current node (which will be the head element) off the stack of open elements. */
589 array_pop($this->stack);
590
591 /* Change the insertion mode to "after head". */
592 $this->mode = self::AFTER_HEAD;
593
594 // Slight logic inversion here to minimize duplication
595 /* A start tag with the tag name "head". */
596 /* An end tag whose tag name is not one of: "body", "html", "br" */
597 } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') ||
598 ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] !== 'html' &&
599 $token['name'] !== 'body' && $token['name'] !== 'br')) {
600 // Parse error. Ignore the token.
601 $this->ignored = true;
602
603 /* Anything else */
604 } else {
605 /* Act as if an end tag token with the tag name "head" had been
606 * seen, and reprocess the current token. */
607 $this->emitToken(array(
608 'name' => 'head',
609 'type' => HTML5_Tokenizer::ENDTAG
610 ));
611
612 /* Then, reprocess the current token. */
613 $this->emitToken($token);
614 }
615 break;
616
617 case self::IN_HEAD_NOSCRIPT:
618 if ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
619 // parse error
620 } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
621 $this->processWithRulesFor($token, self::IN_BODY);
622 } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'noscript') {
623 /* Pop the current node (which will be a noscript element) from the
624 * stack of open elements; the new current node will be a head
625 * element. */
626 array_pop($this->stack);
627 $this->mode = self::IN_HEAD;
628 } elseif (
629 ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) ||
630 ($token['type'] === HTML5_Tokenizer::COMMENT) ||
631 ($token['type'] === HTML5_Tokenizer::STARTTAG && (
632 $token['name'] === 'link' || $token['name'] === 'meta' ||
633 $token['name'] === 'noframes' || $token['name'] === 'style'))) {
634 $this->processWithRulesFor($token, self::IN_HEAD);
635 // inverted logic
636 } elseif (
637 ($token['type'] === HTML5_Tokenizer::STARTTAG && (
638 $token['name'] === 'head' || $token['name'] === 'noscript')) ||
639 ($token['type'] === HTML5_Tokenizer::ENDTAG &&
640 $token['name'] !== 'br')) {
641 // parse error
642 } else {
643 // parse error
644 $this->emitToken(array(
645 'type' => HTML5_Tokenizer::ENDTAG,
646 'name' => 'noscript',
647 ));
648 $this->emitToken($token);
649 }
650 break;
651
652 case self::AFTER_HEAD:
653 /* Handle the token as follows: */
654
655 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
656 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
657 or U+0020 SPACE */
658 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
659 /* Append the character to the current node. */
660 $this->insertText($token['data']);
661
662 /* A comment token */
663 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
664 /* Append a Comment node to the current node with the data attribute
665 set to the data given in the comment token. */
666 $this->insertComment($token['data']);
667
668 } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
669 // parse error
670
671 } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
672 $this->processWithRulesFor($token, self::IN_BODY);
673
674 /* A start tag token with the tag name "body" */
675 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'body') {
676 $this->insertElement($token);
677
678 /* Set the frameset-ok flag to "not ok". */
679 $this->flag_frameset_ok = false;
680
681 /* Change the insertion mode to "in body". */
682 $this->mode = self::IN_BODY;
683
684 /* A start tag token with the tag name "frameset" */
685 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'frameset') {
686 /* Insert a frameset element for the token. */
687 $this->insertElement($token);
688
689 /* Change the insertion mode to "in frameset". */
690 $this->mode = self::IN_FRAMESET;
691
692 /* A start tag token whose tag name is one of: "base", "link", "meta",
693 "script", "style", "title" */
694 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
695 array('base', 'link', 'meta', 'noframes', 'script', 'style', 'title'))) {
696 // parse error
697 /* Push the node pointed to by the head element pointer onto the
698 * stack of open elements. */
699 $this->stack[] = $this->head_pointer;
700 $this->processWithRulesFor($token, self::IN_HEAD);
701 array_splice($this->stack, array_search($this->head_pointer, $this->stack, true), 1);
702
703 // inversion of specification
704 } elseif(
705 ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') ||
706 ($token['type'] === HTML5_Tokenizer::ENDTAG &&
707 $token['name'] !== 'body' && $token['name'] !== 'html' &&
708 $token['name'] !== 'br')) {
709 // parse error
710
711 /* Anything else */
712 } else {
713 $this->emitToken(array(
714 'name' => 'body',
715 'type' => HTML5_Tokenizer::STARTTAG,
716 'attr' => array()
717 ));
718 $this->flag_frameset_ok = true;
719 $this->emitToken($token);
720 }
721 break;
722
723 case self::IN_BODY:
724 /* Handle the token as follows: */
725
726 switch($token['type']) {
727 /* A character token */
728 case HTML5_Tokenizer::CHARACTER:
729 case HTML5_Tokenizer::SPACECHARACTER:
730 /* Reconstruct the active formatting elements, if any. */
731 $this->reconstructActiveFormattingElements();
732
733 /* Append the token's character to the current node. */
734 $this->insertText($token['data']);
735
736 /* If the token is not one of U+0009 CHARACTER TABULATION,
737 * U+000A LINE FEED (LF), U+000C FORM FEED (FF), or U+0020
738 * SPACE, then set the frameset-ok flag to "not ok". */
739 // i.e., if any of the characters is not whitespace
740 if (strlen($token['data']) !== strspn($token['data'], HTML5_Tokenizer::WHITESPACE)) {
741 $this->flag_frameset_ok = false;
742 }
743 break;
744
745 /* A comment token */
746 case HTML5_Tokenizer::COMMENT:
747 /* Append a Comment node to the current node with the data
748 attribute set to the data given in the comment token. */
749 $this->insertComment($token['data']);
750 break;
751
752 case HTML5_Tokenizer::DOCTYPE:
753 // parse error
754 break;
755
756 case HTML5_Tokenizer::EOF:
757 // parse error
758 break;
759
760 case HTML5_Tokenizer::STARTTAG:
761 switch($token['name']) {
762 case 'html':
763 // parse error
764 /* For each attribute on the token, check to see if the
765 * attribute is already present on the top element of the
766 * stack of open elements. If it is not, add the attribute
767 * and its corresponding value to that element. */
768 foreach($token['attr'] as $attr) {
769 if(!$this->stack[0]->hasAttribute($attr['name'])) {
770 $this->stack[0]->setAttribute($attr['name'], $attr['value']);
771 }
772 }
773 break;
774
775 case 'base': case 'command': case 'link': case 'meta': case 'noframes':
776 case 'script': case 'style': case 'title':
777 /* Process the token as if the insertion mode had been "in
778 head". */
779 $this->processWithRulesFor($token, self::IN_HEAD);
780 break;
781
782 /* A start tag token with the tag name "body" */
783 case 'body':
784 /* Parse error. If the second element on the stack of open
785 elements is not a body element, or, if the stack of open
786 elements has only one node on it, then ignore the token.
787 (fragment case) */
788 if(count($this->stack) === 1 || $this->stack[1]->tagName !== 'body') {
789 $this->ignored = true;
790 // Ignore
791
792 /* Otherwise, for each attribute on the token, check to see
793 if the attribute is already present on the body element (the
794 second element) on the stack of open elements. If it is not,
795 add the attribute and its corresponding value to that
796 element. */
797 } else {
798 foreach($token['attr'] as $attr) {
799 if(!$this->stack[1]->hasAttribute($attr['name'])) {
800 $this->stack[1]->setAttribute($attr['name'], $attr['value']);
801 }
802 }
803 }
804 break;
805
806 case 'frameset':
807 // parse error
808 /* If the second element on the stack of open elements is
809 * not a body element, or, if the stack of open elements
810 * has only one node on it, then ignore the token.
811 * (fragment case) */
812 if(count($this->stack) === 1 || $this->stack[1]->tagName !== 'body') {
813 $this->ignored = true;
814 // Ignore
815 } elseif (!$this->flag_frameset_ok) {
816 $this->ignored = true;
817 // Ignore
818 } else {
819 /* 1. Remove the second element on the stack of open
820 * elements from its parent node, if it has one. */
821 if($this->stack[1]->parentNode) {
822 $this->stack[1]->parentNode->removeChild($this->stack[1]);
823 }
824
825 /* 2. Pop all the nodes from the bottom of the stack of
826 * open elements, from the current node up to the root
827 * html element. */
828 array_splice($this->stack, 1);
829
830 $this->insertElement($token);
831 $this->mode = self::IN_FRAMESET;
832 }
833 break;
834
835 // in spec, there is a diversion here
836
837 case 'address': case 'article': case 'aside': case 'blockquote':
838 case 'center': case 'datagrid': case 'details': case 'dir':
839 case 'div': case 'dl': case 'fieldset': case 'figure': case 'footer':
840 case 'header': case 'hgroup': case 'menu': case 'nav':
841 case 'ol': case 'p': case 'section': case 'ul':
842 /* If the stack of open elements has a p element in scope,
843 then act as if an end tag with the tag name p had been
844 seen. */
845 if($this->elementInScope('p')) {
846 $this->emitToken(array(
847 'name' => 'p',
848 'type' => HTML5_Tokenizer::ENDTAG
849 ));
850 }
851
852 /* Insert an HTML element for the token. */
853 $this->insertElement($token);
854 break;
855
856 /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4",
857 "h5", "h6" */
858 case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
859 /* If the stack of open elements has a p element in scope,
860 then act as if an end tag with the tag name p had been seen. */
861 if($this->elementInScope('p')) {
862 $this->emitToken(array(
863 'name' => 'p',
864 'type' => HTML5_Tokenizer::ENDTAG
865 ));
866 }
867
868 /* If the current node is an element whose tag name is one
869 * of "h1", "h2", "h3", "h4", "h5", or "h6", then this is a
870 * parse error; pop the current node off the stack of open
871 * elements. */
872 $peek = array_pop($this->stack);
873 if (in_array($peek->tagName, array("h1", "h2", "h3", "h4", "h5", "h6"))) {
874 // parse error
875 } else {
876 $this->stack[] = $peek;
877 }
878
879 /* Insert an HTML element for the token. */
880 $this->insertElement($token);
881 break;
882
883 case 'pre': case 'listing':
884 /* If the stack of open elements has a p element in scope,
885 then act as if an end tag with the tag name p had been seen. */
886 if($this->elementInScope('p')) {
887 $this->emitToken(array(
888 'name' => 'p',
889 'type' => HTML5_Tokenizer::ENDTAG
890 ));
891 }
892 $this->insertElement($token);
893 /* If the next token is a U+000A LINE FEED (LF) character
894 * token, then ignore that token and move on to the next
895 * one. (Newlines at the start of pre blocks are ignored as
896 * an authoring convenience.) */
897 $this->ignore_lf_token = 2;
898 $this->flag_frameset_ok = false;
899 break;
900
901 /* A start tag whose tag name is "form" */
902 case 'form':
903 /* If the form element pointer is not null, ignore the
904 token with a parse error. */
905 if($this->form_pointer !== null) {
906 $this->ignored = true;
907 // Ignore.
908
909 /* Otherwise: */
910 } else {
911 /* If the stack of open elements has a p element in
912 scope, then act as if an end tag with the tag name p
913 had been seen. */
914 if($this->elementInScope('p')) {
915 $this->emitToken(array(
916 'name' => 'p',
917 'type' => HTML5_Tokenizer::ENDTAG
918 ));
919 }
920
921 /* Insert an HTML element for the token, and set the
922 form element pointer to point to the element created. */
923 $element = $this->insertElement($token);
924 $this->form_pointer = $element;
925 }
926 break;
927
928 // condensed specification
929 case 'li': case 'dc': case 'dd': case 'ds': case 'dt':
930 /* 1. Set the frameset-ok flag to "not ok". */
931 $this->flag_frameset_ok = false;
932
933 $stack_length = count($this->stack) - 1;
934 for($n = $stack_length; 0 <= $n; $n--) {
935 /* 2. Initialise node to be the current node (the
936 bottommost node of the stack). */
937 $stop = false;
938 $node = $this->stack[$n];
939 $cat = $this->getElementCategory($node);
940
941 // for case 'li':
942 /* 3. If node is an li element, then act as if an end
943 * tag with the tag name "li" had been seen, then jump
944 * to the last step. */
945 // for case 'dc': case 'dd': case 'ds': case 'dt':
946 /* If node is a dc, dd, ds or dt element, then act as if an end
947 * tag with the same tag name as node had been seen, then
948 * jump to the last step. */
949 if(($token['name'] === 'li' && $node->tagName === 'li') ||
950 ($token['name'] !== 'li' && ($node->tagName == 'dc' || $node->tagName === 'dd' || $node->tagName == 'ds' || $node->tagName === 'dt'))) { // limited conditional
951 $this->emitToken(array(
952 'type' => HTML5_Tokenizer::ENDTAG,
953 'name' => $node->tagName,
954 ));
955 break;
956 }
957
958 /* 4. If node is not in the formatting category, and is
959 not in the phrasing category, and is not an address,
960 div or p element, then stop this algorithm. */
961 if($cat !== self::FORMATTING && $cat !== self::PHRASING &&
962 $node->tagName !== 'address' && $node->tagName !== 'div' &&
963 $node->tagName !== 'p') {
964 break;
965 }
966
967 /* 5. Otherwise, set node to the previous entry in the
968 * stack of open elements and return to step 2. */
969 }
970
971 /* 6. This is the last step. */
972
973 /* If the stack of open elements has a p element in scope,
974 then act as if an end tag with the tag name p had been
975 seen. */
976 if($this->elementInScope('p')) {
977 $this->emitToken(array(
978 'name' => 'p',
979 'type' => HTML5_Tokenizer::ENDTAG
980 ));
981 }
982
983 /* Finally, insert an HTML element with the same tag
984 name as the token's. */
985 $this->insertElement($token);
986 break;
987
988 /* A start tag token whose tag name is "plaintext" */
989 case 'plaintext':
990 /* If the stack of open elements has a p element in scope,
991 then act as if an end tag with the tag name p had been
992 seen. */
993 if($this->elementInScope('p')) {
994 $this->emitToken(array(
995 'name' => 'p',
996 'type' => HTML5_Tokenizer::ENDTAG
997 ));
998 }
999
1000 /* Insert an HTML element for the token. */
1001 $this->insertElement($token);
1002
1003 $this->content_model = HTML5_Tokenizer::PLAINTEXT;
1004 break;
1005
1006 // more diversions
1007
1008 /* A start tag whose tag name is "a" */
1009 case 'a':
1010 /* If the list of active formatting elements contains
1011 an element whose tag name is "a" between the end of the
1012 list and the last marker on the list (or the start of
1013 the list if there is no marker on the list), then this
1014 is a parse error; act as if an end tag with the tag name
1015 "a" had been seen, then remove that element from the list
1016 of active formatting elements and the stack of open
1017 elements if the end tag didn't already remove it (it
1018 might not have if the element is not in table scope). */
1019 $leng = count($this->a_formatting);
1020
1021 for($n = $leng - 1; $n >= 0; $n--) {
1022 if($this->a_formatting[$n] === self::MARKER) {
1023 break;
1024
1025 } elseif($this->a_formatting[$n]->tagName === 'a') {
1026 $a = $this->a_formatting[$n];
1027 $this->emitToken(array(
1028 'name' => 'a',
1029 'type' => HTML5_Tokenizer::ENDTAG
1030 ));
1031 if (in_array($a, $this->a_formatting)) {
1032 $a_i = array_search($a, $this->a_formatting, true);
1033 if($a_i !== false) array_splice($this->a_formatting, $a_i, 1);
1034 }
1035 if (in_array($a, $this->stack)) {
1036 $a_i = array_search($a, $this->stack, true);
1037 if ($a_i !== false) array_splice($this->stack, $a_i, 1);
1038 }
1039 break;
1040 }
1041 }
1042
1043 /* Reconstruct the active formatting elements, if any. */
1044 $this->reconstructActiveFormattingElements();
1045
1046 /* Insert an HTML element for the token. */
1047 $el = $this->insertElement($token);
1048
1049 /* Add that element to the list of active formatting
1050 elements. */
1051 $this->a_formatting[] = $el;
1052 break;
1053
1054 case 'b': case 'big': case 'code': case 'em': case 'font': case 'i':
1055 case 's': case 'small': case 'strike':
1056 case 'strong': case 'tt': case 'u':
1057 /* Reconstruct the active formatting elements, if any. */
1058 $this->reconstructActiveFormattingElements();
1059
1060 /* Insert an HTML element for the token. */
1061 $el = $this->insertElement($token);
1062
1063 /* Add that element to the list of active formatting
1064 elements. */
1065 $this->a_formatting[] = $el;
1066 break;
1067
1068 case 'nobr':
1069 /* Reconstruct the active formatting elements, if any. */
1070 $this->reconstructActiveFormattingElements();
1071
1072 /* If the stack of open elements has a nobr element in
1073 * scope, then this is a parse error; act as if an end tag
1074 * with the tag name "nobr" had been seen, then once again
1075 * reconstruct the active formatting elements, if any. */
1076 if ($this->elementInScope('nobr')) {
1077 $this->emitToken(array(
1078 'name' => 'nobr',
1079 'type' => HTML5_Tokenizer::ENDTAG,
1080 ));
1081 $this->reconstructActiveFormattingElements();
1082 }
1083
1084 /* Insert an HTML element for the token. */
1085 $el = $this->insertElement($token);
1086
1087 /* Add that element to the list of active formatting
1088 elements. */
1089 $this->a_formatting[] = $el;
1090 break;
1091
1092 // another diversion
1093
1094 /* A start tag token whose tag name is "button" */
1095 case 'button':
1096 /* If the stack of open elements has a button element in scope,
1097 then this is a parse error; act as if an end tag with the tag
1098 name "button" had been seen, then reprocess the token. (We don't
1099 do that. Unnecessary.) (I hope you're right! -- ezyang) */
1100 if($this->elementInScope('button')) {
1101 $this->emitToken(array(
1102 'name' => 'button',
1103 'type' => HTML5_Tokenizer::ENDTAG
1104 ));
1105 }
1106
1107 /* Reconstruct the active formatting elements, if any. */
1108 $this->reconstructActiveFormattingElements();
1109
1110 /* Insert an HTML element for the token. */
1111 $this->insertElement($token);
1112
1113 /* Insert a marker at the end of the list of active
1114 formatting elements. */
1115 $this->a_formatting[] = self::MARKER;
1116
1117 $this->flag_frameset_ok = false;
1118 break;
1119
1120 case 'applet': case 'marquee': case 'object':
1121 /* Reconstruct the active formatting elements, if any. */
1122 $this->reconstructActiveFormattingElements();
1123
1124 /* Insert an HTML element for the token. */
1125 $this->insertElement($token);
1126
1127 /* Insert a marker at the end of the list of active
1128 formatting elements. */
1129 $this->a_formatting[] = self::MARKER;
1130
1131 $this->flag_frameset_ok = false;
1132 break;
1133
1134 // spec diversion
1135
1136 /* A start tag whose tag name is "table" */
1137 case 'table':
1138 /* If the Document is not set to quirks mode, and the
1139 * stack of open elements has a p element in scope, then
1140 * act as if an end tag with the tag name "p" had been
1141 * seen. */
1142 if($this->quirks_mode !== self::QUIRKS_MODE &&
1143 $this->elementInScope('p')) {
1144 $this->emitToken(array(
1145 'name' => 'p',
1146 'type' => HTML5_Tokenizer::ENDTAG
1147 ));
1148 }
1149
1150 /* Insert an HTML element for the token. */
1151 $this->insertElement($token);
1152
1153 $this->flag_frameset_ok = false;
1154
1155 /* Change the insertion mode to "in table". */
1156 $this->mode = self::IN_TABLE;
1157 break;
1158
1159 /* A start tag whose tag name is one of: "area", "basefont",
1160 "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */
1161 case 'area': case 'basefont': case 'bgsound': case 'br':
1162 case 'embed': case 'img': case 'input': case 'keygen': case 'spacer':
1163 case 'wbr':
1164 /* Reconstruct the active formatting elements, if any. */
1165 $this->reconstructActiveFormattingElements();
1166
1167 /* Insert an HTML element for the token. */
1168 $this->insertElement($token);
1169
1170 /* Immediately pop the current node off the stack of open elements. */
1171 array_pop($this->stack);
1172
1173 // YYY: Acknowledge the token's self-closing flag, if it is set.
1174
1175 $this->flag_frameset_ok = false;
1176 break;
1177
1178 case 'param': case 'source':
1179 /* Insert an HTML element for the token. */
1180 $this->insertElement($token);
1181
1182 /* Immediately pop the current node off the stack of open elements. */
1183 array_pop($this->stack);
1184
1185 // YYY: Acknowledge the token's self-closing flag, if it is set.
1186 break;
1187
1188 /* A start tag whose tag name is "hr" */
1189 case 'hr':
1190 /* If the stack of open elements has a p element in scope,
1191 then act as if an end tag with the tag name p had been seen. */
1192 if($this->elementInScope('p')) {
1193 $this->emitToken(array(
1194 'name' => 'p',
1195 'type' => HTML5_Tokenizer::ENDTAG
1196 ));
1197 }
1198
1199 /* Insert an HTML element for the token. */
1200 $this->insertElement($token);
1201
1202 /* Immediately pop the current node off the stack of open elements. */
1203 array_pop($this->stack);
1204
1205 // YYY: Acknowledge the token's self-closing flag, if it is set.
1206
1207 $this->flag_frameset_ok = false;
1208 break;
1209
1210 /* A start tag whose tag name is "image" */
1211 case 'image':
1212 /* Parse error. Change the token's tag name to "img" and
1213 reprocess it. (Don't ask.) */
1214 $token['name'] = 'img';
1215 $this->emitToken($token);
1216 break;
1217
1218 /* A start tag whose tag name is "isindex" */
1219 case 'isindex':
1220 /* Parse error. */
1221
1222 /* If the form element pointer is not null,
1223 then ignore the token. */
1224 if($this->form_pointer === null) {
1225 /* Act as if a start tag token with the tag name "form" had
1226 been seen. */
1227 /* If the token has an attribute called "action", set
1228 * the action attribute on the resulting form
1229 * element to the value of the "action" attribute of
1230 * the token. */
1231 $attr = array();
1232 $action = $this->getAttr($token, 'action');
1233 if ($action !== false) {
1234 $attr[] = array('name' => 'action', 'value' => $action);
1235 }
1236 $this->emitToken(array(
1237 'name' => 'form',
1238 'type' => HTML5_Tokenizer::STARTTAG,
1239 'attr' => $attr
1240 ));
1241
1242 /* Act as if a start tag token with the tag name "hr" had
1243 been seen. */
1244 $this->emitToken(array(
1245 'name' => 'hr',
1246 'type' => HTML5_Tokenizer::STARTTAG,
1247 'attr' => array()
1248 ));
1249
1250 /* Act as if a start tag token with the tag name "label"
1251 had been seen. */
1252 $this->emitToken(array(
1253 'name' => 'label',
1254 'type' => HTML5_Tokenizer::STARTTAG,
1255 'attr' => array()
1256 ));
1257
1258 /* Act as if a stream of character tokens had been seen. */
1259 $prompt = $this->getAttr($token, 'prompt');
1260 if ($prompt === false) {
1261 $prompt = 'This is a searchable index. '.
1262 'Insert your search keywords here: ';
1263 }
1264 $this->emitToken(array(
1265 'data' => $prompt,
1266 'type' => HTML5_Tokenizer::CHARACTER,
1267 ));
1268
1269 /* Act as if a start tag token with the tag name "input"
1270 had been seen, with all the attributes from the "isindex"
1271 token, except with the "name" attribute set to the value
1272 "isindex" (ignoring any explicit "name" attribute). */
1273 $attr = array();
1274 foreach ($token['attr'] as $keypair) {
1275 if ($keypair['name'] === 'name' || $keypair['name'] === 'action' ||
1276 $keypair['name'] === 'prompt') continue;
1277 $attr[] = $keypair;
1278 }
1279 $attr[] = array('name' => 'name', 'value' => 'isindex');
1280
1281 $this->emitToken(array(
1282 'name' => 'input',
1283 'type' => HTML5_Tokenizer::STARTTAG,
1284 'attr' => $attr
1285 ));
1286
1287 /* Act as if an end tag token with the tag name "label"
1288 had been seen. */
1289 $this->emitToken(array(
1290 'name' => 'label',
1291 'type' => HTML5_Tokenizer::ENDTAG
1292 ));
1293
1294 /* Act as if a start tag token with the tag name "hr" had
1295 been seen. */
1296 $this->emitToken(array(
1297 'name' => 'hr',
1298 'type' => HTML5_Tokenizer::STARTTAG
1299 ));
1300
1301 /* Act as if an end tag token with the tag name "form" had
1302 been seen. */
1303 $this->emitToken(array(
1304 'name' => 'form',
1305 'type' => HTML5_Tokenizer::ENDTAG
1306 ));
1307 } else {
1308 $this->ignored = true;
1309 }
1310 break;
1311
1312 /* A start tag whose tag name is "textarea" */
1313 case 'textarea':
1314 $this->insertElement($token);
1315
1316 /* If the next token is a U+000A LINE FEED (LF)
1317 * character token, then ignore that token and move on to
1318 * the next one. (Newlines at the start of textarea
1319 * elements are ignored as an authoring convenience.)
1320 * need flag, see also <pre> */
1321 $this->ignore_lf_token = 2;
1322
1323 $this->original_mode = $this->mode;
1324 $this->flag_frameset_ok = false;
1325 $this->mode = self::IN_CDATA_RCDATA;
1326
1327 /* Switch the tokeniser's content model flag to the
1328 RCDATA state. */
1329 $this->content_model = HTML5_Tokenizer::RCDATA;
1330 break;
1331
1332 /* A start tag token whose tag name is "xmp" */
1333 case 'xmp':
1334 /* If the stack of open elements has a p element in
1335 scope, then act as if an end tag with the tag name
1336 "p" has been seen. */
1337 if ($this->elementInScope('p')) {
1338 $this->emitToken(array(
1339 'name' => 'p',
1340 'type' => HTML5_Tokenizer::ENDTAG
1341 ));
1342 }
1343
1344 /* Reconstruct the active formatting elements, if any. */
1345 $this->reconstructActiveFormattingElements();
1346
1347 $this->flag_frameset_ok = false;
1348
1349 $this->insertCDATAElement($token);
1350 break;
1351
1352 case 'iframe':
1353 $this->flag_frameset_ok = false;
1354 $this->insertCDATAElement($token);
1355 break;
1356
1357 case 'noembed': case 'noscript':
1358 // XSCRIPT: should check scripting flag
1359 $this->insertCDATAElement($token);
1360 break;
1361
1362 /* A start tag whose tag name is "select" */
1363 case 'select':
1364 /* Reconstruct the active formatting elements, if any. */
1365 $this->reconstructActiveFormattingElements();
1366
1367 /* Insert an HTML element for the token. */
1368 $this->insertElement($token);
1369
1370 $this->flag_frameset_ok = false;
1371
1372 /* If the insertion mode is one of in table", "in caption",
1373 * "in column group", "in table body", "in row", or "in
1374 * cell", then switch the insertion mode to "in select in
1375 * table". Otherwise, switch the insertion mode to "in
1376 * select". */
1377 if (
1378 $this->mode === self::IN_TABLE || $this->mode === self::IN_CAPTION ||
1379 $this->mode === self::IN_COLUMN_GROUP || $this->mode ==+self::IN_TABLE_BODY ||
1380 $this->mode === self::IN_ROW || $this->mode === self::IN_CELL
1381 ) {
1382 $this->mode = self::IN_SELECT_IN_TABLE;
1383 } else {
1384 $this->mode = self::IN_SELECT;
1385 }
1386 break;
1387
1388 case 'option': case 'optgroup':
1389 if ($this->elementInScope('option')) {
1390 $this->emitToken(array(
1391 'name' => 'option',
1392 'type' => HTML5_Tokenizer::ENDTAG,
1393 ));
1394 }
1395 $this->reconstructActiveFormattingElements();
1396 $this->insertElement($token);
1397 break;
1398
1399 case 'rp': case 'rt':
1400 /* If the stack of open elements has a ruby element in scope, then generate
1401 * implied end tags. If the current node is not then a ruby element, this is
1402 * a parse error; pop all the nodes from the current node up to the node
1403 * immediately before the bottommost ruby element on the stack of open elements.
1404 */
1405 if ($this->elementInScope('ruby')) {
1406 $this->generateImpliedEndTags();
1407 }
1408 $peek = false;
1409 do {
1410 if ($peek) {
1411 // parse error
1412 }
1413 $peek = array_pop($this->stack);
1414 } while ($peek->tagName !== 'ruby');
1415 $this->stack[] = $peek; // we popped one too many
1416 $this->insertElement($token);
1417 break;
1418
1419 // spec diversion
1420
1421 case 'math':
1422 $this->reconstructActiveFormattingElements();
1423 $token = $this->adjustMathMLAttributes($token);
1424 $token = $this->adjustForeignAttributes($token);
1425 $this->insertForeignElement($token, self::NS_MATHML);
1426 if (isset($token['self-closing'])) {
1427 // XERROR: acknowledge the token's self-closing flag
1428 array_pop($this->stack);
1429 }
1430 if ($this->mode !== self::IN_FOREIGN_CONTENT) {
1431 $this->secondary_mode = $this->mode;
1432 $this->mode = self::IN_FOREIGN_CONTENT;
1433 }
1434 break;
1435
1436 case 'svg':
1437 $this->reconstructActiveFormattingElements();
1438 $token = $this->adjustSVGAttributes($token);
1439 $token = $this->adjustForeignAttributes($token);
1440 $this->insertForeignElement($token, self::NS_SVG);
1441 if (isset($token['self-closing'])) {
1442 // XERROR: acknowledge the token's self-closing flag
1443 array_pop($this->stack);
1444 }
1445 if ($this->mode !== self::IN_FOREIGN_CONTENT) {
1446 $this->secondary_mode = $this->mode;
1447 $this->mode = self::IN_FOREIGN_CONTENT;
1448 }
1449 break;
1450
1451 case 'caption': case 'col': case 'colgroup': case 'frame': case 'head':
1452 case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': case 'tr':
1453 // parse error
1454 break;
1455
1456 /* A start tag token not covered by the previous entries */
1457 default:
1458 /* Reconstruct the active formatting elements, if any. */
1459 $this->reconstructActiveFormattingElements();
1460
1461 $this->insertElement($token);
1462 /* This element will be a phrasing element. */
1463 break;
1464 }
1465 break;
1466
1467 case HTML5_Tokenizer::ENDTAG:
1468 switch($token['name']) {
1469 /* An end tag with the tag name "body" */
1470 case 'body':
1471 /* If the stack of open elements does not have a body
1472 * element in scope, this is a parse error; ignore the
1473 * token. */
1474 if(!$this->elementInScope('body')) {
1475 $this->ignored = true;
1476
1477 /* Otherwise, if there is a node in the stack of open
1478 * elements that is not either a dc element, a dd element,
1479 * a ds element, a dt element, an li element, an optgroup
1480 * element, an option element, a p element, an rp element,
1481 * an rt element, a tbody element, a td element, a tfoot
1482 * element, a th element, a thead element, a tr element,
1483 * the body element, or the html element, then this is a
1484 * parse error.
1485 */
1486 } else {
1487 // XERROR: implement this check for parse error
1488 }
1489
1490 /* Change the insertion mode to "after body". */
1491 $this->mode = self::AFTER_BODY;
1492 break;
1493
1494 /* An end tag with the tag name "html" */
1495 case 'html':
1496 /* Act as if an end tag with tag name "body" had been seen,
1497 then, if that token wasn't ignored, reprocess the current
1498 token. */
1499 $this->emitToken(array(
1500 'name' => 'body',
1501 'type' => HTML5_Tokenizer::ENDTAG
1502 ));
1503
1504 if (!$this->ignored) $this->emitToken($token);
1505 break;
1506
1507 case 'address': case 'article': case 'aside': case 'blockquote':
1508 case 'center': case 'datagrid': case 'details': case 'dir':
1509 case 'div': case 'dl': case 'fieldset': case 'footer':
1510 case 'header': case 'hgroup': case 'listing': case 'menu':
1511 case 'nav': case 'ol': case 'pre': case 'section': case 'ul':
1512 /* If the stack of open elements has an element in scope
1513 with the same tag name as that of the token, then generate
1514 implied end tags. */
1515 if($this->elementInScope($token['name'])) {
1516 $this->generateImpliedEndTags();
1517
1518 /* Now, if the current node is not an element with
1519 the same tag name as that of the token, then this
1520 is a parse error. */
1521 // XERROR: implement parse error logic
1522
1523 /* If the stack of open elements has an element in
1524 scope with the same tag name as that of the token,
1525 then pop elements from this stack until an element
1526 with that tag name has been popped from the stack. */
1527 do {
1528 $node = array_pop($this->stack);
1529 } while ($node->tagName !== $token['name']);
1530 } else {
1531 // parse error
1532 }
1533 break;
1534
1535 /* An end tag whose tag name is "form" */
1536 case 'form':
1537 /* Let node be the element that the form element pointer is set to. */
1538 $node = $this->form_pointer;
1539 /* Set the form element pointer to null. */
1540 $this->form_pointer = null;
1541 /* If node is null or the stack of open elements does not
1542 * have node in scope, then this is a parse error; ignore the token. */
1543 if ($node === null || !in_array($node, $this->stack)) {
1544 // parse error
1545 $this->ignored = true;
1546 } else {
1547 /* 1. Generate implied end tags. */
1548 $this->generateImpliedEndTags();
1549 /* 2. If the current node is not node, then this is a parse error. */
1550 if (end($this->stack) !== $node) {
1551 // parse error
1552 }
1553 /* 3. Remove node from the stack of open elements. */
1554 array_splice($this->stack, array_search($node, $this->stack, true), 1);
1555 }
1556
1557 break;
1558
1559 /* An end tag whose tag name is "p" */
1560 case 'p':
1561 /* If the stack of open elements has a p element in scope,
1562 then generate implied end tags, except for p elements. */
1563 if($this->elementInScope('p')) {
1564 /* Generate implied end tags, except for elements with
1565 * the same tag name as the token. */
1566 $this->generateImpliedEndTags(array('p'));
1567
1568 /* If the current node is not a p element, then this is
1569 a parse error. */
1570 // XERROR: implement
1571
1572 /* Pop elements from the stack of open elements until
1573 * an element with the same tag name as the token has
1574 * been popped from the stack. */
1575 do {
1576 $node = array_pop($this->stack);
1577 } while ($node->tagName !== 'p');
1578
1579 } else {
1580 // parse error
1581 $this->emitToken(array(
1582 'name' => 'p',
1583 'type' => HTML5_Tokenizer::STARTTAG,
1584 ));
1585 $this->emitToken($token);
1586 }
1587 break;
1588
1589 /* An end tag whose tag name is "li" */
1590 case 'li':
1591 /* If the stack of open elements does not have an element
1592 * in list item scope with the same tag name as that of the
1593 * token, then this is a parse error; ignore the token. */
1594 if ($this->elementInScope($token['name'], self::SCOPE_LISTITEM)) {
1595 /* Generate implied end tags, except for elements with the
1596 * same tag name as the token. */
1597 $this->generateImpliedEndTags(array($token['name']));
1598 /* If the current node is not an element with the same tag
1599 * name as that of the token, then this is a parse error. */
1600 // XERROR: parse error
1601 /* Pop elements from the stack of open elements until an
1602 * element with the same tag name as the token has been
1603 * popped from the stack. */
1604 do {
1605 $node = array_pop($this->stack);
1606 } while ($node->tagName !== $token['name']);
1607 } else {
1608 // XERROR: parse error
1609 }
1610 break;
1611
1612 /* An end tag whose tag name is "dc", "dd", "ds", "dt" */
1613 case 'dc': case 'dd': case 'ds': case 'dt':
1614 if($this->elementInScope($token['name'])) {
1615 $this->generateImpliedEndTags(array($token['name']));
1616
1617 /* If the current node is not an element with the same
1618 tag name as the token, then this is a parse error. */
1619 // XERROR: implement parse error
1620
1621 /* Pop elements from the stack of open elements until
1622 * an element with the same tag name as the token has
1623 * been popped from the stack. */
1624 do {
1625 $node = array_pop($this->stack);
1626 } while ($node->tagName !== $token['name']);
1627
1628 } else {
1629 // XERROR: parse error
1630 }
1631 break;
1632
1633 /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
1634 "h5", "h6" */
1635 case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
1636 $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
1637
1638 /* If the stack of open elements has in scope an element whose
1639 tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
1640 generate implied end tags. */
1641 if($this->elementInScope($elements)) {
1642 $this->generateImpliedEndTags();
1643
1644 /* Now, if the current node is not an element with the same
1645 tag name as that of the token, then this is a parse error. */
1646 // XERROR: implement parse error
1647
1648 /* If the stack of open elements has in scope an element
1649 whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
1650 "h6", then pop elements from the stack until an element
1651 with one of those tag names has been popped from the stack. */
1652 do {
1653 $node = array_pop($this->stack);
1654 } while (!in_array($node->tagName, $elements));
1655 } else {
1656 // parse error
1657 }
1658 break;
1659
1660 /* An end tag whose tag name is one of: "a", "b", "big", "em",
1661 "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
1662 case 'a': case 'b': case 'big': case 'code': case 'em': case 'font':
1663 case 'i': case 'nobr': case 's': case 'small': case 'strike':
1664 case 'strong': case 'tt': case 'u':
1665 // XERROR: generally speaking this needs parse error logic
1666 /* 1. Let the formatting element be the last element in
1667 the list of active formatting elements that:
1668 * is between the end of the list and the last scope
1669 marker in the list, if any, or the start of the list
1670 otherwise, and
1671 * has the same tag name as the token.
1672 */
1673 while(true) {
1674 for($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
1675 if($this->a_formatting[$a] === self::MARKER) {
1676 break;
1677
1678 } elseif($this->a_formatting[$a]->tagName === $token['name']) {
1679 $formatting_element = $this->a_formatting[$a];
1680 $in_stack = in_array($formatting_element, $this->stack, true);
1681 $fe_af_pos = $a;
1682 break;
1683 }
1684 }
1685
1686 /* If there is no such node, or, if that node is
1687 also in the stack of open elements but the element
1688 is not in scope, then this is a parse error. Abort
1689 these steps. The token is ignored. */
1690 if(!isset($formatting_element) || ($in_stack &&
1691 !$this->elementInScope($token['name']))) {
1692 $this->ignored = true;
1693 break;
1694
1695 /* Otherwise, if there is such a node, but that node
1696 is not in the stack of open elements, then this is a
1697 parse error; remove the element from the list, and
1698 abort these steps. */
1699 } elseif(isset($formatting_element) && !$in_stack) {
1700 unset($this->a_formatting[$fe_af_pos]);
1701 $this->a_formatting = array_merge($this->a_formatting);
1702 break;
1703 }
1704
1705 /* Otherwise, there is a formatting element and that
1706 * element is in the stack and is in scope. If the
1707 * element is not the current node, this is a parse
1708 * error. In any case, proceed with the algorithm as
1709 * written in the following steps. */
1710 // XERROR: implement me
1711
1712 /* 2. Let the furthest block be the topmost node in the
1713 stack of open elements that is lower in the stack
1714 than the formatting element, and is not an element in
1715 the phrasing or formatting categories. There might
1716 not be one. */
1717 $fe_s_pos = array_search($formatting_element, $this->stack, true);
1718 $length = count($this->stack);
1719
1720 for($s = $fe_s_pos + 1; $s < $length; $s++) {
1721 $category = $this->getElementCategory($this->stack[$s]);
1722
1723 if($category !== self::PHRASING && $category !== self::FORMATTING) {
1724 $furthest_block = $this->stack[$s];
1725 break;
1726 }
1727 }
1728
1729 /* 3. If there is no furthest block, then the UA must
1730 skip the subsequent steps and instead just pop all
1731 the nodes from the bottom of the stack of open
1732 elements, from the current node up to the formatting
1733 element, and remove the formatting element from the
1734 list of active formatting elements. */
1735 if(!isset($furthest_block)) {
1736 for($n = $length - 1; $n >= $fe_s_pos; $n--) {
1737 array_pop($this->stack);
1738 }
1739
1740 unset($this->a_formatting[$fe_af_pos]);
1741 $this->a_formatting = array_merge($this->a_formatting);
1742 break;
1743 }
1744
1745 /* 4. Let the common ancestor be the element
1746 immediately above the formatting element in the stack
1747 of open elements. */
1748 $common_ancestor = $this->stack[$fe_s_pos - 1];
1749
1750 /* 5. Let a bookmark note the position of the
1751 formatting element in the list of active formatting
1752 elements relative to the elements on either side
1753 of it in the list. */
1754 $bookmark = $fe_af_pos;
1755
1756 /* 6. Let node and last node be the furthest block.
1757 Follow these steps: */
1758 $node = $furthest_block;
1759 $last_node = $furthest_block;
1760
1761 while(true) {
1762 for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
1763 /* 6.1 Let node be the element immediately
1764 prior to node in the stack of open elements. */
1765 $node = $this->stack[$n];
1766
1767 /* 6.2 If node is not in the list of active
1768 formatting elements, then remove node from
1769 the stack of open elements and then go back
1770 to step 1. */
1771 if(!in_array($node, $this->a_formatting, true)) {
1772 array_splice($this->stack, $n, 1);
1773
1774 } else {
1775 break;
1776 }
1777 }
1778
1779 /* 6.3 Otherwise, if node is the formatting
1780 element, then go to the next step in the overall
1781 algorithm. */
1782 if($node === $formatting_element) {
1783 break;
1784
1785 /* 6.4 Otherwise, if last node is the furthest
1786 block, then move the aforementioned bookmark to
1787 be immediately after the node in the list of
1788 active formatting elements. */
1789 } elseif($last_node === $furthest_block) {
1790 $bookmark = array_search($node, $this->a_formatting, true) + 1;
1791 }
1792
1793 /* 6.5 Create an element for the token for which
1794 * the element node was created, replace the entry
1795 * for node in the list of active formatting
1796 * elements with an entry for the new element,
1797 * replace the entry for node in the stack of open
1798 * elements with an entry for the new element, and
1799 * let node be the new element. */
1800 // we don't know what the token is anymore
1801 // XDOM
1802 $clone = $node->cloneNode();
1803 $a_pos = array_search($node, $this->a_formatting, true);
1804 $s_pos = array_search($node, $this->stack, true);
1805 $this->a_formatting[$a_pos] = $clone;
1806 $this->stack[$s_pos] = $clone;
1807 $node = $clone;
1808
1809 /* 6.6 Insert last node into node, first removing
1810 it from its previous parent node if any. */
1811 // XDOM
1812 if($last_node->parentNode !== null) {
1813 $last_node->parentNode->removeChild($last_node);
1814 }
1815
1816 // XDOM
1817 $node->appendChild($last_node);
1818
1819 /* 6.7 Let last node be node. */
1820 $last_node = $node;
1821
1822 /* 6.8 Return to step 1 of this inner set of steps. */
1823 }
1824
1825 /* 7. If the common ancestor node is a table, tbody,
1826 * tfoot, thead, or tr element, then, foster parent
1827 * whatever last node ended up being in the previous
1828 * step, first removing it from its previous parent
1829 * node if any. */
1830 // XDOM
1831 if ($last_node->parentNode) { // common step
1832 $last_node->parentNode->removeChild($last_node);
1833 }
1834 if (in_array($common_ancestor->tagName, array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
1835 $this->fosterParent($last_node);
1836 /* Otherwise, append whatever last node ended up being
1837 * in the previous step to the common ancestor node,
1838 * first removing it from its previous parent node if
1839 * any. */
1840 } else {
1841 // XDOM
1842 $common_ancestor->appendChild($last_node);
1843 }
1844
1845 /* 8. Create an element for the token for which the
1846 * formatting element was created. */
1847 // XDOM
1848 $clone = $formatting_element->cloneNode();
1849
1850 /* 9. Take all of the child nodes of the furthest
1851 block and append them to the element created in the
1852 last step. */
1853 // XDOM
1854 while($furthest_block->hasChildNodes()) {
1855 $child = $furthest_block->firstChild;
1856 $furthest_block->removeChild($child);
1857 $clone->appendChild($child);
1858 }
1859
1860 /* 10. Append that clone to the furthest block. */
1861 // XDOM
1862 $furthest_block->appendChild($clone);
1863
1864 /* 11. Remove the formatting element from the list
1865 of active formatting elements, and insert the new element
1866 into the list of active formatting elements at the
1867 position of the aforementioned bookmark. */
1868 $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
1869 array_splice($this->a_formatting, $fe_af_pos, 1);
1870
1871 $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
1872 $af_part2 = array_slice($this->a_formatting, $bookmark);
1873 $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
1874
1875 /* 12. Remove the formatting element from the stack
1876 of open elements, and insert the new element into the stack
1877 of open elements immediately below the position of the
1878 furthest block in that stack. */
1879 $fe_s_pos = array_search($formatting_element, $this->stack, true);
1880 array_splice($this->stack, $fe_s_pos, 1);
1881
1882 $fb_s_pos = array_search($furthest_block, $this->stack, true);
1883 $s_part1 = array_slice($this->stack, 0, $fb_s_pos + 1);
1884 $s_part2 = array_slice($this->stack, $fb_s_pos + 1);
1885 $this->stack = array_merge($s_part1, array($clone), $s_part2);
1886
1887 /* 13. Jump back to step 1 in this series of steps. */
1888 unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
1889 }
1890 break;
1891
1892 case 'applet': case 'button': case 'marquee': case 'object':
1893 /* If the stack of open elements has an element in scope whose
1894 tag name matches the tag name of the token, then generate implied
1895 tags. */
1896 if($this->elementInScope($token['name'])) {
1897 $this->generateImpliedEndTags();
1898
1899 /* Now, if the current node is not an element with the same
1900 tag name as the token, then this is a parse error. */
1901 // XERROR: implement logic
1902
1903 /* Pop elements from the stack of open elements until
1904 * an element with the same tag name as the token has
1905 * been popped from the stack. */
1906 do {
1907 $node = array_pop($this->stack);
1908 } while ($node->tagName !== $token['name']);
1909
1910 /* Clear the list of active formatting elements up to the
1911 * last marker. */
1912 $keys = array_keys($this->a_formatting, self::MARKER, true);
1913 $marker = end($keys);
1914
1915 for($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
1916 array_pop($this->a_formatting);
1917 }
1918 } else {
1919 // parse error
1920 }
1921 break;
1922
1923 case 'br':
1924 // Parse error
1925 $this->emitToken(array(
1926 'name' => 'br',
1927 'type' => HTML5_Tokenizer::STARTTAG,
1928 ));
1929 break;
1930
1931 /* An end tag token not covered by the previous entries */
1932 default:
1933 for($n = count($this->stack) - 1; $n >= 0; $n--) {
1934 /* Initialise node to be the current node (the bottommost
1935 node of the stack). */
1936 $node = $this->stack[$n];
1937
1938 /* If node has the same tag name as the end tag token,
1939 then: */
1940 if($token['name'] === $node->tagName) {
1941 /* Generate implied end tags. */
1942 $this->generateImpliedEndTags();
1943
1944 /* If the tag name of the end tag token does not
1945 match the tag name of the current node, this is a
1946 parse error. */
1947 // XERROR: implement this
1948
1949 /* Pop all the nodes from the current node up to
1950 node, including node, then stop these steps. */
1951 // XSKETCHY
1952 do {
1953 $pop = array_pop($this->stack);
1954 } while ($pop !== $node);
1955 break;
1956
1957 } else {
1958 $category = $this->getElementCategory($node);
1959
1960 if($category !== self::FORMATTING && $category !== self::PHRASING) {
1961 /* Otherwise, if node is in neither the formatting
1962 category nor the phrasing category, then this is a
1963 parse error. Stop this algorithm. The end tag token
1964 is ignored. */
1965 $this->ignored = true;
1966 break;
1967 // parse error
1968 }
1969 }
1970 /* Set node to the previous entry in the stack of open elements. Loop. */
1971 }
1972 break;
1973 }
1974 break;
1975 }
1976 break;
1977
1978 case self::IN_CDATA_RCDATA:
1979 if (
1980 $token['type'] === HTML5_Tokenizer::CHARACTER ||
1981 $token['type'] === HTML5_Tokenizer::SPACECHARACTER
1982 ) {
1983 $this->insertText($token['data']);
1984 } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
1985 // parse error
1986 /* If the current node is a script element, mark the script
1987 * element as "already executed". */
1988 // probably not necessary
1989 array_pop($this->stack);
1990 $this->mode = $this->original_mode;
1991 $this->emitToken($token);
1992 } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'script') {
1993 array_pop($this->stack);
1994 $this->mode = $this->original_mode;
1995 // we're ignoring all of the execution stuff
1996 } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG) {
1997 array_pop($this->stack);
1998 $this->mode = $this->original_mode;
1999 }
2000 break;
2001
2002 case self::IN_TABLE:
2003 $clear = array('html', 'table');
2004
2005 /* A character token */
2006 if ($token['type'] === HTML5_Tokenizer::CHARACTER ||
2007 $token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
2008 /* Let the pending table character tokens
2009 * be an empty list of tokens. */
2010 $this->pendingTableCharacters = "";
2011 $this->pendingTableCharactersDirty = false;
2012 /* Let the original insertion mode be the current
2013 * insertion mode. */
2014 $this->original_mode = $this->mode;
2015 /* Switch the insertion mode to
2016 * "in table text" and
2017 * reprocess the token. */
2018 $this->mode = self::IN_TABLE_TEXT;
2019 $this->emitToken($token);
2020
2021 /* A comment token */
2022 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
2023 /* Append a Comment node to the current node with the data
2024 attribute set to the data given in the comment token. */
2025 $this->insertComment($token['data']);
2026
2027 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
2028 // parse error
2029
2030 /* A start tag whose tag name is "caption" */
2031 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2032 $token['name'] === 'caption') {
2033 /* Clear the stack back to a table context. */
2034 $this->clearStackToTableContext($clear);
2035
2036 /* Insert a marker at the end of the list of active
2037 formatting elements. */
2038 $this->a_formatting[] = self::MARKER;
2039
2040 /* Insert an HTML element for the token, then switch the
2041 insertion mode to "in caption". */
2042 $this->insertElement($token);
2043 $this->mode = self::IN_CAPTION;
2044
2045 /* A start tag whose tag name is "colgroup" */
2046 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2047 $token['name'] === 'colgroup') {
2048 /* Clear the stack back to a table context. */
2049 $this->clearStackToTableContext($clear);
2050
2051 /* Insert an HTML element for the token, then switch the
2052 insertion mode to "in column group". */
2053 $this->insertElement($token);
2054 $this->mode = self::IN_COLUMN_GROUP;
2055
2056 /* A start tag whose tag name is "col" */
2057 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2058 $token['name'] === 'col') {
2059 $this->emitToken(array(
2060 'name' => 'colgroup',
2061 'type' => HTML5_Tokenizer::STARTTAG,
2062 'attr' => array()
2063 ));
2064
2065 $this->emitToken($token);
2066
2067 /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
2068 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
2069 array('tbody', 'tfoot', 'thead'))) {
2070 /* Clear the stack back to a table context. */
2071 $this->clearStackToTableContext($clear);
2072
2073 /* Insert an HTML element for the token, then switch the insertion
2074 mode to "in table body". */
2075 $this->insertElement($token);
2076 $this->mode = self::IN_TABLE_BODY;
2077
2078 /* A start tag whose tag name is one of: "td", "th", "tr" */
2079 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2080 in_array($token['name'], array('td', 'th', 'tr'))) {
2081 /* Act as if a start tag token with the tag name "tbody" had been
2082 seen, then reprocess the current token. */
2083 $this->emitToken(array(
2084 'name' => 'tbody',
2085 'type' => HTML5_Tokenizer::STARTTAG,
2086 'attr' => array()
2087 ));
2088
2089 $this->emitToken($token);
2090
2091 /* A start tag whose tag name is "table" */
2092 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2093 $token['name'] === 'table') {
2094 /* Parse error. Act as if an end tag token with the tag name "table"
2095 had been seen, then, if that token wasn't ignored, reprocess the
2096 current token. */
2097 $this->emitToken(array(
2098 'name' => 'table',
2099 'type' => HTML5_Tokenizer::ENDTAG
2100 ));
2101
2102 if (!$this->ignored) $this->emitToken($token);
2103
2104 /* An end tag whose tag name is "table" */
2105 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2106 $token['name'] === 'table') {
2107 /* If the stack of open elements does not have an element in table
2108 scope with the same tag name as the token, this is a parse error.
2109 Ignore the token. (fragment case) */
2110 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2111 $this->ignored = true;
2112
2113 /* Otherwise: */
2114 } else {
2115 do {
2116 $node = array_pop($this->stack);
2117 } while ($node->tagName !== 'table');
2118
2119 /* Reset the insertion mode appropriately. */
2120 $this->resetInsertionMode();
2121 }
2122
2123 /* An end tag whose tag name is one of: "body", "caption", "col",
2124 "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
2125 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
2126 array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td',
2127 'tfoot', 'th', 'thead', 'tr'))) {
2128 // Parse error. Ignore the token.
2129
2130 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2131 ($token['name'] === 'style' || $token['name'] === 'script')) {
2132 $this->processWithRulesFor($token, self::IN_HEAD);
2133
2134 } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'input' &&
2135 // assignment is intentional
2136 /* If the token does not have an attribute with the name "type", or
2137 * if it does, but that attribute's value is not an ASCII
2138 * case-insensitive match for the string "hidden", then: act as
2139 * described in the "anything else" entry below. */
2140 ($type = $this->getAttr($token, 'type')) && strtolower($type) === 'hidden') {
2141 // I.e., if its an input with the type attribute == 'hidden'
2142 /* Otherwise */
2143 // parse error
2144 $this->insertElement($token);
2145 array_pop($this->stack);
2146 } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
2147 /* If the current node is not the root html element, then this is a parse error. */
2148 if (end($this->stack)->tagName !== 'html') {
2149 // Note: It can only be the current node in the fragment case.
2150 // parse error
2151 }
2152 /* Stop parsing. */
2153 /* Anything else */
2154 } else {
2155 /* Parse error. Process the token as if the insertion mode was "in
2156 body", with the following exception: */
2157
2158 $old = $this->foster_parent;
2159 $this->foster_parent = true;
2160 $this->processWithRulesFor($token, self::IN_BODY);
2161 $this->foster_parent = $old;
2162 }
2163 break;
2164
2165 case self::IN_TABLE_TEXT:
2166 /* A character token */
2167 if($token['type'] === HTML5_Tokenizer::CHARACTER) {
2168 /* Append the character token to the pending table
2169 * character tokens list. */
2170 $this->pendingTableCharacters .= $token['data'];
2171 $this->pendingTableCharactersDirty = true;
2172 } elseif ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
2173 $this->pendingTableCharacters .= $token['data'];
2174 /* Anything else */
2175 } else {
2176 if ($this->pendingTableCharacters !== '' && is_string($this->pendingTableCharacters)) {
2177 /* If any of the tokens in the pending table character tokens list
2178 * are character tokens that are not one of U+0009 CHARACTER
2179 * TABULATION, U+000A LINE FEED (LF), U+000C FORM FEED (FF), or
2180 * U+0020 SPACE, then reprocess those character tokens using the
2181 * rules given in the "anything else" entry in the in table"
2182 * insertion mode.*/
2183 if ($this->pendingTableCharactersDirty) {
2184 /* Parse error. Process the token using the rules for the
2185 * "in body" insertion mode, except that if the current
2186 * node is a table, tbody, tfoot, thead, or tr element,
2187 * then, whenever a node would be inserted into the current
2188 * node, it must instead be foster parented. */
2189 // XERROR
2190 $old = $this->foster_parent;
2191 $this->foster_parent = true;
2192 $text_token = array(
2193 'type' => HTML5_Tokenizer::CHARACTER,
2194 'data' => $this->pendingTableCharacters,
2195 );
2196 $this->processWithRulesFor($text_token, self::IN_BODY);
2197 $this->foster_parent = $old;
2198
2199 /* Otherwise, insert the characters given by the pending table
2200 * character tokens list into the current node. */
2201 } else {
2202 $this->insertText($this->pendingTableCharacters);
2203 }
2204 $this->pendingTableCharacters = null;
2205 $this->pendingTableCharactersNull = null;
2206 }
2207
2208 /* Switch the insertion mode to the original insertion mode and
2209 * reprocess the token.
2210 */
2211 $this->mode = $this->original_mode;
2212 $this->emitToken($token);
2213 }
2214 break;
2215
2216 case self::IN_CAPTION:
2217 /* An end tag whose tag name is "caption" */
2218 if($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'caption') {
2219 /* If the stack of open elements does not have an element in table
2220 scope with the same tag name as the token, this is a parse error.
2221 Ignore the token. (fragment case) */
2222 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2223 $this->ignored = true;
2224 // Ignore
2225
2226 /* Otherwise: */
2227 } else {
2228 /* Generate implied end tags. */
2229 $this->generateImpliedEndTags();
2230
2231 /* Now, if the current node is not a caption element, then this
2232 is a parse error. */
2233 // XERROR: implement
2234
2235 /* Pop elements from this stack until a caption element has
2236 been popped from the stack. */
2237 do {
2238 $node = array_pop($this->stack);
2239 } while ($node->tagName !== 'caption');
2240
2241 /* Clear the list of active formatting elements up to the last
2242 marker. */
2243 $this->clearTheActiveFormattingElementsUpToTheLastMarker();
2244
2245 /* Switch the insertion mode to "in table". */
2246 $this->mode = self::IN_TABLE;
2247 }
2248
2249 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2250 "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
2251 name is "table" */
2252 } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
2253 array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
2254 'thead', 'tr'))) || ($token['type'] === HTML5_Tokenizer::ENDTAG &&
2255 $token['name'] === 'table')) {
2256 /* Parse error. Act as if an end tag with the tag name "caption"
2257 had been seen, then, if that token wasn't ignored, reprocess the
2258 current token. */
2259 $this->emitToken(array(
2260 'name' => 'caption',
2261 'type' => HTML5_Tokenizer::ENDTAG
2262 ));
2263
2264 if (!$this->ignored) $this->emitToken($token);
2265
2266 /* An end tag whose tag name is one of: "body", "col", "colgroup",
2267 "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
2268 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
2269 array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th',
2270 'thead', 'tr'))) {
2271 // Parse error. Ignore the token.
2272 $this->ignored = true;
2273
2274 /* Anything else */
2275 } else {
2276 /* Process the token as if the insertion mode was "in body". */
2277 $this->processWithRulesFor($token, self::IN_BODY);
2278 }
2279 break;
2280
2281 case self::IN_COLUMN_GROUP:
2282 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2283 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2284 or U+0020 SPACE */
2285 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
2286 /* Append the character to the current node. */
2287 $this->insertText($token['data']);
2288
2289 /* A comment token */
2290 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
2291 /* Append a Comment node to the current node with the data
2292 attribute set to the data given in the comment token. */
2293 $this->insertToken($token['data']);
2294
2295 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
2296 // parse error
2297
2298 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
2299 $this->processWithRulesFor($token, self::IN_BODY);
2300
2301 /* A start tag whose tag name is "col" */
2302 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'col') {
2303 /* Insert a col element for the token. Immediately pop the current
2304 node off the stack of open elements. */
2305 $this->insertElement($token);
2306 array_pop($this->stack);
2307 // XERROR: Acknowledge the token's self-closing flag, if it is set.
2308
2309 /* An end tag whose tag name is "colgroup" */
2310 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2311 $token['name'] === 'colgroup') {
2312 /* If the current node is the root html element, then this is a
2313 parse error, ignore the token. (fragment case) */
2314 if(end($this->stack)->tagName === 'html') {
2315 $this->ignored = true;
2316
2317 /* Otherwise, pop the current node (which will be a colgroup
2318 element) from the stack of open elements. Switch the insertion
2319 mode to "in table". */
2320 } else {
2321 array_pop($this->stack);
2322 $this->mode = self::IN_TABLE;
2323 }
2324
2325 /* An end tag whose tag name is "col" */
2326 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'col') {
2327 /* Parse error. Ignore the token. */
2328 $this->ignored = true;
2329
2330 /* An end-of-file token */
2331 /* If the current node is the root html element */
2332 } elseif($token['type'] === HTML5_Tokenizer::EOF && end($this->stack)->tagName === 'html') {
2333 /* Stop parsing */
2334
2335 /* Anything else */
2336 } else {
2337 /* Act as if an end tag with the tag name "colgroup" had been seen,
2338 and then, if that token wasn't ignored, reprocess the current token. */
2339 $this->emitToken(array(
2340 'name' => 'colgroup',
2341 'type' => HTML5_Tokenizer::ENDTAG
2342 ));
2343
2344 if (!$this->ignored) $this->emitToken($token);
2345 }
2346 break;
2347
2348 case self::IN_TABLE_BODY:
2349 $clear = array('tbody', 'tfoot', 'thead', 'html');
2350
2351 /* A start tag whose tag name is "tr" */
2352 if($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'tr') {
2353 /* Clear the stack back to a table body context. */
2354 $this->clearStackToTableContext($clear);
2355
2356 /* Insert a tr element for the token, then switch the insertion
2357 mode to "in row". */
2358 $this->insertElement($token);
2359 $this->mode = self::IN_ROW;
2360
2361 /* A start tag whose tag name is one of: "th", "td" */
2362 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2363 ($token['name'] === 'th' || $token['name'] === 'td')) {
2364 /* Parse error. Act as if a start tag with the tag name "tr" had
2365 been seen, then reprocess the current token. */
2366 $this->emitToken(array(
2367 'name' => 'tr',
2368 'type' => HTML5_Tokenizer::STARTTAG,
2369 'attr' => array()
2370 ));
2371
2372 $this->emitToken($token);
2373
2374 /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
2375 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2376 in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
2377 /* If the stack of open elements does not have an element in table
2378 scope with the same tag name as the token, this is a parse error.
2379 Ignore the token. */
2380 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2381 // Parse error
2382 $this->ignored = true;
2383
2384 /* Otherwise: */
2385 } else {
2386 /* Clear the stack back to a table body context. */
2387 $this->clearStackToTableContext($clear);
2388
2389 /* Pop the current node from the stack of open elements. Switch
2390 the insertion mode to "in table". */
2391 array_pop($this->stack);
2392 $this->mode = self::IN_TABLE;
2393 }
2394
2395 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2396 "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
2397 } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
2398 array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead'))) ||
2399 ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'table')) {
2400 /* If the stack of open elements does not have a tbody, thead, or
2401 tfoot element in table scope, this is a parse error. Ignore the
2402 token. (fragment case) */
2403 if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), self::SCOPE_TABLE)) {
2404 // parse error
2405 $this->ignored = true;
2406
2407 /* Otherwise: */
2408 } else {
2409 /* Clear the stack back to a table body context. */
2410 $this->clearStackToTableContext($clear);
2411
2412 /* Act as if an end tag with the same tag name as the current
2413 node ("tbody", "tfoot", or "thead") had been seen, then
2414 reprocess the current token. */
2415 $this->emitToken(array(
2416 'name' => end($this->stack)->tagName,
2417 'type' => HTML5_Tokenizer::ENDTAG
2418 ));
2419
2420 $this->emitToken($token);
2421 }
2422
2423 /* An end tag whose tag name is one of: "body", "caption", "col",
2424 "colgroup", "html", "td", "th", "tr" */
2425 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
2426 array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
2427 /* Parse error. Ignore the token. */
2428 $this->ignored = true;
2429
2430 /* Anything else */
2431 } else {
2432 /* Process the token as if the insertion mode was "in table". */
2433 $this->processWithRulesFor($token, self::IN_TABLE);
2434 }
2435 break;
2436
2437 case self::IN_ROW:
2438 $clear = array('tr', 'html');
2439
2440 /* A start tag whose tag name is one of: "th", "td" */
2441 if($token['type'] === HTML5_Tokenizer::STARTTAG &&
2442 ($token['name'] === 'th' || $token['name'] === 'td')) {
2443 /* Clear the stack back to a table row context. */
2444 $this->clearStackToTableContext($clear);
2445
2446 /* Insert an HTML element for the token, then switch the insertion
2447 mode to "in cell". */
2448 $this->insertElement($token);
2449 $this->mode = self::IN_CELL;
2450
2451 /* Insert a marker at the end of the list of active formatting
2452 elements. */
2453 $this->a_formatting[] = self::MARKER;
2454
2455 /* An end tag whose tag name is "tr" */
2456 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'tr') {
2457 /* If the stack of open elements does not have an element in table
2458 scope with the same tag name as the token, this is a parse error.
2459 Ignore the token. (fragment case) */
2460 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2461 // Ignore.
2462 $this->ignored = true;
2463
2464 /* Otherwise: */
2465 } else {
2466 /* Clear the stack back to a table row context. */
2467 $this->clearStackToTableContext($clear);
2468
2469 /* Pop the current node (which will be a tr element) from the
2470 stack of open elements. Switch the insertion mode to "in table
2471 body". */
2472 array_pop($this->stack);
2473 $this->mode = self::IN_TABLE_BODY;
2474 }
2475
2476 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2477 "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
2478 } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
2479 array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) ||
2480 ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'table')) {
2481 /* Act as if an end tag with the tag name "tr" had been seen, then,
2482 if that token wasn't ignored, reprocess the current token. */
2483 $this->emitToken(array(
2484 'name' => 'tr',
2485 'type' => HTML5_Tokenizer::ENDTAG
2486 ));
2487 if (!$this->ignored) $this->emitToken($token);
2488
2489 /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
2490 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2491 in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
2492 /* If the stack of open elements does not have an element in table
2493 scope with the same tag name as the token, this is a parse error.
2494 Ignore the token. */
2495 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2496 $this->ignored = true;
2497
2498 /* Otherwise: */
2499 } else {
2500 /* Otherwise, act as if an end tag with the tag name "tr" had
2501 been seen, then reprocess the current token. */
2502 $this->emitToken(array(
2503 'name' => 'tr',
2504 'type' => HTML5_Tokenizer::ENDTAG
2505 ));
2506
2507 $this->emitToken($token);
2508 }
2509
2510 /* An end tag whose tag name is one of: "body", "caption", "col",
2511 "colgroup", "html", "td", "th" */
2512 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
2513 array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th'))) {
2514 /* Parse error. Ignore the token. */
2515 $this->ignored = true;
2516
2517 /* Anything else */
2518 } else {
2519 /* Process the token as if the insertion mode was "in table". */
2520 $this->processWithRulesFor($token, self::IN_TABLE);
2521 }
2522 break;
2523
2524 case self::IN_CELL:
2525 /* An end tag whose tag name is one of: "td", "th" */
2526 if($token['type'] === HTML5_Tokenizer::ENDTAG &&
2527 ($token['name'] === 'td' || $token['name'] === 'th')) {
2528 /* If the stack of open elements does not have an element in table
2529 scope with the same tag name as that of the token, then this is a
2530 parse error and the token must be ignored. */
2531 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2532 $this->ignored = true;
2533
2534 /* Otherwise: */
2535 } else {
2536 /* Generate implied end tags, except for elements with the same
2537 tag name as the token. */
2538 $this->generateImpliedEndTags(array($token['name']));
2539
2540 /* Now, if the current node is not an element with the same tag
2541 name as the token, then this is a parse error. */
2542 // XERROR: Implement parse error code
2543
2544 /* Pop elements from this stack until an element with the same
2545 tag name as the token has been popped from the stack. */
2546 do {
2547 $node = array_pop($this->stack);
2548 } while ($node->tagName !== $token['name']);
2549
2550 /* Clear the list of active formatting elements up to the last
2551 marker. */
2552 $this->clearTheActiveFormattingElementsUpToTheLastMarker();
2553
2554 /* Switch the insertion mode to "in row". (The current node
2555 will be a tr element at this point.) */
2556 $this->mode = self::IN_ROW;
2557 }
2558
2559 /* A start tag whose tag name is one of: "caption", "col", "colgroup",
2560 "tbody", "td", "tfoot", "th", "thead", "tr" */
2561 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
2562 array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
2563 'thead', 'tr'))) {
2564 /* If the stack of open elements does not have a td or th element
2565 in table scope, then this is a parse error; ignore the token.
2566 (fragment case) */
2567 if(!$this->elementInScope(array('td', 'th'), self::SCOPE_TABLE)) {
2568 // parse error
2569 $this->ignored = true;
2570
2571 /* Otherwise, close the cell (see below) and reprocess the current
2572 token. */
2573 } else {
2574 $this->closeCell();
2575 $this->emitToken($token);
2576 }
2577
2578 /* An end tag whose tag name is one of: "body", "caption", "col",
2579 "colgroup", "html" */
2580 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
2581 array('body', 'caption', 'col', 'colgroup', 'html'))) {
2582 /* Parse error. Ignore the token. */
2583 $this->ignored = true;
2584
2585 /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
2586 "thead", "tr" */
2587 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
2588 array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
2589 /* If the stack of open elements does not have a td or th element
2590 in table scope, then this is a parse error; ignore the token.
2591 (innerHTML case) */
2592 if(!$this->elementInScope(array('td', 'th'), self::SCOPE_TABLE)) {
2593 // Parse error
2594 $this->ignored = true;
2595
2596 /* Otherwise, close the cell (see below) and reprocess the current
2597 token. */
2598 } else {
2599 $this->closeCell();
2600 $this->emitToken($token);
2601 }
2602
2603 /* Anything else */
2604 } else {
2605 /* Process the token as if the insertion mode was "in body". */
2606 $this->processWithRulesFor($token, self::IN_BODY);
2607 }
2608 break;
2609
2610 case self::IN_SELECT:
2611 /* Handle the token as follows: */
2612
2613 /* A character token */
2614 if(
2615 $token['type'] === HTML5_Tokenizer::CHARACTER ||
2616 $token['type'] === HTML5_Tokenizer::SPACECHARACTER
2617 ) {
2618 /* Append the token's character to the current node. */
2619 $this->insertText($token['data']);
2620
2621 /* A comment token */
2622 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
2623 /* Append a Comment node to the current node with the data
2624 attribute set to the data given in the comment token. */
2625 $this->insertComment($token['data']);
2626
2627 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
2628 // parse error
2629
2630 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
2631 $this->processWithRulesFor($token, self::INBODY);
2632
2633 /* A start tag token whose tag name is "option" */
2634 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2635 $token['name'] === 'option') {
2636 /* If the current node is an option element, act as if an end tag
2637 with the tag name "option" had been seen. */
2638 if(end($this->stack)->tagName === 'option') {
2639 $this->emitToken(array(
2640 'name' => 'option',
2641 'type' => HTML5_Tokenizer::ENDTAG
2642 ));
2643 }
2644
2645 /* Insert an HTML element for the token. */
2646 $this->insertElement($token);
2647
2648 /* A start tag token whose tag name is "optgroup" */
2649 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2650 $token['name'] === 'optgroup') {
2651 /* If the current node is an option element, act as if an end tag
2652 with the tag name "option" had been seen. */
2653 if(end($this->stack)->tagName === 'option') {
2654 $this->emitToken(array(
2655 'name' => 'option',
2656 'type' => HTML5_Tokenizer::ENDTAG
2657 ));
2658 }
2659
2660 /* If the current node is an optgroup element, act as if an end tag
2661 with the tag name "optgroup" had been seen. */
2662 if(end($this->stack)->tagName === 'optgroup') {
2663 $this->emitToken(array(
2664 'name' => 'optgroup',
2665 'type' => HTML5_Tokenizer::ENDTAG
2666 ));
2667 }
2668
2669 /* Insert an HTML element for the token. */
2670 $this->insertElement($token);
2671
2672 /* An end tag token whose tag name is "optgroup" */
2673 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2674 $token['name'] === 'optgroup') {
2675 /* First, if the current node is an option element, and the node
2676 immediately before it in the stack of open elements is an optgroup
2677 element, then act as if an end tag with the tag name "option" had
2678 been seen. */
2679 $elements_in_stack = count($this->stack);
2680
2681 if($this->stack[$elements_in_stack - 1]->tagName === 'option' &&
2682 $this->stack[$elements_in_stack - 2]->tagName === 'optgroup') {
2683 $this->emitToken(array(
2684 'name' => 'option',
2685 'type' => HTML5_Tokenizer::ENDTAG
2686 ));
2687 }
2688
2689 /* If the current node is an optgroup element, then pop that node
2690 from the stack of open elements. Otherwise, this is a parse error,
2691 ignore the token. */
2692 if(end($this->stack)->tagName === 'optgroup') {
2693 array_pop($this->stack);
2694 } else {
2695 // parse error
2696 $this->ignored = true;
2697 }
2698
2699 /* An end tag token whose tag name is "option" */
2700 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2701 $token['name'] === 'option') {
2702 /* If the current node is an option element, then pop that node
2703 from the stack of open elements. Otherwise, this is a parse error,
2704 ignore the token. */
2705 if(end($this->stack)->tagName === 'option') {
2706 array_pop($this->stack);
2707 } else {
2708 // parse error
2709 $this->ignored = true;
2710 }
2711
2712 /* An end tag whose tag name is "select" */
2713 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2714 $token['name'] === 'select') {
2715 /* If the stack of open elements does not have an element in table
2716 scope with the same tag name as the token, this is a parse error.
2717 Ignore the token. (fragment case) */
2718 if(!$this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2719 $this->ignored = true;
2720 // parse error
2721
2722 /* Otherwise: */
2723 } else {
2724 /* Pop elements from the stack of open elements until a select
2725 element has been popped from the stack. */
2726 do {
2727 $node = array_pop($this->stack);
2728 } while ($node->tagName !== 'select');
2729
2730 /* Reset the insertion mode appropriately. */
2731 $this->resetInsertionMode();
2732 }
2733
2734 /* A start tag whose tag name is "select" */
2735 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'select') {
2736 /* Parse error. Act as if the token had been an end tag with the
2737 tag name "select" instead. */
2738 $this->emitToken(array(
2739 'name' => 'select',
2740 'type' => HTML5_Tokenizer::ENDTAG
2741 ));
2742
2743 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
2744 ($token['name'] === 'input' || $token['name'] === 'keygen' || $token['name'] === 'textarea')) {
2745 // parse error
2746 $this->emitToken(array(
2747 'name' => 'select',
2748 'type' => HTML5_Tokenizer::ENDTAG
2749 ));
2750 $this->emitToken($token);
2751
2752 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'script') {
2753 $this->processWithRulesFor($token, self::IN_HEAD);
2754
2755 } elseif($token['type'] === HTML5_Tokenizer::EOF) {
2756 // XERROR: If the current node is not the root html element, then this is a parse error.
2757 /* Stop parsing */
2758
2759 /* Anything else */
2760 } else {
2761 /* Parse error. Ignore the token. */
2762 $this->ignored = true;
2763 }
2764 break;
2765
2766 case self::IN_SELECT_IN_TABLE:
2767
2768 if($token['type'] === HTML5_Tokenizer::STARTTAG &&
2769 in_array($token['name'], array('caption', 'table', 'tbody',
2770 'tfoot', 'thead', 'tr', 'td', 'th'))) {
2771 // parse error
2772 $this->emitToken(array(
2773 'name' => 'select',
2774 'type' => HTML5_Tokenizer::ENDTAG,
2775 ));
2776 $this->emitToken($token);
2777
2778 /* An end tag whose tag name is one of: "caption", "table", "tbody",
2779 "tfoot", "thead", "tr", "td", "th" */
2780 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
2781 in_array($token['name'], array('caption', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'td', 'th'))) {
2782 /* Parse error. */
2783 // parse error
2784
2785 /* If the stack of open elements has an element in table scope with
2786 the same tag name as that of the token, then act as if an end tag
2787 with the tag name "select" had been seen, and reprocess the token.
2788 Otherwise, ignore the token. */
2789 if($this->elementInScope($token['name'], self::SCOPE_TABLE)) {
2790 $this->emitToken(array(
2791 'name' => 'select',
2792 'type' => HTML5_Tokenizer::ENDTAG
2793 ));
2794
2795 $this->emitToken($token);
2796 } else {
2797 $this->ignored = true;
2798 }
2799 } else {
2800 $this->processWithRulesFor($token, self::IN_SELECT);
2801 }
2802 break;
2803
2804 case self::IN_FOREIGN_CONTENT:
2805 if ($token['type'] === HTML5_Tokenizer::CHARACTER ||
2806 $token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
2807 $this->insertText($token['data']);
2808 } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
2809 $this->insertComment($token['data']);
2810 } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
2811 // XERROR: parse error
2812 } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
2813 $token['name'] === 'script' && end($this->stack)->tagName === 'script' &&
2814 // XDOM
2815 end($this->stack)->namespaceURI === self::NS_SVG) {
2816 array_pop($this->stack);
2817 // a bunch of script running mumbo jumbo
2818 } elseif (
2819 ($token['type'] === HTML5_Tokenizer::STARTTAG &&
2820 ((
2821 $token['name'] !== 'mglyph' &&
2822 $token['name'] !== 'malignmark' &&
2823 // XDOM
2824 end($this->stack)->namespaceURI === self::NS_MATHML &&
2825 in_array(end($this->stack)->tagName, array('mi', 'mo', 'mn', 'ms', 'mtext'))
2826 ) ||
2827 (
2828 $token['name'] === 'svg' &&
2829 // XDOM
2830 end($this->stack)->namespaceURI === self::NS_MATHML &&
2831 end($this->stack)->tagName === 'annotation-xml'
2832 ) ||
2833 (
2834 // XDOM
2835 end($this->stack)->namespaceURI === self::NS_SVG &&
2836 in_array(end($this->stack)->tagName, array('foreignObject', 'desc', 'title'))
2837 ) ||
2838 (
2839 // XSKETCHY && XDOM
2840 end($this->stack)->namespaceURI === self::NS_HTML
2841 ))
2842 ) || $token['type'] === HTML5_Tokenizer::ENDTAG
2843 ) {
2844 $this->processWithRulesFor($token, $this->secondary_mode);
2845 /* If, after doing so, the insertion mode is still "in foreign
2846 * content", but there is no element in scope that has a namespace
2847 * other than the HTML namespace, switch the insertion mode to the
2848 * secondary insertion mode. */
2849 if ($this->mode === self::IN_FOREIGN_CONTENT) {
2850 $found = false;
2851 // this basically duplicates elementInScope()
2852 for ($i = count($this->stack) - 1; $i >= 0; $i--) {
2853 // XDOM
2854 $node = $this->stack[$i];
2855 if ($node->namespaceURI !== self::NS_HTML) {
2856 $found = true;
2857 break;
2858 } elseif (in_array($node->tagName, array('table', 'html',
2859 'applet', 'caption', 'td', 'th', 'button', 'marquee',
2860 'object')) || ($node->tagName === 'foreignObject' &&
2861 $node->namespaceURI === self::NS_SVG)) {
2862 break;
2863 }
2864 }
2865 if (!$found) {
2866 $this->mode = $this->secondary_mode;
2867 }
2868 }
2869 } elseif ($token['type'] === HTML5_Tokenizer::EOF || (
2870 $token['type'] === HTML5_Tokenizer::STARTTAG &&
2871 (in_array($token['name'], array('b', "big", "blockquote", "body", "br",
2872 "center", "code", "dc", "dd", "div", "dl", "ds", "dt", "em", "embed", "h1", "h2",
2873 "h3", "h4", "h5", "h6", "head", "hr", "i", "img", "li", "listing",
2874 "menu", "meta", "nobr", "ol", "p", "pre", "ruby", "s", "small",
2875 "span", "strong", "strike", "sub", "sup", "table", "tt", "u", "ul",
2876 "var")) || ($token['name'] === 'font' && ($this->getAttr($token, 'color') ||
2877 $this->getAttr($token, 'face') || $this->getAttr($token, 'size')))))) {
2878 // XERROR: parse error
2879 do {
2880 $node = array_pop($this->stack);
2881 // XDOM
2882 } while ($node->namespaceURI !== self::NS_HTML);
2883 $this->stack[] = $node;
2884 $this->mode = $this->secondary_mode;
2885 $this->emitToken($token);
2886 } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG) {
2887 static $svg_lookup = array(
2888 'altglyph' => 'altGlyph',
2889 'altglyphdef' => 'altGlyphDef',
2890 'altglyphitem' => 'altGlyphItem',
2891 'animatecolor' => 'animateColor',
2892 'animatemotion' => 'animateMotion',
2893 'animatetransform' => 'animateTransform',
2894 'clippath' => 'clipPath',
2895 'feblend' => 'feBlend',
2896 'fecolormatrix' => 'feColorMatrix',
2897 'fecomponenttransfer' => 'feComponentTransfer',
2898 'fecomposite' => 'feComposite',
2899 'feconvolvematrix' => 'feConvolveMatrix',
2900 'fediffuselighting' => 'feDiffuseLighting',
2901 'fedisplacementmap' => 'feDisplacementMap',
2902 'fedistantlight' => 'feDistantLight',
2903 'feflood' => 'feFlood',
2904 'fefunca' => 'feFuncA',
2905 'fefuncb' => 'feFuncB',
2906 'fefuncg' => 'feFuncG',
2907 'fefuncr' => 'feFuncR',
2908 'fegaussianblur' => 'feGaussianBlur',
2909 'feimage' => 'feImage',
2910 'femerge' => 'feMerge',
2911 'femergenode' => 'feMergeNode',
2912 'femorphology' => 'feMorphology',
2913 'feoffset' => 'feOffset',
2914 'fepointlight' => 'fePointLight',
2915 'fespecularlighting' => 'feSpecularLighting',
2916 'fespotlight' => 'feSpotLight',
2917 'fetile' => 'feTile',
2918 'feturbulence' => 'feTurbulence',
2919 'foreignobject' => 'foreignObject',
2920 'glyphref' => 'glyphRef',
2921 'lineargradient' => 'linearGradient',
2922 'radialgradient' => 'radialGradient',
2923 'textpath' => 'textPath',
2924 );
2925 // XDOM
2926 $current = end($this->stack);
2927 if ($current->namespaceURI === self::NS_MATHML) {
2928 $token = $this->adjustMathMLAttributes($token);
2929 }
2930 if ($current->namespaceURI === self::NS_SVG &&
2931 isset($svg_lookup[$token['name']])) {
2932 $token['name'] = $svg_lookup[$token['name']];
2933 }
2934 if ($current->namespaceURI === self::NS_SVG) {
2935 $token = $this->adjustSVGAttributes($token);
2936 }
2937 $token = $this->adjustForeignAttributes($token);
2938 $this->insertForeignElement($token, $current->namespaceURI);
2939 if (isset($token['self-closing'])) {
2940 array_pop($this->stack);
2941 // XERROR: acknowledge self-closing flag
2942 }
2943 }
2944 break;
2945
2946 case self::AFTER_BODY:
2947 /* Handle the token as follows: */
2948
2949 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2950 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2951 or U+0020 SPACE */
2952 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
2953 /* Process the token as it would be processed if the insertion mode
2954 was "in body". */
2955 $this->processWithRulesFor($token, self::IN_BODY);
2956
2957 /* A comment token */
2958 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
2959 /* Append a Comment node to the first element in the stack of open
2960 elements (the html element), with the data attribute set to the
2961 data given in the comment token. */
2962 // XDOM
2963 $comment = $this->dom->createComment($token['data']);
2964 $this->stack[0]->appendChild($comment);
2965
2966 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
2967 // parse error
2968
2969 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
2970 $this->processWithRulesFor($token, self::IN_BODY);
2971
2972 /* An end tag with the tag name "html" */
2973 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'html') {
2974 /* If the parser was originally created as part of the HTML
2975 * fragment parsing algorithm, this is a parse error; ignore
2976 * the token. (fragment case) */
2977 $this->ignored = true;
2978 // XERROR: implement this
2979
2980 $this->mode = self::AFTER_AFTER_BODY;
2981
2982 } elseif($token['type'] === HTML5_Tokenizer::EOF) {
2983 /* Stop parsing */
2984
2985 /* Anything else */
2986 } else {
2987 /* Parse error. Set the insertion mode to "in body" and reprocess
2988 the token. */
2989 $this->mode = self::IN_BODY;
2990 $this->emitToken($token);
2991 }
2992 break;
2993
2994 case self::IN_FRAMESET:
2995 /* Handle the token as follows: */
2996
2997 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
2998 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
2999 U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
3000 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
3001 /* Append the character to the current node. */
3002 $this->insertText($token['data']);
3003
3004 /* A comment token */
3005 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
3006 /* Append a Comment node to the current node with the data
3007 attribute set to the data given in the comment token. */
3008 $this->insertComment($token['data']);
3009
3010 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
3011 // parse error
3012
3013 /* A start tag with the tag name "frameset" */
3014 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
3015 $token['name'] === 'frameset') {
3016 $this->insertElement($token);
3017
3018 /* An end tag with the tag name "frameset" */
3019 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
3020 $token['name'] === 'frameset') {
3021 /* If the current node is the root html element, then this is a
3022 parse error; ignore the token. (fragment case) */
3023 if(end($this->stack)->tagName === 'html') {
3024 $this->ignored = true;
3025 // Parse error
3026
3027 } else {
3028 /* Otherwise, pop the current node from the stack of open
3029 elements. */
3030 array_pop($this->stack);
3031
3032 /* If the parser was not originally created as part of the HTML
3033 * fragment parsing algorithm (fragment case), and the current
3034 * node is no longer a frameset element, then switch the
3035 * insertion mode to "after frameset". */
3036 $this->mode = self::AFTER_FRAMESET;
3037 }
3038
3039 /* A start tag with the tag name "frame" */
3040 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
3041 $token['name'] === 'frame') {
3042 /* Insert an HTML element for the token. */
3043 $this->insertElement($token);
3044
3045 /* Immediately pop the current node off the stack of open elements. */
3046 array_pop($this->stack);
3047
3048 // XERROR: Acknowledge the token's self-closing flag, if it is set.
3049
3050 /* A start tag with the tag name "noframes" */
3051 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
3052 $token['name'] === 'noframes') {
3053 /* Process the token using the rules for the "in head" insertion mode. */
3054 $this->processwithRulesFor($token, self::IN_HEAD);
3055
3056 } elseif($token['type'] === HTML5_Tokenizer::EOF) {
3057 // XERROR: If the current node is not the root html element, then this is a parse error.
3058 /* Stop parsing */
3059 /* Anything else */
3060 } else {
3061 /* Parse error. Ignore the token. */
3062 $this->ignored = true;
3063 }
3064 break;
3065
3066 case self::AFTER_FRAMESET:
3067 /* Handle the token as follows: */
3068
3069 /* A character token that is one of one of U+0009 CHARACTER TABULATION,
3070 U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
3071 U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
3072 if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
3073 /* Append the character to the current node. */
3074 $this->insertText($token['data']);
3075
3076 /* A comment token */
3077 } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
3078 /* Append a Comment node to the current node with the data
3079 attribute set to the data given in the comment token. */
3080 $this->insertComment($token['data']);
3081
3082 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
3083 // parse error
3084
3085 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
3086 $this->processWithRulesFor($token, self::IN_BODY);
3087
3088 /* An end tag with the tag name "html" */
3089 } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
3090 $token['name'] === 'html') {
3091 $this->mode = self::AFTER_AFTER_FRAMESET;
3092
3093 /* A start tag with the tag name "noframes" */
3094 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
3095 $token['name'] === 'noframes') {
3096 $this->processWithRulesFor($token, self::IN_HEAD);
3097
3098 } elseif($token['type'] === HTML5_Tokenizer::EOF) {
3099 /* Stop parsing */
3100
3101 /* Anything else */
3102 } else {
3103 /* Parse error. Ignore the token. */
3104 $this->ignored = true;
3105 }
3106 break;
3107
3108 case self::AFTER_AFTER_BODY:
3109 /* A comment token */
3110 if($token['type'] === HTML5_Tokenizer::COMMENT) {
3111 /* Append a Comment node to the Document object with the data
3112 attribute set to the data given in the comment token. */
3113 // XDOM
3114 $comment = $this->dom->createComment($token['data']);
3115 $this->dom->appendChild($comment);
3116
3117 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE ||
3118 $token['type'] === HTML5_Tokenizer::SPACECHARACTER ||
3119 ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html')) {
3120 $this->processWithRulesFor($token, self::IN_BODY);
3121
3122 /* An end-of-file token */
3123 } elseif($token['type'] === HTML5_Tokenizer::EOF) {
3124 /* OMG DONE!! */
3125 } else {
3126 // parse error
3127 $this->mode = self::IN_BODY;
3128 $this->emitToken($token);
3129 }
3130 break;
3131
3132 case self::AFTER_AFTER_FRAMESET:
3133 /* A comment token */
3134 if($token['type'] === HTML5_Tokenizer::COMMENT) {
3135 /* Append a Comment node to the Document object with the data
3136 attribute set to the data given in the comment token. */
3137 // XDOM
3138 $comment = $this->dom->createComment($token['data']);
3139 $this->dom->appendChild($comment);
3140
3141 } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE ||
3142 $token['type'] === HTML5_Tokenizer::SPACECHARACTER ||
3143 ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html')) {
3144 $this->processWithRulesFor($token, self::IN_BODY);
3145
3146 /* An end-of-file token */
3147 } elseif($token['type'] === HTML5_Tokenizer::EOF) {
3148 /* OMG DONE!! */
3149 } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'nofrmaes') {
3150 $this->processWithRulesFor($token, self::IN_HEAD);
3151 } else {
3152 // parse error
3153 }
3154 break;
3155 }
3156 // end funky indenting
3157 }
3158
3159 private function insertElement($token, $append = true) {
3160 $el = $this->dom->createElementNS(self::NS_HTML, $token['name']);
3161
3162 if (!empty($token['attr'])) {
3163 foreach($token['attr'] as $attr) {
3164 if(!$el->hasAttribute($attr['name'])) {
3165 $el->setAttribute($attr['name'], $attr['value']);
3166 }
3167 }
3168 }
3169 if ($append) {
3170 $this->appendToRealParent($el);
3171 $this->stack[] = $el;
3172 }
3173
3174 return $el;
3175 }
3176
3177 private function insertText($data) {
3178 if ($data === '') return;
3179 if ($this->ignore_lf_token) {
3180 if ($data[0] === "\n") {
3181 $data = substr($data, 1);
3182 if ($data === false) return;
3183 }
3184 }
3185 $text = $this->dom->createTextNode($data);
3186 $this->appendToRealParent($text);
3187 }
3188
3189 private function insertComment($data) {
3190 $comment = $this->dom->createComment($data);
3191 $this->appendToRealParent($comment);
3192 }
3193
3194 private function appendToRealParent($node) {
3195 // this is only for the foster_parent case
3196 /* If the current node is a table, tbody, tfoot, thead, or tr
3197 element, then, whenever a node would be inserted into the current
3198 node, it must instead be inserted into the foster parent element. */
3199 if(!$this->foster_parent || !in_array(end($this->stack)->tagName,
3200 array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
3201 end($this->stack)->appendChild($node);
3202 } else {
3203 $this->fosterParent($node);
3204 }
3205 }
3206
3207 private function elementInScope($el, $scope = self::SCOPE) {
3208 if(is_array($el)) {
3209 foreach($el as $element) {
3210 if($this->elementInScope($element, $scope)) {
3211 return true;
3212 }
3213 }
3214
3215 return false;
3216 }
3217
3218 $leng = count($this->stack);
3219
3220 for($n = 0; $n < $leng; $n++) {
3221 /* 1. Initialise node to be the current node (the bottommost node of
3222 the stack). */
3223 $node = $this->stack[$leng - 1 - $n];
3224
3225 if($node->tagName === $el) {
3226 /* 2. If node is the target node, terminate in a match state. */
3227 return true;
3228
3229 // We've expanded the logic for these states a little differently;
3230 // Hixie's refactoring into "specific scope" is more general, but
3231 // this "gets the job done"
3232
3233 // these are the common states for all scopes
3234 } elseif($node->tagName === 'table' || $node->tagName === 'html') {
3235 return false;
3236
3237 // these are valid for "in scope" and "in list item scope"
3238 } elseif($scope !== self::SCOPE_TABLE &&
3239 (in_array($node->tagName, array('applet', 'caption', 'td',
3240 'th', 'button', 'marquee', 'object')) ||
3241 $node->tagName === 'foreignObject' && $node->namespaceURI === self::NS_SVG)) {
3242 return false;
3243
3244
3245 // these are valid for "in list item scope"
3246 } elseif($scope === self::SCOPE_LISTITEM && in_array($node->tagName, array('ol', 'ul'))) {
3247 return false;
3248 }
3249
3250 /* Otherwise, set node to the previous entry in the stack of open
3251 elements and return to step 2. (This will never fail, since the loop
3252 will always terminate in the previous step if the top of the stack
3253 is reached.) */
3254 }
3255 }
3256
3257 private function reconstructActiveFormattingElements() {
3258 /* 1. If there are no entries in the list of active formatting elements,
3259 then there is nothing to reconstruct; stop this algorithm. */
3260 $formatting_elements = count($this->a_formatting);
3261
3262 if($formatting_elements === 0) {
3263 return false;
3264 }
3265
3266 /* 3. Let entry be the last (most recently added) element in the list
3267 of active formatting elements. */
3268 $entry = end($this->a_formatting);
3269
3270 /* 2. If the last (most recently added) entry in the list of active
3271 formatting elements is a marker, or if it is an element that is in the
3272 stack of open elements, then there is nothing to reconstruct; stop this
3273 algorithm. */
3274 if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
3275 return false;
3276 }
3277
3278 for($a = $formatting_elements - 1; $a >= 0; true) {
3279 /* 4. If there are no entries before entry in the list of active
3280 formatting elements, then jump to step 8. */
3281 if($a === 0) {
3282 $step_seven = false;
3283 break;
3284 }
3285
3286 /* 5. Let entry be the entry one earlier than entry in the list of
3287 active formatting elements. */
3288 $a--;
3289 $entry = $this->a_formatting[$a];
3290
3291 /* 6. If entry is neither a marker nor an element that is also in
3292 thetack of open elements, go to step 4. */
3293 if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
3294 break;
3295 }
3296 }
3297
3298 while(true) {
3299 /* 7. Let entry be the element one later than entry in the list of
3300 active formatting elements. */
3301 if(isset($step_seven) && $step_seven === true) {
3302 $a++;
3303 $entry = $this->a_formatting[$a];
3304 }
3305
3306 /* 8. Perform a shallow clone of the element entry to obtain clone. */
3307 $clone = $entry->cloneNode();
3308
3309 /* 9. Append clone to the current node and push it onto the stack
3310 of open elements so that it is the new current node. */
3311 $this->appendToRealParent($clone);
3312 $this->stack[] = $clone;
3313
3314 /* 10. Replace the entry for entry in the list with an entry for
3315 clone. */
3316 $this->a_formatting[$a] = $clone;
3317
3318 /* 11. If the entry for clone in the list of active formatting
3319 elements is not the last entry in the list, return to step 7. */
3320 if(end($this->a_formatting) !== $clone) {
3321 $step_seven = true;
3322 } else {
3323 break;
3324 }
3325 }
3326 }
3327
3328 private function clearTheActiveFormattingElementsUpToTheLastMarker() {
3329 /* When the steps below require the UA to clear the list of active
3330 formatting elements up to the last marker, the UA must perform the
3331 following steps: */
3332
3333 while(true) {
3334 /* 1. Let entry be the last (most recently added) entry in the list
3335 of active formatting elements. */
3336 $entry = end($this->a_formatting);
3337
3338 /* 2. Remove entry from the list of active formatting elements. */
3339 array_pop($this->a_formatting);
3340
3341 /* 3. If entry was a marker, then stop the algorithm at this point.
3342 The list has been cleared up to the last marker. */
3343 if($entry === self::MARKER) {
3344 break;
3345 }
3346 }
3347 }
3348
3349 private function generateImpliedEndTags($exclude = array()) {
3350 /* When the steps below require the UA to generate implied end tags,
3351 * then, while the current node is a dc element, a dd element, a ds
3352 * element, a dt element, an li element, an option element, an optgroup
3353 * element, a p element, an rp element, or an rt element, the UA must
3354 * pop the current node off the stack of open elements. */
3355 $node = end($this->stack);
3356 $elements = array_diff(array('dc', 'dd', 'ds', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude);
3357
3358 while(in_array(end($this->stack)->tagName, $elements)) {
3359 array_pop($this->stack);
3360 }
3361 }
3362
3363 private function getElementCategory($node) {
3364 if (!is_object($node)) debug_print_backtrace();
3365 $name = $node->tagName;
3366 if(in_array($name, $this->special))
3367 return self::SPECIAL;
3368
3369 elseif(in_array($name, $this->scoping))
3370 return self::SCOPING;
3371
3372 elseif(in_array($name, $this->formatting))
3373 return self::FORMATTING;
3374
3375 else
3376 return self::PHRASING;
3377 }
3378
3379 private function clearStackToTableContext($elements) {
3380 /* When the steps above require the UA to clear the stack back to a
3381 table context, it means that the UA must, while the current node is not
3382 a table element or an html element, pop elements from the stack of open
3383 elements. */
3384 while(true) {
3385 $name = end($this->stack)->tagName;
3386
3387 if(in_array($name, $elements)) {
3388 break;
3389 } else {
3390 array_pop($this->stack);
3391 }
3392 }
3393 }
3394
3395 private function resetInsertionMode($context = null) {
3396 /* 1. Let last be false. */
3397 $last = false;
3398 $leng = count($this->stack);
3399
3400 for($n = $leng - 1; $n >= 0; $n--) {
3401 /* 2. Let node be the last node in the stack of open elements. */
3402 $node = $this->stack[$n];
3403
3404 /* 3. If node is the first node in the stack of open elements, then
3405 * set last to true and set node to the context element. (fragment
3406 * case) */
3407 if($this->stack[0]->isSameNode($node)) {
3408 $last = true;
3409 $node = $context;
3410 }
3411
3412 /* 4. If node is a select element, then switch the insertion mode to
3413 "in select" and abort these steps. (fragment case) */
3414 if($node->tagName === 'select') {
3415 $this->mode = self::IN_SELECT;
3416 break;
3417
3418 /* 5. If node is a td or th element, then switch the insertion mode
3419 to "in cell" and abort these steps. */
3420 } elseif($node->tagName === 'td' || $node->nodeName === 'th') {
3421 $this->mode = self::IN_CELL;
3422 break;
3423
3424 /* 6. If node is a tr element, then switch the insertion mode to
3425 "in row" and abort these steps. */
3426 } elseif($node->tagName === 'tr') {
3427 $this->mode = self::IN_ROW;
3428 break;
3429
3430 /* 7. If node is a tbody, thead, or tfoot element, then switch the
3431 insertion mode to "in table body" and abort these steps. */
3432 } elseif(in_array($node->tagName, array('tbody', 'thead', 'tfoot'))) {
3433 $this->mode = self::IN_TABLE_BODY;
3434 break;
3435
3436 /* 8. If node is a caption element, then switch the insertion mode
3437 to "in caption" and abort these steps. */
3438 } elseif($node->tagName === 'caption') {
3439 $this->mode = self::IN_CAPTION;
3440 break;
3441
3442 /* 9. If node is a colgroup element, then switch the insertion mode
3443 to "in column group" and abort these steps. (innerHTML case) */
3444 } elseif($node->tagName === 'colgroup') {
3445 $this->mode = self::IN_COLUMN_GROUP;
3446 break;
3447
3448 /* 10. If node is a table element, then switch the insertion mode
3449 to "in table" and abort these steps. */
3450 } elseif($node->tagName === 'table') {
3451 $this->mode = self::IN_TABLE;
3452 break;
3453
3454 /* 11. If node is an element from the MathML namespace or the SVG
3455 * namespace, then switch the insertion mode to "in foreign
3456 * content", let the secondary insertion mode be "in body", and
3457 * abort these steps. */
3458 } elseif($node->namespaceURI === self::NS_SVG ||
3459 $node->namespaceURI === self::NS_MATHML) {
3460 $this->mode = self::IN_FOREIGN_CONTENT;
3461 $this->secondary_mode = self::IN_BODY;
3462 break;
3463
3464 /* 12. If node is a head element, then switch the insertion mode
3465 to "in body" ("in body"! not "in head"!) and abort these steps.
3466 (fragment case) */
3467 } elseif($node->tagName === 'head') {
3468 $this->mode = self::IN_BODY;
3469 break;
3470
3471 /* 13. If node is a body element, then switch the insertion mode to
3472 "in body" and abort these steps. */
3473 } elseif($node->tagName === 'body') {
3474 $this->mode = self::IN_BODY;
3475 break;
3476
3477 /* 14. If node is a frameset element, then switch the insertion
3478 mode to "in frameset" and abort these steps. (fragment case) */
3479 } elseif($node->tagName === 'frameset') {
3480 $this->mode = self::IN_FRAMESET;
3481 break;
3482
3483 /* 15. If node is an html element, then: if the head element
3484 pointer is null, switch the insertion mode to "before head",
3485 otherwise, switch the insertion mode to "after head". In either
3486 case, abort these steps. (fragment case) */
3487 } elseif($node->tagName === 'html') {
3488 $this->mode = ($this->head_pointer === null)
3489 ? self::BEFORE_HEAD
3490 : self::AFTER_HEAD;
3491
3492 break;
3493
3494 /* 16. If last is true, then set the insertion mode to "in body"
3495 and abort these steps. (fragment case) */
3496 } elseif($last) {
3497 $this->mode = self::IN_BODY;
3498 break;
3499 }
3500 }
3501 }
3502
3503 private function closeCell() {
3504 /* If the stack of open elements has a td or th element in table scope,
3505 then act as if an end tag token with that tag name had been seen. */
3506 foreach(array('td', 'th') as $cell) {
3507 if($this->elementInScope($cell, self::SCOPE_TABLE)) {
3508 $this->emitToken(array(
3509 'name' => $cell,
3510 'type' => HTML5_Tokenizer::ENDTAG
3511 ));
3512
3513 break;
3514 }
3515 }
3516 }
3517
3518 private function processWithRulesFor($token, $mode) {
3519 /* "using the rules for the m insertion mode", where m is one of these
3520 * modes, the user agent must use the rules described under the m
3521 * insertion mode's section, but must leave the insertion mode
3522 * unchanged unless the rules in m themselves switch the insertion mode
3523 * to a new value. */
3524 return $this->emitToken($token, $mode);
3525 }
3526
3527 private function insertCDATAElement($token) {
3528 $this->insertElement($token);
3529 $this->original_mode = $this->mode;
3530 $this->mode = self::IN_CDATA_RCDATA;
3531 $this->content_model = HTML5_Tokenizer::CDATA;
3532 }
3533
3534 private function insertRCDATAElement($token) {
3535 $this->insertElement($token);
3536 $this->original_mode = $this->mode;
3537 $this->mode = self::IN_CDATA_RCDATA;
3538 $this->content_model = HTML5_Tokenizer::RCDATA;
3539 }
3540
3541 private function getAttr($token, $key) {
3542 if (!isset($token['attr'])) return false;
3543 $ret = false;
3544 foreach ($token['attr'] as $keypair) {
3545 if ($keypair['name'] === $key) $ret = $keypair['value'];
3546 }
3547 return $ret;
3548 }
3549
3550 private function getCurrentTable() {
3551 /* The current table is the last table element in the stack of open
3552 * elements, if there is one. If there is no table element in the stack
3553 * of open elements (fragment case), then the current table is the
3554 * first element in the stack of open elements (the html element). */
3555 for ($i = count($this->stack) - 1; $i >= 0; $i--) {
3556 if ($this->stack[$i]->tagName === 'table') {
3557 return $this->stack[$i];
3558 }
3559 }
3560 return $this->stack[0];
3561 }
3562
3563 private function getFosterParent() {
3564 /* The foster parent element is the parent element of the last
3565 table element in the stack of open elements, if there is a
3566 table element and it has such a parent element. If there is no
3567 table element in the stack of open elements (innerHTML case),
3568 then the foster parent element is the first element in the
3569 stack of open elements (the html element). Otherwise, if there
3570 is a table element in the stack of open elements, but the last
3571 table element in the stack of open elements has no parent, or
3572 its parent node is not an element, then the foster parent
3573 element is the element before the last table element in the
3574 stack of open elements. */
3575 for($n = count($this->stack) - 1; $n >= 0; $n--) {
3576 if($this->stack[$n]->tagName === 'table') {
3577 $table = $this->stack[$n];
3578 break;
3579 }
3580 }
3581
3582 if(isset($table) && $table->parentNode !== null) {
3583 return $table->parentNode;
3584
3585 } elseif(!isset($table)) {
3586 return $this->stack[0];
3587
3588 } elseif(isset($table) && ($table->parentNode === null ||
3589 $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
3590 return $this->stack[$n - 1];
3591 }
3592 }
3593
3594 public function fosterParent($node) {
3595 $foster_parent = $this->getFosterParent();
3596 $table = $this->getCurrentTable(); // almost equivalent to last table element, except it can be html
3597 /* When a node node is to be foster parented, the node node must be
3598 * be inserted into the foster parent element. */
3599 /* If the foster parent element is the parent element of the last table
3600 * element in the stack of open elements, then node must be inserted
3601 * immediately before the last table element in the stack of open
3602 * elements in the foster parent element; otherwise, node must be
3603 * appended to the foster parent element. */
3604 if ($table->tagName === 'table' && $table->parentNode->isSameNode($foster_parent)) {
3605 $foster_parent->insertBefore($node, $table);
3606 } else {
3607 $foster_parent->appendChild($node);
3608 }
3609 }
3610
3611 /**
3612 * For debugging, prints the stack
3613 */
3614 private function printStack() {
3615 $names = array();
3616 foreach ($this->stack as $i => $element) {
3617 $names[] = $element->tagName;
3618 }
3619 echo " -> stack [" . implode(', ', $names) . "]\n";
3620 }
3621
3622 /**
3623 * For debugging, prints active formatting elements
3624 */
3625 private function printActiveFormattingElements() {
3626 if (!$this->a_formatting) return;
3627 $names = array();
3628 foreach ($this->a_formatting as $node) {
3629 if ($node === self::MARKER) $names[] = 'MARKER';
3630 else $names[] = $node->tagName;
3631 }
3632 echo " -> active formatting [" . implode(', ', $names) . "]\n";
3633 }
3634
3635 public function currentTableIsTainted() {
3636 return !empty($this->getCurrentTable()->tainted);
3637 }
3638
3639 /**
3640 * Sets up the tree constructor for building a fragment.
3641 */
3642 public function setupContext($context = null) {
3643 $this->fragment = true;
3644 if ($context) {
3645 $context = $this->dom->createElementNS(self::NS_HTML, $context);
3646 /* 4.1. Set the HTML parser's tokenization stage's content model
3647 * flag according to the context element, as follows: */
3648 switch ($context->tagName) {
3649 case 'title': case 'textarea':
3650 $this->content_model = HTML5_Tokenizer::RCDATA;
3651 break;
3652 case 'style': case 'script': case 'xmp': case 'iframe':
3653 case 'noembed': case 'noframes':
3654 $this->content_model = HTML5_Tokenizer::CDATA;
3655 break;
3656 case 'noscript':
3657 // XSCRIPT: assuming scripting is enabled
3658 $this->content_model = HTML5_Tokenizer::CDATA;
3659 break;
3660 case 'plaintext':
3661 $this->content_model = HTML5_Tokenizer::PLAINTEXT;
3662 break;
3663 }
3664 /* 4.2. Let root be a new html element with no attributes. */
3665 $root = $this->dom->createElementNS(self::NS_HTML, 'html');
3666 $this->root = $root;
3667 /* 4.3 Append the element root to the Document node created above. */
3668 $this->dom->appendChild($root);
3669 /* 4.4 Set up the parser's stack of open elements so that it
3670 * contains just the single element root. */
3671 $this->stack = array($root);
3672 /* 4.5 Reset the parser's insertion mode appropriately. */
3673 $this->resetInsertionMode($context);
3674 /* 4.6 Set the parser's form element pointer to the nearest node
3675 * to the context element that is a form element (going straight up
3676 * the ancestor chain, and including the element itself, if it is a
3677 * form element), or, if there is no such form element, to null. */
3678 $node = $context;
3679 do {
3680 if ($node->tagName === 'form') {
3681 $this->form_pointer = $node;
3682 break;
3683 }
3684 } while ($node = $node->parentNode);
3685 }
3686 }
3687
3688 public function adjustMathMLAttributes($token) {
3689 foreach ($token['attr'] as &$kp) {
3690 if ($kp['name'] === 'definitionurl') {
3691 $kp['name'] = 'definitionURL';
3692 }
3693 }
3694 return $token;
3695 }
3696
3697 public function adjustSVGAttributes($token) {
3698 static $lookup = array(
3699 'attributename' => 'attributeName',
3700 'attributetype' => 'attributeType',
3701 'basefrequency' => 'baseFrequency',
3702 'baseprofile' => 'baseProfile',
3703 'calcmode' => 'calcMode',
3704 'clippathunits' => 'clipPathUnits',
3705 'contentscripttype' => 'contentScriptType',
3706 'contentstyletype' => 'contentStyleType',
3707 'diffuseconstant' => 'diffuseConstant',
3708 'edgemode' => 'edgeMode',
3709 'externalresourcesrequired' => 'externalResourcesRequired',
3710 'filterres' => 'filterRes',
3711 'filterunits' => 'filterUnits',
3712 'glyphref' => 'glyphRef',
3713 'gradienttransform' => 'gradientTransform',
3714 'gradientunits' => 'gradientUnits',
3715 'kernelmatrix' => 'kernelMatrix',
3716 'kernelunitlength' => 'kernelUnitLength',
3717 'keypoints' => 'keyPoints',
3718 'keysplines' => 'keySplines',
3719 'keytimes' => 'keyTimes',
3720 'lengthadjust' => 'lengthAdjust',
3721 'limitingconeangle' => 'limitingConeAngle',
3722 'markerheight' => 'markerHeight',
3723 'markerunits' => 'markerUnits',
3724 'markerwidth' => 'markerWidth',
3725 'maskcontentunits' => 'maskContentUnits',
3726 'maskunits' => 'maskUnits',
3727 'numoctaves' => 'numOctaves',
3728 'pathlength' => 'pathLength',
3729 'patterncontentunits' => 'patternContentUnits',
3730 'patterntransform' => 'patternTransform',
3731 'patternunits' => 'patternUnits',
3732 'pointsatx' => 'pointsAtX',
3733 'pointsaty' => 'pointsAtY',
3734 'pointsatz' => 'pointsAtZ',
3735 'preservealpha' => 'preserveAlpha',
3736 'preserveaspectratio' => 'preserveAspectRatio',
3737 'primitiveunits' => 'primitiveUnits',
3738 'refx' => 'refX',
3739 'refy' => 'refY',
3740 'repeatcount' => 'repeatCount',
3741 'repeatdur' => 'repeatDur',
3742 'requiredextensions' => 'requiredExtensions',
3743 'requiredfeatures' => 'requiredFeatures',
3744 'specularconstant' => 'specularConstant',
3745 'specularexponent' => 'specularExponent',
3746 'spreadmethod' => 'spreadMethod',
3747 'startoffset' => 'startOffset',
3748 'stddeviation' => 'stdDeviation',
3749 'stitchtiles' => 'stitchTiles',
3750 'surfacescale' => 'surfaceScale',
3751 'systemlanguage' => 'systemLanguage',
3752 'tablevalues' => 'tableValues',
3753 'targetx' => 'targetX',
3754 'targety' => 'targetY',
3755 'textlength' => 'textLength',
3756 'viewbox' => 'viewBox',
3757 'viewtarget' => 'viewTarget',
3758 'xchannelselector' => 'xChannelSelector',
3759 'ychannelselector' => 'yChannelSelector',
3760 'zoomandpan' => 'zoomAndPan',
3761 );
3762 foreach ($token['attr'] as &$kp) {
3763 if (isset($lookup[$kp['name']])) {
3764 $kp['name'] = $lookup[$kp['name']];
3765 }
3766 }
3767 return $token;
3768 }
3769
3770 public function adjustForeignAttributes($token) {
3771 static $lookup = array(
3772 'xlink:actuate' => array('xlink', 'actuate', self::NS_XLINK),
3773 'xlink:arcrole' => array('xlink', 'arcrole', self::NS_XLINK),
3774 'xlink:href' => array('xlink', 'href', self::NS_XLINK),
3775 'xlink:role' => array('xlink', 'role', self::NS_XLINK),
3776 'xlink:show' => array('xlink', 'show', self::NS_XLINK),
3777 'xlink:title' => array('xlink', 'title', self::NS_XLINK),
3778 'xlink:type' => array('xlink', 'type', self::NS_XLINK),
3779 'xml:base' => array('xml', 'base', self::NS_XML),
3780 'xml:lang' => array('xml', 'lang', self::NS_XML),
3781 'xml:space' => array('xml', 'space', self::NS_XML),
3782 'xmlns' => array(null, 'xmlns', self::NS_XMLNS),
3783 'xmlns:xlink' => array('xmlns', 'xlink', self::NS_XMLNS),
3784 );
3785 foreach ($token['attr'] as &$kp) {
3786 if (isset($lookup[$kp['name']])) {
3787 $kp['name'] = $lookup[$kp['name']];
3788 }
3789 }
3790 return $token;
3791 }
3792
3793 public function insertForeignElement($token, $namespaceURI) {
3794 $el = $this->dom->createElementNS($namespaceURI, $token['name']);
3795 if (!empty($token['attr'])) {
3796 foreach ($token['attr'] as $kp) {
3797 $attr = $kp['name'];
3798 if (is_array($attr)) {
3799 $ns = $attr[2];
3800 $attr = $attr[1];
3801 } else {
3802 $ns = self::NS_HTML;
3803 }
3804 if (!$el->hasAttributeNS($ns, $attr)) {
3805 // XSKETCHY: work around godawful libxml bug
3806 if ($ns === self::NS_XLINK) {
3807 $el->setAttribute('xlink:'.$attr, $kp['value']);
3808 } elseif ($ns === self::NS_HTML) {
3809 // Another godawful libxml bug
3810 $el->setAttribute($attr, $kp['value']);
3811 } else {
3812 $el->setAttributeNS($ns, $attr, $kp['value']);
3813 }
3814 }
3815 }
3816 }
3817 $this->appendToRealParent($el);
3818 $this->stack[] = $el;
3819 // XERROR: see below
3820 /* If the newly created element has an xmlns attribute in the XMLNS
3821 * namespace whose value is not exactly the same as the element's
3822 * namespace, that is a parse error. Similarly, if the newly created
3823 * element has an xmlns:xlink attribute in the XMLNS namespace whose
3824 * value is not the XLink Namespace, that is a parse error. */
3825 }
3826
3827 public function save() {
3828 $this->dom->normalize();
3829 if (!$this->fragment) {
3830 return $this->dom;
3831 } else {
3832 if ($this->root) {
3833 return $this->root->childNodes;
3834 } else {
3835 return $this->dom->childNodes;
3836 }
3837 }
3838 }
3839}
3840
diff --git a/inc/3rdparty/libraries/html5/named-character-references.ser b/inc/3rdparty/libraries/html5/named-character-references.ser
new file mode 100644
index 00000000..e3ae0502
--- /dev/null
+++ b/inc/3rdparty/libraries/html5/named-character-references.ser
@@ -0,0 +1 @@
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/inc/3rdparty/libraries/humble-http-agent/CookieJar.php b/inc/3rdparty/libraries/humble-http-agent/CookieJar.php
new file mode 100644
index 00000000..83e94f14
--- /dev/null
+++ b/inc/3rdparty/libraries/humble-http-agent/CookieJar.php
@@ -0,0 +1,404 @@
1<?php
2/**
3 * Cookie Jar
4 *
5 * PHP class for handling cookies, as defined by the Netscape spec:
6 * <http://curl.haxx.se/rfc/cookie_spec.html>
7 *
8 * This class should be used to handle cookies (storing cookies from HTTP response messages, and
9 * sending out cookies in HTTP request messages). This has been adapted for FiveFilters.org
10 * from the original version used in HTTP Navigator. See http://www.keyvan.net/code/http-navigator/
11 *
12 * This class is mainly based on Cookies.pm <http://search.cpan.org/author/GAAS/libwww-perl-5.65/
13 * lib/HTTP/Cookies.pm> from the libwww-perl collection <http://www.linpro.no/lwp/>.
14 * Unlike Cookies.pm, this class only supports the Netscape cookie spec, not RFC 2965.
15 *
16 * @version 0.5
17 * @date 2011-03-15
18 * @see http://php.net/HttpRequestPool
19 * @author Keyvan Minoukadeh
20 * @copyright 2011 Keyvan Minoukadeh
21 * @license http://www.gnu.org/licenses/agpl-3.0.html AGPL v3
22 */
23
24class CookieJar
25{
26 /**
27 * Cookies - array containing all cookies.
28 *
29 * <pre>
30 * Cookies are stored like this:
31 * [domain][path][name] = array
32 * where array is:
33 * 0 => value, 1 => secure, 2 => expires
34 * </pre>
35 * @var array
36 * @access private
37 */
38 public $cookies = array();
39 public $debug = false;
40
41 /**
42 * Constructor
43 */
44 function __construct() {
45 }
46
47 protected function debug($msg, $file=null, $line=null) {
48 if ($this->debug) {
49 $mem = round(memory_get_usage()/1024, 2);
50 $memPeak = round(memory_get_peak_usage()/1024, 2);
51 echo '* ',$msg;
52 if (isset($file, $line)) echo " ($file line $line)";
53 echo ' - mem used: ',$mem," (peak: $memPeak)\n";
54 ob_flush();
55 flush();
56 }
57 }
58
59 /**
60 * Get matching cookies
61 *
62 * Only use this method if you cannot use add_cookie_header(), for example, if you want to use
63 * this cookie jar class without using the request class.
64 *
65 * @param array $param associative array containing 'domain', 'path', 'secure' keys
66 * @return string
67 * @see add_cookie_header()
68 */
69 public function getMatchingCookies($url)
70 {
71 if (($parts = @parse_url($url)) && isset($parts['scheme'], $parts['host'], $parts['path'])) {
72 $param['domain'] = $parts['host'];
73 $param['path'] = $parts['path'];
74 $param['secure'] = (strtolower($parts['scheme']) == 'https');
75 unset($parts);
76 } else {
77 return false;
78 }
79 // RFC 2965 notes:
80 // If multiple cookies satisfy the criteria above, they are ordered in
81 // the Cookie header such that those with more specific Path attributes
82 // precede those with less specific. Ordering with respect to other
83 // attributes (e.g., Domain) is unspecified.
84 $domain = $param['domain'];
85 if (strpos($domain, '.') === false) $domain .= '.local';
86 $request_path = $param['path'];
87 if ($request_path == '') $request_path = '/';
88 $request_secure = $param['secure'];
89 $now = time();
90 $matched_cookies = array();
91 // domain - find matching domains
92 $this->debug('Finding matching domains for '.$domain, __FILE__, __LINE__);
93 while (strpos($domain, '.') !== false) {
94 if (isset($this->cookies[$domain])) {
95 $this->debug(' domain match found: '.$domain);
96 $cookies =& $this->cookies[$domain];
97 } else {
98 $domain = $this->_reduce_domain($domain);
99 continue;
100 }
101 // paths - find matching paths starting from most specific
102 $this->debug(' - Finding matching paths for '.$request_path);
103 $paths = array_keys($cookies);
104 usort($paths, array($this, '_cmp_length'));
105 foreach ($paths as $path) {
106 // continue to next cookie if request path does not path-match cookie path
107 if (!$this->_path_match($request_path, $path)) continue;
108 // loop through cookie names
109 $this->debug(' path match found: '.$path);
110 foreach ($cookies[$path] as $name => $values) {
111 // if this cookie is secure but request isn't, continue to next cookie
112 if ($values[1] && !$request_secure) continue;
113 // if cookie is not a session cookie and has expired, continue to next cookie
114 if (is_int($values[2]) && ($values[2] < $now)) continue;
115 // cookie matches request
116 $this->debug(' cookie match: '.$name.'='.$values[0]);
117 $matched_cookies[] = $name.'='.$values[0];
118 }
119 }
120 $domain = $this->_reduce_domain($domain);
121 }
122 // return cookies
123 return implode('; ', $matched_cookies);
124 }
125
126 /**
127 * Parse Set-Cookie values.
128 *
129 * Only use this method if you cannot use extract_cookies(), for example, if you want to use
130 * this cookie jar class without using the response class.
131 *
132 * @param array $set_cookies array holding 1 or more "Set-Cookie" header values
133 * @param array $param associative array containing 'host', 'path' keys
134 * @return void
135 * @see extract_cookies()
136 */
137 public function storeCookies($url, $set_cookies)
138 {
139 if (count($set_cookies) == 0) return;
140 $param = @parse_url($url);
141 if (!is_array($param) || !isset($param['host'])) return;
142 $request_host = $param['host'];
143 if (strpos($request_host, '.') === false) $request_host .= '.local';
144 $request_path = @$param['path'];
145 if ($request_path == '') $request_path = '/';
146 //
147 // loop through set-cookie headers
148 //
149 foreach ($set_cookies as $set_cookie) {
150 $this->debug('Parsing: '.$set_cookie);
151 // temporary cookie store (before adding to jar)
152 $tmp_cookie = array();
153 $param = explode(';', $set_cookie);
154 // loop through params
155 for ($x=0; $x<count($param); $x++) {
156 $key_val = explode('=', $param[$x], 2);
157 if (count($key_val) != 2) {
158 // if the first param isn't a name=value pair, continue to the next set-cookie
159 // header
160 if ($x == 0) continue 2;
161 // check for secure flag
162 if (strtolower(trim($key_val[0])) == 'secure') $tmp_cookie['secure'] = true;
163 // continue to next param
164 continue;
165 }
166 list($key, $val) = array_map('trim', $key_val);
167 // first name=value pair is the cookie name and value
168 // the name and value are stored under 'name' and 'value' to avoid conflicts
169 // with later parameters.
170 if ($x == 0) {
171 $tmp_cookie = array('name'=>$key, 'value'=>$val);
172 continue;
173 }
174 $key = strtolower($key);
175 if (in_array($key, array('expires', 'path', 'domain', 'secure'))) {
176 $tmp_cookie[$key] = $val;
177 }
178 }
179 //
180 // set cookie
181 //
182 // check domain
183 if (isset($tmp_cookie['domain']) && ($tmp_cookie['domain'] != $request_host) &&
184 ($tmp_cookie['domain'] != ".$request_host")) {
185 $domain = $tmp_cookie['domain'];
186 if ((strpos($domain, '.') === false) && ($domain != 'local')) {
187 $this->debug(' - domain "'.$domain.'" has no dot and is not a local domain');
188 continue;
189 }
190 if (preg_match('/\.[0-9]+$/', $domain)) {
191 $this->debug(' - domain "'.$domain.'" appears to be an ip address');
192 continue;
193 }
194 if (substr($domain, 0, 1) != '.') $domain = ".$domain";
195 if (!$this->_domain_match($request_host, $domain)) {
196 $this->debug(' - request host "'.$request_host.'" does not domain-match "'.$domain.'"');
197 continue;
198 }
199 } else {
200 // if domain is not specified in the set-cookie header, domain will default to
201 // the request host
202 $domain = $request_host;
203 }
204 // check path
205 if (isset($tmp_cookie['path']) && ($tmp_cookie['path'] != '')) {
206 $path = urldecode($tmp_cookie['path']);
207 if (!$this->_path_match($request_path, $path)) {
208 $this->debug(' - request path "'.$request_path.'" does not path-match "'.$path.'"');
209 continue;
210 }
211 } else {
212 $path = $request_path;
213 $path = substr($path, 0, strrpos($path, '/'));
214 if ($path == '') $path = '/';
215 }
216 // check if secure
217 $secure = (isset($tmp_cookie['secure'])) ? true : false;
218 // check expiry
219 if (isset($tmp_cookie['expires'])) {
220 if (($expires = strtotime($tmp_cookie['expires'])) < 0) {
221 $expires = null;
222 }
223 } else {
224 $expires = null;
225 }
226 // set cookie
227 $this->set_cookie($domain, $path, $tmp_cookie['name'], $tmp_cookie['value'], $secure, $expires);
228 }
229 }
230
231 // return array of set-cookie values extracted from HTTP response headers (string $h)
232 public function extractCookies($h) {
233 $x = 0;
234 $lines = 0;
235 $headers = array();
236 $last_match = false;
237 $h = explode("\n", $h);
238 foreach ($h as $line) {
239 $line = rtrim($line);
240 $lines++;
241
242 $trimmed_line = trim($line);
243 if (isset($line_last)) {
244 // check if we have \r\n\r\n (indicating the end of headers)
245 // some servers will not use CRLF (\r\n), so we make CR (\r) optional.
246 // if (preg_match('/\015?\012\015?\012/', $line_last.$line)) {
247 // break;
248 // }
249 // As an alternative, we can check if the current trimmed line is empty
250 if ($trimmed_line == '') {
251 break;
252 }
253
254 // check for continuation line...
255 // RFC 2616 Section 2.2 "Basic Rules":
256 // HTTP/1.1 header field values can be folded onto multiple lines if the
257 // continuation line begins with a space or horizontal tab. All linear
258 // white space, including folding, has the same semantics as SP. A
259 // recipient MAY replace any linear white space with a single SP before
260 // interpreting the field value or forwarding the message downstream.
261 if ($last_match && preg_match('/^\s+(.*)/', $line, $match)) {
262 // append to previous header value
263 $headers[$x-1] .= ' '.rtrim($match[1]);
264 continue;
265 }
266 }
267 $line_last = $line;
268
269 // split header name and value
270 if (preg_match('/^Set-Cookie\s*:\s*(.*)/i', $line, $match)) {
271 $headers[$x++] = rtrim($match[1]);
272 $last_match = true;
273 } else {
274 $last_match = false;
275 }
276 }
277 return $headers;
278 }
279
280 /**
281 * Set Cookie
282 * @param string $domain
283 * @param string $path
284 * @param string $name cookie name
285 * @param string $value cookie value
286 * @param bool $secure
287 * @param int $expires expiry time (null if session cookie, <= 0 will delete cookie)
288 * @return void
289 */
290 function set_cookie($domain, $path, $name, $value, $secure=false, $expires=null)
291 {
292 if ($domain == '') return;
293 if ($path == '') return;
294 if ($name == '') return;
295 // check if cookie needs to go
296 if (isset($expires) && ($expires <= 0)) {
297 if (isset($this->cookies[$domain][$path][$name])) unset($this->cookies[$domain][$path][$name]);
298 return;
299 }
300 if ($value == '') return;
301 $this->cookies[$domain][$path][$name] = array($value, $secure, $expires);
302 return;
303 }
304
305 /**
306 * Clear cookies - [domain [,path [,name]]] - call method with no arguments to clear all cookies.
307 * @param string $domain
308 * @param string $path
309 * @param string $name
310 * @return void
311 */
312 function clear($domain=null, $path=null, $name=null)
313 {
314 if (!isset($domain)) {
315 $this->cookies = array();
316 } elseif (!isset($path)) {
317 if (isset($this->cookies[$domain])) unset($this->cookies[$domain]);
318 } elseif (!isset($name)) {
319 if (isset($this->cookies[$domain][$path])) unset($this->cookies[$domain][$path]);
320 } elseif (isset($name)) {
321 if (isset($this->cookies[$domain][$path][$name])) unset($this->cookies[$domain][$path][$name]);
322 }
323 }
324
325 /**
326 * Compare string length - used for sorting
327 * @access private
328 * @return int
329 */
330 function _cmp_length($a, $b)
331 {
332 $la = strlen($a); $lb = strlen($b);
333 if ($la == $lb) return 0;
334 return ($la > $lb) ? -1 : 1;
335 }
336
337 /**
338 * Reduce domain
339 * @param string $domain
340 * @return string
341 * @access private
342 */
343 function _reduce_domain($domain)
344 {
345 if ($domain == '') return '';
346 if (substr($domain, 0, 1) == '.') return substr($domain, 1);
347 return substr($domain, strpos($domain, '.'));
348 }
349
350 /**
351 * Path match - check if path1 path-matches path2
352 *
353 * From RFC 2965:
354 * <i>For two strings that represent paths, P1 and P2, P1 path-matches P2
355 * if P2 is a prefix of P1 (including the case where P1 and P2 string-
356 * compare equal). Thus, the string /tec/waldo path-matches /tec.</i>
357 * @param string $path1
358 * @param string $path2
359 * @return bool
360 * @access private
361 */
362 function _path_match($path1, $path2)
363 {
364 return (substr($path1, 0, strlen($path2)) == $path2);
365 }
366
367 /**
368 * Domain match - check if domain1 domain-matches domain2
369 *
370 * A few extracts from RFC 2965:
371 * - A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com
372 * would be rejected, because H is y.x and contains a dot.
373 *
374 * - A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com
375 * would be accepted.
376 *
377 * - A Set-Cookie2 with Domain=.com or Domain=.com., will always be
378 * rejected, because there is no embedded dot.
379 *
380 * - A Set-Cookie2 from request-host example for Domain=.local will
381 * be accepted, because the effective host name for the request-
382 * host is example.local, and example.local domain-matches .local.
383 *
384 * I'm ignoring the first point for now (must check to see how other browsers handle
385 * this rule for Set-Cookie headers)
386 *
387 * @param string $domain1
388 * @param string $domain2
389 * @return bool
390 * @access private
391 */
392 function _domain_match($domain1, $domain2)
393 {
394 $domain1 = strtolower($domain1);
395 $domain2 = strtolower($domain2);
396 while (strpos($domain1, '.') !== false) {
397 if ($domain1 == $domain2) return true;
398 $domain1 = $this->_reduce_domain($domain1);
399 continue;
400 }
401 return false;
402 }
403}
404?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/humble-http-agent/HumbleHttpAgent.php b/inc/3rdparty/libraries/humble-http-agent/HumbleHttpAgent.php
new file mode 100644
index 00000000..e4f1b3b3
--- /dev/null
+++ b/inc/3rdparty/libraries/humble-http-agent/HumbleHttpAgent.php
@@ -0,0 +1,779 @@
1<?php
2/**
3 * Humble HTTP Agent
4 *
5 * This class is designed to take advantage of parallel HTTP requests
6 * offered by PHP's PECL HTTP extension or the curl_multi_* functions.
7 * For environments which do not have these options, it reverts to standard sequential
8 * requests (using file_get_contents())
9 *
10 * @version 1.1
11 * @date 2012-08-20
12 * @see http://php.net/HttpRequestPool
13 * @author Keyvan Minoukadeh
14 * @copyright 2011-2012 Keyvan Minoukadeh
15 * @license http://www.gnu.org/licenses/agpl-3.0.html AGPL v3
16 */
17
18class HumbleHttpAgent
19{
20 const METHOD_REQUEST_POOL = 1;
21 const METHOD_CURL_MULTI = 2;
22 const METHOD_FILE_GET_CONTENTS = 4;
23 //const UA_BROWSER = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1';
24 const UA_BROWSER = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.92 Safari/535.2';
25 const UA_PHP = 'PHP/5.2';
26 const REF_GOOGLE = 'http://www.google.co.uk/url?sa=t&source=web&cd=1';
27
28 protected $requests = array();
29 protected $redirectQueue = array();
30 protected $requestOptions;
31 protected $maxParallelRequests = 5;
32 protected $cache = null; //TODO
33 protected $httpContext;
34 protected $minimiseMemoryUse = false; //TODO
35 protected $method;
36 protected $cookieJar;
37 public $debug = false;
38 public $debugVerbose = false;
39 public $rewriteHashbangFragment = true; // see http://code.google.com/web/ajaxcrawling/docs/specification.html
40 public $maxRedirects = 5;
41 public $userAgentMap = array();
42 public $rewriteUrls = array();
43 public $userAgentDefault;
44 public $referer;
45 //public $userAgent = 'Mozilla/5.0';
46
47 // Prevent certain file/mime types
48 // HTTP responses which match these content types will
49 // be returned without body.
50 public $headerOnlyTypes = array();
51 // URLs ending with one of these extensions will
52 // prompt Humble HTTP Agent to send a HEAD request first
53 // to see if returned content type matches $headerOnlyTypes.
54 public $headerOnlyClues = array('pdf','mp3','zip','exe','gif','gzip','gz','jpeg','jpg','mpg','mpeg','png','ppt','mov');
55 // AJAX triggers to search for.
56 // for AJAX sites, e.g. Blogger with its dynamic views templates.
57 public $ajaxTriggers = array("<meta name='fragment' content='!'",'<meta name="fragment" content="!"',"<meta content='!' name='fragment'",'<meta content="!" name="fragment"');
58
59 //TODO: set max file size
60 //TODO: normalise headers
61
62 function __construct($requestOptions=null, $method=null) {
63 $this->userAgentDefault = self::UA_BROWSER;
64 $this->referer = self::REF_GOOGLE;
65 // set the request method
66 if (in_array($method, array(1,2,4))) {
67 $this->method = $method;
68 } else {
69 if (class_exists('HttpRequestPool')) {
70 $this->method = self::METHOD_REQUEST_POOL;
71 } elseif (function_exists('curl_multi_init')) {
72 $this->method = self::METHOD_CURL_MULTI;
73 } else {
74 $this->method = self::METHOD_FILE_GET_CONTENTS;
75 }
76 }
77 if ($this->method == self::METHOD_CURL_MULTI) {
78 require_once(dirname(__FILE__).'/RollingCurl.php');
79 }
80 // create cookie jar
81 $this->cookieJar = new CookieJar();
82 // set request options (redirect must be 0)
83 $this->requestOptions = array(
84 'timeout' => 15,
85 'redirect' => 0 // we handle redirects manually so we can rewrite the new hashbang URLs that are creeping up over the web
86 // TODO: test onprogress?
87 );
88 if (is_array($requestOptions)) {
89 $this->requestOptions = array_merge($this->requestOptions, $requestOptions);
90 }
91 $this->httpContext = array(
92 'http' => array(
93 'ignore_errors' => true,
94 'timeout' => $this->requestOptions['timeout'],
95 'max_redirects' => $this->requestOptions['redirect'],
96 'header' => "Accept: */*\r\n"
97 )
98 );
99 }
100
101 protected function debug($msg) {
102 if ($this->debug) {
103 $mem = round(memory_get_usage()/1024, 2);
104 $memPeak = round(memory_get_peak_usage()/1024, 2);
105 echo '* ',$msg;
106 if ($this->debugVerbose) echo ' - mem used: ',$mem," (peak: $memPeak)";
107 echo "\n";
108 ob_flush();
109 flush();
110 }
111 }
112
113 protected function getUserAgent($url, $asArray=false) {
114 $host = @parse_url($url, PHP_URL_HOST);
115 if (strtolower(substr($host, 0, 4)) == 'www.') {
116 $host = substr($host, 4);
117 }
118 if ($host) {
119 $try = array($host);
120 $split = explode('.', $host);
121 if (count($split) > 1) {
122 array_shift($split);
123 $try[] = '.'.implode('.', $split);
124 }
125 foreach ($try as $h) {
126 if (isset($this->userAgentMap[$h])) {
127 $ua = $this->userAgentMap[$h];
128 break;
129 }
130 }
131 }
132 if (!isset($ua)) $ua = $this->userAgentDefault;
133 if ($asArray) {
134 return array('User-Agent' => $ua);
135 } else {
136 return 'User-Agent: '.$ua;
137 }
138 }
139
140 public function rewriteHashbangFragment($url) {
141 // return $url if there's no '#!'
142 if (strpos($url, '#!') === false) return $url;
143 // split $url and rewrite
144 // TODO: is SimplePie_IRI included?
145 $iri = new SimplePie_IRI($url);
146 $fragment = substr($iri->fragment, 1); // strip '!'
147 $iri->fragment = null;
148 if (isset($iri->query)) {
149 parse_str($iri->query, $query);
150 } else {
151 $query = array();
152 }
153 $query['_escaped_fragment_'] = (string)$fragment;
154 $iri->query = str_replace('%2F', '/', http_build_query($query)); // needed for some sites
155 return $iri->get_iri();
156 }
157
158 public function getUglyURL($url, $html) {
159 if ($html == '') return false;
160 $found = false;
161 foreach ($this->ajaxTriggers as $string) {
162 if (stripos($html, $string)) {
163 $found = true;
164 break;
165 }
166 }
167 if (!$found) return false;
168 $iri = new SimplePie_IRI($url);
169 if (isset($iri->query)) {
170 parse_str($iri->query, $query);
171 } else {
172 $query = array();
173 }
174 $query['_escaped_fragment_'] = '';
175 $iri->query = str_replace('%2F', '/', http_build_query($query)); // needed for some sites
176 return $iri->get_iri();
177 }
178
179 public function removeFragment($url) {
180 $pos = strpos($url, '#');
181 if ($pos === false) {
182 return $url;
183 } else {
184 return substr($url, 0, $pos);
185 }
186 }
187
188 public function rewriteUrls($url) {
189 foreach ($this->rewriteUrls as $find => $action) {
190 if (strpos($url, $find) !== false) {
191 if (is_array($action)) {
192 return strtr($url, $action);
193 }
194 }
195 }
196 return $url;
197 }
198
199 public function enableDebug($bool=true) {
200 $this->debug = (bool)$bool;
201 }
202
203 public function minimiseMemoryUse($bool = true) {
204 $this->minimiseMemoryUse = $bool;
205 }
206
207 public function setMaxParallelRequests($max) {
208 $this->maxParallelRequests = $max;
209 }
210
211 public function validateUrl($url) {
212 $url = filter_var($url, FILTER_SANITIZE_URL);
213 $test = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED);
214 // deal with bug http://bugs.php.net/51192 (present in PHP 5.2.13 and PHP 5.3.2)
215 if ($test === false) {
216 $test = filter_var(strtr($url, '-', '_'), FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED);
217 }
218 if ($test !== false && $test !== null && preg_match('!^https?://!', $url)) {
219 return $url;
220 } else {
221 return false;
222 }
223 }
224
225 public function fetchAll(array $urls) {
226 $this->fetchAllOnce($urls, $isRedirect=false);
227 $redirects = 0;
228 while (!empty($this->redirectQueue) && ++$redirects <= $this->maxRedirects) {
229 $this->debug("Following redirects #$redirects...");
230 $this->fetchAllOnce($this->redirectQueue, $isRedirect=true);
231 }
232 }
233
234 // fetch all URLs without following redirects
235 public function fetchAllOnce(array $urls, $isRedirect=false) {
236 if (!$isRedirect) $urls = array_unique($urls);
237 if (empty($urls)) return;
238
239 //////////////////////////////////////////////////////
240 // parallel (HttpRequestPool)
241 if ($this->method == self::METHOD_REQUEST_POOL) {
242 $this->debug('Starting parallel fetch (HttpRequestPool)');
243 try {
244 while (count($urls) > 0) {
245 $this->debug('Processing set of '.min($this->maxParallelRequests, count($urls)));
246 $subset = array_splice($urls, 0, $this->maxParallelRequests);
247 $pool = new HttpRequestPool();
248 foreach ($subset as $orig => $url) {
249 if (!$isRedirect) $orig = $url;
250 unset($this->redirectQueue[$orig]);
251 $this->debug("...$url");
252 if (!$isRedirect && isset($this->requests[$url])) {
253 $this->debug("......in memory");
254 /*
255 } elseif ($this->isCached($url)) {
256 $this->debug("......is cached");
257 if (!$this->minimiseMemoryUse) {
258 $this->requests[$url] = $this->getCached($url);
259 }
260 */
261 } else {
262 $this->debug("......adding to pool");
263 $req_url = $this->rewriteUrls($url);
264 $req_url = ($this->rewriteHashbangFragment) ? $this->rewriteHashbangFragment($req_url) : $req_url;
265 $req_url = $this->removeFragment($req_url);
266 if (!empty($this->headerOnlyTypes) && !isset($this->requests[$orig]['wrongGuess']) && $this->possibleUnsupportedType($req_url)) {
267 $_meth = HttpRequest::METH_HEAD;
268 } else {
269 $_meth = HttpRequest::METH_GET;
270 unset($this->requests[$orig]['wrongGuess']);
271 }
272 $httpRequest = new HttpRequest($req_url, $_meth, $this->requestOptions);
273 // send cookies, if we have any
274 if ($cookies = $this->cookieJar->getMatchingCookies($req_url)) {
275 $this->debug("......sending cookies: $cookies");
276 $httpRequest->addHeaders(array('Cookie' => $cookies));
277 }
278 //$httpRequest->addHeaders(array('User-Agent' => $this->userAgent));
279 $httpRequest->addHeaders($this->getUserAgent($req_url, true));
280 // add referer for picky sites
281 $httpRequest->addheaders(array('Referer' => $this->referer));
282 $this->requests[$orig] = array('headers'=>null, 'body'=>null, 'httpRequest'=>$httpRequest);
283 $this->requests[$orig]['original_url'] = $orig;
284 $pool->attach($httpRequest);
285 }
286 }
287 // did we get anything into the pool?
288 if (count($pool) > 0) {
289 $this->debug('Sending request...');
290 try {
291 $pool->send();
292 } catch (HttpRequestPoolException $e) {
293 // do nothing
294 }
295 $this->debug('Received responses');
296 foreach($subset as $orig => $url) {
297 if (!$isRedirect) $orig = $url;
298 $request = $this->requests[$orig]['httpRequest'];
299 //$this->requests[$orig]['headers'] = $this->headersToString($request->getResponseHeader());
300 // getResponseHeader() doesn't return status line, so, for consistency...
301 $this->requests[$orig]['headers'] = substr($request->getRawResponseMessage(), 0, $request->getResponseInfo('header_size'));
302 // check content type
303 // TODO: use getResponseHeader('content-type') or getResponseInfo()
304 if ($this->headerOnlyType($this->requests[$orig]['headers'])) {
305 $this->requests[$orig]['body'] = '';
306 $_header_only_type = true;
307 $this->debug('Header only type returned');
308 } else {
309 $this->requests[$orig]['body'] = $request->getResponseBody();
310 $_header_only_type = false;
311 }
312 $this->requests[$orig]['effective_url'] = $request->getResponseInfo('effective_url');
313 $this->requests[$orig]['status_code'] = $status_code = $request->getResponseCode();
314 // is redirect?
315 if ((in_array($status_code, array(300, 301, 302, 303, 307)) || $status_code > 307 && $status_code < 400) && $request->getResponseHeader('location')) {
316 $redirectURL = $request->getResponseHeader('location');
317 if (!preg_match('!^https?://!i', $redirectURL)) {
318 $redirectURL = SimplePie_Misc::absolutize_url($redirectURL, $url);
319 }
320 if ($this->validateURL($redirectURL)) {
321 $this->debug('Redirect detected. Valid URL: '.$redirectURL);
322 // store any cookies
323 $cookies = $request->getResponseHeader('set-cookie');
324 if ($cookies && !is_array($cookies)) $cookies = array($cookies);
325 if ($cookies) $this->cookieJar->storeCookies($url, $cookies);
326 $this->redirectQueue[$orig] = $redirectURL;
327 } else {
328 $this->debug('Redirect detected. Invalid URL: '.$redirectURL);
329 }
330 } elseif (!$_header_only_type && $request->getMethod() === HttpRequest::METH_HEAD) {
331 // the response content-type did not match our 'header only' types,
332 // but we'd issues a HEAD request because we assumed it would. So
333 // let's queue a proper GET request for this item...
334 $this->debug('Wrong guess at content-type, queing GET request');
335 $this->requests[$orig]['wrongGuess'] = true;
336 $this->redirectQueue[$orig] = $this->requests[$orig]['effective_url'];
337 } elseif (strpos($this->requests[$orig]['effective_url'], '_escaped_fragment_') === false) {
338 // check for <meta name='fragment' content='!'/>
339 // for AJAX sites, e.g. Blogger with its dynamic views templates.
340 // Based on Google's spec: https://developers.google.com/webmasters/ajax-crawling/docs/specification
341 if (isset($this->requests[$orig]['body'])) {
342 $redirectURL = $this->getUglyURL($this->requests[$orig]['effective_url'], substr($this->requests[$orig]['body'], 0, 4000));
343 if ($redirectURL) {
344 $this->debug('AJAX trigger (meta name="fragment" content="!") found. Queueing '.$redirectURL);
345 $this->redirectQueue[$orig] = $redirectURL;
346 }
347 }
348 }
349 //die($url.' -multi- '.$request->getResponseInfo('effective_url'));
350 $pool->detach($request);
351 unset($this->requests[$orig]['httpRequest'], $request);
352 /*
353 if ($this->minimiseMemoryUse) {
354 if ($this->cache($url)) {
355 unset($this->requests[$url]);
356 }
357 }
358 */
359 }
360 }
361 }
362 } catch (HttpException $e) {
363 $this->debug($e);
364 return false;
365 }
366 }
367
368 //////////////////////////////////////////////////////////
369 // parallel (curl_multi_*)
370 elseif ($this->method == self::METHOD_CURL_MULTI) {
371 $this->debug('Starting parallel fetch (curl_multi_*)');
372 while (count($urls) > 0) {
373 $this->debug('Processing set of '.min($this->maxParallelRequests, count($urls)));
374 $subset = array_splice($urls, 0, $this->maxParallelRequests);
375 $pool = new RollingCurl(array($this, 'handleCurlResponse'));
376 $pool->window_size = count($subset);
377
378 foreach ($subset as $orig => $url) {
379 if (!$isRedirect) $orig = $url;
380 unset($this->redirectQueue[$orig]);
381 $this->debug("...$url");
382 if (!$isRedirect && isset($this->requests[$url])) {
383 $this->debug("......in memory");
384 /*
385 } elseif ($this->isCached($url)) {
386 $this->debug("......is cached");
387 if (!$this->minimiseMemoryUse) {
388 $this->requests[$url] = $this->getCached($url);
389 }
390 */
391 } else {
392 $this->debug("......adding to pool");
393 $req_url = $this->rewriteUrls($url);
394 $req_url = ($this->rewriteHashbangFragment) ? $this->rewriteHashbangFragment($req_url) : $req_url;
395 $req_url = $this->removeFragment($req_url);
396 if (!empty($this->headerOnlyTypes) && !isset($this->requests[$orig]['wrongGuess']) && $this->possibleUnsupportedType($req_url)) {
397 $_meth = 'HEAD';
398 } else {
399 $_meth = 'GET';
400 unset($this->requests[$orig]['wrongGuess']);
401 }
402 $headers = array();
403 //$headers[] = 'User-Agent: '.$this->userAgent;
404 $headers[] = $this->getUserAgent($req_url);
405 // add referer for picky sites
406 $headers[] = 'Referer: '.$this->referer;
407 // send cookies, if we have any
408 if ($cookies = $this->cookieJar->getMatchingCookies($req_url)) {
409 $this->debug("......sending cookies: $cookies");
410 $headers[] = 'Cookie: '.$cookies;
411 }
412 $httpRequest = new RollingCurlRequest($req_url, $_meth, null, $headers, array(
413 CURLOPT_CONNECTTIMEOUT => $this->requestOptions['timeout'],
414 CURLOPT_TIMEOUT => $this->requestOptions['timeout']
415 ));
416 $httpRequest->set_original_url($orig);
417 $this->requests[$orig] = array('headers'=>null, 'body'=>null, 'httpRequest'=>$httpRequest);
418 $this->requests[$orig]['original_url'] = $orig; // TODO: is this needed anymore?
419 $pool->add($httpRequest);
420 }
421 }
422 // did we get anything into the pool?
423 if (count($pool) > 0) {
424 $this->debug('Sending request...');
425 $pool->execute(); // this will call handleCurlResponse() and populate $this->requests[$orig]
426 $this->debug('Received responses');
427 foreach($subset as $orig => $url) {
428 if (!$isRedirect) $orig = $url;
429 // $this->requests[$orig]['headers']
430 // $this->requests[$orig]['body']
431 // $this->requests[$orig]['effective_url']
432 // check content type
433 if ($this->headerOnlyType($this->requests[$orig]['headers'])) {
434 $this->requests[$orig]['body'] = '';
435 $_header_only_type = true;
436 $this->debug('Header only type returned');
437 } else {
438 $_header_only_type = false;
439 }
440 $status_code = $this->requests[$orig]['status_code'];
441 if ((in_array($status_code, array(300, 301, 302, 303, 307)) || $status_code > 307 && $status_code < 400) && isset($this->requests[$orig]['location'])) {
442 $redirectURL = $this->requests[$orig]['location'];
443 if (!preg_match('!^https?://!i', $redirectURL)) {
444 $redirectURL = SimplePie_Misc::absolutize_url($redirectURL, $url);
445 }
446 if ($this->validateURL($redirectURL)) {
447 $this->debug('Redirect detected. Valid URL: '.$redirectURL);
448 // store any cookies
449 $cookies = $this->cookieJar->extractCookies($this->requests[$orig]['headers']);
450 if (!empty($cookies)) $this->cookieJar->storeCookies($url, $cookies);
451 $this->redirectQueue[$orig] = $redirectURL;
452 } else {
453 $this->debug('Redirect detected. Invalid URL: '.$redirectURL);
454 }
455 } elseif (!$_header_only_type && $this->requests[$orig]['method'] == 'HEAD') {
456 // the response content-type did not match our 'header only' types,
457 // but we'd issues a HEAD request because we assumed it would. So
458 // let's queue a proper GET request for this item...
459 $this->debug('Wrong guess at content-type, queing GET request');
460 $this->requests[$orig]['wrongGuess'] = true;
461 $this->redirectQueue[$orig] = $this->requests[$orig]['effective_url'];
462 } elseif (strpos($this->requests[$orig]['effective_url'], '_escaped_fragment_') === false) {
463 // check for <meta name='fragment' content='!'/>
464 // for AJAX sites, e.g. Blogger with its dynamic views templates.
465 // Based on Google's spec: https://developers.google.com/webmasters/ajax-crawling/docs/specification
466 if (isset($this->requests[$orig]['body'])) {
467 $redirectURL = $this->getUglyURL($this->requests[$orig]['effective_url'], substr($this->requests[$orig]['body'], 0, 4000));
468 if ($redirectURL) {
469 $this->debug('AJAX trigger (meta name="fragment" content="!") found. Queueing '.$redirectURL);
470 $this->redirectQueue[$orig] = $redirectURL;
471 }
472 }
473 }
474 // die($url.' -multi- '.$request->getResponseInfo('effective_url'));
475 unset($this->requests[$orig]['httpRequest'], $this->requests[$orig]['method']);
476 }
477 }
478 }
479 }
480
481 //////////////////////////////////////////////////////
482 // sequential (file_get_contents)
483 else {
484 $this->debug('Starting sequential fetch (file_get_contents)');
485 $this->debug('Processing set of '.count($urls));
486 foreach ($urls as $orig => $url) {
487 if (!$isRedirect) $orig = $url;
488 unset($this->redirectQueue[$orig]);
489 $this->debug("...$url");
490 if (!$isRedirect && isset($this->requests[$url])) {
491 $this->debug("......in memory");
492 /*
493 } elseif ($this->isCached($url)) {
494 $this->debug("......is cached");
495 if (!$this->minimiseMemoryUse) {
496 $this->requests[$url] = $this->getCached($url);
497 }
498 */
499 } else {
500 $this->debug("Sending request for $url");
501 $this->requests[$orig]['original_url'] = $orig;
502 $req_url = $this->rewriteUrls($url);
503 $req_url = ($this->rewriteHashbangFragment) ? $this->rewriteHashbangFragment($req_url) : $req_url;
504 $req_url = $this->removeFragment($req_url);
505 // send cookies, if we have any
506 $httpContext = $this->httpContext;
507 $httpContext['http']['header'] .= $this->getUserAgent($req_url)."\r\n";
508 // add referer for picky sites
509 $httpContext['http']['header'] .= 'Referer: '.$this->referer."\r\n";
510 if ($cookies = $this->cookieJar->getMatchingCookies($req_url)) {
511 $this->debug("......sending cookies: $cookies");
512 $httpContext['http']['header'] .= 'Cookie: '.$cookies."\r\n";
513 }
514 if (false !== ($html = @file_get_contents($req_url, false, stream_context_create($httpContext)))) {
515 $this->debug('Received response');
516 // get status code
517 if (!isset($http_response_header[0]) || !preg_match('!^HTTP/\d+\.\d+\s+(\d+)!', trim($http_response_header[0]), $match)) {
518 $this->debug('Error: no status code found');
519 // TODO: handle error - no status code
520 } else {
521 $this->requests[$orig]['headers'] = $this->headersToString($http_response_header, false);
522 // check content type
523 if ($this->headerOnlyType($this->requests[$orig]['headers'])) {
524 $this->requests[$orig]['body'] = '';
525 } else {
526 $this->requests[$orig]['body'] = $html;
527 }
528 $this->requests[$orig]['effective_url'] = $req_url;
529 $this->requests[$orig]['status_code'] = $status_code = (int)$match[1];
530 unset($match);
531 // handle redirect
532 if (preg_match('/^Location:(.*?)$/mi', $this->requests[$orig]['headers'], $match)) {
533 $this->requests[$orig]['location'] = trim($match[1]);
534 }
535 if ((in_array($status_code, array(300, 301, 302, 303, 307)) || $status_code > 307 && $status_code < 400) && isset($this->requests[$orig]['location'])) {
536 $redirectURL = $this->requests[$orig]['location'];
537 if (!preg_match('!^https?://!i', $redirectURL)) {
538 $redirectURL = SimplePie_Misc::absolutize_url($redirectURL, $url);
539 }
540 if ($this->validateURL($redirectURL)) {
541 $this->debug('Redirect detected. Valid URL: '.$redirectURL);
542 // store any cookies
543 $cookies = $this->cookieJar->extractCookies($this->requests[$orig]['headers']);
544 if (!empty($cookies)) $this->cookieJar->storeCookies($url, $cookies);
545 $this->redirectQueue[$orig] = $redirectURL;
546 } else {
547 $this->debug('Redirect detected. Invalid URL: '.$redirectURL);
548 }
549 } elseif (strpos($this->requests[$orig]['effective_url'], '_escaped_fragment_') === false) {
550 // check for <meta name='fragment' content='!'/>
551 // for AJAX sites, e.g. Blogger with its dynamic views templates.
552 // Based on Google's spec: https://developers.google.com/webmasters/ajax-crawling/docs/specification
553 if (isset($this->requests[$orig]['body'])) {
554 $redirectURL = $this->getUglyURL($this->requests[$orig]['effective_url'], substr($this->requests[$orig]['body'], 0, 4000));
555 if ($redirectURL) {
556 $this->debug('AJAX trigger (meta name="fragment" content="!") found. Queueing '.$redirectURL);
557 $this->redirectQueue[$orig] = $redirectURL;
558 }
559 }
560 }
561 }
562 } else {
563 $this->debug('Error retrieving URL');
564 //print_r($req_url);
565 //print_r($http_response_header);
566 //print_r($html);
567
568 // TODO: handle error - failed to retrieve URL
569 }
570 }
571 }
572 }
573 }
574
575 public function handleCurlResponse($response, $info, $request) {
576 $orig = $request->url_original;
577 $this->requests[$orig]['headers'] = substr($response, 0, $info['header_size']);
578 $this->requests[$orig]['body'] = substr($response, $info['header_size']);
579 $this->requests[$orig]['method'] = $request->method;
580 $this->requests[$orig]['effective_url'] = $info['url'];
581 $this->requests[$orig]['status_code'] = (int)$info['http_code'];
582 if (preg_match('/^Location:(.*?)$/mi', $this->requests[$orig]['headers'], $match)) {
583 $this->requests[$orig]['location'] = trim($match[1]);
584 }
585 }
586
587 protected function headersToString(array $headers, $associative=true) {
588 if (!$associative) {
589 return implode("\n", $headers);
590 } else {
591 $str = '';
592 foreach ($headers as $key => $val) {
593 if (is_array($val)) {
594 foreach ($val as $v) $str .= "$key: $v\n";
595 } else {
596 $str .= "$key: $val\n";
597 }
598 }
599 return rtrim($str);
600 }
601 }
602
603 public function get($url, $remove=false, $gzdecode=true) {
604 $url = "$url";
605 if (isset($this->requests[$url]) && isset($this->requests[$url]['body'])) {
606 $this->debug("URL already fetched - in memory ($url, effective: {$this->requests[$url]['effective_url']})");
607 $response = $this->requests[$url];
608 /*
609 } elseif ($this->isCached($url)) {
610 $this->debug("URL already fetched - in disk cache ($url)");
611 $response = $this->getCached($url);
612 $this->requests[$url] = $response;
613 */
614 } else {
615 $this->debug("Fetching URL ($url)");
616 $this->fetchAll(array($url));
617 if (isset($this->requests[$url]) && isset($this->requests[$url]['body'])) {
618 $response = $this->requests[$url];
619 } else {
620 $this->debug("Request failed");
621 $response = false;
622 }
623 }
624 /*
625 if ($this->minimiseMemoryUse && $response) {
626 $this->cache($url);
627 unset($this->requests[$url]);
628 }
629 */
630 if ($remove && $response) unset($this->requests[$url]);
631 if ($gzdecode && stripos($response['headers'], 'Content-Encoding: gzip')) {
632 if ($html = gzdecode($response['body'])) {
633 $response['body'] = $html;
634 }
635 }
636 return $response;
637 }
638
639 public function parallelSupport() {
640 return class_exists('HttpRequestPool') || function_exists('curl_multi_init');
641 }
642
643 private function headerOnlyType($headers) {
644 if (preg_match('!^Content-Type:\s*(([a-z-]+)/([^;\r\n ]+))!im', $headers, $match)) {
645 // look for full mime type (e.g. image/jpeg) or just type (e.g. image)
646 $match[1] = strtolower(trim($match[1]));
647 $match[2] = strtolower(trim($match[2]));
648 foreach (array($match[1], $match[2]) as $mime) {
649 if (in_array($mime, $this->headerOnlyTypes)) return true;
650 }
651 }
652 return false;
653 }
654
655 private function possibleUnsupportedType($url) {
656 $path = @parse_url($url, PHP_URL_PATH);
657 if ($path && strpos($path, '.') !== false) {
658 $ext = strtolower(trim(pathinfo($path, PATHINFO_EXTENSION)));
659 return in_array($ext, $this->headerOnlyClues);
660 }
661 return false;
662 }
663}
664
665// gzdecode from http://www.php.net/manual/en/function.gzdecode.php#82930
666if (!function_exists('gzdecode')) {
667 function gzdecode($data,&$filename='',&$error='',$maxlength=null)
668 {
669 $len = strlen($data);
670 if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
671 $error = "Not in GZIP format.";
672 return null; // Not GZIP format (See RFC 1952)
673 }
674 $method = ord(substr($data,2,1)); // Compression method
675 $flags = ord(substr($data,3,1)); // Flags
676 if ($flags & 31 != $flags) {
677 $error = "Reserved bits not allowed.";
678 return null;
679 }
680 // NOTE: $mtime may be negative (PHP integer limitations)
681 $mtime = unpack("V", substr($data,4,4));
682 $mtime = $mtime[1];
683 $xfl = substr($data,8,1);
684 $os = substr($data,8,1);
685 $headerlen = 10;
686 $extralen = 0;
687 $extra = "";
688 if ($flags & 4) {
689 // 2-byte length prefixed EXTRA data in header
690 if ($len - $headerlen - 2 < 8) {
691 return false; // invalid
692 }
693 $extralen = unpack("v",substr($data,8,2));
694 $extralen = $extralen[1];
695 if ($len - $headerlen - 2 - $extralen < 8) {
696 return false; // invalid
697 }
698 $extra = substr($data,10,$extralen);
699 $headerlen += 2 + $extralen;
700 }
701 $filenamelen = 0;
702 $filename = "";
703 if ($flags & 8) {
704 // C-style string
705 if ($len - $headerlen - 1 < 8) {
706 return false; // invalid
707 }
708 $filenamelen = strpos(substr($data,$headerlen),chr(0));
709 if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
710 return false; // invalid
711 }
712 $filename = substr($data,$headerlen,$filenamelen);
713 $headerlen += $filenamelen + 1;
714 }
715 $commentlen = 0;
716 $comment = "";
717 if ($flags & 16) {
718 // C-style string COMMENT data in header
719 if ($len - $headerlen - 1 < 8) {
720 return false; // invalid
721 }
722 $commentlen = strpos(substr($data,$headerlen),chr(0));
723 if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
724 return false; // Invalid header format
725 }
726 $comment = substr($data,$headerlen,$commentlen);
727 $headerlen += $commentlen + 1;
728 }
729 $headercrc = "";
730 if ($flags & 2) {
731 // 2-bytes (lowest order) of CRC32 on header present
732 if ($len - $headerlen - 2 < 8) {
733 return false; // invalid
734 }
735 $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
736 $headercrc = unpack("v", substr($data,$headerlen,2));
737 $headercrc = $headercrc[1];
738 if ($headercrc != $calccrc) {
739 $error = "Header checksum failed.";
740 return false; // Bad header CRC
741 }
742 $headerlen += 2;
743 }
744 // GZIP FOOTER
745 $datacrc = unpack("V",substr($data,-8,4));
746 $datacrc = sprintf('%u',$datacrc[1] & 0xFFFFFFFF);
747 $isize = unpack("V",substr($data,-4));
748 $isize = $isize[1];
749 // decompression:
750 $bodylen = $len-$headerlen-8;
751 if ($bodylen < 1) {
752 // IMPLEMENTATION BUG!
753 return null;
754 }
755 $body = substr($data,$headerlen,$bodylen);
756 $data = "";
757 if ($bodylen > 0) {
758 switch ($method) {
759 case 8:
760 // Currently the only supported compression method:
761 $data = gzinflate($body,$maxlength);
762 break;
763 default:
764 $error = "Unknown compression method.";
765 return false;
766 }
767 } // zero-byte body content is allowed
768 // Verifiy CRC32
769 $crc = sprintf("%u",crc32($data));
770 $crcOK = $crc == $datacrc;
771 $lenOK = $isize == strlen($data);
772 if (!$lenOK || !$crcOK) {
773 $error = ( $lenOK ? '' : 'Length check FAILED. ') . ( $crcOK ? '' : 'Checksum FAILED.');
774 return false;
775 }
776 return $data;
777 }
778}
779?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/humble-http-agent/RollingCurl.php b/inc/3rdparty/libraries/humble-http-agent/RollingCurl.php
new file mode 100644
index 00000000..d24dc690
--- /dev/null
+++ b/inc/3rdparty/libraries/humble-http-agent/RollingCurl.php
@@ -0,0 +1,402 @@
1<?php
2/*
3Authored by Josh Fraser (www.joshfraser.com)
4Released under Apache License 2.0
5
6Maintained by Alexander Makarov, http://rmcreative.ru/
7
8Modified by Keyvan Minoukadeh for the Five Filters project: http://fivefilters.org
9*/
10
11/**
12 * Class that represent a single curl request
13 */
14class RollingCurlRequest {
15 public $url = false;
16 public $url_original = false; // used for tracking redirects
17 public $method = 'GET';
18 public $post_data = null;
19 public $headers = null;
20 public $options = null;
21
22 /**
23 * @param string $url
24 * @param string $method
25 * @param $post_data
26 * @param $headers
27 * @param $options
28 * @return void
29 */
30 function __construct($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
31 $this->url = $url;
32 $this->url_original = $url;
33 $this->method = $method;
34 $this->post_data = $post_data;
35 $this->headers = $headers;
36 $this->options = $options;
37 }
38
39 /**
40 * @param string $url
41 * @return void
42 */
43 public function set_original_url($url) {
44 $this->url_original = $url;
45 }
46 /**
47 * @return void
48 */
49 public function __destruct() {
50 unset($this->url, $this->url_original, $this->method, $this->post_data, $this->headers, $this->options);
51 }
52}
53
54/**
55 * RollingCurl custom exception
56 */
57class RollingCurlException extends Exception {
58}
59
60/**
61 * Class that holds a rolling queue of curl requests.
62 *
63 * @throws RollingCurlException
64 */
65class RollingCurl implements Countable {
66 /**
67 * @var int
68 *
69 * Window size is the max number of simultaneous connections allowed.
70 *
71 * REMEMBER TO RESPECT THE SERVERS:
72 * Sending too many requests at one time can easily be perceived
73 * as a DOS attack. Increase this window_size if you are making requests
74 * to multiple servers or have permission from the receving server admins.
75 */
76 private $window_size = 5;
77
78 /**
79 * @var float
80 *
81 * Timeout is the timeout used for curl_multi_select.
82 */
83 private $timeout = 10;
84
85 /**
86 * @var string|array
87 *
88 * Callback function to be applied to each result.
89 */
90 private $callback;
91
92 /**
93 * @var array
94 *
95 * Set your base options that you want to be used with EVERY request.
96 */
97 protected $options = array(
98 CURLOPT_SSL_VERIFYPEER => 0,
99 CURLOPT_RETURNTRANSFER => 1,
100 CURLOPT_CONNECTTIMEOUT => 30,
101 CURLOPT_TIMEOUT => 30
102 );
103
104 /**
105 * @var array
106 */
107 private $headers = array();
108
109 /**
110 * @var Request[]
111 *
112 * The request queue
113 */
114 private $requests = array();
115
116 /**
117 * @var RequestMap[]
118 *
119 * Maps handles to request indexes
120 */
121 private $requestMap = array();
122
123 /**
124 * @param $callback
125 * Callback function to be applied to each result.
126 *
127 * Can be specified as 'my_callback_function'
128 * or array($object, 'my_callback_method').
129 *
130 * Function should take three parameters: $response, $info, $request.
131 * $response is response body, $info is additional curl info.
132 * $request is the original request
133 *
134 * @return void
135 */
136 function __construct($callback = null) {
137 $this->callback = $callback;
138 }
139
140 /**
141 * @param string $name
142 * @return mixed
143 */
144 public function __get($name) {
145 return (isset($this->{$name})) ? $this->{$name} : null;
146 }
147
148 /**
149 * @param string $name
150 * @param mixed $value
151 * @return bool
152 */
153 public function __set($name, $value) {
154 // append the base options & headers
155 if ($name == "options" || $name == "headers") {
156 $this->{$name} = $value + $this->{$name};
157 } else {
158 $this->{$name} = $value;
159 }
160 return true;
161 }
162
163 /**
164 * Count number of requests added (Countable interface)
165 *
166 * @return int
167 */
168 public function count() {
169 return count($this->requests);
170 }
171
172 /**
173 * Add a request to the request queue
174 *
175 * @param Request $request
176 * @return bool
177 */
178 public function add($request) {
179 $this->requests[] = $request;
180 return true;
181 }
182
183 /**
184 * Create new Request and add it to the request queue
185 *
186 * @param string $url
187 * @param string $method
188 * @param $post_data
189 * @param $headers
190 * @param $options
191 * @return bool
192 */
193 public function request($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
194 $this->requests[] = new RollingCurlRequest($url, $method, $post_data, $headers, $options);
195 return true;
196 }
197
198 /**
199 * Perform GET request
200 *
201 * @param string $url
202 * @param $headers
203 * @param $options
204 * @return bool
205 */
206 public function get($url, $headers = null, $options = null) {
207 return $this->request($url, "GET", null, $headers, $options);
208 }
209
210 /**
211 * Perform POST request
212 *
213 * @param string $url
214 * @param $post_data
215 * @param $headers
216 * @param $options
217 * @return bool
218 */
219 public function post($url, $post_data = null, $headers = null, $options = null) {
220 return $this->request($url, "POST", $post_data, $headers, $options);
221 }
222
223 /**
224 * Execute processing
225 *
226 * @param int $window_size Max number of simultaneous connections
227 * @return string|bool
228 */
229 public function execute($window_size = null) {
230 // rolling curl window must always be greater than 1
231 if (sizeof($this->requests) == 1) {
232 return $this->single_curl();
233 } else {
234 // start the rolling curl. window_size is the max number of simultaneous connections
235 return $this->rolling_curl($window_size);
236 }
237 }
238
239 /**
240 * Performs a single curl request
241 *
242 * @access private
243 * @return string
244 */
245 private function single_curl() {
246 $ch = curl_init();
247 $request = array_shift($this->requests);
248 $options = $this->get_options($request);
249 curl_setopt_array($ch, $options);
250 $output = curl_exec($ch);
251 $info = curl_getinfo($ch);
252
253 // it's not neccesary to set a callback for one-off requests
254 if ($this->callback) {
255 $callback = $this->callback;
256 if (is_callable($this->callback)) {
257 call_user_func($callback, $output, $info, $request);
258 }
259 }
260 else
261 return $output;
262 return true;
263 }
264
265 /**
266 * Performs multiple curl requests
267 *
268 * @access private
269 * @throws RollingCurlException
270 * @param int $window_size Max number of simultaneous connections
271 * @return bool
272 */
273 private function rolling_curl($window_size = null) {
274 if ($window_size)
275 $this->window_size = $window_size;
276
277 // make sure the rolling window isn't greater than the # of urls
278 if (sizeof($this->requests) < $this->window_size)
279 $this->window_size = sizeof($this->requests);
280
281 if ($this->window_size < 2) {
282 throw new RollingCurlException("Window size must be greater than 1");
283 }
284
285 $master = curl_multi_init();
286
287 // start the first batch of requests
288 for ($i = 0; $i < $this->window_size; $i++) {
289 $ch = curl_init();
290
291 $options = $this->get_options($this->requests[$i]);
292
293 curl_setopt_array($ch, $options);
294 curl_multi_add_handle($master, $ch);
295
296 // Add to our request Maps
297 $key = (string) $ch;
298 $this->requestMap[$key] = $i;
299 }
300
301 do {
302 while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ;
303 if ($execrun != CURLM_OK)
304 break;
305 // a request was just completed -- find out which one
306 while ($done = curl_multi_info_read($master)) {
307
308 // get the info and content returned on the request
309 $info = curl_getinfo($done['handle']);
310 $output = curl_multi_getcontent($done['handle']);
311
312 // send the return values to the callback function.
313 $callback = $this->callback;
314 if (is_callable($callback)) {
315 $key = (string) $done['handle'];
316 $request = $this->requests[$this->requestMap[$key]];
317 unset($this->requestMap[$key]);
318 call_user_func($callback, $output, $info, $request);
319 }
320
321 // start a new request (it's important to do this before removing the old one)
322 if ($i < sizeof($this->requests) && isset($this->requests[$i]) && $i < count($this->requests)) {
323 $ch = curl_init();
324 $options = $this->get_options($this->requests[$i]);
325 curl_setopt_array($ch, $options);
326 curl_multi_add_handle($master, $ch);
327
328 // Add to our request Maps
329 $key = (string) $ch;
330 $this->requestMap[$key] = $i;
331 $i++;
332 }
333
334 // remove the curl handle that just completed
335 curl_multi_remove_handle($master, $done['handle']);
336
337 }
338
339 // Block for data in / output; error handling is done by curl_multi_exec
340 //if ($running) curl_multi_select($master, $this->timeout);
341 // removing timeout as it causes problems on Windows with PHP 5.3.5 and Curl 7.20.0
342 if ($running) curl_multi_select($master);
343
344 } while ($running);
345 curl_multi_close($master);
346 return true;
347 }
348
349
350 /**
351 * Helper function to set up a new request by setting the appropriate options
352 *
353 * @access private
354 * @param Request $request
355 * @return array
356 */
357 private function get_options($request) {
358 // options for this entire curl object
359 $options = $this->__get('options');
360 // We're managing reirects in PHP - allows us to intervene and rewrite/block URLs
361 // before the next request goes out.
362 $options[CURLOPT_FOLLOWLOCATION] = 0;
363 $options[CURLOPT_MAXREDIRS] = 0;
364 //if (ini_get('safe_mode') == 'Off' || !ini_get('safe_mode')) {
365 // $options[CURLOPT_FOLLOWLOCATION] = 1;
366 // $options[CURLOPT_MAXREDIRS] = 5;
367 //}
368 $headers = $this->__get('headers');
369 // append custom headers for this specific request
370 if ($request->headers) {
371 $headers = $headers + $request->headers;
372 }
373
374 // append custom options for this specific request
375 if ($request->options) {
376 $options = $request->options + $options;
377 }
378
379 // set the request URL
380 $options[CURLOPT_URL] = $request->url;
381
382 if ($headers) {
383 $options[CURLOPT_HTTPHEADER] = $headers;
384 }
385 // return response headers
386 $options[CURLOPT_HEADER] = 1;
387
388 // send HEAD request?
389 if ($request->method == 'HEAD') {
390 $options[CURLOPT_NOBODY] = 1;
391 }
392
393 return $options;
394 }
395
396 /**
397 * @return void
398 */
399 public function __destruct() {
400 unset($this->window_size, $this->callback, $this->options, $this->headers, $this->requests);
401 }
402} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/humble-http-agent/SimplePie_HumbleHttpAgent.php b/inc/3rdparty/libraries/humble-http-agent/SimplePie_HumbleHttpAgent.php
new file mode 100644
index 00000000..ecd46d5f
--- /dev/null
+++ b/inc/3rdparty/libraries/humble-http-agent/SimplePie_HumbleHttpAgent.php
@@ -0,0 +1,79 @@
1<?php
2/**
3 * Humble HTTP Agent extension for SimplePie_File
4 *
5 * This class is designed to extend and override SimplePie_File
6 * in order to prevent duplicate HTTP requests being sent out.
7 * The idea is to initialise an instance of Humble HTTP Agent
8 * and attach it, to a static class variable, of this class.
9 * SimplePie will then automatically initialise this class
10 *
11 * @date 2011-02-28
12 */
13
14class SimplePie_HumbleHttpAgent extends SimplePie_File
15{
16 protected static $agent;
17 var $url;
18 var $useragent;
19 var $success = true;
20 var $headers = array();
21 var $body;
22 var $status_code;
23 var $redirects = 0;
24 var $error;
25 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
26
27 public static function set_agent(HumbleHttpAgent $agent) {
28 self::$agent = $agent;
29 }
30
31 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
32 if (class_exists('idna_convert'))
33 {
34 $idn = new idna_convert();
35 $parsed = SimplePie_Misc::parse_url($url);
36 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
37 }
38 $this->url = $url;
39 $this->useragent = $useragent;
40 if (preg_match('/^http(s)?:\/\//i', $url))
41 {
42 if (!is_array($headers))
43 {
44 $headers = array();
45 }
46 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
47 $headers2 = array();
48 foreach ($headers as $key => $value) {
49 $headers2[] = "$key: $value";
50 }
51 //TODO: allow for HTTP headers
52 // curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
53
54 $response = self::$agent->get($url);
55
56 if ($response === false || !isset($response['status_code'])) {
57 $this->error = 'failed to fetch URL';
58 $this->success = false;
59 } else {
60 // The extra lines at the end are there to satisfy SimplePie's HTTP parser.
61 // The class expects a full HTTP message, whereas we're giving it only
62 // headers - the new lines indicate the start of the body.
63 $parser = new SimplePie_HTTP_Parser($response['headers']."\r\n\r\n");
64 if ($parser->parse()) {
65 $this->headers = $parser->headers;
66 //$this->body = $parser->body;
67 $this->body = $response['body'];
68 $this->status_code = $parser->status_code;
69 }
70 }
71 }
72 else
73 {
74 $this->error = 'invalid URL';
75 $this->success = false;
76 }
77 }
78}
79?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/language-detect/LanguageDetect.php b/inc/3rdparty/libraries/language-detect/LanguageDetect.php
new file mode 100644
index 00000000..09b11546
--- /dev/null
+++ b/inc/3rdparty/libraries/language-detect/LanguageDetect.php
@@ -0,0 +1,1635 @@
1<?php
2
3/**
4 * Detects the language of a given piece of text.
5 *
6 * Attempts to detect the language of a sample of text by correlating ranked
7 * 3-gram frequencies to a table of 3-gram frequencies of known languages.
8 *
9 * Implements a version of a technique originally proposed by Cavnar & Trenkle
10 * (1994): "N-Gram-Based Text Categorization"
11 *
12 * PHP versions 4 and 5
13 *
14 * @category Text
15 * @package Text_LanguageDetect
16 * @author Nicholas Pisarro <infinityminusnine+pear@gmail.com>
17 * @copyright 2005-2006 Nicholas Pisarro
18 * @license http://www.debian.org/misc/bsd.license BSD
19 * @version CVS: $Id: LanguageDetect.php,v 1.20 2008/07/01 02:09:15 taak Exp $
20 * @link http://pear.php.net/package/Text_LanguageDetect/
21 * @link http://langdetect.blogspot.com/
22 */
23
24//require_once 'PEAR.php';
25require_once 'Parser.php';
26
27/**
28 * Language detection class
29 *
30 * Requires the langauge model database (lang.dat) that should have
31 * accompanied this class definition in order to be instantiated.
32 *
33 * Example usage:
34 *
35 * <code>
36 * require_once 'Text/LanguageDetect.php';
37 *
38 * $l = new Text_LanguageDetect;
39 *
40 * $stdin = fopen('php://stdin', 'r');
41 *
42 * echo "Supported languages:\n";
43 *
44 * $langs = $l->getLanguages();
45 * if (PEAR::isError($langs)) {
46 * die($langs->getMessage());
47 * }
48 *
49 * sort($langs);
50 * echo join(', ', $langs);
51 *
52 * while ($line = fgets($stdin)) {
53 * print_r($l->detect($line, 4));
54 * }
55 * </code>
56 *
57 * @category Text
58 * @package Text_LanguageDetect
59 * @author Nicholas Pisarro <infinityminusnine+pear@gmail.com>
60 * @copyright 2005 Nicholas Pisarro
61 * @license http://www.debian.org/misc/bsd.license BSD
62 * @version Release: @package_version@
63 * @todo allow users to generate their own language models
64 */
65
66class Text_LanguageDetect
67{
68 /**
69 * The filename that stores the trigram data for the detector
70 *
71 * If this value starts with a slash (/) or a dot (.) the value of
72 * $this->_data_dir will be ignored
73 *
74 * @var string
75 * @access private
76 */
77 var $_db_filename = './lang.dat';
78
79 /**
80 * The filename that stores the unicode block definitions
81 *
82 * If this value starts with a slash (/) or a dot (.) the value of
83 * $this->_data_dir will be ignored
84 *
85 * @var string
86 * @access private
87 */
88 var $_unicode_db_filename = './unicode_blocks.dat';
89
90 /**
91 * The data directory
92 *
93 * Should be set by PEAR installer
94 *
95 * @var string
96 * @access private
97 */
98 var $_data_dir = '@data_dir@';
99
100 /**
101 * The trigram data for comparison
102 *
103 * Will be loaded on start from $this->_db_filename
104 *
105 * May be set to a PEAR_Error object if there is an error during its
106 * initialization
107 *
108 * @var array
109 * @access private
110 */
111 var $_lang_db = array();
112
113 /**
114 * stores the map of the trigram data to unicode characters
115 *
116 * @access private
117 * @var array
118 */
119 var $_unicode_map;
120
121 /**
122 * The size of the trigram data arrays
123 *
124 * @var int
125 * @access private
126 */
127 var $_threshold = 300;
128
129 /**
130 * the maximum possible score.
131 *
132 * needed for score normalization. Different depending on the
133 * perl compatibility setting
134 *
135 * @access private
136 * @var int
137 * @see setPerlCompatible()
138 */
139 var $_max_score = 0;
140
141 /**
142 * Whether or not to simulate perl's Language::Guess exactly
143 *
144 * @access private
145 * @var bool
146 * @see setPerlCompatible()
147 */
148 var $_perl_compatible = false;
149
150 /**
151 * Whether to use the unicode block detection to speed up processing
152 *
153 * @access private
154 * @var bool
155 */
156 var $_use_unicode_narrowing = true;
157
158 /**
159 * stores the result of the clustering operation
160 *
161 * @access private
162 * @var array
163 * @see clusterLanguages()
164 */
165 var $_clusters;
166
167 /**
168 * Constructor
169 *
170 * Will attempt to load the language database. If it fails, you will get
171 * a PEAR_Error object returned when you try to use detect()
172 *
173 */
174 function Text_LanguageDetect($db=null, $unicode_db=null)
175 {
176 if (isset($db)) $this->_db_filename = $db;
177 if (isset($unicode_db)) $this->_unicode_db_filename = $unicode_db;
178
179 $data = $this->_readdb($this->_db_filename);
180 $this->_lang_db = $data['trigram'];
181
182 if (isset($data['trigram-unicodemap'])) {
183 $this->_unicode_map = $data['trigram-unicodemap'];
184 }
185
186 // Not yet implemented:
187 if (isset($data['trigram-clusters'])) {
188 $this->_clusters = $data['trigram-clusters'];
189 }
190 }
191
192 /**
193 * Returns the path to the location of the database
194 *
195 * @access private
196 * @return string expected path to the language model database
197 */
198 function _get_data_loc($fname)
199 {
200 return $fname;
201 }
202
203 /**
204 * Loads the language trigram database from filename
205 *
206 * Trigram datbase should be a serialize()'d array
207 *
208 * @access private
209 * @param string $fname the filename where the data is stored
210 * @return array the language model data
211 * @throws PEAR_Error
212 */
213 function _readdb($fname)
214 {
215 // finds the correct data dir
216 $fname = $this->_get_data_loc($fname);
217
218 // input check
219 if (!file_exists($fname)) {
220 throw new Exception('Language database does not exist.');
221 } elseif (!is_readable($fname)) {
222 throw new Exception('Language database is not readable.');
223 }
224
225 if (function_exists('file_get_contents')) {
226 return unserialize(file_get_contents($fname));
227 } else {
228 // if you don't have file_get_contents(),
229 // then this is the next fastest way
230 ob_start();
231 readfile($fname);
232 $contents = ob_get_contents();
233 ob_end_clean();
234 return unserialize($contents);
235 }
236 }
237
238
239 /**
240 * Checks if this object is ready to detect languages
241 *
242 * @access private
243 * @param mixed &$err error object to be returned by reference, if any
244 * @return bool true if no errors
245 */
246 function _setup_ok(&$err)
247 {
248 if (!is_array($this->_lang_db)) {
249 if (ini_get('magic_quotes_runtime')) {
250 throw new Exception('Error loading database. Try turning magic_quotes_runtime off.');
251 } else {
252 throw new Exception('Language database is not an array.');
253 }
254 return false;
255
256 } elseif (empty($this->_lang_db)) {
257 throw new Exception('Language database has no elements.');
258 return false;
259
260 } else {
261 return true;
262 }
263 }
264
265 /**
266 * Omits languages
267 *
268 * Pass this function the name of or an array of names of
269 * languages that you don't want considered
270 *
271 * If you're only expecting a limited set of languages, this can greatly
272 * speed up processing
273 *
274 * @access public
275 * @param mixed $omit_list language name or array of names to omit
276 * @param bool $include_only if true will include (rather than
277 * exclude) only those in the list
278 * @return int number of languages successfully deleted
279 * @throws PEAR_Error
280 */
281 function omitLanguages($omit_list, $include_only = false)
282 {
283
284 // setup check
285 if (!$this->_setup_ok($err)) {
286 return $err;
287 }
288
289 $deleted = 0;
290
291 // deleting the given languages
292 if (!$include_only) {
293 if (!is_array($omit_list)) {
294 $omit_list = strtolower($omit_list); // case desensitize
295 if (isset($this->_lang_db[$omit_list])) {
296 unset($this->_lang_db[$omit_list]);
297 $deleted++;
298 }
299 } else {
300 foreach ($omit_list as $omit_lang) {
301 if (isset($this->_lang_db[$omit_lang])) {
302 unset($this->_lang_db[$omit_lang]);
303 $deleted++;
304 }
305 }
306 }
307
308 // deleting all except the given languages
309 } else {
310 if (!is_array($omit_list)) {
311 $omit_list = array($omit_list);
312 }
313
314 // case desensitize
315 foreach ($omit_list as $key => $omit_lang) {
316 $omit_list[$key] = strtolower($omit_lang);
317 }
318
319 foreach (array_keys($this->_lang_db) as $lang) {
320 if (!in_array($lang, $omit_list)) {
321 unset($this->_lang_db[$lang]);
322 $deleted++;
323 }
324 }
325 }
326
327 // reset the cluster cache if the number of languages changes
328 // this will then have to be recalculated
329 if (isset($this->_clusters) && $deleted > 0) {
330 unset($this->_clusters);
331 }
332
333 return $deleted;
334 }
335
336
337 /**
338 * Returns the number of languages that this object can detect
339 *
340 * @access public
341 * @return int the number of languages
342 * @throws PEAR_Error
343 */
344 function getLanguageCount()
345 {
346 if (!$this->_setup_ok($err)) {
347 return $err;
348 } else {
349 return count($this->_lang_db);
350 }
351 }
352
353 /**
354 * Returns true if a given language exists
355 *
356 * If passed an array of names, will return true only if all exist
357 *
358 * @access public
359 * @param mixed $lang language name or array of language names
360 * @return bool true if language model exists
361 * @throws PEAR_Error
362 */
363 function languageExists($lang)
364 {
365 if (!$this->_setup_ok($err)) {
366 return $err;
367 } else {
368 // string
369 if (is_string($lang)) {
370 return isset($this->_lang_db[strtolower($lang)]);
371
372 // array
373 } elseif (is_array($lang)) {
374 foreach ($lang as $test_lang) {
375 if (!isset($this->_lang_db[strtolower($test_lang)])) {
376 return false;
377 }
378 }
379 return true;
380
381 // other (error)
382 } else {
383 throw new Exception('Unknown type passed to languageExists()');
384 }
385 }
386 }
387
388 /**
389 * Returns the list of detectable languages
390 *
391 * @access public
392 * @return array the names of the languages known to this object
393 * @throws PEAR_Error
394 */
395 function getLanguages()
396 {
397 if (!$this->_setup_ok($err)) {
398 return $err;
399 } else {
400 return array_keys($this->_lang_db);
401 }
402 }
403
404 /**
405 * Make this object behave like Language::Guess
406 *
407 * @access public
408 * @param bool $setting false to turn off perl compatibility
409 */
410 function setPerlCompatible($setting = true)
411 {
412 if (is_bool($setting)) { // input check
413 $this->_perl_compatible = $setting;
414
415 if ($setting == true) {
416 $this->_max_score = $this->_threshold;
417 } else {
418 $this->_max_score = 0;
419 }
420 }
421
422 }
423
424 /**
425 * Whether to use unicode block ranges in detection
426 *
427 * Should speed up most detections if turned on (detault is on). In some
428 * circumstances it may be slower, such as for large text samples (> 10K)
429 * in languages that use latin scripts. In other cases it should speed up
430 * detection noticeably.
431 *
432 * @access public
433 * @param bool $setting false to turn off
434 */
435 function useUnicodeBlocks($setting = true)
436 {
437 if (is_bool($setting)) {
438 $this->_use_unicode_narrowing = $setting;
439 }
440 }
441
442 /**
443 * Converts a piece of text into trigrams
444 *
445 * Superceded by the Text_LanguageDetect_Parser class
446 *
447 * @access private
448 * @param string $text text to convert
449 * @return array array of trigram frequencies
450 */
451 function _trigram($text)
452 {
453 $s = new Text_LanguageDetect_Parser($text, $this->_db_filename, $this->_unicode_db_filename);
454 $s->prepareTrigram();
455 $s->prepareUnicode(false);
456 $s->setPadStart(!$this->_perl_compatible);
457 $s->analyze();
458 return $s->getTrigramFreqs();
459 }
460
461 /**
462 * Converts a set of trigrams from frequencies to ranks
463 *
464 * Thresholds (cuts off) the list at $this->_threshold
465 *
466 * @access protected
467 * @param array $arr array of trgram
468 * @return array ranks of trigrams
469 */
470 function _arr_rank(&$arr)
471 {
472
473 // sorts alphabetically first as a standard way of breaking rank ties
474 $this->_bub_sort($arr);
475
476 // below might also work, but seemed to introduce errors in testing
477 //ksort($arr);
478 //asort($arr);
479
480 $rank = array();
481
482 $i = 0;
483 foreach ($arr as $key => $value) {
484 $rank[$key] = $i++;
485
486 // cut off at a standard threshold
487 if ($i >= $this->_threshold) {
488 break;
489 }
490 }
491
492 return $rank;
493 }
494
495 /**
496 * Sorts an array by value breaking ties alphabetically
497 *
498 * @access private
499 * @param array &$arr the array to sort
500 */
501 function _bub_sort(&$arr)
502 {
503 // should do the same as this perl statement:
504 // sort { $trigrams{$b} == $trigrams{$a} ? $a cmp $b : $trigrams{$b} <=> $trigrams{$a} }
505
506 // needs to sort by both key and value at once
507 // using the key to break ties for the value
508
509 // converts array into an array of arrays of each key and value
510 // may be a better way of doing this
511 $combined = array();
512
513 foreach ($arr as $key => $value) {
514 $combined[] = array($key, $value);
515 }
516
517 usort($combined, array($this, '_sort_func'));
518
519 $replacement = array();
520 foreach ($combined as $key => $value) {
521 list($new_key, $new_value) = $value;
522 $replacement[$new_key] = $new_value;
523 }
524
525 $arr = $replacement;
526 }
527
528 /**
529 * Sort function used by bubble sort
530 *
531 * Callback function for usort().
532 *
533 * @access private
534 * @param array first param passed by usort()
535 * @param array second param passed by usort()
536 * @return int 1 if $a is greater, -1 if not
537 * @see _bub_sort()
538 */
539 function _sort_func($a, $b)
540 {
541 // each is actually a key/value pair, so that it can compare using both
542 list($a_key, $a_value) = $a;
543 list($b_key, $b_value) = $b;
544
545 // if the values are the same, break ties using the key
546 if ($a_value == $b_value) {
547 return strcmp($a_key, $b_key);
548
549 // if not, just sort normally
550 } else {
551 if ($a_value > $b_value) {
552 return -1;
553 } else {
554 return 1;
555 }
556 }
557
558 // 0 should not be possible because keys must be unique
559 }
560
561 /**
562 * Calculates a linear rank-order distance statistic between two sets of
563 * ranked trigrams
564 *
565 * Sums the differences in rank for each trigram. If the trigram does not
566 * appear in both, consider it a difference of $this->_threshold.
567 *
568 * This distance measure was proposed by Cavnar & Trenkle (1994). Despite
569 * its simplicity it has been shown to be highly accurate for language
570 * identification tasks.
571 *
572 * @access private
573 * @param array $arr1 the reference set of trigram ranks
574 * @param array $arr2 the target set of trigram ranks
575 * @return int the sum of the differences between the ranks of
576 * the two trigram sets
577 */
578 function _distance(&$arr1, &$arr2)
579 {
580 $sumdist = 0;
581
582 foreach ($arr2 as $key => $value) {
583 if (isset($arr1[$key])) {
584 $distance = abs($value - $arr1[$key]);
585 } else {
586 // $this->_threshold sets the maximum possible distance value
587 // for any one pair of trigrams
588 $distance = $this->_threshold;
589 }
590 $sumdist += $distance;
591 }
592
593 return $sumdist;
594
595 // todo: there are other distance statistics to try, e.g. relative
596 // entropy, but they're probably more costly to compute
597 }
598
599 /**
600 * Normalizes the score returned by _distance()
601 *
602 * Different if perl compatible or not
603 *
604 * @access private
605 * @param int $score the score from _distance()
606 * @param int $base_count the number of trigrams being considered
607 * @return float the normalized score
608 * @see _distance()
609 */
610 function _normalize_score($score, $base_count = null)
611 {
612 if ($base_count === null) {
613 $base_count = $this->_threshold;
614 }
615
616 if (!$this->_perl_compatible) {
617 return 1 - ($score / $base_count / $this->_threshold);
618 } else {
619 return floor($score / $base_count);
620 }
621 }
622
623
624 /**
625 * Detects the closeness of a sample of text to the known languages
626 *
627 * Calculates the statistical difference between the text and
628 * the trigrams for each language, normalizes the score then
629 * returns results for all languages in sorted order
630 *
631 * If perl compatible, the score is 300-0, 0 being most similar.
632 * Otherwise, it's 0-1 with 1 being most similar.
633 *
634 * The $sample text should be at least a few sentences in length;
635 * should be ascii-7 or utf8 encoded, if another and the mbstring extension
636 * is present it will try to detect and convert. However, experience has
637 * shown that mb_detect_encoding() *does not work very well* with at least
638 * some types of encoding.
639 *
640 * @access public
641 * @param string $sample a sample of text to compare.
642 * @param int $limit if specified, return an array of the most likely
643 * $limit languages and their scores.
644 * @return mixed sorted array of language scores, blank array if no
645 * useable text was found, or PEAR_Error if error
646 * with the object setup
647 * @see _distance()
648 * @throws PEAR_Error
649 */
650 function detect($sample, $limit = 0)
651 {
652 if (!$this->_setup_ok($err)) {
653 return $err;
654 }
655
656 // input check
657 if (!Text_LanguageDetect_Parser::validateString($sample)) {
658 return array();
659 }
660
661 // check char encoding
662 // (only if mbstring extension is compiled and PHP > 4.0.6)
663 if (function_exists('mb_detect_encoding')
664 && function_exists('mb_convert_encoding')) {
665
666 // mb_detect_encoding isn't very reliable, to say the least
667 // detection should still work with a sufficient sample of ascii characters
668 $encoding = mb_detect_encoding($sample);
669
670 // mb_detect_encoding() will return FALSE if detection fails
671 // don't attempt conversion if that's the case
672 if ($encoding != 'ASCII' && $encoding != 'UTF-8' && $encoding !== false) {
673
674 if (function_exists('mb_list_encodings')) {
675
676 // verify the encoding exists in mb_list_encodings
677 if (in_array($encoding, mb_list_encodings())) {
678 $sample = mb_convert_encoding($sample, 'UTF-8', $encoding);
679 }
680
681 // if the previous condition failed:
682 // somehow we detected an encoding that also we don't support
683
684 } else {
685 // php 4 doesnt have mb_list_encodings()
686 // so attempt with error suppression
687 $sample = @mb_convert_encoding($sample, 'UTF-8', $encoding);
688 }
689 }
690 }
691
692 $sample_obj = new Text_LanguageDetect_Parser($sample, $this->_db_filename, $this->_unicode_db_filename);
693 $sample_obj->prepareTrigram();
694 if ($this->_use_unicode_narrowing) {
695 $sample_obj->prepareUnicode();
696 }
697 $sample_obj->setPadStart(!$this->_perl_compatible);
698 $sample_obj->analyze();
699
700 $trigram_freqs =& $sample_obj->getTrigramRanks();
701 $trigram_count = count($trigram_freqs);
702
703 if ($trigram_count == 0) {
704 return array();
705 }
706
707 $scores = array();
708
709 // use unicode block detection to narrow down the possibilities
710 if ($this->_use_unicode_narrowing) {
711 $blocks =& $sample_obj->getUnicodeBlocks();
712
713 if (is_array($blocks)) {
714 $present_blocks = array_keys($blocks);
715 } else {
716 throw new Exception('Error during block detection');
717 }
718
719 $possible_langs = array();
720
721 foreach ($present_blocks as $blockname) {
722 if (isset($this->_unicode_map[$blockname])) {
723
724 $possible_langs = array_merge(
725 $possible_langs,
726 array_keys($this->_unicode_map[$blockname])
727 );
728
729 // todo: faster way to do this?
730 }
731 }
732
733 // could also try an intersect operation rather than a union
734 // in other words, choose languages whose trigrams contain
735 // ALL of the unicode blocks found in this sample
736 // would improve speed but would be completely thrown off by an
737 // unexpected character, like an umlaut appearing in english text
738
739 $possible_langs = array_intersect(
740 array_keys($this->_lang_db),
741 array_unique($possible_langs)
742 );
743
744 // needs to intersect it with the keys of _lang_db in case
745 // languages have been omitted
746
747 // or just try 'em all
748 } else {
749 $possible_langs = array_keys($this->_lang_db);
750 }
751
752
753 foreach ($possible_langs as $lang) {
754 $scores[$lang] =
755 $this->_normalize_score(
756 $this->_distance($this->_lang_db[$lang], $trigram_freqs),
757 $trigram_count);
758 }
759
760 unset($sample_obj);
761
762 if ($this->_perl_compatible) {
763 asort($scores);
764 } else {
765 arsort($scores);
766 }
767
768 // todo: drop languages with a score of $this->_max_score?
769
770 // limit the number of returned scores
771 if ($limit && is_numeric($limit)) {
772 $limited_scores = array();
773
774 $i = 0;
775
776 foreach ($scores as $key => $value) {
777 if ($i++ >= $limit) {
778 break;
779 }
780
781 $limited_scores[$key] = $value;
782 }
783
784 return $limited_scores;
785 } else {
786 return $scores;
787 }
788 }
789
790 /**
791 * Returns only the most similar language to the text sample
792 *
793 * Calls $this->detect() and returns only the top result
794 *
795 * @access public
796 * @param string $sample text to detect the language of
797 * @return string the name of the most likely language
798 * or null if no language is similar
799 * @see detect()
800 * @throws PEAR_Error
801 */
802 function detectSimple($sample)
803 {
804 $scores = $this->detect($sample, 1);
805
806 // if top language has the maximum possible score,
807 // then the top score will have been picked at random
808 if ( !is_array($scores)
809 || empty($scores)
810 || current($scores) == $this->_max_score) {
811
812 return null;
813
814 } else {
815 return ucfirst(key($scores));
816 }
817 }
818
819 /**
820 * Returns an array containing the most similar language and a confidence
821 * rating
822 *
823 * Confidence is a simple measure calculated from the similarity score
824 * minus the similarity score from the next most similar language
825 * divided by the highest possible score. Languages that have closely
826 * related cousins (e.g. Norwegian and Danish) should generally have lower
827 * confidence scores.
828 *
829 * The similarity score answers the question "How likely is the text the
830 * returned language regardless of the other languages considered?" The
831 * confidence score is one way of answering the question "how likely is the
832 * text the detected language relative to the rest of the language model
833 * set?"
834 *
835 * To see how similar languages are a priori, see languageSimilarity()
836 *
837 * @access public
838 * @param string $sample text for which language will be detected
839 * @return array most similar language, score and confidence rating
840 * or null if no language is similar
841 * @see detect()
842 * @throws PEAR_Error
843 */
844 function detectConfidence($sample)
845 {
846 $scores = $this->detect($sample, 2);
847
848 // if most similar language has the max score, it
849 // will have been picked at random
850 if ( !is_array($scores)
851 || empty($scores)
852 || current($scores) == $this->_max_score) {
853
854 return null;
855 }
856
857 $arr['language'] = ucfirst(key($scores));
858 $arr['similarity'] = current($scores);
859 if (next($scores) !== false) { // if false then no next element
860 // the goal is to return a higher value if the distance between
861 // the similarity of the first score and the second score is high
862
863 if ($this->_perl_compatible) {
864
865 $arr['confidence'] =
866 (current($scores) - $arr['similarity']) / $this->_max_score;
867
868 } else {
869
870 $arr['confidence'] = $arr['similarity'] - current($scores);
871
872 }
873
874 } else {
875 $arr['confidence'] = null;
876 }
877
878 return $arr;
879 }
880
881 /**
882 * Returns the distribution of unicode blocks in a given utf8 string
883 *
884 * For the block name of a single char, use unicodeBlockName()
885 *
886 * @access public
887 * @param string $str input string. Must be ascii or utf8
888 * @param bool $skip_symbols if true, skip ascii digits, symbols and
889 * non-printing characters. Includes spaces,
890 * newlines and common punctutation characters.
891 * @return array
892 * @throws PEAR_Error
893 */
894 function detectUnicodeBlocks($str, $skip_symbols)
895 {
896 // input check
897 if (!is_bool($skip_symbols)) {
898 throw new Exception('Second parameter must be boolean');
899 }
900
901 if (!is_string($str)) {
902 throw new Exception('First parameter was not a string');
903 }
904
905 $sample_obj = new Text_LanguageDetect_Parser($str, $this->_db_filename, $this->_unicode_db_filename);
906 $sample_obj->prepareUnicode();
907 $sample_obj->prepareTrigram(false);
908 $sample_obj->setUnicodeSkipSymbols($skip_symbols);
909 $sample_obj->analyze();
910 $blocks =& $sample_obj->getUnicodeBlocks();
911 unset($sample_obj);
912 return $blocks;
913 }
914
915 /**
916 * Returns the block name for a given unicode value
917 *
918 * If passed a string, will assume it is being passed a UTF8-formatted
919 * character and will automatically convert. Otherwise it will assume it
920 * is being passed a numeric unicode value.
921 *
922 * Make sure input is of the correct type!
923 *
924 * @access public
925 * @param mixed $unicode unicode value or utf8 char
926 * @return mixed the block name string or false if not found
927 * @throws PEAR_Error
928 */
929 function unicodeBlockName($unicode) {
930 if (is_string($unicode)) {
931 // assume it is being passed a utf8 char, so convert it
932
933 // input check
934 if ($this->utf8strlen($unicode) > 1) {
935 throw new Exception('Pass this function only a single char');
936 }
937
938 $unicode = $this->_utf8char2unicode($unicode);
939
940 if ($unicode == -1) {
941 throw new Exception('Malformatted char');
942 }
943
944 // input check
945 } elseif (!is_int($unicode)) {
946 throw new Exception('Input must be of type string or int.');
947 }
948
949 $blocks =& $this->_read_unicode_block_db();
950
951 $result = $this->_unicode_block_name($unicode, $blocks);
952
953 if ($result == -1) {
954 return false;
955 } else {
956 return $result[2];
957 }
958 }
959
960 /**
961 * Searches the unicode block database
962 *
963 * Returns the block name for a given unicode value. unicodeBlockName() is
964 * the public interface for this function, which does input checks which
965 * this function omits for speed.
966 *
967 * @access protected
968 * @param int $unicode the unicode value
969 * @param array &$blocks the block database
970 * @param int $block_count the number of defined blocks in the database
971 * @see unicodeBlockName()
972 */
973 function _unicode_block_name($unicode, &$blocks, $block_count = -1) {
974 // for a reference, see
975 // http://www.unicode.org/Public/UNIDATA/Blocks.txt
976
977 // assume that ascii characters are the most common
978 // so try it first for efficiency
979 if ($unicode <= $blocks[0][1]) {
980 return $blocks[0];
981 }
982
983 // the optional $block_count param is for efficiency
984 // so we this function doesn't have to run count() every time
985 if ($block_count != -1) {
986 $high = $block_count - 1;
987 } else {
988 $high = count($blocks) - 1;
989 }
990
991 $low = 1; // start with 1 because ascii was 0
992
993 // your average binary search algorithm
994 while ($low <= $high) {
995 $mid = floor(($low + $high) / 2);
996
997 // if it's lower than the lower bound
998 if ($unicode < $blocks[$mid][0]) {
999 $high = $mid - 1;
1000
1001 // if it's higher than the upper bound
1002 } elseif ($unicode > $blocks[$mid][1]) {
1003 $low = $mid + 1;
1004
1005 // found it
1006 } else {
1007 return $blocks[$mid];
1008 }
1009 }
1010
1011 // failed to find the block
1012 return -1;
1013
1014 // todo: differentiate when it's out of range or when it falls
1015 // into an unassigned range?
1016 }
1017
1018 /**
1019 * Brings up the unicode block database
1020 *
1021 * @access protected
1022 * @return array the database of unicode block definitions
1023 * @throws PEAR_Error
1024 */
1025 function &_read_unicode_block_db() {
1026 // since the unicode definitions are always going to be the same,
1027 // might as well share the memory for the db with all other instances
1028 // of this class
1029 static $data;
1030
1031 if (!isset($data)) {
1032 $data = $this->_readdb($this->_unicode_db_filename);
1033 }
1034
1035 return $data;
1036 }
1037
1038 /**
1039 * Calculate the similarities between the language models
1040 *
1041 * Use this function to see how similar languages are to each other.
1042 *
1043 * If passed 2 language names, will return just those languages compared.
1044 * If passed 1 language name, will return that language compared to
1045 * all others.
1046 * If passed none, will return an array of every language model compared
1047 * to every other one.
1048 *
1049 * @access public
1050 * @param string $lang1 the name of the first language to be compared
1051 * @param string $lang2 the name of the second language to be compared
1052 * @return array scores of every language compared
1053 * or the score of just the provided languages
1054 * or null if one of the supplied languages does not exist
1055 * @throws PEAR_Error
1056 */
1057 function languageSimilarity($lang1 = null, $lang2 = null)
1058 {
1059 if (!$this->_setup_ok($err)) {
1060 return $err;
1061 }
1062
1063 if ($lang1 != null) {
1064 $lang1 = strtolower($lang1);
1065
1066 // check if language model exists
1067 if (!isset($this->_lang_db[$lang1])) {
1068 return null;
1069 }
1070
1071 if ($lang2 != null) {
1072
1073 // can't only set the second param
1074 if ($lang1 == null) {
1075 return null;
1076 // check if language model exists
1077 } elseif (!isset($this->_lang_db[$lang2])) {
1078 return null;
1079 }
1080
1081 $lang2 = strtolower($lang2);
1082
1083 // compare just these two languages
1084 return $this->_normalize_score(
1085 $this->_distance(
1086 $this->_lang_db[$lang1],
1087 $this->_lang_db[$lang2]
1088 )
1089 );
1090
1091
1092 // compare just $lang1 to all languages
1093 } else {
1094 $return_arr = array();
1095 foreach ($this->_lang_db as $key => $value) {
1096 if ($key != $lang1) { // don't compare a language to itself
1097 $return_arr[$key] = $this->_normalize_score(
1098 $this->_distance($this->_lang_db[$lang1], $value));
1099 }
1100 }
1101 asort($return_arr);
1102
1103 return $return_arr;
1104 }
1105
1106
1107 // compare all languages to each other
1108 } else {
1109 $return_arr = array();
1110 foreach (array_keys($this->_lang_db) as $lang1) {
1111 foreach (array_keys($this->_lang_db) as $lang2) {
1112
1113 // skip comparing languages to themselves
1114 if ($lang1 != $lang2) {
1115
1116 // don't re-calculate what's already been done
1117 if (isset($return_arr[$lang2][$lang1])) {
1118
1119 $return_arr[$lang1][$lang2] =
1120 $return_arr[$lang2][$lang1];
1121
1122 // calculate
1123 } else {
1124
1125 $return_arr[$lang1][$lang2] =
1126 $this->_normalize_score(
1127 $this->_distance(
1128 $this->_lang_db[$lang1],
1129 $this->_lang_db[$lang2]
1130 )
1131 );
1132
1133 }
1134 }
1135 }
1136 }
1137 return $return_arr;
1138 }
1139 }
1140
1141 /**
1142 * Cluster known languages according to languageSimilarity()
1143 *
1144 * WARNING: this method is EXPERIMENTAL. It is not recommended for common
1145 * use, and it may disappear or its functionality may change in future
1146 * releases without notice.
1147 *
1148 * Uses a nearest neighbor technique to generate the maximum possible
1149 * number of dendograms from the similarity data.
1150 *
1151 * @access public
1152 * @return array language cluster data
1153 * @throws PEAR_Error
1154 * @see languageSimilarity()
1155 * @deprecated this function will eventually be removed and placed into
1156 * the model generation class
1157 */
1158 function clusterLanguages()
1159 {
1160 // todo: set the maximum number of clusters
1161
1162 // setup check
1163 if (!$this->_setup_ok($err)) {
1164 return $err;
1165 }
1166
1167 // return cached result, if any
1168 if (isset($this->_clusters)) {
1169 return $this->_clusters;
1170 }
1171
1172 $langs = array_keys($this->_lang_db);
1173
1174 $arr = $this->languageSimilarity();
1175
1176 sort($langs);
1177
1178 foreach ($langs as $lang) {
1179 if (!isset($this->_lang_db[$lang])) {
1180 throw new Exception("missing $lang!\n");
1181 }
1182 }
1183
1184 // http://www.psychstat.missouristate.edu/multibook/mlt04m.html
1185 foreach ($langs as $old_key => $lang1) {
1186 $langs[$lang1] = $lang1;
1187 unset($langs[$old_key]);
1188 }
1189
1190 $i = 0;
1191 while (count($langs) > 2 && $i++ < 200) {
1192 $highest_score = -1;
1193 $highest_key1 = '';
1194 $highest_key2 = '';
1195 foreach ($langs as $lang1) {
1196 foreach ($langs as $lang2) {
1197 if ( $lang1 != $lang2
1198 && $arr[$lang1][$lang2] > $highest_score) {
1199 $highest_score = $arr[$lang1][$lang2];
1200 $highest_key1 = $lang1;
1201 $highest_key2 = $lang2;
1202 }
1203 }
1204 }
1205
1206 if (!$highest_key1) {
1207 // should not ever happen
1208 throw new Exception("no highest key? (step: $i)");
1209 }
1210
1211 if ($highest_score == 0) {
1212 // languages are perfectly dissimilar
1213 break;
1214 }
1215
1216 // $highest_key1 and $highest_key2 are most similar
1217 $sum1 = array_sum($arr[$highest_key1]);
1218 $sum2 = array_sum($arr[$highest_key2]);
1219
1220 // use the score for the one that is most similar to the rest of
1221 // the field as the score for the group
1222 // todo: could try averaging or "centroid" method instead
1223 // seems like that might make more sense
1224 // actually nearest neighbor may be better for binary searching
1225
1226
1227 // for "Complete Linkage"/"furthest neighbor"
1228 // sign should be <
1229 // for "Single Linkage"/"nearest neighbor" method
1230 // should should be >
1231 // results seem to be pretty much the same with either method
1232
1233 // figure out which to delete and which to replace
1234 if ($sum1 > $sum2) {
1235 $replaceme = $highest_key1;
1236 $deleteme = $highest_key2;
1237 } else {
1238 $replaceme = $highest_key2;
1239 $deleteme = $highest_key1;
1240 }
1241
1242 $newkey = $replaceme . ':' . $deleteme;
1243
1244 // $replaceme is most similar to remaining languages
1245 // replace $replaceme with '$newkey', deleting $deleteme
1246
1247 // keep a record of which fork is really which language
1248 $really_lang = $replaceme;
1249 while (isset($really_map[$really_lang])) {
1250 $really_lang = $really_map[$really_lang];
1251 }
1252 $really_map[$newkey] = $really_lang;
1253
1254
1255 // replace the best fitting key, delete the other
1256 foreach ($arr as $key1 => $arr2) {
1257 foreach ($arr2 as $key2 => $value2) {
1258 if ($key2 == $replaceme) {
1259 $arr[$key1][$newkey] = $arr[$key1][$key2];
1260 unset($arr[$key1][$key2]);
1261 // replacing $arr[$key1][$key2] with $arr[$key1][$newkey]
1262 }
1263
1264 if ($key1 == $replaceme) {
1265 $arr[$newkey][$key2] = $arr[$key1][$key2];
1266 unset($arr[$key1][$key2]);
1267 // replacing $arr[$key1][$key2] with $arr[$newkey][$key2]
1268 }
1269
1270 if ($key1 == $deleteme || $key2 == $deleteme) {
1271 // deleting $arr[$key1][$key2]
1272 unset($arr[$key1][$key2]);
1273 }
1274 }
1275 }
1276
1277
1278 unset($langs[$highest_key1]);
1279 unset($langs[$highest_key2]);
1280 $langs[$newkey] = $newkey;
1281
1282
1283 // some of these may be overkill
1284 $result_data[$newkey] = array(
1285 'newkey' => $newkey,
1286 'count' => $i,
1287 'diff' => abs($sum1 - $sum2),
1288 'score' => $highest_score,
1289 'bestfit' => $replaceme,
1290 'otherfit' => $deleteme,
1291 'really' => $really_lang,
1292 );
1293 }
1294
1295 $return_val = array(
1296 'open_forks' => $langs,
1297 // the top level of clusters
1298 // clusters that are mutually exclusive
1299 // or specified by a specific maximum
1300
1301 'fork_data' => $result_data,
1302 // data for each split
1303
1304 'name_map' => $really_map,
1305 // which cluster is really which language
1306 // using the nearest neighbor technique, the cluster
1307 // inherits all of the properties of its most-similar member
1308 // this keeps track
1309 );
1310
1311
1312 // saves the result in the object
1313 $this->_clusters = $return_val;
1314
1315 return $return_val;
1316 }
1317
1318
1319 /**
1320 * Perform an intelligent detection based on clusterLanguages()
1321 *
1322 * WARNING: this method is EXPERIMENTAL. It is not recommended for common
1323 * use, and it may disappear or its functionality may change in future
1324 * releases without notice.
1325 *
1326 * This compares the sample text to top the top level of clusters. If the
1327 * sample is similar to the cluster it will drop down and compare it to the
1328 * languages in the cluster, and so on until it hits a leaf node.
1329 *
1330 * this should find the language in considerably fewer compares
1331 * (the equivalent of a binary search), however clusterLanguages() is costly
1332 * and the loss of accuracy from this technique is significant.
1333 *
1334 * This method may need to be 'fuzzier' in order to become more accurate.
1335 *
1336 * This function could be more useful if the universe of possible languages
1337 * was very large, however in such cases some method of Bayesian inference
1338 * might be more helpful.
1339 *
1340 * @see clusterLanguages()
1341 * @access public
1342 * @param string $str input string
1343 * @return array language scores (only those compared)
1344 * @throws PEAR_Error
1345 */
1346 function clusteredSearch($str)
1347 {
1348
1349 // input check
1350 if (!Text_LanguageDetect_Parser::validateString($str)) {
1351 return array();
1352 }
1353
1354 // clusterLanguages() will return a cached result if possible
1355 // so it's safe to call it every time
1356 $result = $this->clusterLanguages();
1357
1358 $dendogram_start = $result['open_forks'];
1359 $dendogram_data = $result['fork_data'];
1360 $dendogram_alias = $result['name_map'];
1361
1362 $sample_obj = new Text_LanguageDetect_Parser($str, $this->_db_filename, $this->_unicode_db_filename);
1363 $sample_obj->prepareTrigram();
1364 $sample_obj->setPadStart(!$this->_perl_compatible);
1365 $sample_obj->analyze();
1366 $sample_result = $sample_obj->getTrigramRanks();
1367 $sample_count = count($sample_result);
1368
1369 // input check
1370 if ($sample_count == 0) {
1371 return array();
1372 }
1373
1374 $i = 0; // counts the number of steps
1375
1376 foreach ($dendogram_start as $lang) {
1377 if (isset($dendogram_alias[$lang])) {
1378 $lang_key = $dendogram_alias[$lang];
1379 } else {
1380 $lang_key = $lang;
1381 }
1382
1383 $scores[$lang] = $this->_normalize_score(
1384 $this->_distance($this->_lang_db[$lang_key], $sample_result),
1385 $sample_count);
1386
1387 $i++;
1388 }
1389
1390 if ($this->_perl_compatible) {
1391 asort($scores);
1392 } else {
1393 arsort($scores);
1394 }
1395
1396 $top_score = current($scores);
1397 $top_key = key($scores);
1398
1399 // of starting forks, $top_key is the most similar to the sample
1400
1401 $cur_key = $top_key;
1402 while (isset($dendogram_data[$cur_key])) {
1403 $lang1 = $dendogram_data[$cur_key]['bestfit'];
1404 $lang2 = $dendogram_data[$cur_key]['otherfit'];
1405 foreach (array($lang1, $lang2) as $lang) {
1406 if (isset($dendogram_alias[$lang])) {
1407 $lang_key = $dendogram_alias[$lang];
1408 } else {
1409 $lang_key = $lang;
1410 }
1411
1412 $scores[$lang] = $this->_normalize_score(
1413 $this->_distance($this->_lang_db[$lang_key], $sample_result),
1414 $sample_count);
1415
1416 //todo: does not need to do same comparison again
1417 }
1418
1419 $i++;
1420
1421 if ($scores[$lang1] > $scores[$lang2]) {
1422 $cur_key = $lang1;
1423 $loser_key = $lang2;
1424 } else {
1425 $cur_key = $lang2;
1426 $loser_key = $lang1;
1427 }
1428
1429 $diff = $scores[$cur_key] - $scores[$loser_key];
1430
1431 // $cur_key ({$dendogram_alias[$cur_key]}) wins
1432 // over $loser_key ({$dendogram_alias[$loser_key]})
1433 // with a difference of $diff
1434 }
1435
1436 // found result in $i compares
1437
1438 // rather than sorting the result, preserve it so that you can see
1439 // which paths the algorithm decided to take along the tree
1440
1441 // but sometimes the last item is only the second highest
1442 if ( ($this->_perl_compatible && (end($scores) > prev($scores)))
1443 || (!$this->_perl_compatible && (end($scores) < prev($scores)))) {
1444
1445 $real_last_score = current($scores);
1446 $real_last_key = key($scores);
1447
1448 // swaps the 2nd-to-last item for the last item
1449 unset($scores[$real_last_key]);
1450 $scores[$real_last_key] = $real_last_score;
1451 }
1452
1453
1454 if (!$this->_perl_compatible) {
1455 $scores = array_reverse($scores, true);
1456 // second param requires php > 4.0.3
1457 }
1458
1459 return $scores;
1460 }
1461
1462 /**
1463 * ut8-safe strlen()
1464 *
1465 * Returns the numbers of characters (not bytes) in a utf8 string
1466 *
1467 * @static
1468 * @access public
1469 * @param string $str string to get the length of
1470 * @return int number of chars
1471 */
1472 function utf8strlen($str)
1473 {
1474 // utf8_decode() will convert unknown chars to '?', which is actually
1475 // ideal for counting.
1476
1477 return strlen(utf8_decode($str));
1478
1479 // idea stolen from dokuwiki
1480 }
1481
1482 /**
1483 * Returns the unicode value of a utf8 char
1484 *
1485 * @access protected
1486 * @param string $char a utf8 (possibly multi-byte) char
1487 * @return int unicode value or -1 if malformatted
1488 */
1489 function _utf8char2unicode($char) {
1490
1491 // strlen() here will actually get the binary length of a single char
1492 switch (strlen($char)) {
1493
1494 // for a reference, see http://en.wikipedia.org/wiki/UTF-8
1495
1496 case 1:
1497 // normal ASCII-7 byte
1498 // 0xxxxxxx --> 0xxxxxxx
1499 return ord($char{0});
1500
1501 case 2:
1502 // 2 byte unicode
1503 // 110zzzzx 10xxxxxx --> 00000zzz zxxxxxxx
1504 $z = (ord($char{0}) & 0x000001F) << 6;
1505 $x = (ord($char{1}) & 0x0000003F);
1506
1507 return ($z | $x);
1508
1509 case 3:
1510 // 3 byte unicode
1511 // 1110zzzz 10zxxxxx 10xxxxxx --> zzzzzxxx xxxxxxxx
1512 $z = (ord($char{0}) & 0x0000000F) << 12;
1513 $x1 = (ord($char{1}) & 0x0000003F) << 6;
1514 $x2 = (ord($char{2}) & 0x0000003F);
1515
1516 return ($z | $x1 | $x2);
1517
1518 case 4:
1519 // 4 byte unicode
1520 // 11110zzz 10zzxxxx 10xxxxxx 10xxxxxx -->
1521 // 000zzzzz xxxxxxxx xxxxxxxx
1522 $z1 = (ord($char{0}) & 0x00000007) << 18;
1523 $z2 = (ord($char{1}) & 0x0000003F) << 12;
1524 $x1 = (ord($char{2}) & 0x0000003F) << 6;
1525 $x2 = (ord($char{3}) & 0x0000003F);
1526
1527 return ($z1 | $z2 | $x1 | $x2);
1528
1529 default:
1530 // error: malformatted char?
1531 return -1;
1532 }
1533 }
1534
1535 /**
1536 * utf8-safe fast character iterator
1537 *
1538 * Will get the next character starting from $counter, which will then be
1539 * incremented. If a multi-byte char the bytes will be concatenated and
1540 * $counter will be incremeted by the number of bytes in the char.
1541 *
1542 * @access private
1543 * @param string &$str the string being iterated over
1544 * @param int &$counter the iterator, will increment by reference
1545 * @param bool $special_convert whether to do special conversions
1546 * @return char the next (possibly multi-byte) char from $counter
1547 */
1548 function _next_char(&$str, &$counter, $special_convert = false)
1549 {
1550
1551 $char = $str{$counter++};
1552 $ord = ord($char);
1553
1554 // for a description of the utf8 system see
1555 // http://www.phpclasses.org/browse/file/5131.html
1556
1557 // normal ascii one byte char
1558 if ($ord <= 127) {
1559
1560 // special conversions needed for this package
1561 // (that only apply to regular ascii characters)
1562 // lower case, and convert all non-alphanumeric characters
1563 // other than "'" to space
1564 if ($special_convert && $char != ' ' && $char != "'") {
1565 if ($ord >= 65 && $ord <= 90) { // A-Z
1566 $char = chr($ord + 32); // lower case
1567 } elseif ($ord < 97 || $ord > 122) { // NOT a-z
1568 $char = ' '; // convert to space
1569 }
1570 }
1571
1572 return $char;
1573
1574 // multi-byte chars
1575 } elseif ($ord >> 5 == 6) { // two-byte char
1576 $nextchar = $str{$counter++}; // get next byte
1577
1578 // lower-casing of non-ascii characters is still incomplete
1579
1580 if ($special_convert) {
1581 // lower case latin accented characters
1582 if ($ord == 195) {
1583 $nextord = ord($nextchar);
1584 $nextord_adj = $nextord + 64;
1585 // for a reference, see
1586 // http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
1587
1588 // &Agrave; - &THORN; but not &times;
1589 if ( $nextord_adj >= 192
1590 && $nextord_adj <= 222
1591 && $nextord_adj != 215) {
1592
1593 $nextchar = chr($nextord + 32);
1594 }
1595
1596 // lower case cyrillic alphabet
1597 } elseif ($ord == 208) {
1598 $nextord = ord($nextchar);
1599 // if A - Pe
1600 if ($nextord >= 144 && $nextord <= 159) {
1601 // lower case
1602 $nextchar = chr($nextord + 32);
1603
1604 // if Er - Ya
1605 } elseif ($nextord >= 160 && $nextord <= 175) {
1606 // lower case
1607 $char = chr(209); // == $ord++
1608 $nextchar = chr($nextord - 32);
1609 }
1610 }
1611 }
1612
1613 // tag on next byte
1614 return $char . $nextchar;
1615
1616 } elseif ($ord >> 4 == 14) { // three-byte char
1617
1618 // tag on next 2 bytes
1619 return $char . $str{$counter++} . $str{$counter++};
1620
1621 } elseif ($ord >> 3 == 30) { // four-byte char
1622
1623 // tag on next 3 bytes
1624 return $char . $str{$counter++} . $str{$counter++} . $str{$counter++};
1625
1626 } else {
1627 // error?
1628 }
1629 }
1630
1631}
1632
1633/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
1634
1635?>
diff --git a/inc/3rdparty/libraries/language-detect/Parser.php b/inc/3rdparty/libraries/language-detect/Parser.php
new file mode 100644
index 00000000..7f15fa98
--- /dev/null
+++ b/inc/3rdparty/libraries/language-detect/Parser.php
@@ -0,0 +1,354 @@
1<?php
2
3/**
4 * This class represents a text sample to be parsed.
5 *
6 * @category Text
7 * @package Text_LanguageDetect
8 * @author Nicholas Pisarro
9 * @copyright 2006
10 * @license BSD
11 * @version CVS: $Id: Parser.php,v 1.5 2006/03/11 05:45:05 taak Exp $
12 * @link http://pear.php.net/package/Text_LanguageDetect/
13 * @link http://langdetect.blogspot.com/
14 */
15
16/**
17 * This class represents a text sample to be parsed.
18 *
19 * This separates the analysis of a text sample from the primary LanguageDetect
20 * class. After a new profile has been built, the data can be retrieved using
21 * the accessor functions.
22 *
23 * This class is intended to be used by the Text_LanguageDetect class, not
24 * end-users.
25 *
26 * @category Text
27 * @package Text_LanguageDetect
28 * @author Nicholas Pisarro
29 * @copyright 2006
30 * @license BSD
31 * @version release: 0.2.3
32 */
33class Text_LanguageDetect_Parser extends Text_LanguageDetect
34{
35 /**
36 * the piece of text being parsed
37 *
38 * @access private
39 * @var string
40 */
41 var $_string;
42
43 /**
44 * stores the trigram frequencies of the sample
45 *
46 * @access private
47 * @var string
48 */
49 var $_trigrams = array();
50
51 /**
52 * stores the trigram ranks of the sample
53 *
54 * @access private
55 * @var array
56 */
57 var $_trigram_ranks = array();
58
59 /**
60 * stores the unicode blocks of the sample
61 *
62 * @access private
63 * @var array
64 */
65 var $_unicode_blocks = array();
66
67 /**
68 * Whether the parser should compile the unicode ranges
69 *
70 * @access private
71 * @var bool
72 */
73 var $_compile_unicode = false;
74
75 /**
76 * Whether the parser should compile trigrams
77 *
78 * @access private
79 * @var bool
80 */
81 var $_compile_trigram = false;
82
83 /**
84 * Whether the trigram parser should pad the beginning of the string
85 *
86 * @access private
87 * @var bool
88 */
89 var $_trigram_pad_start = false;
90
91 /**
92 * Whether the unicode parser should skip non-alphabetical ascii chars
93 *
94 * @access private
95 * @var bool
96 */
97 var $_unicode_skip_symbols = true;
98
99 /**
100 * Constructor
101 *
102 * @access private
103 * @param string $string string to be parsed
104 */
105 function Text_LanguageDetect_Parser($string, $db=null, $unicode_db=null) {
106 if (isset($db)) $this->_db_filename = $db;
107 if (isset($unicode_db)) $this->_unicode_db_filename = $unicode_db;
108 $this->_string = $string;
109 }
110
111 /**
112 * Returns true if a string is suitable for parsing
113 *
114 * @static
115 * @access public
116 * @param string $str input string to test
117 * @return bool true if acceptable, false if not
118 */
119 function validateString($str) {
120 if (!empty($str) && strlen($str) > 3 && preg_match('/\S/', $str)) {
121 return true;
122 } else {
123 return false;
124 }
125 }
126
127 /**
128 * turn on/off trigram counting
129 *
130 * @access public
131 * @param bool $bool true for on, false for off
132 */
133 function prepareTrigram($bool = true)
134 {
135 $this->_compile_trigram = $bool;
136 }
137
138 /**
139 * turn on/off unicode block counting
140 *
141 * @access public
142 * @param bool $bool true for on, false for off
143 */
144 function prepareUnicode($bool = true)
145 {
146 $this->_compile_unicode = $bool;
147 }
148
149 /**
150 * turn on/off padding the beginning of the sample string
151 *
152 * @access public
153 * @param bool $bool true for on, false for off
154 */
155 function setPadStart($bool = true)
156 {
157 $this->_trigram_pad_start = $bool;
158 }
159
160 /**
161 * Should the unicode block counter skip non-alphabetical ascii chars?
162 *
163 * @access public
164 * @param bool $bool true for on, false for off
165 */
166 function setUnicodeSkipSymbols($bool = true)
167 {
168 $this->_unicode_skip_symbols = $bool;
169 }
170
171 /**
172 * Returns the trigram ranks for the text sample
173 *
174 * @access public
175 * @return array trigram ranks in the text sample
176 */
177 function &getTrigramRanks()
178 {
179 return $this->_trigram_ranks;
180 }
181
182 /**
183 * Return the trigram freqency table
184 *
185 * only used in testing to make sure the parser is working
186 *
187 * @access public
188 * @return array trigram freqencies in the text sample
189 */
190 function &getTrigramFreqs()
191 {
192 return $this->_trigram;
193 }
194
195 /**
196 * returns the array of unicode blocks
197 *
198 * @access public
199 * @return array unicode blocks in the text sample
200 */
201 function &getUnicodeBlocks()
202 {
203 return $this->_unicode_blocks;
204 }
205
206 /**
207 * Executes the parsing operation
208 *
209 * Be sure to call the set*() functions to set options and the
210 * prepare*() functions first to tell it what kind of data to compute
211 *
212 * Afterwards the get*() functions can be used to access the compiled
213 * information.
214 *
215 * @access public
216 */
217 function analyze()
218 {
219 $len = strlen($this->_string);
220 $byte_counter = 0;
221
222
223 // unicode startup
224 if ($this->_compile_unicode) {
225 $blocks =& $this->_read_unicode_block_db();
226
227 $block_count = count($blocks);
228
229 $skipped_count = 0;
230 $unicode_chars = array();
231 }
232
233 // trigram startup
234 if ($this->_compile_trigram) {
235 // initialize them as blank so the parser will skip the first two
236 // (since it skips trigrams with more than 2 contiguous spaces)
237 $a = ' ';
238 $b = ' ';
239
240 // kludge
241 // if it finds a valid trigram to start and the start pad option is
242 // off, then set a variable that will be used to reduce this
243 // trigram after parsing has finished
244 if (!$this->_trigram_pad_start) {
245 $a = $this->_next_char($this->_string, $byte_counter, true);
246
247 if ($a != ' ') {
248 $b = $this->_next_char($this->_string, $byte_counter, true);
249 $dropone = " $a$b";
250 }
251
252 $byte_counter = 0;
253 $a = ' ';
254 $b = ' ';
255 }
256 }
257
258 while ($byte_counter < $len) {
259 $char = $this->_next_char($this->_string, $byte_counter, true);
260
261
262 // language trigram detection
263 if ($this->_compile_trigram) {
264 if (!($b == ' ' && ($a == ' ' || $char == ' '))) {
265 if (!isset($this->_trigram[$a . $b . $char])) {
266 $this->_trigram[$a . $b . $char] = 1;
267 } else {
268 $this->_trigram[$a . $b . $char]++;
269 }
270 }
271
272 $a = $b;
273 $b = $char;
274 }
275
276 // unicode block detection
277 if ($this->_compile_unicode) {
278 if ($this->_unicode_skip_symbols
279 && strlen($char) == 1
280 && ($char < 'A' || $char > 'z'
281 || ($char > 'Z' && $char < 'a'))
282 && $char != "'") { // does not skip the apostrophe
283 // since it's included in the language
284 // models
285
286 $skipped_count++;
287 continue;
288 }
289
290 // build an array of all the characters
291 if (isset($unicode_chars[$char])) {
292 $unicode_chars[$char]++;
293 } else {
294 $unicode_chars[$char] = 1;
295 }
296 }
297
298 // todo: add byte detection here
299 }
300
301 // unicode cleanup
302 if ($this->_compile_unicode) {
303 foreach ($unicode_chars as $utf8_char => $count) {
304 $search_result = $this->_unicode_block_name(
305 $this->_utf8char2unicode($utf8_char), $blocks, $block_count);
306
307 if ($search_result != -1) {
308 $block_name = $search_result[2];
309 } else {
310 $block_name = '[Malformatted]';
311 }
312
313 if (isset($this->_unicode_blocks[$block_name])) {
314 $this->_unicode_blocks[$block_name] += $count;
315 } else {
316 $this->_unicode_blocks[$block_name] = $count;
317 }
318 }
319 }
320
321
322 // trigram cleanup
323 if ($this->_compile_trigram) {
324 // pad the end
325 if ($b != ' ') {
326 if (!isset($this->_trigram["$a$b "])) {
327 $this->_trigram["$a$b "] = 1;
328 } else {
329 $this->_trigram["$a$b "]++;
330 }
331 }
332
333 // perl compatibility; Language::Guess does not pad the beginning
334 // kludge
335 if (isset($dropone)) {
336 if ($this->_trigram[$dropone] == 1) {
337 unset($this->_trigram[$dropone]);
338 } else {
339 $this->_trigram[$dropone]--;
340 }
341 }
342
343 if (!empty($this->_trigram)) {
344 $this->_trigram_ranks = $this->_arr_rank($this->_trigram);
345 } else {
346 $this->_trigram_ranks = array();
347 }
348 }
349 }
350}
351
352/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
353
354?>
diff --git a/inc/3rdparty/libraries/language-detect/lang.dat b/inc/3rdparty/libraries/language-detect/lang.dat
new file mode 100644
index 00000000..c2a44f56
--- /dev/null
+++ b/inc/3rdparty/libraries/language-detect/lang.dat
@@ -0,0 +1 @@
a:2:{s:7:"trigram";a:52:{s:8:"albanian";a:300:{s:4:"të ";s:1:"0";s:4:" të";s:1:"1";s:4:"në ";s:1:"2";s:4:"për";s:1:"3";s:4:" pë";s:1:"4";s:3:" e ";s:1:"5";s:3:"sht";s:1:"6";s:4:" në";s:1:"7";s:3:" sh";s:1:"8";s:3:"se ";s:1:"9";s:3:"et ";s:2:"10";s:4:"ë s";s:2:"11";s:4:"ë t";s:2:"12";s:3:" se";s:2:"13";s:3:"he ";s:2:"14";s:4:"jë ";s:2:"15";s:4:"ër ";s:2:"16";s:3:"dhe";s:2:"17";s:3:" pa";s:2:"18";s:4:"ë n";s:2:"19";s:4:"ë p";s:2:"20";s:4:" që";s:2:"21";s:3:" dh";s:2:"22";s:4:"një";s:2:"23";s:4:"ë m";s:2:"24";s:3:" nj";s:2:"25";s:4:"ësh";s:2:"26";s:3:"in ";s:2:"27";s:3:" me";s:2:"28";s:4:"që ";s:2:"29";s:3:" po";s:2:"30";s:3:"e n";s:2:"31";s:3:"e t";s:2:"32";s:3:"ish";s:2:"33";s:4:"më ";s:2:"34";s:4:"së ";s:2:"35";s:3:"me ";s:2:"36";s:4:"htë";s:2:"37";s:3:" ka";s:2:"38";s:3:" si";s:2:"39";s:3:"e k";s:2:"40";s:3:"e p";s:2:"41";s:3:" i ";s:2:"42";s:4:"anë";s:2:"43";s:3:"ar ";s:2:"44";s:3:" nu";s:2:"45";s:3:"und";s:2:"46";s:3:"ve ";s:2:"47";s:4:" ës";s:2:"48";s:3:"e s";s:2:"49";s:4:" më";s:2:"50";s:3:"nuk";s:2:"51";s:3:"par";s:2:"52";s:3:"uar";s:2:"53";s:3:"uk ";s:2:"54";s:3:"jo ";s:2:"55";s:4:"rë ";s:2:"56";s:3:"ta ";s:2:"57";s:4:"ë f";s:2:"58";s:3:"en ";s:2:"59";s:3:"it ";s:2:"60";s:3:"min";s:2:"61";s:3:"het";s:2:"62";s:3:"n e";s:2:"63";s:3:"ri ";s:2:"64";s:3:"shq";s:2:"65";s:4:"ë d";s:2:"66";s:3:" do";s:2:"67";s:3:" nd";s:2:"68";s:3:"sh ";s:2:"69";s:4:"ën ";s:2:"70";s:4:"atë";s:2:"71";s:3:"hqi";s:2:"72";s:3:"ist";s:2:"73";s:4:"ë q";s:2:"74";s:3:" gj";s:2:"75";s:3:" ng";s:2:"76";s:3:" th";s:2:"77";s:3:"a n";s:2:"78";s:3:"do ";s:2:"79";s:3:"end";s:2:"80";s:3:"imi";s:2:"81";s:3:"ndi";s:2:"82";s:3:"r t";s:2:"83";s:3:"rat";s:2:"84";s:4:"ë b";s:2:"85";s:4:"ëri";s:2:"86";s:3:" mu";s:2:"87";s:3:"art";s:2:"88";s:3:"ash";s:2:"89";s:3:"qip";s:2:"90";s:3:" ko";s:2:"91";s:3:"e m";s:2:"92";s:3:"edh";s:2:"93";s:3:"eri";s:2:"94";s:3:"je ";s:2:"95";s:3:"ka ";s:2:"96";s:3:"nga";s:2:"97";s:3:"si ";s:2:"98";s:3:"te ";s:2:"99";s:4:"ë k";s:3:"100";s:4:"ësi";s:3:"101";s:3:" ma";s:3:"102";s:3:" ti";s:3:"103";s:3:"eve";s:3:"104";s:3:"hje";s:3:"105";s:3:"ira";s:3:"106";s:3:"mun";s:3:"107";s:3:"on ";s:3:"108";s:3:"po ";s:3:"109";s:3:"re ";s:3:"110";s:3:" pr";s:3:"111";s:3:"im ";s:3:"112";s:3:"lit";s:3:"113";s:3:"o t";s:3:"114";s:3:"ur ";s:3:"115";s:4:"ë e";s:3:"116";s:4:"ë v";s:3:"117";s:4:"ët ";s:3:"118";s:3:" ku";s:3:"119";s:4:" së";s:3:"120";s:3:"e d";s:3:"121";s:3:"es ";s:3:"122";s:3:"ga ";s:3:"123";s:3:"iti";s:3:"124";s:3:"jet";s:3:"125";s:4:"ndë";s:3:"126";s:3:"oli";s:3:"127";s:3:"shi";s:3:"128";s:3:"tje";s:3:"129";s:4:" bë";s:3:"130";s:3:" z ";s:3:"131";s:3:"gje";s:3:"132";s:3:"kan";s:3:"133";s:3:"shk";s:3:"134";s:4:"ënd";s:3:"135";s:4:"ës ";s:3:"136";s:3:" de";s:3:"137";s:3:" kj";s:3:"138";s:3:" ru";s:3:"139";s:3:" vi";s:3:"140";s:3:"ara";s:3:"141";s:3:"gov";s:3:"142";s:3:"kjo";s:3:"143";s:3:"or ";s:3:"144";s:3:"r p";s:3:"145";s:3:"rto";s:3:"146";s:3:"rug";s:3:"147";s:3:"tet";s:3:"148";s:3:"ugo";s:3:"149";s:3:"ali";s:3:"150";s:3:"arr";s:3:"151";s:3:"at ";s:3:"152";s:3:"d t";s:3:"153";s:3:"ht ";s:3:"154";s:3:"i p";s:3:"155";s:4:"ipë";s:3:"156";s:3:"izi";s:3:"157";s:4:"jnë";s:3:"158";s:3:"n n";s:3:"159";s:3:"ohe";s:3:"160";s:3:"shu";s:3:"161";s:4:"shë";s:3:"162";s:3:"t e";s:3:"163";s:3:"tik";s:3:"164";s:3:"a e";s:3:"165";s:4:"arë";s:3:"166";s:4:"etë";s:3:"167";s:3:"hum";s:3:"168";s:3:"nd ";s:3:"169";s:3:"ndr";s:3:"170";s:3:"osh";s:3:"171";s:3:"ova";s:3:"172";s:3:"rim";s:3:"173";s:3:"tos";s:3:"174";s:3:"va ";s:3:"175";s:3:" fa";s:3:"176";s:3:" fi";s:3:"177";s:3:"a s";s:3:"178";s:3:"hen";s:3:"179";s:3:"i n";s:3:"180";s:3:"mar";s:3:"181";s:3:"ndo";s:3:"182";s:3:"por";s:3:"183";s:3:"ris";s:3:"184";s:3:"sa ";s:3:"185";s:3:"sis";s:3:"186";s:4:"tës";s:3:"187";s:4:"umë";s:3:"188";s:3:"viz";s:3:"189";s:3:"zit";s:3:"190";s:3:" di";s:3:"191";s:3:" mb";s:3:"192";s:3:"aj ";s:3:"193";s:3:"ana";s:3:"194";s:3:"ata";s:3:"195";s:4:"dër";s:3:"196";s:3:"e a";s:3:"197";s:3:"esh";s:3:"198";s:3:"ime";s:3:"199";s:3:"jes";s:3:"200";s:3:"lar";s:3:"201";s:3:"n s";s:3:"202";s:3:"nte";s:3:"203";s:3:"pol";s:3:"204";s:3:"r n";s:3:"205";s:3:"ran";s:3:"206";s:3:"res";s:3:"207";s:4:"rrë";s:3:"208";s:3:"tar";s:3:"209";s:4:"ë a";s:3:"210";s:4:"ë i";s:3:"211";s:3:" at";s:3:"212";s:3:" jo";s:3:"213";s:4:" kë";s:3:"214";s:3:" re";s:3:"215";s:3:"a k";s:3:"216";s:3:"ai ";s:3:"217";s:3:"akt";s:3:"218";s:4:"hë ";s:3:"219";s:4:"hën";s:3:"220";s:3:"i i";s:3:"221";s:3:"i m";s:3:"222";s:3:"ia ";s:3:"223";s:3:"men";s:3:"224";s:3:"nis";s:3:"225";s:3:"shm";s:3:"226";s:3:"str";s:3:"227";s:3:"t k";s:3:"228";s:3:"t n";s:3:"229";s:3:"t s";s:3:"230";s:4:"ë g";s:3:"231";s:4:"ërk";s:3:"232";s:4:"ëve";s:3:"233";s:3:" ai";s:3:"234";s:3:" ci";s:3:"235";s:3:" ed";s:3:"236";s:3:" ja";s:3:"237";s:3:" kr";s:3:"238";s:3:" qe";s:3:"239";s:3:" ta";s:3:"240";s:3:" ve";s:3:"241";s:3:"a p";s:3:"242";s:3:"cil";s:3:"243";s:3:"el ";s:3:"244";s:4:"erë";s:3:"245";s:3:"gji";s:3:"246";s:3:"hte";s:3:"247";s:3:"i t";s:3:"248";s:3:"jen";s:3:"249";s:3:"jit";s:3:"250";s:3:"k d";s:3:"251";s:4:"mën";s:3:"252";s:3:"n t";s:3:"253";s:3:"nyr";s:3:"254";s:3:"ori";s:3:"255";s:3:"pas";s:3:"256";s:3:"ra ";s:3:"257";s:3:"rie";s:3:"258";s:4:"rës";s:3:"259";s:3:"tor";s:3:"260";s:3:"uaj";s:3:"261";s:3:"yre";s:3:"262";s:4:"ëm ";s:3:"263";s:4:"ëny";s:3:"264";s:3:" ar";s:3:"265";s:3:" du";s:3:"266";s:3:" ga";s:3:"267";s:3:" je";s:3:"268";s:4:"dës";s:3:"269";s:3:"e e";s:3:"270";s:3:"e z";s:3:"271";s:3:"ha ";s:3:"272";s:3:"hme";s:3:"273";s:3:"ika";s:3:"274";s:3:"ini";s:3:"275";s:3:"ite";s:3:"276";s:3:"ith";s:3:"277";s:3:"koh";s:3:"278";s:3:"kra";s:3:"279";s:3:"ku ";s:3:"280";s:3:"lim";s:3:"281";s:3:"lis";s:3:"282";s:4:"qën";s:3:"283";s:4:"rën";s:3:"284";s:3:"s s";s:3:"285";s:3:"t d";s:3:"286";s:3:"t t";s:3:"287";s:3:"tir";s:3:"288";s:4:"tën";s:3:"289";s:3:"ver";s:3:"290";s:4:"ë j";s:3:"291";s:3:" ba";s:3:"292";s:3:" in";s:3:"293";s:3:" tr";s:3:"294";s:3:" zg";s:3:"295";s:3:"a a";s:3:"296";s:3:"a m";s:3:"297";s:3:"a t";s:3:"298";s:3:"abr";s:3:"299";}s:6:"arabic";a:300:{s:5:" ال";s:1:"0";s:6:"الع";s:1:"1";s:6:"لعر";s:1:"2";s:6:"عرا";s:1:"3";s:6:"راق";s:1:"4";s:5:" في";s:1:"5";s:5:"في ";s:1:"6";s:5:"ين ";s:1:"7";s:5:"ية ";s:1:"8";s:5:"ن ا";s:1:"9";s:6:"الم";s:2:"10";s:5:"ات ";s:2:"11";s:5:"من ";s:2:"12";s:5:"ي ا";s:2:"13";s:5:" من";s:2:"14";s:6:"الأ";s:2:"15";s:5:"ة ا";s:2:"16";s:5:"اق ";s:2:"17";s:5:" وا";s:2:"18";s:5:"اء ";s:2:"19";s:6:"الإ";s:2:"20";s:5:" أن";s:2:"21";s:6:"وال";s:2:"22";s:5:"ما ";s:2:"23";s:5:" عل";s:2:"24";s:5:"لى ";s:2:"25";s:5:"ت ا";s:2:"26";s:5:"ون ";s:2:"27";s:5:"هم ";s:2:"28";s:6:"اقي";s:2:"29";s:5:"ام ";s:2:"30";s:5:"ل ا";s:2:"31";s:5:"أن ";s:2:"32";s:5:"م ا";s:2:"33";s:6:"الت";s:2:"34";s:5:"لا ";s:2:"35";s:6:"الا";s:2:"36";s:5:"ان ";s:2:"37";s:5:"ها ";s:2:"38";s:5:"ال ";s:2:"39";s:5:"ة و";s:2:"40";s:5:"ا ا";s:2:"41";s:6:"رها";s:2:"42";s:6:"لام";s:2:"43";s:6:"يين";s:2:"44";s:5:" ول";s:2:"45";s:6:"لأم";s:2:"46";s:5:"نا ";s:2:"47";s:6:"على";s:2:"48";s:5:"ن ي";s:2:"49";s:6:"الب";s:2:"50";s:5:"اد ";s:2:"51";s:6:"الق";s:2:"52";s:5:"د ا";s:2:"53";s:5:"ذا ";s:2:"54";s:5:"ه ا";s:2:"55";s:5:" با";s:2:"56";s:6:"الد";s:2:"57";s:5:"ب ا";s:2:"58";s:6:"مري";s:2:"59";s:5:"لم ";s:2:"60";s:5:" إن";s:2:"61";s:5:" لل";s:2:"62";s:6:"سلا";s:2:"63";s:6:"أمر";s:2:"64";s:6:"ريك";s:2:"65";s:5:"مة ";s:2:"66";s:5:"ى ا";s:2:"67";s:5:"ا ي";s:2:"68";s:5:" عن";s:2:"69";s:5:" هذ";s:2:"70";s:5:"ء ا";s:2:"71";s:5:"ر ا";s:2:"72";s:6:"كان";s:2:"73";s:6:"قتل";s:2:"74";s:6:"إسل";s:2:"75";s:6:"الح";s:2:"76";s:5:"وا ";s:2:"77";s:5:" إل";s:2:"78";s:5:"ا أ";s:2:"79";s:6:"بال";s:2:"80";s:5:"ن م";s:2:"81";s:6:"الس";s:2:"82";s:5:"رة ";s:2:"83";s:6:"لإس";s:2:"84";s:5:"ن و";s:2:"85";s:6:"هاب";s:2:"86";s:5:"ي و";s:2:"87";s:5:"ير ";s:2:"88";s:5:" كا";s:2:"89";s:5:"لة ";s:2:"90";s:6:"يات";s:2:"91";s:5:" لا";s:2:"92";s:6:"انت";s:2:"93";s:5:"ن أ";s:2:"94";s:6:"يكي";s:2:"95";s:6:"الر";s:2:"96";s:6:"الو";s:2:"97";s:5:"ة ف";s:2:"98";s:5:"دة ";s:2:"99";s:6:"الج";s:3:"100";s:5:"قي ";s:3:"101";s:5:"وي ";s:3:"102";s:6:"الذ";s:3:"103";s:6:"الش";s:3:"104";s:6:"امي";s:3:"105";s:6:"اني";s:3:"106";s:5:"ذه ";s:3:"107";s:5:"عن ";s:3:"108";s:6:"لما";s:3:"109";s:6:"هذه";s:3:"110";s:5:"ول ";s:3:"111";s:5:"اف ";s:3:"112";s:6:"اوي";s:3:"113";s:6:"بري";s:3:"114";s:5:"ة ل";s:3:"115";s:5:" أم";s:3:"116";s:5:" لم";s:3:"117";s:5:" ما";s:3:"118";s:5:"يد ";s:3:"119";s:5:" أي";s:3:"120";s:6:"إره";s:3:"121";s:5:"ع ا";s:3:"122";s:6:"عمل";s:3:"123";s:6:"ولا";s:3:"124";s:6:"إلى";s:3:"125";s:6:"ابي";s:3:"126";s:5:"ن ف";s:3:"127";s:6:"ختط";s:3:"128";s:5:"لك ";s:3:"129";s:5:"نه ";s:3:"130";s:5:"ني ";s:3:"131";s:5:"إن ";s:3:"132";s:6:"دين";s:3:"133";s:5:"ف ا";s:3:"134";s:6:"لذي";s:3:"135";s:5:"ي أ";s:3:"136";s:5:"ي ب";s:3:"137";s:5:" وأ";s:3:"138";s:5:"ا ع";s:3:"139";s:6:"الخ";s:3:"140";s:5:"تل ";s:3:"141";s:5:"تي ";s:3:"142";s:5:"قد ";s:3:"143";s:6:"لدي";s:3:"144";s:5:" كل";s:3:"145";s:5:" مع";s:3:"146";s:5:"اب ";s:3:"147";s:6:"اخت";s:3:"148";s:5:"ار ";s:3:"149";s:6:"الن";s:3:"150";s:6:"علا";s:3:"151";s:5:"م و";s:3:"152";s:5:"مع ";s:3:"153";s:5:"س ا";s:3:"154";s:5:"كل ";s:3:"155";s:6:"لاء";s:3:"156";s:5:"ن ب";s:3:"157";s:5:"ن ت";s:3:"158";s:5:"ي م";s:3:"159";s:6:"عرب";s:3:"160";s:5:"م ب";s:3:"161";s:5:" وق";s:3:"162";s:5:" يق";s:3:"163";s:5:"ا ل";s:3:"164";s:5:"ا م";s:3:"165";s:6:"الف";s:3:"166";s:6:"تطا";s:3:"167";s:6:"داد";s:3:"168";s:6:"لمس";s:3:"169";s:5:"له ";s:3:"170";s:6:"هذا";s:3:"171";s:5:" مح";s:3:"172";s:6:"ؤلا";s:3:"173";s:5:"بي ";s:3:"174";s:5:"ة م";s:3:"175";s:5:"ن ل";s:3:"176";s:6:"هؤل";s:3:"177";s:5:"كن ";s:3:"178";s:6:"لإر";s:3:"179";s:6:"لتي";s:3:"180";s:5:" أو";s:3:"181";s:5:" ان";s:3:"182";s:5:" عم";s:3:"183";s:5:"ا ف";s:3:"184";s:5:"ة أ";s:3:"185";s:6:"طاف";s:3:"186";s:5:"عب ";s:3:"187";s:5:"ل م";s:3:"188";s:5:"ن ع";s:3:"189";s:5:"ور ";s:3:"190";s:5:"يا ";s:3:"191";s:5:" يس";s:3:"192";s:5:"ا ت";s:3:"193";s:5:"ة ب";s:3:"194";s:6:"راء";s:3:"195";s:6:"عال";s:3:"196";s:6:"قوا";s:3:"197";s:6:"قية";s:3:"198";s:6:"لعا";s:3:"199";s:5:"م ي";s:3:"200";s:5:"مي ";s:3:"201";s:6:"مية";s:3:"202";s:6:"نية";s:3:"203";s:5:"أي ";s:3:"204";s:6:"ابا";s:3:"205";s:6:"بغد";s:3:"206";s:5:"بل ";s:3:"207";s:5:"رب ";s:3:"208";s:6:"عما";s:3:"209";s:6:"غدا";s:3:"210";s:6:"مال";s:3:"211";s:6:"ملي";s:3:"212";s:5:"يس ";s:3:"213";s:5:" بأ";s:3:"214";s:5:" بع";s:3:"215";s:5:" بغ";s:3:"216";s:5:" وم";s:3:"217";s:6:"بات";s:3:"218";s:6:"بية";s:3:"219";s:6:"ذلك";s:3:"220";s:5:"عة ";s:3:"221";s:6:"قاو";s:3:"222";s:6:"قيي";s:3:"223";s:5:"كي ";s:3:"224";s:5:"م م";s:3:"225";s:5:"ي ع";s:3:"226";s:5:" عر";s:3:"227";s:5:" قا";s:3:"228";s:5:"ا و";s:3:"229";s:5:"رى ";s:3:"230";s:5:"ق ا";s:3:"231";s:6:"وات";s:3:"232";s:5:"وم ";s:3:"233";s:5:" هؤ";s:3:"234";s:5:"ا ب";s:3:"235";s:6:"دام";s:3:"236";s:5:"دي ";s:3:"237";s:6:"رات";s:3:"238";s:6:"شعب";s:3:"239";s:6:"لان";s:3:"240";s:6:"لشع";s:3:"241";s:6:"لقو";s:3:"242";s:6:"ليا";s:3:"243";s:5:"ن ه";s:3:"244";s:5:"ي ت";s:3:"245";s:5:"ي ي";s:3:"246";s:5:" وه";s:3:"247";s:5:" يح";s:3:"248";s:6:"جرا";s:3:"249";s:6:"جما";s:3:"250";s:6:"حمد";s:3:"251";s:5:"دم ";s:3:"252";s:5:"كم ";s:3:"253";s:6:"لاو";s:3:"254";s:6:"لره";s:3:"255";s:6:"ماع";s:3:"256";s:5:"ن ق";s:3:"257";s:5:"نة ";s:3:"258";s:5:"هي ";s:3:"259";s:5:" بل";s:3:"260";s:5:" به";s:3:"261";s:5:" له";s:3:"262";s:5:" وي";s:3:"263";s:5:"ا ك";s:3:"264";s:6:"اذا";s:3:"265";s:5:"اع ";s:3:"266";s:5:"ت م";s:3:"267";s:6:"تخا";s:3:"268";s:6:"خاب";s:3:"269";s:5:"ر م";s:3:"270";s:6:"لمت";s:3:"271";s:6:"مسل";s:3:"272";s:5:"ى أ";s:3:"273";s:6:"يست";s:3:"274";s:6:"يطا";s:3:"275";s:5:" لأ";s:3:"276";s:5:" لي";s:3:"277";s:6:"أمن";s:3:"278";s:6:"است";s:3:"279";s:6:"بعض";s:3:"280";s:5:"ة ت";s:3:"281";s:5:"ري ";s:3:"282";s:6:"صدا";s:3:"283";s:5:"ق و";s:3:"284";s:6:"قول";s:3:"285";s:5:"مد ";s:3:"286";s:6:"نتخ";s:3:"287";s:6:"نفس";s:3:"288";s:6:"نها";s:3:"289";s:6:"هنا";s:3:"290";s:6:"أعم";s:3:"291";s:6:"أنه";s:3:"292";s:6:"ائن";s:3:"293";s:6:"الآ";s:3:"294";s:6:"الك";s:3:"295";s:5:"حة ";s:3:"296";s:5:"د م";s:3:"297";s:5:"ر ع";s:3:"298";s:6:"ربي";s:3:"299";}s:5:"azeri";a:300:{s:4:"lər";s:1:"0";s:3:"in ";s:1:"1";s:4:"ın ";s:1:"2";s:3:"lar";s:1:"3";s:3:"da ";s:1:"4";s:3:"an ";s:1:"5";s:3:"ir ";s:1:"6";s:4:"də ";s:1:"7";s:3:"ki ";s:1:"8";s:3:" bi";s:1:"9";s:4:"ən ";s:2:"10";s:4:"əri";s:2:"11";s:4:"arı";s:2:"12";s:4:"ər ";s:2:"13";s:3:"dir";s:2:"14";s:3:"nda";s:2:"15";s:3:" ki";s:2:"16";s:3:"rin";s:2:"17";s:4:"nın";s:2:"18";s:4:"əsi";s:2:"19";s:3:"ini";s:2:"20";s:3:" ed";s:2:"21";s:3:" qa";s:2:"22";s:4:" tə";s:2:"23";s:3:" ba";s:2:"24";s:3:" ol";s:2:"25";s:4:"ası";s:2:"26";s:4:"ilə";s:2:"27";s:4:"rın";s:2:"28";s:3:" ya";s:2:"29";s:4:"anı";s:2:"30";s:4:" və";s:2:"31";s:4:"ndə";s:2:"32";s:3:"ni ";s:2:"33";s:3:"ara";s:2:"34";s:5:"ını";s:2:"35";s:4:"ınd";s:2:"36";s:3:" bu";s:2:"37";s:3:"si ";s:2:"38";s:3:"ib ";s:2:"39";s:3:"aq ";s:2:"40";s:4:"dən";s:2:"41";s:3:"iya";s:2:"42";s:4:"nə ";s:2:"43";s:4:"rə ";s:2:"44";s:3:"n b";s:2:"45";s:4:"sın";s:2:"46";s:4:"və ";s:2:"47";s:3:"iri";s:2:"48";s:4:"lə ";s:2:"49";s:3:"nin";s:2:"50";s:4:"əli";s:2:"51";s:3:" de";s:2:"52";s:4:" mü";s:2:"53";s:3:"bir";s:2:"54";s:3:"n s";s:2:"55";s:3:"ri ";s:2:"56";s:4:"ək ";s:2:"57";s:3:" az";s:2:"58";s:4:" sə";s:2:"59";s:3:"ar ";s:2:"60";s:3:"bil";s:2:"61";s:4:"zər";s:2:"62";s:3:"bu ";s:2:"63";s:3:"dan";s:2:"64";s:3:"edi";s:2:"65";s:3:"ind";s:2:"66";s:3:"man";s:2:"67";s:3:"un ";s:2:"68";s:5:"ərə";s:2:"69";s:3:" ha";s:2:"70";s:3:"lan";s:2:"71";s:4:"yyə";s:2:"72";s:3:"iyy";s:2:"73";s:3:" il";s:2:"74";s:3:" ne";s:2:"75";s:3:"r k";s:2:"76";s:4:"ə b";s:2:"77";s:3:" is";s:2:"78";s:3:"na ";s:2:"79";s:3:"nun";s:2:"80";s:4:"ır ";s:2:"81";s:3:" da";s:2:"82";s:4:" hə";s:2:"83";s:3:"a b";s:2:"84";s:4:"inə";s:2:"85";s:3:"sin";s:2:"86";s:3:"yan";s:2:"87";s:4:"ərb";s:2:"88";s:4:" də";s:2:"89";s:4:" mə";s:2:"90";s:4:" qə";s:2:"91";s:4:"dır";s:2:"92";s:3:"li ";s:2:"93";s:3:"ola";s:2:"94";s:3:"rba";s:2:"95";s:4:"azə";s:2:"96";s:3:"can";s:2:"97";s:4:"lı ";s:2:"98";s:3:"nla";s:2:"99";s:3:" et";s:3:"100";s:4:" gö";s:3:"101";s:4:"alı";s:3:"102";s:3:"ayc";s:3:"103";s:3:"bay";s:3:"104";s:3:"eft";s:3:"105";s:3:"ist";s:3:"106";s:3:"n i";s:3:"107";s:3:"nef";s:3:"108";s:4:"tlə";s:3:"109";s:3:"yca";s:3:"110";s:4:"yət";s:3:"111";s:5:"əcə";s:3:"112";s:3:" la";s:3:"113";s:3:"ild";s:3:"114";s:4:"nı ";s:3:"115";s:3:"tin";s:3:"116";s:3:"ldi";s:3:"117";s:3:"lik";s:3:"118";s:3:"n h";s:3:"119";s:3:"n m";s:3:"120";s:3:"oyu";s:3:"121";s:3:"raq";s:3:"122";s:3:"ya ";s:3:"123";s:4:"əti";s:3:"124";s:3:" ar";s:3:"125";s:3:"ada";s:3:"126";s:4:"edə";s:3:"127";s:3:"mas";s:3:"128";s:4:"sı ";s:3:"129";s:4:"ına";s:3:"130";s:4:"ə d";s:3:"131";s:5:"ələ";s:3:"132";s:4:"ayı";s:3:"133";s:3:"iyi";s:3:"134";s:3:"lma";s:3:"135";s:4:"mək";s:3:"136";s:3:"n d";s:3:"137";s:3:"ti ";s:3:"138";s:3:"yin";s:3:"139";s:3:"yun";s:3:"140";s:4:"ət ";s:3:"141";s:4:"azı";s:3:"142";s:3:"ft ";s:3:"143";s:3:"i t";s:3:"144";s:3:"lli";s:3:"145";s:3:"n a";s:3:"146";s:3:"ra ";s:3:"147";s:4:" cə";s:3:"148";s:4:" gə";s:3:"149";s:3:" ko";s:3:"150";s:4:" nə";s:3:"151";s:3:" oy";s:3:"152";s:3:"a d";s:3:"153";s:3:"ana";s:3:"154";s:4:"cək";s:3:"155";s:3:"eyi";s:3:"156";s:3:"ilm";s:3:"157";s:3:"irl";s:3:"158";s:3:"lay";s:3:"159";s:3:"liy";s:3:"160";s:3:"lub";s:3:"161";s:4:"n ə";s:3:"162";s:3:"ril";s:3:"163";s:4:"rlə";s:3:"164";s:3:"unu";s:3:"165";s:3:"ver";s:3:"166";s:4:"ün ";s:3:"167";s:4:"ə o";s:3:"168";s:4:"əni";s:3:"169";s:3:" he";s:3:"170";s:3:" ma";s:3:"171";s:3:" on";s:3:"172";s:3:" pa";s:3:"173";s:3:"ala";s:3:"174";s:3:"dey";s:3:"175";s:3:"i m";s:3:"176";s:3:"ima";s:3:"177";s:4:"lmə";s:3:"178";s:4:"mət";s:3:"179";s:3:"par";s:3:"180";s:4:"yə ";s:3:"181";s:4:"ətl";s:3:"182";s:3:" al";s:3:"183";s:3:" mi";s:3:"184";s:3:" sa";s:3:"185";s:4:" əl";s:3:"186";s:4:"adı";s:3:"187";s:4:"akı";s:3:"188";s:3:"and";s:3:"189";s:3:"ard";s:3:"190";s:3:"art";s:3:"191";s:3:"ayi";s:3:"192";s:3:"i a";s:3:"193";s:3:"i q";s:3:"194";s:3:"i y";s:3:"195";s:3:"ili";s:3:"196";s:3:"ill";s:3:"197";s:4:"isə";s:3:"198";s:3:"n o";s:3:"199";s:3:"n q";s:3:"200";s:3:"olu";s:3:"201";s:3:"rla";s:3:"202";s:4:"stə";s:3:"203";s:4:"sə ";s:3:"204";s:3:"tan";s:3:"205";s:3:"tel";s:3:"206";s:3:"yar";s:3:"207";s:5:"ədə";s:3:"208";s:3:" me";s:3:"209";s:4:" rə";s:3:"210";s:3:" ve";s:3:"211";s:3:" ye";s:3:"212";s:3:"a k";s:3:"213";s:3:"at ";s:3:"214";s:4:"baş";s:3:"215";s:3:"diy";s:3:"216";s:3:"ent";s:3:"217";s:3:"eti";s:3:"218";s:4:"həs";s:3:"219";s:3:"i i";s:3:"220";s:3:"ik ";s:3:"221";s:3:"la ";s:3:"222";s:4:"miş";s:3:"223";s:3:"n n";s:3:"224";s:3:"nu ";s:3:"225";s:3:"qar";s:3:"226";s:3:"ran";s:3:"227";s:4:"tər";s:3:"228";s:3:"xan";s:3:"229";s:4:"ə a";s:3:"230";s:4:"ə g";s:3:"231";s:4:"ə t";s:3:"232";s:4:" dü";s:3:"233";s:3:"ama";s:3:"234";s:3:"b k";s:3:"235";s:3:"dil";s:3:"236";s:3:"era";s:3:"237";s:3:"etm";s:3:"238";s:3:"i b";s:3:"239";s:3:"kil";s:3:"240";s:3:"mil";s:3:"241";s:3:"n r";s:3:"242";s:3:"qla";s:3:"243";s:3:"r s";s:3:"244";s:3:"ras";s:3:"245";s:3:"siy";s:3:"246";s:3:"son";s:3:"247";s:3:"tim";s:3:"248";s:3:"yer";s:3:"249";s:4:"ə k";s:3:"250";s:4:" gü";s:3:"251";s:3:" so";s:3:"252";s:4:" sö";s:3:"253";s:3:" te";s:3:"254";s:3:" xa";s:3:"255";s:3:"ai ";s:3:"256";s:3:"bar";s:3:"257";s:3:"cti";s:3:"258";s:3:"di ";s:3:"259";s:3:"eri";s:3:"260";s:4:"gör";s:3:"261";s:4:"gün";s:3:"262";s:4:"gəl";s:3:"263";s:4:"hbə";s:3:"264";s:4:"ihə";s:3:"265";s:3:"iki";s:3:"266";s:3:"isi";s:3:"267";s:3:"lin";s:3:"268";s:3:"mai";s:3:"269";s:3:"maq";s:3:"270";s:3:"n k";s:3:"271";s:3:"n t";s:3:"272";s:3:"n v";s:3:"273";s:3:"onu";s:3:"274";s:3:"qan";s:3:"275";s:4:"qəz";s:3:"276";s:4:"tə ";s:3:"277";s:3:"xal";s:3:"278";s:3:"yib";s:3:"279";s:3:"yih";s:3:"280";s:3:"zet";s:3:"281";s:4:"zır";s:3:"282";s:4:"ıb ";s:3:"283";s:4:"ə m";s:3:"284";s:4:"əze";s:3:"285";s:3:" br";s:3:"286";s:3:" in";s:3:"287";s:4:" i̇";s:3:"288";s:3:" pr";s:3:"289";s:3:" ta";s:3:"290";s:3:" to";s:3:"291";s:5:" üç";s:3:"292";s:3:"a o";s:3:"293";s:3:"ali";s:3:"294";s:3:"ani";s:3:"295";s:3:"anl";s:3:"296";s:3:"aql";s:3:"297";s:3:"azi";s:3:"298";s:3:"bri";s:3:"299";}s:7:"bengali";a:300:{s:7:"ার ";s:1:"0";s:7:"য় ";s:1:"1";s:9:"েয়";s:1:"2";s:9:"য়া";s:1:"3";s:7:" কর";s:1:"4";s:7:"েত ";s:1:"5";s:7:" কা";s:1:"6";s:7:" পা";s:1:"7";s:7:" তা";s:1:"8";s:7:"না ";s:1:"9";s:9:"ায়";s:2:"10";s:7:"ের ";s:2:"11";s:9:"য়ে";s:2:"12";s:7:" বা";s:2:"13";s:7:"েব ";s:2:"14";s:7:" যা";s:2:"15";s:7:" হে";s:2:"16";s:7:" সা";s:2:"17";s:7:"ান ";s:2:"18";s:7:"েছ ";s:2:"19";s:7:" িন";s:2:"20";s:7:"েল ";s:2:"21";s:7:" িদ";s:2:"22";s:7:" না";s:2:"23";s:7:" িব";s:2:"24";s:7:"েক ";s:2:"25";s:7:"লা ";s:2:"26";s:7:"তা ";s:2:"27";s:7:" বઘ";s:2:"28";s:7:" িক";s:2:"29";s:9:"করে";s:2:"30";s:7:" পચ";s:2:"31";s:9:"াের";s:2:"32";s:9:"িনে";s:2:"33";s:7:"রা ";s:2:"34";s:7:" োব";s:2:"35";s:7:"কা ";s:2:"36";s:7:" কে";s:2:"37";s:7:" টা";s:2:"38";s:7:"র ক";s:2:"39";s:9:"েলা";s:2:"40";s:7:" োক";s:2:"41";s:7:" মা";s:2:"42";s:7:" োদ";s:2:"43";s:7:" োম";s:2:"44";s:7:"দর ";s:2:"45";s:7:"়া ";s:2:"46";s:9:"িদে";s:2:"47";s:9:"াকা";s:2:"48";s:9:"়েছ";s:2:"49";s:9:"েদর";s:2:"50";s:7:" আে";s:2:"51";s:5:" ও ";s:2:"52";s:7:"াল ";s:2:"53";s:7:"িট ";s:2:"54";s:7:" মু";s:2:"55";s:9:"কের";s:2:"56";s:9:"হয়";s:2:"57";s:9:"করা";s:2:"58";s:7:"পর ";s:2:"59";s:9:"পাে";s:2:"60";s:7:" এক";s:2:"61";s:7:" পদ";s:2:"62";s:9:"টাক";s:2:"63";s:7:"ড় ";s:2:"64";s:9:"কান";s:2:"65";s:7:"টা ";s:2:"66";s:9:"দગা";s:2:"67";s:9:"পদગ";s:2:"68";s:9:"াড়";s:2:"69";s:9:"োকা";s:2:"70";s:9:"ওয়";s:2:"71";s:9:"কাপ";s:2:"72";s:9:"হেয";s:2:"73";s:9:"েনর";s:2:"74";s:7:" হয";s:2:"75";s:9:"দেয";s:2:"76";s:7:"নর ";s:2:"77";s:9:"ানা";s:2:"78";s:9:"ােল";s:2:"79";s:7:" আর";s:2:"80";s:5:" ় ";s:2:"81";s:9:"বઘব";s:2:"82";s:9:"িয়";s:2:"83";s:7:" দা";s:2:"84";s:7:" সম";s:2:"85";s:9:"কার";s:2:"86";s:9:"হার";s:2:"87";s:7:"াই ";s:2:"88";s:9:"ড়া";s:2:"89";s:9:"িবি";s:2:"90";s:7:" রা";s:2:"91";s:7:" লা";s:2:"92";s:9:"নার";s:2:"93";s:9:"বহা";s:2:"94";s:7:"বা ";s:2:"95";s:9:"যায";s:2:"96";s:7:"েন ";s:2:"97";s:9:"ઘবহ";s:2:"98";s:7:" ভা";s:2:"99";s:7:" সে";s:3:"100";s:7:" োয";s:3:"101";s:7:"রর ";s:3:"102";s:9:"়ার";s:3:"103";s:9:"়াল";s:3:"104";s:7:"ગা ";s:3:"105";s:9:"থেক";s:3:"106";s:9:"ভাে";s:3:"107";s:7:"়ে ";s:3:"108";s:9:"েরর";s:3:"109";s:7:" ধর";s:3:"110";s:7:" হা";s:3:"111";s:7:"নઘ ";s:3:"112";s:9:"রেন";s:3:"113";s:9:"ােব";s:3:"114";s:9:"িড়";s:3:"115";s:7:"ির ";s:3:"116";s:7:" োথ";s:3:"117";s:9:"তার";s:3:"118";s:9:"বিভ";s:3:"119";s:9:"রেত";s:3:"120";s:9:"সাে";s:3:"121";s:9:"াকে";s:3:"122";s:9:"ােত";s:3:"123";s:9:"িভਭ";s:3:"124";s:7:"ে ব";s:3:"125";s:9:"োথে";s:3:"126";s:7:" োপ";s:3:"127";s:7:" োস";s:3:"128";s:9:"বার";s:3:"129";s:7:"ভਭ ";s:3:"130";s:7:"রন ";s:3:"131";s:7:"াম ";s:3:"132";s:7:" এখ";s:3:"133";s:7:"আর ";s:3:"134";s:9:"কাে";s:3:"135";s:7:"দন ";s:3:"136";s:9:"সাজ";s:3:"137";s:9:"ােক";s:3:"138";s:9:"ােন";s:3:"139";s:9:"েনা";s:3:"140";s:7:" ঘে";s:3:"141";s:7:" তে";s:3:"142";s:7:" রে";s:3:"143";s:9:"তেব";s:3:"144";s:7:"বন ";s:3:"145";s:9:"বઘা";s:3:"146";s:9:"েড়";s:3:"147";s:9:"েবন";s:3:"148";s:7:" খু";s:3:"149";s:7:" চা";s:3:"150";s:7:" সু";s:3:"151";s:7:"কে ";s:3:"152";s:9:"ধরে";s:3:"153";s:7:"র ো";s:3:"154";s:7:"় ি";s:3:"155";s:7:"া ি";s:3:"156";s:9:"ােথ";s:3:"157";s:9:"াਠা";s:3:"158";s:7:"িদ ";s:3:"159";s:7:"িন ";s:3:"160";s:7:" অন";s:3:"161";s:7:" আপ";s:3:"162";s:7:" আম";s:3:"163";s:7:" থা";s:3:"164";s:7:" বચ";s:3:"165";s:7:" োফ";s:3:"166";s:7:" ৌত";s:3:"167";s:9:"ঘের";s:3:"168";s:7:"তে ";s:3:"169";s:9:"ময়";s:3:"170";s:9:"যাਠ";s:3:"171";s:7:"র স";s:3:"172";s:9:"রাখ";s:3:"173";s:7:"া ব";s:3:"174";s:7:"া ো";s:3:"175";s:9:"ালা";s:3:"176";s:7:"িক ";s:3:"177";s:7:"িশ ";s:3:"178";s:7:"েখ ";s:3:"179";s:7:" এর";s:3:"180";s:7:" চઓ";s:3:"181";s:7:" িড";s:3:"182";s:7:"খন ";s:3:"183";s:9:"ড়ে";s:3:"184";s:7:"র ব";s:3:"185";s:7:"়র ";s:3:"186";s:9:"াইে";s:3:"187";s:9:"ােদ";s:3:"188";s:9:"িদন";s:3:"189";s:9:"েরন";s:3:"190";s:7:" তੴ";s:3:"191";s:9:"ছাড";s:3:"192";s:9:"জনઘ";s:3:"193";s:9:"তাই";s:3:"194";s:7:"মা ";s:3:"195";s:9:"মাে";s:3:"196";s:9:"লার";s:3:"197";s:7:"াজ ";s:3:"198";s:9:"াতা";s:3:"199";s:9:"ামা";s:3:"200";s:9:"ਊেল";s:3:"201";s:9:"ગার";s:3:"202";s:7:" সব";s:3:"203";s:9:"আপন";s:3:"204";s:9:"একট";s:3:"205";s:9:"কাি";s:3:"206";s:9:"জাই";s:3:"207";s:7:"টর ";s:3:"208";s:9:"ডজা";s:3:"209";s:9:"দেখ";s:3:"210";s:9:"পনা";s:3:"211";s:7:"রও ";s:3:"212";s:7:"লে ";s:3:"213";s:9:"হেব";s:3:"214";s:9:"াজা";s:3:"215";s:9:"ািট";s:3:"216";s:9:"িডজ";s:3:"217";s:7:"েথ ";s:3:"218";s:7:" এব";s:3:"219";s:7:" জন";s:3:"220";s:7:" জা";s:3:"221";s:9:"আমা";s:3:"222";s:9:"গেল";s:3:"223";s:9:"জান";s:3:"224";s:9:"নেত";s:3:"225";s:9:"বিশ";s:3:"226";s:9:"মুে";s:3:"227";s:9:"মেয";s:3:"228";s:7:"র প";s:3:"229";s:7:"সে ";s:3:"230";s:9:"হেল";s:3:"231";s:7:"় ো";s:3:"232";s:7:"া হ";s:3:"233";s:9:"াওয";s:3:"234";s:9:"োমক";s:3:"235";s:9:"ઘাি";s:3:"236";s:7:" অে";s:3:"237";s:5:" ট ";s:3:"238";s:7:" োগ";s:3:"239";s:7:" োন";s:3:"240";s:7:"জর ";s:3:"241";s:9:"তির";s:3:"242";s:9:"দাম";s:3:"243";s:9:"পড়";s:3:"244";s:9:"পার";s:3:"245";s:9:"বাঘ";s:3:"246";s:9:"মকা";s:3:"247";s:9:"মাম";s:3:"248";s:9:"য়র";s:3:"249";s:9:"যাে";s:3:"250";s:7:"র ম";s:3:"251";s:7:"রে ";s:3:"252";s:7:"লর ";s:3:"253";s:7:"া ক";s:3:"254";s:7:"াগ ";s:3:"255";s:9:"াবা";s:3:"256";s:9:"ারা";s:3:"257";s:9:"ািন";s:3:"258";s:7:"ে গ";s:3:"259";s:7:"েগ ";s:3:"260";s:9:"েলর";s:3:"261";s:9:"োদখ";s:3:"262";s:9:"োবি";s:3:"263";s:7:"ઓল ";s:3:"264";s:7:" দে";s:3:"265";s:7:" পু";s:3:"266";s:7:" বে";s:3:"267";s:9:"অেন";s:3:"268";s:9:"এখন";s:3:"269";s:9:"কছু";s:3:"270";s:9:"কাল";s:3:"271";s:9:"গেয";s:3:"272";s:7:"ছন ";s:3:"273";s:7:"ত প";s:3:"274";s:9:"নেয";s:3:"275";s:9:"পাি";s:3:"276";s:7:"মন ";s:3:"277";s:7:"র আ";s:3:"278";s:9:"রার";s:3:"279";s:7:"াও ";s:3:"280";s:7:"াপ ";s:3:"281";s:9:"িকছ";s:3:"282";s:9:"িগে";s:3:"283";s:9:"েছন";s:3:"284";s:9:"েজর";s:3:"285";s:9:"োমা";s:3:"286";s:9:"োমে";s:3:"287";s:9:"ৌতি";s:3:"288";s:9:"ઘাে";s:3:"289";s:3:" ' ";s:3:"290";s:7:" এছ";s:3:"291";s:7:" ছা";s:3:"292";s:7:" বল";s:3:"293";s:7:" যি";s:3:"294";s:7:" শি";s:3:"295";s:7:" িম";s:3:"296";s:7:" োল";s:3:"297";s:9:"এছা";s:3:"298";s:7:"খা ";s:3:"299";}s:9:"bulgarian";a:300:{s:5:"на ";s:1:"0";s:5:" на";s:1:"1";s:5:"то ";s:1:"2";s:5:" пр";s:1:"3";s:5:" за";s:1:"4";s:5:"та ";s:1:"5";s:5:" по";s:1:"6";s:6:"ите";s:1:"7";s:5:"те ";s:1:"8";s:5:"а п";s:1:"9";s:5:"а с";s:2:"10";s:5:" от";s:2:"11";s:5:"за ";s:2:"12";s:6:"ата";s:2:"13";s:5:"ия ";s:2:"14";s:4:" в ";s:2:"15";s:5:"е н";s:2:"16";s:5:" да";s:2:"17";s:5:"а н";s:2:"18";s:5:" се";s:2:"19";s:5:" ко";s:2:"20";s:5:"да ";s:2:"21";s:5:"от ";s:2:"22";s:6:"ани";s:2:"23";s:6:"пре";s:2:"24";s:5:"не ";s:2:"25";s:6:"ени";s:2:"26";s:5:"о н";s:2:"27";s:5:"ни ";s:2:"28";s:5:"се ";s:2:"29";s:4:" и ";s:2:"30";s:5:"но ";s:2:"31";s:6:"ане";s:2:"32";s:6:"ето";s:2:"33";s:5:"а в";s:2:"34";s:5:"ва ";s:2:"35";s:6:"ван";s:2:"36";s:5:"е п";s:2:"37";s:5:"а о";s:2:"38";s:6:"ото";s:2:"39";s:6:"ран";s:2:"40";s:5:"ат ";s:2:"41";s:6:"ред";s:2:"42";s:5:" не";s:2:"43";s:5:"а д";s:2:"44";s:5:"и п";s:2:"45";s:5:" до";s:2:"46";s:6:"про";s:2:"47";s:5:" съ";s:2:"48";s:5:"ли ";s:2:"49";s:6:"при";s:2:"50";s:6:"ния";s:2:"51";s:6:"ски";s:2:"52";s:6:"тел";s:2:"53";s:5:"а и";s:2:"54";s:5:"по ";s:2:"55";s:5:"ри ";s:2:"56";s:4:" е ";s:2:"57";s:5:" ка";s:2:"58";s:6:"ира";s:2:"59";s:6:"кат";s:2:"60";s:6:"ние";s:2:"61";s:6:"нит";s:2:"62";s:5:"е з";s:2:"63";s:5:"и с";s:2:"64";s:5:"о с";s:2:"65";s:6:"ост";s:2:"66";s:5:"че ";s:2:"67";s:5:" ра";s:2:"68";s:6:"ист";s:2:"69";s:5:"о п";s:2:"70";s:5:" из";s:2:"71";s:5:" са";s:2:"72";s:5:"е д";s:2:"73";s:6:"ини";s:2:"74";s:5:"ки ";s:2:"75";s:6:"мин";s:2:"76";s:5:" ми";s:2:"77";s:5:"а б";s:2:"78";s:6:"ава";s:2:"79";s:5:"е в";s:2:"80";s:5:"ие ";s:2:"81";s:6:"пол";s:2:"82";s:6:"ств";s:2:"83";s:5:"т н";s:2:"84";s:5:" въ";s:2:"85";s:5:" ст";s:2:"86";s:5:" то";s:2:"87";s:6:"аза";s:2:"88";s:5:"е о";s:2:"89";s:5:"ов ";s:2:"90";s:5:"ст ";s:2:"91";s:5:"ът ";s:2:"92";s:5:"и н";s:2:"93";s:6:"ият";s:2:"94";s:6:"нат";s:2:"95";s:5:"ра ";s:2:"96";s:5:" бъ";s:2:"97";s:5:" че";s:2:"98";s:6:"алн";s:2:"99";s:5:"е с";s:3:"100";s:5:"ен ";s:3:"101";s:6:"ест";s:3:"102";s:5:"и д";s:3:"103";s:6:"лен";s:3:"104";s:6:"нис";s:3:"105";s:5:"о о";s:3:"106";s:6:"ови";s:3:"107";s:5:" об";s:3:"108";s:5:" сл";s:3:"109";s:5:"а р";s:3:"110";s:6:"ато";s:3:"111";s:6:"кон";s:3:"112";s:6:"нос";s:3:"113";s:6:"ров";s:3:"114";s:5:"ще ";s:3:"115";s:5:" ре";s:3:"116";s:4:" с ";s:3:"117";s:5:" сп";s:3:"118";s:6:"ват";s:3:"119";s:6:"еше";s:3:"120";s:5:"и в";s:3:"121";s:6:"иет";s:3:"122";s:5:"о в";s:3:"123";s:6:"ове";s:3:"124";s:6:"ста";s:3:"125";s:5:"а к";s:3:"126";s:5:"а т";s:3:"127";s:6:"дат";s:3:"128";s:6:"ент";s:3:"129";s:5:"ка ";s:3:"130";s:6:"лед";s:3:"131";s:6:"нет";s:3:"132";s:6:"ори";s:3:"133";s:6:"стр";s:3:"134";s:6:"стъ";s:3:"135";s:5:"ти ";s:3:"136";s:6:"тър";s:3:"137";s:5:" те";s:3:"138";s:5:"а з";s:3:"139";s:5:"а м";s:3:"140";s:5:"ад ";s:3:"141";s:6:"ана";s:3:"142";s:6:"ено";s:3:"143";s:5:"и о";s:3:"144";s:6:"ина";s:3:"145";s:6:"ити";s:3:"146";s:5:"ма ";s:3:"147";s:6:"ска";s:3:"148";s:6:"сле";s:3:"149";s:6:"тво";s:3:"150";s:6:"тер";s:3:"151";s:6:"ция";s:3:"152";s:5:"ят ";s:3:"153";s:5:" бе";s:3:"154";s:5:" де";s:3:"155";s:5:" па";s:3:"156";s:6:"ате";s:3:"157";s:6:"вен";s:3:"158";s:5:"ви ";s:3:"159";s:6:"вит";s:3:"160";s:5:"и з";s:3:"161";s:5:"и и";s:3:"162";s:6:"нар";s:3:"163";s:6:"нов";s:3:"164";s:6:"ова";s:3:"165";s:6:"пов";s:3:"166";s:6:"рез";s:3:"167";s:6:"рит";s:3:"168";s:5:"са ";s:3:"169";s:6:"ята";s:3:"170";s:5:" го";s:3:"171";s:5:" ще";s:3:"172";s:6:"али";s:3:"173";s:5:"в п";s:3:"174";s:6:"гра";s:3:"175";s:5:"е и";s:3:"176";s:6:"еди";s:3:"177";s:6:"ели";s:3:"178";s:6:"или";s:3:"179";s:6:"каз";s:3:"180";s:6:"кит";s:3:"181";s:6:"лно";s:3:"182";s:6:"мен";s:3:"183";s:6:"оли";s:3:"184";s:6:"раз";s:3:"185";s:5:" ве";s:3:"186";s:5:" гр";s:3:"187";s:5:" им";s:3:"188";s:5:" ме";s:3:"189";s:5:" пъ";s:3:"190";s:6:"ави";s:3:"191";s:6:"ако";s:3:"192";s:6:"ача";s:3:"193";s:6:"вин";s:3:"194";s:5:"во ";s:3:"195";s:6:"гов";s:3:"196";s:6:"дан";s:3:"197";s:5:"ди ";s:3:"198";s:5:"до ";s:3:"199";s:5:"ед ";s:3:"200";s:6:"ери";s:3:"201";s:6:"еро";s:3:"202";s:6:"жда";s:3:"203";s:6:"ито";s:3:"204";s:6:"ков";s:3:"205";s:6:"кол";s:3:"206";s:6:"лни";s:3:"207";s:6:"мер";s:3:"208";s:6:"нач";s:3:"209";s:5:"о з";s:3:"210";s:6:"ола";s:3:"211";s:5:"он ";s:3:"212";s:6:"она";s:3:"213";s:6:"пра";s:3:"214";s:6:"рав";s:3:"215";s:6:"рем";s:3:"216";s:6:"сия";s:3:"217";s:6:"сти";s:3:"218";s:5:"т п";s:3:"219";s:6:"тан";s:3:"220";s:5:"ха ";s:3:"221";s:5:"ше ";s:3:"222";s:6:"шен";s:3:"223";s:6:"ълг";s:3:"224";s:5:" ба";s:3:"225";s:5:" си";s:3:"226";s:6:"аро";s:3:"227";s:6:"бъл";s:3:"228";s:5:"в р";s:3:"229";s:6:"гар";s:3:"230";s:5:"е е";s:3:"231";s:6:"елн";s:3:"232";s:6:"еме";s:3:"233";s:6:"ико";s:3:"234";s:6:"има";s:3:"235";s:5:"ко ";s:3:"236";s:6:"кои";s:3:"237";s:5:"ла ";s:3:"238";s:6:"лга";s:3:"239";s:5:"о д";s:3:"240";s:6:"ози";s:3:"241";s:6:"оит";s:3:"242";s:6:"под";s:3:"243";s:6:"рес";s:3:"244";s:6:"рие";s:3:"245";s:6:"сто";s:3:"246";s:5:"т к";s:3:"247";s:5:"т м";s:3:"248";s:5:"т с";s:3:"249";s:6:"уст";s:3:"250";s:5:" би";s:3:"251";s:5:" дв";s:3:"252";s:5:" дъ";s:3:"253";s:5:" ма";s:3:"254";s:5:" мо";s:3:"255";s:5:" ни";s:3:"256";s:5:" ос";s:3:"257";s:6:"ала";s:3:"258";s:6:"анс";s:3:"259";s:6:"ара";s:3:"260";s:6:"ати";s:3:"261";s:6:"аци";s:3:"262";s:6:"беш";s:3:"263";s:6:"вър";s:3:"264";s:5:"е р";s:3:"265";s:6:"едв";s:3:"266";s:6:"ема";s:3:"267";s:6:"жав";s:3:"268";s:5:"и к";s:3:"269";s:6:"иал";s:3:"270";s:6:"ица";s:3:"271";s:6:"иче";s:3:"272";s:6:"кия";s:3:"273";s:6:"лит";s:3:"274";s:5:"о б";s:3:"275";s:6:"ово";s:3:"276";s:6:"оди";s:3:"277";s:6:"ока";s:3:"278";s:6:"пос";s:3:"279";s:6:"род";s:3:"280";s:6:"сед";s:3:"281";s:6:"слу";s:3:"282";s:5:"т и";s:3:"283";s:6:"тов";s:3:"284";s:6:"ува";s:3:"285";s:6:"циа";s:3:"286";s:6:"чес";s:3:"287";s:5:"я з";s:3:"288";s:5:" во";s:3:"289";s:5:" ил";s:3:"290";s:5:" ск";s:3:"291";s:5:" тр";s:3:"292";s:5:" це";s:3:"293";s:6:"ами";s:3:"294";s:6:"ари";s:3:"295";s:6:"бат";s:3:"296";s:5:"би ";s:3:"297";s:6:"бра";s:3:"298";s:6:"бъд";s:3:"299";}s:7:"cebuano";a:300:{s:3:"ng ";s:1:"0";s:3:"sa ";s:1:"1";s:3:" sa";s:1:"2";s:3:"ang";s:1:"3";s:3:"ga ";s:1:"4";s:3:"nga";s:1:"5";s:3:" ka";s:1:"6";s:3:" ng";s:1:"7";s:3:"an ";s:1:"8";s:3:" an";s:1:"9";s:3:" na";s:2:"10";s:3:" ma";s:2:"11";s:3:" ni";s:2:"12";s:3:"a s";s:2:"13";s:3:"a n";s:2:"14";s:3:"on ";s:2:"15";s:3:" pa";s:2:"16";s:3:" si";s:2:"17";s:3:"a k";s:2:"18";s:3:"a m";s:2:"19";s:3:" ba";s:2:"20";s:3:"ong";s:2:"21";s:3:"a i";s:2:"22";s:3:"ila";s:2:"23";s:3:" mg";s:2:"24";s:3:"mga";s:2:"25";s:3:"a p";s:2:"26";s:3:"iya";s:2:"27";s:3:"a a";s:2:"28";s:3:"ay ";s:2:"29";s:3:"ka ";s:2:"30";s:3:"ala";s:2:"31";s:3:"ing";s:2:"32";s:3:"g m";s:2:"33";s:3:"n s";s:2:"34";s:3:"g n";s:2:"35";s:3:"lan";s:2:"36";s:3:" gi";s:2:"37";s:3:"na ";s:2:"38";s:3:"ni ";s:2:"39";s:3:"o s";s:2:"40";s:3:"g p";s:2:"41";s:3:"n n";s:2:"42";s:3:" da";s:2:"43";s:3:"ag ";s:2:"44";s:3:"pag";s:2:"45";s:3:"g s";s:2:"46";s:3:"yan";s:2:"47";s:3:"ayo";s:2:"48";s:3:"o n";s:2:"49";s:3:"si ";s:2:"50";s:3:" mo";s:2:"51";s:3:"a b";s:2:"52";s:3:"g a";s:2:"53";s:3:"ail";s:2:"54";s:3:"g b";s:2:"55";s:3:"han";s:2:"56";s:3:"a d";s:2:"57";s:3:"asu";s:2:"58";s:3:"nag";s:2:"59";s:3:"ya ";s:2:"60";s:3:"man";s:2:"61";s:3:"ne ";s:2:"62";s:3:"pan";s:2:"63";s:3:"kon";s:2:"64";s:3:" il";s:2:"65";s:3:" la";s:2:"66";s:3:"aka";s:2:"67";s:3:"ako";s:2:"68";s:3:"ana";s:2:"69";s:3:"bas";s:2:"70";s:3:"ko ";s:2:"71";s:3:"od ";s:2:"72";s:3:"yo ";s:2:"73";s:3:" di";s:2:"74";s:3:" ko";s:2:"75";s:3:" ug";s:2:"76";s:3:"a u";s:2:"77";s:3:"g k";s:2:"78";s:3:"kan";s:2:"79";s:3:"la ";s:2:"80";s:3:"len";s:2:"81";s:3:"sur";s:2:"82";s:3:"ug ";s:2:"83";s:3:" ai";s:2:"84";s:3:"apa";s:2:"85";s:3:"aw ";s:2:"86";s:3:"d s";s:2:"87";s:3:"g d";s:2:"88";s:3:"g g";s:2:"89";s:3:"ile";s:2:"90";s:3:"nin";s:2:"91";s:3:" iy";s:2:"92";s:3:" su";s:2:"93";s:3:"ene";s:2:"94";s:3:"og ";s:2:"95";s:3:"ot ";s:2:"96";s:3:"aba";s:2:"97";s:3:"aha";s:2:"98";s:3:"as ";s:2:"99";s:3:"imo";s:3:"100";s:3:" ki";s:3:"101";s:3:"a t";s:3:"102";s:3:"aga";s:3:"103";s:3:"ban";s:3:"104";s:3:"ero";s:3:"105";s:3:"nan";s:3:"106";s:3:"o k";s:3:"107";s:3:"ran";s:3:"108";s:3:"ron";s:3:"109";s:3:"sil";s:3:"110";s:3:"una";s:3:"111";s:3:"usa";s:3:"112";s:3:" us";s:3:"113";s:3:"a g";s:3:"114";s:3:"ahi";s:3:"115";s:3:"ani";s:3:"116";s:3:"er ";s:3:"117";s:3:"ha ";s:3:"118";s:3:"i a";s:3:"119";s:3:"rer";s:3:"120";s:3:"yon";s:3:"121";s:3:" pu";s:3:"122";s:3:"ini";s:3:"123";s:3:"nak";s:3:"124";s:3:"ro ";s:3:"125";s:3:"to ";s:3:"126";s:3:"ure";s:3:"127";s:3:" ed";s:3:"128";s:3:" og";s:3:"129";s:3:" wa";s:3:"130";s:3:"ili";s:3:"131";s:3:"mo ";s:3:"132";s:3:"n a";s:3:"133";s:3:"nd ";s:3:"134";s:3:"o a";s:3:"135";s:3:" ad";s:3:"136";s:3:" du";s:3:"137";s:3:" pr";s:3:"138";s:3:"aro";s:3:"139";s:3:"i s";s:3:"140";s:3:"ma ";s:3:"141";s:3:"n m";s:3:"142";s:3:"ulo";s:3:"143";s:3:"und";s:3:"144";s:3:" ta";s:3:"145";s:3:"ara";s:3:"146";s:3:"asa";s:3:"147";s:3:"ato";s:3:"148";s:3:"awa";s:3:"149";s:3:"dmu";s:3:"150";s:3:"e n";s:3:"151";s:3:"edm";s:3:"152";s:3:"ina";s:3:"153";s:3:"mak";s:3:"154";s:3:"mun";s:3:"155";s:3:"niy";s:3:"156";s:3:"san";s:3:"157";s:3:"wa ";s:3:"158";s:3:" tu";s:3:"159";s:3:" un";s:3:"160";s:3:"a l";s:3:"161";s:3:"bay";s:3:"162";s:3:"iga";s:3:"163";s:3:"ika";s:3:"164";s:3:"ita";s:3:"165";s:3:"kin";s:3:"166";s:3:"lis";s:3:"167";s:3:"may";s:3:"168";s:3:"os ";s:3:"169";s:3:" ar";s:3:"170";s:3:"ad ";s:3:"171";s:3:"ali";s:3:"172";s:3:"ama";s:3:"173";s:3:"ers";s:3:"174";s:3:"ipa";s:3:"175";s:3:"isa";s:3:"176";s:3:"mao";s:3:"177";s:3:"nim";s:3:"178";s:3:"t s";s:3:"179";s:3:"tin";s:3:"180";s:3:" ak";s:3:"181";s:3:" ap";s:3:"182";s:3:" hi";s:3:"183";s:3:"abo";s:3:"184";s:3:"agp";s:3:"185";s:3:"ano";s:3:"186";s:3:"ata";s:3:"187";s:3:"g i";s:3:"188";s:3:"gan";s:3:"189";s:3:"gka";s:3:"190";s:3:"gpa";s:3:"191";s:3:"i m";s:3:"192";s:3:"iha";s:3:"193";s:3:"k s";s:3:"194";s:3:"law";s:3:"195";s:3:"or ";s:3:"196";s:3:"rs ";s:3:"197";s:3:"siy";s:3:"198";s:3:"tag";s:3:"199";s:3:" al";s:3:"200";s:3:" at";s:3:"201";s:3:" ha";s:3:"202";s:3:" hu";s:3:"203";s:3:" im";s:3:"204";s:3:"a h";s:3:"205";s:3:"bu ";s:3:"206";s:3:"e s";s:3:"207";s:3:"gma";s:3:"208";s:3:"kas";s:3:"209";s:3:"lag";s:3:"210";s:3:"mon";s:3:"211";s:3:"nah";s:3:"212";s:3:"ngo";s:3:"213";s:3:"r s";s:3:"214";s:3:"ra ";s:3:"215";s:3:"sab";s:3:"216";s:3:"sam";s:3:"217";s:3:"sul";s:3:"218";s:3:"uba";s:3:"219";s:3:"uha";s:3:"220";s:3:" lo";s:3:"221";s:3:" re";s:3:"222";s:3:"ada";s:3:"223";s:3:"aki";s:3:"224";s:3:"aya";s:3:"225";s:3:"bah";s:3:"226";s:3:"ce ";s:3:"227";s:3:"d n";s:3:"228";s:3:"lab";s:3:"229";s:3:"pa ";s:3:"230";s:3:"pak";s:3:"231";s:3:"s n";s:3:"232";s:3:"s s";s:3:"233";s:3:"tan";s:3:"234";s:3:"taw";s:3:"235";s:3:"te ";s:3:"236";s:3:"uma";s:3:"237";s:3:"ura";s:3:"238";s:3:" in";s:3:"239";s:3:" lu";s:3:"240";s:3:"a c";s:3:"241";s:3:"abi";s:3:"242";s:3:"at ";s:3:"243";s:3:"awo";s:3:"244";s:3:"bat";s:3:"245";s:3:"dal";s:3:"246";s:3:"dla";s:3:"247";s:3:"ele";s:3:"248";s:3:"g t";s:3:"249";s:3:"g u";s:3:"250";s:3:"gay";s:3:"251";s:3:"go ";s:3:"252";s:3:"hab";s:3:"253";s:3:"hin";s:3:"254";s:3:"i e";s:3:"255";s:3:"i n";s:3:"256";s:3:"kab";s:3:"257";s:3:"kap";s:3:"258";s:3:"lay";s:3:"259";s:3:"lin";s:3:"260";s:3:"nil";s:3:"261";s:3:"pam";s:3:"262";s:3:"pas";s:3:"263";s:3:"pro";s:3:"264";s:3:"pul";s:3:"265";s:3:"ta ";s:3:"266";s:3:"ton";s:3:"267";s:3:"uga";s:3:"268";s:3:"ugm";s:3:"269";s:3:"unt";s:3:"270";s:3:" co";s:3:"271";s:3:" gu";s:3:"272";s:3:" mi";s:3:"273";s:3:" pi";s:3:"274";s:3:" ti";s:3:"275";s:3:"a o";s:3:"276";s:3:"abu";s:3:"277";s:3:"adl";s:3:"278";s:3:"ado";s:3:"279";s:3:"agh";s:3:"280";s:3:"agk";s:3:"281";s:3:"ao ";s:3:"282";s:3:"art";s:3:"283";s:3:"bal";s:3:"284";s:3:"cit";s:3:"285";s:3:"di ";s:3:"286";s:3:"dto";s:3:"287";s:3:"dun";s:3:"288";s:3:"ent";s:3:"289";s:3:"g e";s:3:"290";s:3:"gon";s:3:"291";s:3:"gug";s:3:"292";s:3:"ia ";s:3:"293";s:3:"iba";s:3:"294";s:3:"ice";s:3:"295";s:3:"in ";s:3:"296";s:3:"inu";s:3:"297";s:3:"it ";s:3:"298";s:3:"kaa";s:3:"299";}s:8:"croatian";a:300:{s:3:"je ";s:1:"0";s:3:" na";s:1:"1";s:3:" pr";s:1:"2";s:3:" po";s:1:"3";s:3:"na ";s:1:"4";s:3:" je";s:1:"5";s:3:" za";s:1:"6";s:3:"ije";s:1:"7";s:3:"ne ";s:1:"8";s:3:" i ";s:1:"9";s:3:"ti ";s:2:"10";s:3:"da ";s:2:"11";s:3:" ko";s:2:"12";s:3:" ne";s:2:"13";s:3:"li ";s:2:"14";s:3:" bi";s:2:"15";s:3:" da";s:2:"16";s:3:" u ";s:2:"17";s:3:"ma ";s:2:"18";s:3:"mo ";s:2:"19";s:3:"a n";s:2:"20";s:3:"ih ";s:2:"21";s:3:"za ";s:2:"22";s:3:"a s";s:2:"23";s:3:"ko ";s:2:"24";s:3:"i s";s:2:"25";s:3:"a p";s:2:"26";s:3:"koj";s:2:"27";s:3:"pro";s:2:"28";s:3:"ju ";s:2:"29";s:3:"se ";s:2:"30";s:3:" go";s:2:"31";s:3:"ost";s:2:"32";s:3:"to ";s:2:"33";s:3:"va ";s:2:"34";s:3:" do";s:2:"35";s:3:" to";s:2:"36";s:3:"e n";s:2:"37";s:3:"i p";s:2:"38";s:3:" od";s:2:"39";s:3:" ra";s:2:"40";s:3:"no ";s:2:"41";s:3:"ako";s:2:"42";s:3:"ka ";s:2:"43";s:3:"ni ";s:2:"44";s:3:" ka";s:2:"45";s:3:" se";s:2:"46";s:3:" mo";s:2:"47";s:3:" st";s:2:"48";s:3:"i n";s:2:"49";s:3:"ima";s:2:"50";s:3:"ja ";s:2:"51";s:3:"pri";s:2:"52";s:3:"vat";s:2:"53";s:3:"sta";s:2:"54";s:3:" su";s:2:"55";s:3:"ati";s:2:"56";s:3:"e p";s:2:"57";s:3:"ta ";s:2:"58";s:3:"tsk";s:2:"59";s:3:"e i";s:2:"60";s:3:"nij";s:2:"61";s:3:" tr";s:2:"62";s:3:"cij";s:2:"63";s:3:"jen";s:2:"64";s:3:"nos";s:2:"65";s:3:"o s";s:2:"66";s:3:" iz";s:2:"67";s:3:"om ";s:2:"68";s:3:"tro";s:2:"69";s:3:"ili";s:2:"70";s:3:"iti";s:2:"71";s:3:"pos";s:2:"72";s:3:" al";s:2:"73";s:3:"a i";s:2:"74";s:3:"a o";s:2:"75";s:3:"e s";s:2:"76";s:3:"ija";s:2:"77";s:3:"ini";s:2:"78";s:3:"pre";s:2:"79";s:3:"str";s:2:"80";s:3:"la ";s:2:"81";s:3:"og ";s:2:"82";s:3:"ovo";s:2:"83";s:3:" sv";s:2:"84";s:3:"ekt";s:2:"85";s:3:"nje";s:2:"86";s:3:"o p";s:2:"87";s:3:"odi";s:2:"88";s:3:"rva";s:2:"89";s:3:" ni";s:2:"90";s:3:"ali";s:2:"91";s:3:"min";s:2:"92";s:3:"rij";s:2:"93";s:3:"a t";s:2:"94";s:3:"a z";s:2:"95";s:3:"ats";s:2:"96";s:3:"iva";s:2:"97";s:3:"o t";s:2:"98";s:3:"od ";s:2:"99";s:3:"oje";s:3:"100";s:3:"ra ";s:3:"101";s:3:" hr";s:3:"102";s:3:"a m";s:3:"103";s:3:"a u";s:3:"104";s:3:"hrv";s:3:"105";s:3:"im ";s:3:"106";s:3:"ke ";s:3:"107";s:3:"o i";s:3:"108";s:3:"ovi";s:3:"109";s:3:"red";s:3:"110";s:3:"riv";s:3:"111";s:3:"te ";s:3:"112";s:3:"bi ";s:3:"113";s:3:"e o";s:3:"114";s:3:"god";s:3:"115";s:3:"i d";s:3:"116";s:3:"lek";s:3:"117";s:3:"umi";s:3:"118";s:3:"zvo";s:3:"119";s:3:"din";s:3:"120";s:3:"e u";s:3:"121";s:3:"ene";s:3:"122";s:3:"jed";s:3:"123";s:3:"ji ";s:3:"124";s:3:"lje";s:3:"125";s:3:"nog";s:3:"126";s:3:"su ";s:3:"127";s:3:" a ";s:3:"128";s:3:" el";s:3:"129";s:3:" mi";s:3:"130";s:3:" o ";s:3:"131";s:3:"a d";s:3:"132";s:3:"alu";s:3:"133";s:3:"ele";s:3:"134";s:3:"i u";s:3:"135";s:3:"izv";s:3:"136";s:3:"ktr";s:3:"137";s:3:"lum";s:3:"138";s:3:"o d";s:3:"139";s:3:"ori";s:3:"140";s:3:"rad";s:3:"141";s:3:"sto";s:3:"142";s:3:"a k";s:3:"143";s:3:"anj";s:3:"144";s:3:"ava";s:3:"145";s:3:"e k";s:3:"146";s:3:"men";s:3:"147";s:3:"nic";s:3:"148";s:3:"o j";s:3:"149";s:3:"oj ";s:3:"150";s:3:"ove";s:3:"151";s:3:"ski";s:3:"152";s:3:"tvr";s:3:"153";s:3:"una";s:3:"154";s:3:"vor";s:3:"155";s:3:" di";s:3:"156";s:3:" no";s:3:"157";s:3:" s ";s:3:"158";s:3:" ta";s:3:"159";s:3:" tv";s:3:"160";s:3:"i i";s:3:"161";s:3:"i o";s:3:"162";s:3:"kak";s:3:"163";s:4:"roš";s:3:"164";s:3:"sko";s:3:"165";s:3:"vod";s:3:"166";s:3:" sa";s:3:"167";s:4:" će";s:3:"168";s:3:"a b";s:3:"169";s:3:"adi";s:3:"170";s:3:"amo";s:3:"171";s:3:"eni";s:3:"172";s:3:"gov";s:3:"173";s:3:"iju";s:3:"174";s:3:"ku ";s:3:"175";s:3:"o n";s:3:"176";s:3:"ora";s:3:"177";s:3:"rav";s:3:"178";s:3:"ruj";s:3:"179";s:3:"smo";s:3:"180";s:3:"tav";s:3:"181";s:3:"tru";s:3:"182";s:3:"u p";s:3:"183";s:3:"ve ";s:3:"184";s:3:" in";s:3:"185";s:3:" pl";s:3:"186";s:3:"aci";s:3:"187";s:3:"bit";s:3:"188";s:3:"de ";s:3:"189";s:4:"diš";s:3:"190";s:3:"ema";s:3:"191";s:3:"i m";s:3:"192";s:3:"ika";s:3:"193";s:4:"išt";s:3:"194";s:3:"jer";s:3:"195";s:3:"ki ";s:3:"196";s:3:"mog";s:3:"197";s:3:"nik";s:3:"198";s:3:"nov";s:3:"199";s:3:"nu ";s:3:"200";s:3:"oji";s:3:"201";s:3:"oli";s:3:"202";s:3:"pla";s:3:"203";s:3:"pod";s:3:"204";s:3:"st ";s:3:"205";s:3:"sti";s:3:"206";s:3:"tra";s:3:"207";s:3:"tre";s:3:"208";s:3:"vo ";s:3:"209";s:3:" sm";s:3:"210";s:4:" št";s:3:"211";s:3:"dan";s:3:"212";s:3:"e z";s:3:"213";s:3:"i t";s:3:"214";s:3:"io ";s:3:"215";s:3:"ist";s:3:"216";s:3:"kon";s:3:"217";s:3:"lo ";s:3:"218";s:3:"stv";s:3:"219";s:3:"u s";s:3:"220";s:3:"uje";s:3:"221";s:3:"ust";s:3:"222";s:4:"će ";s:3:"223";s:4:"ći ";s:3:"224";s:4:"što";s:3:"225";s:3:" dr";s:3:"226";s:3:" im";s:3:"227";s:3:" li";s:3:"228";s:3:"ada";s:3:"229";s:3:"aft";s:3:"230";s:3:"ani";s:3:"231";s:3:"ao ";s:3:"232";s:3:"ars";s:3:"233";s:3:"ata";s:3:"234";s:3:"e t";s:3:"235";s:3:"emo";s:3:"236";s:3:"i k";s:3:"237";s:3:"ine";s:3:"238";s:3:"jem";s:3:"239";s:3:"kov";s:3:"240";s:3:"lik";s:3:"241";s:3:"lji";s:3:"242";s:3:"mje";s:3:"243";s:3:"naf";s:3:"244";s:3:"ner";s:3:"245";s:3:"nih";s:3:"246";s:3:"nja";s:3:"247";s:3:"ogo";s:3:"248";s:3:"oiz";s:3:"249";s:3:"ome";s:3:"250";s:3:"pot";s:3:"251";s:3:"ran";s:3:"252";s:3:"ri ";s:3:"253";s:3:"roi";s:3:"254";s:3:"rtk";s:3:"255";s:3:"ska";s:3:"256";s:3:"ter";s:3:"257";s:3:"u i";s:3:"258";s:3:"u o";s:3:"259";s:3:"vi ";s:3:"260";s:3:"vrt";s:3:"261";s:3:" me";s:3:"262";s:3:" ug";s:3:"263";s:3:"ak ";s:3:"264";s:3:"ama";s:3:"265";s:4:"drž";s:3:"266";s:3:"e e";s:3:"267";s:3:"e g";s:3:"268";s:3:"e m";s:3:"269";s:3:"em ";s:3:"270";s:3:"eme";s:3:"271";s:3:"enj";s:3:"272";s:3:"ent";s:3:"273";s:3:"er ";s:3:"274";s:3:"ere";s:3:"275";s:3:"erg";s:3:"276";s:3:"eur";s:3:"277";s:3:"go ";s:3:"278";s:3:"i b";s:3:"279";s:3:"i z";s:3:"280";s:3:"jet";s:3:"281";s:3:"ksi";s:3:"282";s:3:"o u";s:3:"283";s:3:"oda";s:3:"284";s:3:"ona";s:3:"285";s:3:"pra";s:3:"286";s:3:"reb";s:3:"287";s:3:"rem";s:3:"288";s:3:"rop";s:3:"289";s:3:"tri";s:3:"290";s:4:"žav";s:3:"291";s:3:" ci";s:3:"292";s:3:" eu";s:3:"293";s:3:" re";s:3:"294";s:3:" te";s:3:"295";s:3:" uv";s:3:"296";s:3:" ve";s:3:"297";s:3:"aju";s:3:"298";s:3:"an ";s:3:"299";}s:5:"czech";a:300:{s:3:" pr";s:1:"0";s:3:" po";s:1:"1";s:4:"ní ";s:1:"2";s:3:"pro";s:1:"3";s:3:" na";s:1:"4";s:3:"na ";s:1:"5";s:4:" př";s:1:"6";s:3:"ch ";s:1:"7";s:3:" je";s:1:"8";s:3:" ne";s:1:"9";s:4:"že ";s:2:"10";s:4:" že";s:2:"11";s:3:" se";s:2:"12";s:3:" do";s:2:"13";s:3:" ro";s:2:"14";s:3:" st";s:2:"15";s:3:" v ";s:2:"16";s:3:" ve";s:2:"17";s:4:"pře";s:2:"18";s:3:"se ";s:2:"19";s:3:"ho ";s:2:"20";s:3:"sta";s:2:"21";s:3:" to";s:2:"22";s:3:" vy";s:2:"23";s:3:" za";s:2:"24";s:3:"ou ";s:2:"25";s:3:" a ";s:2:"26";s:3:"to ";s:2:"27";s:3:" by";s:2:"28";s:3:"la ";s:2:"29";s:3:"ce ";s:2:"30";s:3:"e v";s:2:"31";s:3:"ist";s:2:"32";s:3:"le ";s:2:"33";s:3:"pod";s:2:"34";s:4:"í p";s:2:"35";s:3:" vl";s:2:"36";s:3:"e n";s:2:"37";s:3:"e s";s:2:"38";s:3:"je ";s:2:"39";s:4:"ké ";s:2:"40";s:3:"by ";s:2:"41";s:3:"em ";s:2:"42";s:4:"ých";s:2:"43";s:3:" od";s:2:"44";s:3:"ova";s:2:"45";s:4:"řed";s:2:"46";s:3:"dy ";s:2:"47";s:4:"ení";s:2:"48";s:3:"kon";s:2:"49";s:3:"li ";s:2:"50";s:4:"ně ";s:2:"51";s:3:"str";s:2:"52";s:4:" zá";s:2:"53";s:3:"ve ";s:2:"54";s:3:" ka";s:2:"55";s:3:" sv";s:2:"56";s:3:"e p";s:2:"57";s:3:"it ";s:2:"58";s:4:"lád";s:2:"59";s:3:"oho";s:2:"60";s:3:"rov";s:2:"61";s:3:"roz";s:2:"62";s:3:"ter";s:2:"63";s:4:"vlá";s:2:"64";s:4:"ím ";s:2:"65";s:3:" ko";s:2:"66";s:3:"hod";s:2:"67";s:3:"nis";s:2:"68";s:5:"pří";s:2:"69";s:4:"ský";s:2:"70";s:3:" mi";s:2:"71";s:3:" ob";s:2:"72";s:3:" so";s:2:"73";s:3:"a p";s:2:"74";s:3:"ali";s:2:"75";s:3:"bud";s:2:"76";s:3:"edn";s:2:"77";s:3:"ick";s:2:"78";s:3:"kte";s:2:"79";s:3:"ku ";s:2:"80";s:3:"o s";s:2:"81";s:3:"al ";s:2:"82";s:3:"ci ";s:2:"83";s:3:"e t";s:2:"84";s:3:"il ";s:2:"85";s:3:"ny ";s:2:"86";s:4:"né ";s:2:"87";s:3:"odl";s:2:"88";s:4:"ová";s:2:"89";s:3:"rot";s:2:"90";s:3:"sou";s:2:"91";s:5:"ání";s:2:"92";s:3:" bu";s:2:"93";s:3:" mo";s:2:"94";s:3:" o ";s:2:"95";s:3:"ast";s:2:"96";s:3:"byl";s:2:"97";s:3:"de ";s:2:"98";s:3:"ek ";s:2:"99";s:3:"ost";s:3:"100";s:4:" mí";s:3:"101";s:3:" ta";s:3:"102";s:3:"es ";s:3:"103";s:3:"jed";s:3:"104";s:3:"ky ";s:3:"105";s:3:"las";s:3:"106";s:3:"m p";s:3:"107";s:3:"nes";s:3:"108";s:4:"ním";s:3:"109";s:3:"ran";s:3:"110";s:3:"rem";s:3:"111";s:3:"ros";s:3:"112";s:4:"ého";s:3:"113";s:3:" de";s:3:"114";s:3:" kt";s:3:"115";s:3:" ni";s:3:"116";s:3:" si";s:3:"117";s:4:" vý";s:3:"118";s:3:"at ";s:3:"119";s:4:"jí ";s:3:"120";s:4:"ký ";s:3:"121";s:3:"mi ";s:3:"122";s:3:"pre";s:3:"123";s:3:"tak";s:3:"124";s:3:"tan";s:3:"125";s:3:"y v";s:3:"126";s:4:"řek";s:3:"127";s:3:" ch";s:3:"128";s:3:" li";s:3:"129";s:4:" ná";s:3:"130";s:3:" pa";s:3:"131";s:4:" ře";s:3:"132";s:3:"da ";s:3:"133";s:3:"dle";s:3:"134";s:3:"dne";s:3:"135";s:3:"i p";s:3:"136";s:3:"i v";s:3:"137";s:3:"ly ";s:3:"138";s:3:"min";s:3:"139";s:3:"o n";s:3:"140";s:3:"o v";s:3:"141";s:3:"pol";s:3:"142";s:3:"tra";s:3:"143";s:3:"val";s:3:"144";s:4:"vní";s:3:"145";s:4:"ích";s:3:"146";s:4:"ý p";s:3:"147";s:4:"řej";s:3:"148";s:3:" ce";s:3:"149";s:3:" kd";s:3:"150";s:3:" le";s:3:"151";s:3:"a s";s:3:"152";s:3:"a z";s:3:"153";s:3:"cen";s:3:"154";s:3:"e k";s:3:"155";s:3:"eds";s:3:"156";s:3:"ekl";s:3:"157";s:3:"emi";s:3:"158";s:3:"kl ";s:3:"159";s:3:"lat";s:3:"160";s:3:"lo ";s:3:"161";s:4:"mié";s:3:"162";s:3:"nov";s:3:"163";s:3:"pra";s:3:"164";s:3:"sku";s:3:"165";s:4:"ské";s:3:"166";s:3:"sti";s:3:"167";s:3:"tav";s:3:"168";s:3:"ti ";s:3:"169";s:3:"ty ";s:3:"170";s:4:"ván";s:3:"171";s:4:"vé ";s:3:"172";s:3:"y n";s:3:"173";s:3:"y s";s:3:"174";s:4:"í s";s:3:"175";s:4:"í v";s:3:"176";s:4:"ě p";s:3:"177";s:3:" dn";s:3:"178";s:4:" ně";s:3:"179";s:3:" sp";s:3:"180";s:4:" čs";s:3:"181";s:3:"a n";s:3:"182";s:3:"a t";s:3:"183";s:3:"ak ";s:3:"184";s:4:"dní";s:3:"185";s:3:"doh";s:3:"186";s:3:"e b";s:3:"187";s:3:"e m";s:3:"188";s:3:"ejn";s:3:"189";s:3:"ena";s:3:"190";s:3:"est";s:3:"191";s:3:"ini";s:3:"192";s:3:"m z";s:3:"193";s:3:"nal";s:3:"194";s:3:"nou";s:3:"195";s:4:"ná ";s:3:"196";s:3:"ovi";s:3:"197";s:4:"ové";s:3:"198";s:4:"ový";s:3:"199";s:3:"rsk";s:3:"200";s:4:"stá";s:3:"201";s:4:"tí ";s:3:"202";s:4:"tře";s:3:"203";s:4:"tů ";s:3:"204";s:3:"ude";s:3:"205";s:3:"za ";s:3:"206";s:4:"é p";s:3:"207";s:4:"ém ";s:3:"208";s:4:"í d";s:3:"209";s:3:" ir";s:3:"210";s:3:" zv";s:3:"211";s:3:"ale";s:3:"212";s:4:"aně";s:3:"213";s:3:"ave";s:3:"214";s:4:"cké";s:3:"215";s:3:"den";s:3:"216";s:3:"e z";s:3:"217";s:3:"ech";s:3:"218";s:3:"en ";s:3:"219";s:4:"erý";s:3:"220";s:3:"hla";s:3:"221";s:3:"i s";s:3:"222";s:4:"iér";s:3:"223";s:3:"lov";s:3:"224";s:3:"mu ";s:3:"225";s:3:"neb";s:3:"226";s:3:"nic";s:3:"227";s:3:"o b";s:3:"228";s:3:"o m";s:3:"229";s:3:"pad";s:3:"230";s:3:"pot";s:3:"231";s:3:"rav";s:3:"232";s:3:"rop";s:3:"233";s:4:"rý ";s:3:"234";s:3:"sed";s:3:"235";s:3:"si ";s:3:"236";s:3:"t p";s:3:"237";s:3:"tic";s:3:"238";s:3:"tu ";s:3:"239";s:4:"tě ";s:3:"240";s:3:"u p";s:3:"241";s:3:"u v";s:3:"242";s:4:"vá ";s:3:"243";s:5:"výš";s:3:"244";s:4:"zvý";s:3:"245";s:5:"ční";s:3:"246";s:5:"ří ";s:3:"247";s:4:"ům ";s:3:"248";s:3:" bl";s:3:"249";s:3:" br";s:3:"250";s:3:" ho";s:3:"251";s:3:" ja";s:3:"252";s:3:" re";s:3:"253";s:3:" s ";s:3:"254";s:3:" z ";s:3:"255";s:3:" zd";s:3:"256";s:3:"a v";s:3:"257";s:3:"ani";s:3:"258";s:3:"ato";s:3:"259";s:3:"bla";s:3:"260";s:3:"bri";s:3:"261";s:4:"ečn";s:3:"262";s:4:"eře";s:3:"263";s:3:"h v";s:3:"264";s:3:"i n";s:3:"265";s:3:"ie ";s:3:"266";s:3:"ila";s:3:"267";s:3:"irs";s:3:"268";s:3:"ite";s:3:"269";s:3:"kov";s:3:"270";s:3:"nos";s:3:"271";s:3:"o o";s:3:"272";s:3:"o p";s:3:"273";s:3:"oce";s:3:"274";s:3:"ody";s:3:"275";s:3:"ohl";s:3:"276";s:3:"oli";s:3:"277";s:3:"ovo";s:3:"278";s:3:"pla";s:3:"279";s:4:"poč";s:3:"280";s:4:"prá";s:3:"281";s:3:"ra ";s:3:"282";s:3:"rit";s:3:"283";s:3:"rod";s:3:"284";s:3:"ry ";s:3:"285";s:3:"sd ";s:3:"286";s:3:"sko";s:3:"287";s:3:"ssd";s:3:"288";s:3:"tel";s:3:"289";s:3:"u s";s:3:"290";s:3:"vat";s:3:"291";s:4:"veř";s:3:"292";s:3:"vit";s:3:"293";s:3:"vla";s:3:"294";s:3:"y p";s:3:"295";s:4:"áln";s:3:"296";s:4:"čss";s:3:"297";s:4:"šen";s:3:"298";s:3:" al";s:3:"299";}s:6:"danish";a:300:{s:3:"er ";s:1:"0";s:3:"en ";s:1:"1";s:3:" de";s:1:"2";s:3:"et ";s:1:"3";s:3:"der";s:1:"4";s:3:"de ";s:1:"5";s:3:"for";s:1:"6";s:3:" fo";s:1:"7";s:3:" i ";s:1:"8";s:3:"at ";s:1:"9";s:3:" at";s:2:"10";s:3:"re ";s:2:"11";s:3:"det";s:2:"12";s:3:" ha";s:2:"13";s:3:"nde";s:2:"14";s:3:"ere";s:2:"15";s:3:"ing";s:2:"16";s:3:"den";s:2:"17";s:3:" me";s:2:"18";s:3:" og";s:2:"19";s:3:"ger";s:2:"20";s:3:"ter";s:2:"21";s:3:" er";s:2:"22";s:3:" si";s:2:"23";s:3:"and";s:2:"24";s:3:" af";s:2:"25";s:3:"or ";s:2:"26";s:3:" st";s:2:"27";s:3:" ti";s:2:"28";s:3:" en";s:2:"29";s:3:"og ";s:2:"30";s:3:"ar ";s:2:"31";s:3:"il ";s:2:"32";s:3:"r s";s:2:"33";s:3:"ige";s:2:"34";s:3:"til";s:2:"35";s:3:"ke ";s:2:"36";s:3:"r e";s:2:"37";s:3:"af ";s:2:"38";s:3:"kke";s:2:"39";s:3:" ma";s:2:"40";s:4:" på";s:2:"41";s:3:"om ";s:2:"42";s:4:"på ";s:2:"43";s:3:"ed ";s:2:"44";s:3:"ge ";s:2:"45";s:3:"end";s:2:"46";s:3:"nge";s:2:"47";s:3:"t s";s:2:"48";s:3:"e s";s:2:"49";s:3:"ler";s:2:"50";s:3:" sk";s:2:"51";s:3:"els";s:2:"52";s:3:"ern";s:2:"53";s:3:"sig";s:2:"54";s:3:"ne ";s:2:"55";s:3:"lig";s:2:"56";s:3:"r d";s:2:"57";s:3:"ska";s:2:"58";s:3:" vi";s:2:"59";s:3:"har";s:2:"60";s:3:" be";s:2:"61";s:3:" se";s:2:"62";s:3:"an ";s:2:"63";s:3:"ikk";s:2:"64";s:3:"lle";s:2:"65";s:3:"gen";s:2:"66";s:3:"n f";s:2:"67";s:3:"ste";s:2:"68";s:3:"t a";s:2:"69";s:3:"t d";s:2:"70";s:3:"rin";s:2:"71";s:3:" ik";s:2:"72";s:3:"es ";s:2:"73";s:3:"ng ";s:2:"74";s:3:"ver";s:2:"75";s:3:"r b";s:2:"76";s:3:"sen";s:2:"77";s:3:"ede";s:2:"78";s:3:"men";s:2:"79";s:3:"r i";s:2:"80";s:3:" he";s:2:"81";s:3:" et";s:2:"82";s:3:"ig ";s:2:"83";s:3:"lan";s:2:"84";s:3:"med";s:2:"85";s:3:"nd ";s:2:"86";s:3:"rne";s:2:"87";s:3:" da";s:2:"88";s:3:" in";s:2:"89";s:3:"e t";s:2:"90";s:3:"mme";s:2:"91";s:3:"und";s:2:"92";s:3:" om";s:2:"93";s:3:"e e";s:2:"94";s:3:"e m";s:2:"95";s:3:"her";s:2:"96";s:3:"le ";s:2:"97";s:3:"r f";s:2:"98";s:3:"t f";s:2:"99";s:4:"så ";s:3:"100";s:3:"te ";s:3:"101";s:3:" so";s:3:"102";s:3:"ele";s:3:"103";s:3:"t e";s:3:"104";s:3:" ko";s:3:"105";s:3:"est";s:3:"106";s:3:"ske";s:3:"107";s:3:" bl";s:3:"108";s:3:"e f";s:3:"109";s:3:"ekt";s:3:"110";s:3:"mar";s:3:"111";s:3:"bru";s:3:"112";s:3:"e a";s:3:"113";s:3:"el ";s:3:"114";s:3:"ers";s:3:"115";s:3:"ret";s:3:"116";s:3:"som";s:3:"117";s:3:"tte";s:3:"118";s:3:"ve ";s:3:"119";s:3:" la";s:3:"120";s:3:" ud";s:3:"121";s:3:" ve";s:3:"122";s:3:"age";s:3:"123";s:3:"e d";s:3:"124";s:3:"e h";s:3:"125";s:3:"lse";s:3:"126";s:3:"man";s:3:"127";s:3:"rug";s:3:"128";s:3:"sel";s:3:"129";s:3:"ser";s:3:"130";s:3:" fi";s:3:"131";s:3:" op";s:3:"132";s:3:" pr";s:3:"133";s:3:"dt ";s:3:"134";s:3:"e i";s:3:"135";s:3:"n m";s:3:"136";s:3:"r m";s:3:"137";s:3:" an";s:3:"138";s:3:" re";s:3:"139";s:3:" sa";s:3:"140";s:3:"ion";s:3:"141";s:3:"ner";s:3:"142";s:3:"res";s:3:"143";s:3:"t i";s:3:"144";s:3:"get";s:3:"145";s:3:"n s";s:3:"146";s:3:"one";s:3:"147";s:3:"orb";s:3:"148";s:3:"t h";s:3:"149";s:3:"vis";s:3:"150";s:4:"år ";s:3:"151";s:3:" fr";s:3:"152";s:3:"bil";s:3:"153";s:3:"e k";s:3:"154";s:3:"ens";s:3:"155";s:3:"ind";s:3:"156";s:3:"omm";s:3:"157";s:3:"t m";s:3:"158";s:3:" hv";s:3:"159";s:3:" je";s:3:"160";s:3:"dan";s:3:"161";s:3:"ent";s:3:"162";s:3:"fte";s:3:"163";s:3:"nin";s:3:"164";s:3:" mi";s:3:"165";s:3:"e o";s:3:"166";s:3:"e p";s:3:"167";s:3:"n o";s:3:"168";s:3:"nte";s:3:"169";s:3:" ku";s:3:"170";s:3:"ell";s:3:"171";s:3:"nas";s:3:"172";s:3:"ore";s:3:"173";s:3:"r h";s:3:"174";s:3:"r k";s:3:"175";s:3:"sta";s:3:"176";s:3:"sto";s:3:"177";s:3:"dag";s:3:"178";s:3:"eri";s:3:"179";s:3:"kun";s:3:"180";s:3:"lde";s:3:"181";s:3:"mer";s:3:"182";s:3:"r a";s:3:"183";s:3:"r v";s:3:"184";s:3:"rek";s:3:"185";s:3:"rer";s:3:"186";s:3:"t o";s:3:"187";s:3:"tor";s:3:"188";s:4:"tør";s:3:"189";s:4:" få";s:3:"190";s:4:" må";s:3:"191";s:3:" to";s:3:"192";s:3:"boe";s:3:"193";s:3:"che";s:3:"194";s:3:"e v";s:3:"195";s:3:"i d";s:3:"196";s:3:"ive";s:3:"197";s:3:"kab";s:3:"198";s:3:"ns ";s:3:"199";s:3:"oel";s:3:"200";s:3:"se ";s:3:"201";s:3:"t v";s:3:"202";s:3:" al";s:3:"203";s:3:" bo";s:3:"204";s:3:" un";s:3:"205";s:3:"ans";s:3:"206";s:3:"dre";s:3:"207";s:3:"ire";s:3:"208";s:4:"køb";s:3:"209";s:3:"ors";s:3:"210";s:3:"ove";s:3:"211";s:3:"ren";s:3:"212";s:3:"t b";s:3:"213";s:4:"ør ";s:3:"214";s:3:" ka";s:3:"215";s:3:"ald";s:3:"216";s:3:"bet";s:3:"217";s:3:"gt ";s:3:"218";s:3:"isk";s:3:"219";s:3:"kal";s:3:"220";s:3:"kom";s:3:"221";s:3:"lev";s:3:"222";s:3:"n d";s:3:"223";s:3:"n i";s:3:"224";s:3:"pri";s:3:"225";s:3:"r p";s:3:"226";s:3:"rbr";s:3:"227";s:4:"søg";s:3:"228";s:3:"tel";s:3:"229";s:4:" så";s:3:"230";s:3:" te";s:3:"231";s:3:" va";s:3:"232";s:3:"al ";s:3:"233";s:3:"dir";s:3:"234";s:3:"eje";s:3:"235";s:3:"fis";s:3:"236";s:4:"gså";s:3:"237";s:3:"isc";s:3:"238";s:3:"jer";s:3:"239";s:3:"ker";s:3:"240";s:3:"ogs";s:3:"241";s:3:"sch";s:3:"242";s:3:"st ";s:3:"243";s:3:"t k";s:3:"244";s:3:"uge";s:3:"245";s:3:" di";s:3:"246";s:3:"ag ";s:3:"247";s:3:"d a";s:3:"248";s:3:"g i";s:3:"249";s:3:"ill";s:3:"250";s:3:"l a";s:3:"251";s:3:"lsk";s:3:"252";s:3:"n a";s:3:"253";s:3:"on ";s:3:"254";s:3:"sam";s:3:"255";s:3:"str";s:3:"256";s:3:"tet";s:3:"257";s:3:"var";s:3:"258";s:3:" mo";s:3:"259";s:3:"art";s:3:"260";s:3:"ash";s:3:"261";s:3:"att";s:3:"262";s:3:"e b";s:3:"263";s:3:"han";s:3:"264";s:3:"hav";s:3:"265";s:3:"kla";s:3:"266";s:3:"kon";s:3:"267";s:3:"n t";s:3:"268";s:3:"ned";s:3:"269";s:3:"r o";s:3:"270";s:3:"ra ";s:3:"271";s:3:"rre";s:3:"272";s:3:"ves";s:3:"273";s:3:"vil";s:3:"274";s:3:" el";s:3:"275";s:3:" kr";s:3:"276";s:3:" ov";s:3:"277";s:3:"ann";s:3:"278";s:3:"e u";s:3:"279";s:3:"ess";s:3:"280";s:3:"fra";s:3:"281";s:3:"g a";s:3:"282";s:3:"g d";s:3:"283";s:3:"int";s:3:"284";s:3:"ngs";s:3:"285";s:3:"rde";s:3:"286";s:3:"tra";s:3:"287";s:4:" år";s:3:"288";s:3:"akt";s:3:"289";s:3:"asi";s:3:"290";s:3:"em ";s:3:"291";s:3:"gel";s:3:"292";s:3:"gym";s:3:"293";s:3:"hol";s:3:"294";s:3:"kan";s:3:"295";s:3:"mna";s:3:"296";s:3:"n h";s:3:"297";s:3:"nsk";s:3:"298";s:3:"old";s:3:"299";}s:5:"dutch";a:300:{s:3:"en ";s:1:"0";s:3:"de ";s:1:"1";s:3:" de";s:1:"2";s:3:"et ";s:1:"3";s:3:"an ";s:1:"4";s:3:" he";s:1:"5";s:3:"er ";s:1:"6";s:3:" va";s:1:"7";s:3:"n d";s:1:"8";s:3:"van";s:1:"9";s:3:"een";s:2:"10";s:3:"het";s:2:"11";s:3:" ge";s:2:"12";s:3:"oor";s:2:"13";s:3:" ee";s:2:"14";s:3:"der";s:2:"15";s:3:" en";s:2:"16";s:3:"ij ";s:2:"17";s:3:"aar";s:2:"18";s:3:"gen";s:2:"19";s:3:"te ";s:2:"20";s:3:"ver";s:2:"21";s:3:" in";s:2:"22";s:3:" me";s:2:"23";s:3:"aan";s:2:"24";s:3:"den";s:2:"25";s:3:" we";s:2:"26";s:3:"at ";s:2:"27";s:3:"in ";s:2:"28";s:3:" da";s:2:"29";s:3:" te";s:2:"30";s:3:"eer";s:2:"31";s:3:"nde";s:2:"32";s:3:"ter";s:2:"33";s:3:"ste";s:2:"34";s:3:"n v";s:2:"35";s:3:" vo";s:2:"36";s:3:" zi";s:2:"37";s:3:"ing";s:2:"38";s:3:"n h";s:2:"39";s:3:"voo";s:2:"40";s:3:"is ";s:2:"41";s:3:" op";s:2:"42";s:3:"tie";s:2:"43";s:3:" aa";s:2:"44";s:3:"ede";s:2:"45";s:3:"erd";s:2:"46";s:3:"ers";s:2:"47";s:3:" be";s:2:"48";s:3:"eme";s:2:"49";s:3:"ten";s:2:"50";s:3:"ken";s:2:"51";s:3:"n e";s:2:"52";s:3:" ni";s:2:"53";s:3:" ve";s:2:"54";s:3:"ent";s:2:"55";s:3:"ijn";s:2:"56";s:3:"jn ";s:2:"57";s:3:"mee";s:2:"58";s:3:"iet";s:2:"59";s:3:"n w";s:2:"60";s:3:"ng ";s:2:"61";s:3:"nie";s:2:"62";s:3:" is";s:2:"63";s:3:"cht";s:2:"64";s:3:"dat";s:2:"65";s:3:"ere";s:2:"66";s:3:"ie ";s:2:"67";s:3:"ijk";s:2:"68";s:3:"n b";s:2:"69";s:3:"rde";s:2:"70";s:3:"ar ";s:2:"71";s:3:"e b";s:2:"72";s:3:"e a";s:2:"73";s:3:"met";s:2:"74";s:3:"t d";s:2:"75";s:3:"el ";s:2:"76";s:3:"ond";s:2:"77";s:3:"t h";s:2:"78";s:3:" al";s:2:"79";s:3:"e w";s:2:"80";s:3:"op ";s:2:"81";s:3:"ren";s:2:"82";s:3:" di";s:2:"83";s:3:" on";s:2:"84";s:3:"al ";s:2:"85";s:3:"and";s:2:"86";s:3:"bij";s:2:"87";s:3:"zij";s:2:"88";s:3:" bi";s:2:"89";s:3:" hi";s:2:"90";s:3:" wi";s:2:"91";s:3:"or ";s:2:"92";s:3:"r d";s:2:"93";s:3:"t v";s:2:"94";s:3:" wa";s:2:"95";s:3:"e h";s:2:"96";s:3:"lle";s:2:"97";s:3:"rt ";s:2:"98";s:3:"ang";s:2:"99";s:3:"hij";s:3:"100";s:3:"men";s:3:"101";s:3:"n a";s:3:"102";s:3:"n z";s:3:"103";s:3:"rs ";s:3:"104";s:3:" om";s:3:"105";s:3:"e o";s:3:"106";s:3:"e v";s:3:"107";s:3:"end";s:3:"108";s:3:"est";s:3:"109";s:3:"n t";s:3:"110";s:3:"par";s:3:"111";s:3:" pa";s:3:"112";s:3:" pr";s:3:"113";s:3:" ze";s:3:"114";s:3:"e g";s:3:"115";s:3:"e p";s:3:"116";s:3:"n p";s:3:"117";s:3:"ord";s:3:"118";s:3:"oud";s:3:"119";s:3:"raa";s:3:"120";s:3:"sch";s:3:"121";s:3:"t e";s:3:"122";s:3:"ege";s:3:"123";s:3:"ich";s:3:"124";s:3:"ien";s:3:"125";s:3:"aat";s:3:"126";s:3:"ek ";s:3:"127";s:3:"len";s:3:"128";s:3:"n m";s:3:"129";s:3:"nge";s:3:"130";s:3:"nt ";s:3:"131";s:3:"ove";s:3:"132";s:3:"rd ";s:3:"133";s:3:"wer";s:3:"134";s:3:" ma";s:3:"135";s:3:" mi";s:3:"136";s:3:"daa";s:3:"137";s:3:"e k";s:3:"138";s:3:"lij";s:3:"139";s:3:"mer";s:3:"140";s:3:"n g";s:3:"141";s:3:"n o";s:3:"142";s:3:"om ";s:3:"143";s:3:"sen";s:3:"144";s:3:"t b";s:3:"145";s:3:"wij";s:3:"146";s:3:" ho";s:3:"147";s:3:"e m";s:3:"148";s:3:"ele";s:3:"149";s:3:"gem";s:3:"150";s:3:"heb";s:3:"151";s:3:"pen";s:3:"152";s:3:"ude";s:3:"153";s:3:" bo";s:3:"154";s:3:" ja";s:3:"155";s:3:"die";s:3:"156";s:3:"e e";s:3:"157";s:3:"eli";s:3:"158";s:3:"erk";s:3:"159";s:3:"le ";s:3:"160";s:3:"pro";s:3:"161";s:3:"rij";s:3:"162";s:3:" er";s:3:"163";s:3:" za";s:3:"164";s:3:"e d";s:3:"165";s:3:"ens";s:3:"166";s:3:"ind";s:3:"167";s:3:"ke ";s:3:"168";s:3:"n k";s:3:"169";s:3:"nd ";s:3:"170";s:3:"nen";s:3:"171";s:3:"nte";s:3:"172";s:3:"r h";s:3:"173";s:3:"s d";s:3:"174";s:3:"s e";s:3:"175";s:3:"t z";s:3:"176";s:3:" b ";s:3:"177";s:3:" co";s:3:"178";s:3:" ik";s:3:"179";s:3:" ko";s:3:"180";s:3:" ov";s:3:"181";s:3:"eke";s:3:"182";s:3:"hou";s:3:"183";s:3:"ik ";s:3:"184";s:3:"iti";s:3:"185";s:3:"lan";s:3:"186";s:3:"ns ";s:3:"187";s:3:"t g";s:3:"188";s:3:"t m";s:3:"189";s:3:" do";s:3:"190";s:3:" le";s:3:"191";s:3:" zo";s:3:"192";s:3:"ams";s:3:"193";s:3:"e z";s:3:"194";s:3:"g v";s:3:"195";s:3:"it ";s:3:"196";s:3:"je ";s:3:"197";s:3:"ls ";s:3:"198";s:3:"maa";s:3:"199";s:3:"n i";s:3:"200";s:3:"nke";s:3:"201";s:3:"rke";s:3:"202";s:3:"uit";s:3:"203";s:3:" ha";s:3:"204";s:3:" ka";s:3:"205";s:3:" mo";s:3:"206";s:3:" re";s:3:"207";s:3:" st";s:3:"208";s:3:" to";s:3:"209";s:3:"age";s:3:"210";s:3:"als";s:3:"211";s:3:"ark";s:3:"212";s:3:"art";s:3:"213";s:3:"ben";s:3:"214";s:3:"e r";s:3:"215";s:3:"e s";s:3:"216";s:3:"ert";s:3:"217";s:3:"eze";s:3:"218";s:3:"ht ";s:3:"219";s:3:"ijd";s:3:"220";s:3:"lem";s:3:"221";s:3:"r v";s:3:"222";s:3:"rte";s:3:"223";s:3:"t p";s:3:"224";s:3:"zeg";s:3:"225";s:3:"zic";s:3:"226";s:3:"aak";s:3:"227";s:3:"aal";s:3:"228";s:3:"ag ";s:3:"229";s:3:"ale";s:3:"230";s:3:"bbe";s:3:"231";s:3:"ch ";s:3:"232";s:3:"e t";s:3:"233";s:3:"ebb";s:3:"234";s:3:"erz";s:3:"235";s:3:"ft ";s:3:"236";s:3:"ge ";s:3:"237";s:3:"led";s:3:"238";s:3:"mst";s:3:"239";s:3:"n n";s:3:"240";s:3:"oek";s:3:"241";s:3:"r i";s:3:"242";s:3:"t o";s:3:"243";s:3:"t w";s:3:"244";s:3:"tel";s:3:"245";s:3:"tte";s:3:"246";s:3:"uur";s:3:"247";s:3:"we ";s:3:"248";s:3:"zit";s:3:"249";s:3:" af";s:3:"250";s:3:" li";s:3:"251";s:3:" ui";s:3:"252";s:3:"ak ";s:3:"253";s:3:"all";s:3:"254";s:3:"aut";s:3:"255";s:3:"doo";s:3:"256";s:3:"e i";s:3:"257";s:3:"ene";s:3:"258";s:3:"erg";s:3:"259";s:3:"ete";s:3:"260";s:3:"ges";s:3:"261";s:3:"hee";s:3:"262";s:3:"jaa";s:3:"263";s:3:"jke";s:3:"264";s:3:"kee";s:3:"265";s:3:"kel";s:3:"266";s:3:"kom";s:3:"267";s:3:"lee";s:3:"268";s:3:"moe";s:3:"269";s:3:"n s";s:3:"270";s:3:"ort";s:3:"271";s:3:"rec";s:3:"272";s:3:"s o";s:3:"273";s:3:"s v";s:3:"274";s:3:"teg";s:3:"275";s:3:"tij";s:3:"276";s:3:"ven";s:3:"277";s:3:"waa";s:3:"278";s:3:"wel";s:3:"279";s:3:" an";s:3:"280";s:3:" au";s:3:"281";s:3:" bu";s:3:"282";s:3:" gr";s:3:"283";s:3:" pl";s:3:"284";s:3:" ti";s:3:"285";s:3:"'' ";s:3:"286";s:3:"ade";s:3:"287";s:3:"dag";s:3:"288";s:3:"e l";s:3:"289";s:3:"ech";s:3:"290";s:3:"eel";s:3:"291";s:3:"eft";s:3:"292";s:3:"ger";s:3:"293";s:3:"gt ";s:3:"294";s:3:"ig ";s:3:"295";s:3:"itt";s:3:"296";s:3:"j d";s:3:"297";s:3:"ppe";s:3:"298";s:3:"rda";s:3:"299";}s:7:"english";a:300:{s:3:" th";s:1:"0";s:3:"the";s:1:"1";s:3:"he ";s:1:"2";s:3:"ed ";s:1:"3";s:3:" to";s:1:"4";s:3:" in";s:1:"5";s:3:"er ";s:1:"6";s:3:"ing";s:1:"7";s:3:"ng ";s:1:"8";s:3:" an";s:1:"9";s:3:"nd ";s:2:"10";s:3:" of";s:2:"11";s:3:"and";s:2:"12";s:3:"to ";s:2:"13";s:3:"of ";s:2:"14";s:3:" co";s:2:"15";s:3:"at ";s:2:"16";s:3:"on ";s:2:"17";s:3:"in ";s:2:"18";s:3:" a ";s:2:"19";s:3:"d t";s:2:"20";s:3:" he";s:2:"21";s:3:"e t";s:2:"22";s:3:"ion";s:2:"23";s:3:"es ";s:2:"24";s:3:" re";s:2:"25";s:3:"re ";s:2:"26";s:3:"hat";s:2:"27";s:3:" sa";s:2:"28";s:3:" st";s:2:"29";s:3:" ha";s:2:"30";s:3:"her";s:2:"31";s:3:"tha";s:2:"32";s:3:"tio";s:2:"33";s:3:"or ";s:2:"34";s:3:" ''";s:2:"35";s:3:"en ";s:2:"36";s:3:" wh";s:2:"37";s:3:"e s";s:2:"38";s:3:"ent";s:2:"39";s:3:"n t";s:2:"40";s:3:"s a";s:2:"41";s:3:"as ";s:2:"42";s:3:"for";s:2:"43";s:3:"is ";s:2:"44";s:3:"t t";s:2:"45";s:3:" be";s:2:"46";s:3:"ld ";s:2:"47";s:3:"e a";s:2:"48";s:3:"rs ";s:2:"49";s:3:" wa";s:2:"50";s:3:"ut ";s:2:"51";s:3:"ve ";s:2:"52";s:3:"ll ";s:2:"53";s:3:"al ";s:2:"54";s:3:" ma";s:2:"55";s:3:"e i";s:2:"56";s:3:" fo";s:2:"57";s:3:"'s ";s:2:"58";s:3:"an ";s:2:"59";s:3:"est";s:2:"60";s:3:" hi";s:2:"61";s:3:" mo";s:2:"62";s:3:" se";s:2:"63";s:3:" pr";s:2:"64";s:3:"s t";s:2:"65";s:3:"ate";s:2:"66";s:3:"st ";s:2:"67";s:3:"ter";s:2:"68";s:3:"ere";s:2:"69";s:3:"ted";s:2:"70";s:3:"nt ";s:2:"71";s:3:"ver";s:2:"72";s:3:"d a";s:2:"73";s:3:" wi";s:2:"74";s:3:"se ";s:2:"75";s:3:"e c";s:2:"76";s:3:"ect";s:2:"77";s:3:"ns ";s:2:"78";s:3:" on";s:2:"79";s:3:"ly ";s:2:"80";s:3:"tol";s:2:"81";s:3:"ey ";s:2:"82";s:3:"r t";s:2:"83";s:3:" ca";s:2:"84";s:3:"ati";s:2:"85";s:3:"ts ";s:2:"86";s:3:"all";s:2:"87";s:3:" no";s:2:"88";s:3:"his";s:2:"89";s:3:"s o";s:2:"90";s:3:"ers";s:2:"91";s:3:"con";s:2:"92";s:3:"e o";s:2:"93";s:3:"ear";s:2:"94";s:3:"f t";s:2:"95";s:3:"e w";s:2:"96";s:3:"was";s:2:"97";s:3:"ons";s:2:"98";s:3:"sta";s:2:"99";s:3:"'' ";s:3:"100";s:3:"sti";s:3:"101";s:3:"n a";s:3:"102";s:3:"sto";s:3:"103";s:3:"t h";s:3:"104";s:3:" we";s:3:"105";s:3:"id ";s:3:"106";s:3:"th ";s:3:"107";s:3:" it";s:3:"108";s:3:"ce ";s:3:"109";s:3:" di";s:3:"110";s:3:"ave";s:3:"111";s:3:"d h";s:3:"112";s:3:"cou";s:3:"113";s:3:"pro";s:3:"114";s:3:"ad ";s:3:"115";s:3:"oll";s:3:"116";s:3:"ry ";s:3:"117";s:3:"d s";s:3:"118";s:3:"e m";s:3:"119";s:3:" so";s:3:"120";s:3:"ill";s:3:"121";s:3:"cti";s:3:"122";s:3:"te ";s:3:"123";s:3:"tor";s:3:"124";s:3:"eve";s:3:"125";s:3:"g t";s:3:"126";s:3:"it ";s:3:"127";s:3:" ch";s:3:"128";s:3:" de";s:3:"129";s:3:"hav";s:3:"130";s:3:"oul";s:3:"131";s:3:"ty ";s:3:"132";s:3:"uld";s:3:"133";s:3:"use";s:3:"134";s:3:" al";s:3:"135";s:3:"are";s:3:"136";s:3:"ch ";s:3:"137";s:3:"me ";s:3:"138";s:3:"out";s:3:"139";s:3:"ove";s:3:"140";s:3:"wit";s:3:"141";s:3:"ys ";s:3:"142";s:3:"chi";s:3:"143";s:3:"t a";s:3:"144";s:3:"ith";s:3:"145";s:3:"oth";s:3:"146";s:3:" ab";s:3:"147";s:3:" te";s:3:"148";s:3:" wo";s:3:"149";s:3:"s s";s:3:"150";s:3:"res";s:3:"151";s:3:"t w";s:3:"152";s:3:"tin";s:3:"153";s:3:"e b";s:3:"154";s:3:"e h";s:3:"155";s:3:"nce";s:3:"156";s:3:"t s";s:3:"157";s:3:"y t";s:3:"158";s:3:"e p";s:3:"159";s:3:"ele";s:3:"160";s:3:"hin";s:3:"161";s:3:"s i";s:3:"162";s:3:"nte";s:3:"163";s:3:" li";s:3:"164";s:3:"le ";s:3:"165";s:3:" do";s:3:"166";s:3:"aid";s:3:"167";s:3:"hey";s:3:"168";s:3:"ne ";s:3:"169";s:3:"s w";s:3:"170";s:3:" as";s:3:"171";s:3:" fr";s:3:"172";s:3:" tr";s:3:"173";s:3:"end";s:3:"174";s:3:"sai";s:3:"175";s:3:" el";s:3:"176";s:3:" ne";s:3:"177";s:3:" su";s:3:"178";s:3:"'t ";s:3:"179";s:3:"ay ";s:3:"180";s:3:"hou";s:3:"181";s:3:"ive";s:3:"182";s:3:"lec";s:3:"183";s:3:"n't";s:3:"184";s:3:" ye";s:3:"185";s:3:"but";s:3:"186";s:3:"d o";s:3:"187";s:3:"o t";s:3:"188";s:3:"y o";s:3:"189";s:3:" ho";s:3:"190";s:3:" me";s:3:"191";s:3:"be ";s:3:"192";s:3:"cal";s:3:"193";s:3:"e e";s:3:"194";s:3:"had";s:3:"195";s:3:"ple";s:3:"196";s:3:" at";s:3:"197";s:3:" bu";s:3:"198";s:3:" la";s:3:"199";s:3:"d b";s:3:"200";s:3:"s h";s:3:"201";s:3:"say";s:3:"202";s:3:"t i";s:3:"203";s:3:" ar";s:3:"204";s:3:"e f";s:3:"205";s:3:"ght";s:3:"206";s:3:"hil";s:3:"207";s:3:"igh";s:3:"208";s:3:"int";s:3:"209";s:3:"not";s:3:"210";s:3:"ren";s:3:"211";s:3:" is";s:3:"212";s:3:" pa";s:3:"213";s:3:" sh";s:3:"214";s:3:"ays";s:3:"215";s:3:"com";s:3:"216";s:3:"n s";s:3:"217";s:3:"r a";s:3:"218";s:3:"rin";s:3:"219";s:3:"y a";s:3:"220";s:3:" un";s:3:"221";s:3:"n c";s:3:"222";s:3:"om ";s:3:"223";s:3:"thi";s:3:"224";s:3:" mi";s:3:"225";s:3:"by ";s:3:"226";s:3:"d i";s:3:"227";s:3:"e d";s:3:"228";s:3:"e n";s:3:"229";s:3:"t o";s:3:"230";s:3:" by";s:3:"231";s:3:"e r";s:3:"232";s:3:"eri";s:3:"233";s:3:"old";s:3:"234";s:3:"ome";s:3:"235";s:3:"whe";s:3:"236";s:3:"yea";s:3:"237";s:3:" gr";s:3:"238";s:3:"ar ";s:3:"239";s:3:"ity";s:3:"240";s:3:"mpl";s:3:"241";s:3:"oun";s:3:"242";s:3:"one";s:3:"243";s:3:"ow ";s:3:"244";s:3:"r s";s:3:"245";s:3:"s f";s:3:"246";s:3:"tat";s:3:"247";s:3:" ba";s:3:"248";s:3:" vo";s:3:"249";s:3:"bou";s:3:"250";s:3:"sam";s:3:"251";s:3:"tim";s:3:"252";s:3:"vot";s:3:"253";s:3:"abo";s:3:"254";s:3:"ant";s:3:"255";s:3:"ds ";s:3:"256";s:3:"ial";s:3:"257";s:3:"ine";s:3:"258";s:3:"man";s:3:"259";s:3:"men";s:3:"260";s:3:" or";s:3:"261";s:3:" po";s:3:"262";s:3:"amp";s:3:"263";s:3:"can";s:3:"264";s:3:"der";s:3:"265";s:3:"e l";s:3:"266";s:3:"les";s:3:"267";s:3:"ny ";s:3:"268";s:3:"ot ";s:3:"269";s:3:"rec";s:3:"270";s:3:"tes";s:3:"271";s:3:"tho";s:3:"272";s:3:"ica";s:3:"273";s:3:"ild";s:3:"274";s:3:"ir ";s:3:"275";s:3:"nde";s:3:"276";s:3:"ose";s:3:"277";s:3:"ous";s:3:"278";s:3:"pre";s:3:"279";s:3:"ste";s:3:"280";s:3:"era";s:3:"281";s:3:"per";s:3:"282";s:3:"r o";s:3:"283";s:3:"red";s:3:"284";s:3:"rie";s:3:"285";s:3:" bo";s:3:"286";s:3:" le";s:3:"287";s:3:"ali";s:3:"288";s:3:"ars";s:3:"289";s:3:"ore";s:3:"290";s:3:"ric";s:3:"291";s:3:"s m";s:3:"292";s:3:"str";s:3:"293";s:3:" fa";s:3:"294";s:3:"ess";s:3:"295";s:3:"ie ";s:3:"296";s:3:"ist";s:3:"297";s:3:"lat";s:3:"298";s:3:"uri";s:3:"299";}s:8:"estonian";a:300:{s:3:"st ";s:1:"0";s:3:" ka";s:1:"1";s:3:"on ";s:1:"2";s:3:"ja ";s:1:"3";s:3:" va";s:1:"4";s:3:" on";s:1:"5";s:3:" ja";s:1:"6";s:3:" ko";s:1:"7";s:3:"se ";s:1:"8";s:3:"ast";s:1:"9";s:3:"le ";s:2:"10";s:3:"es ";s:2:"11";s:3:"as ";s:2:"12";s:3:"is ";s:2:"13";s:3:"ud ";s:2:"14";s:3:" sa";s:2:"15";s:3:"da ";s:2:"16";s:3:"ga ";s:2:"17";s:3:" ta";s:2:"18";s:3:"aja";s:2:"19";s:3:"sta";s:2:"20";s:3:" ku";s:2:"21";s:3:" pe";s:2:"22";s:3:"a k";s:2:"23";s:3:"est";s:2:"24";s:3:"ist";s:2:"25";s:3:"ks ";s:2:"26";s:3:"ta ";s:2:"27";s:3:"al ";s:2:"28";s:3:"ava";s:2:"29";s:3:"id ";s:2:"30";s:3:"saa";s:2:"31";s:3:"mis";s:2:"32";s:3:"te ";s:2:"33";s:3:"val";s:2:"34";s:3:" et";s:2:"35";s:3:"nud";s:2:"36";s:3:" te";s:2:"37";s:3:"inn";s:2:"38";s:3:" se";s:2:"39";s:3:" tu";s:2:"40";s:3:"a v";s:2:"41";s:3:"alu";s:2:"42";s:3:"e k";s:2:"43";s:3:"ise";s:2:"44";s:3:"lu ";s:2:"45";s:3:"ma ";s:2:"46";s:3:"mes";s:2:"47";s:3:" mi";s:2:"48";s:3:"et ";s:2:"49";s:3:"iku";s:2:"50";s:3:"lin";s:2:"51";s:3:"ad ";s:2:"52";s:3:"el ";s:2:"53";s:3:"ime";s:2:"54";s:3:"ne ";s:2:"55";s:3:"nna";s:2:"56";s:3:" ha";s:2:"57";s:3:" in";s:2:"58";s:3:" ke";s:2:"59";s:4:" võ";s:2:"60";s:3:"a s";s:2:"61";s:3:"a t";s:2:"62";s:3:"ab ";s:2:"63";s:3:"e s";s:2:"64";s:3:"esi";s:2:"65";s:3:" la";s:2:"66";s:3:" li";s:2:"67";s:3:"e v";s:2:"68";s:3:"eks";s:2:"69";s:3:"ema";s:2:"70";s:3:"las";s:2:"71";s:3:"les";s:2:"72";s:3:"rju";s:2:"73";s:3:"tle";s:2:"74";s:3:"tsi";s:2:"75";s:3:"tus";s:2:"76";s:3:"upa";s:2:"77";s:3:"use";s:2:"78";s:3:"ust";s:2:"79";s:3:"var";s:2:"80";s:4:" lä";s:2:"81";s:3:"ali";s:2:"82";s:3:"arj";s:2:"83";s:3:"de ";s:2:"84";s:3:"ete";s:2:"85";s:3:"i t";s:2:"86";s:3:"iga";s:2:"87";s:3:"ilm";s:2:"88";s:3:"kui";s:2:"89";s:3:"li ";s:2:"90";s:3:"tul";s:2:"91";s:3:" ei";s:2:"92";s:3:" me";s:2:"93";s:4:" sõ";s:2:"94";s:3:"aal";s:2:"95";s:3:"ata";s:2:"96";s:3:"dus";s:2:"97";s:3:"ei ";s:2:"98";s:3:"nik";s:2:"99";s:3:"pea";s:3:"100";s:3:"s k";s:3:"101";s:3:"s o";s:3:"102";s:3:"sal";s:3:"103";s:4:"sõn";s:3:"104";s:3:"ter";s:3:"105";s:3:"ul ";s:3:"106";s:4:"või";s:3:"107";s:3:" el";s:3:"108";s:3:" ne";s:3:"109";s:3:"a j";s:3:"110";s:3:"ate";s:3:"111";s:3:"end";s:3:"112";s:3:"i k";s:3:"113";s:3:"ita";s:3:"114";s:3:"kar";s:3:"115";s:3:"kor";s:3:"116";s:3:"l o";s:3:"117";s:3:"lt ";s:3:"118";s:3:"maa";s:3:"119";s:3:"oli";s:3:"120";s:3:"sti";s:3:"121";s:3:"vad";s:3:"122";s:5:"ään";s:3:"123";s:3:" ju";s:3:"124";s:4:" jä";s:3:"125";s:4:" kü";s:3:"126";s:3:" ma";s:3:"127";s:3:" po";s:3:"128";s:4:" üt";s:3:"129";s:3:"aas";s:3:"130";s:3:"aks";s:3:"131";s:3:"at ";s:3:"132";s:3:"ed ";s:3:"133";s:3:"eri";s:3:"134";s:3:"hoi";s:3:"135";s:3:"i s";s:3:"136";s:3:"ka ";s:3:"137";s:3:"la ";s:3:"138";s:3:"nni";s:3:"139";s:3:"oid";s:3:"140";s:3:"pai";s:3:"141";s:3:"rit";s:3:"142";s:3:"us ";s:3:"143";s:4:"ütl";s:3:"144";s:3:" aa";s:3:"145";s:3:" lo";s:3:"146";s:3:" to";s:3:"147";s:3:" ve";s:3:"148";s:3:"a e";s:3:"149";s:3:"ada";s:3:"150";s:3:"aid";s:3:"151";s:3:"ami";s:3:"152";s:3:"and";s:3:"153";s:3:"dla";s:3:"154";s:3:"e j";s:3:"155";s:3:"ega";s:3:"156";s:3:"gi ";s:3:"157";s:3:"gu ";s:3:"158";s:3:"i p";s:3:"159";s:3:"idl";s:3:"160";s:3:"ik ";s:3:"161";s:3:"ini";s:3:"162";s:3:"jup";s:3:"163";s:3:"kal";s:3:"164";s:3:"kas";s:3:"165";s:3:"kes";s:3:"166";s:3:"koh";s:3:"167";s:3:"s e";s:3:"168";s:3:"s p";s:3:"169";s:3:"sel";s:3:"170";s:3:"sse";s:3:"171";s:3:"ui ";s:3:"172";s:3:" pi";s:3:"173";s:3:" si";s:3:"174";s:3:"aru";s:3:"175";s:3:"eda";s:3:"176";s:3:"eva";s:3:"177";s:3:"fil";s:3:"178";s:3:"i v";s:3:"179";s:3:"ida";s:3:"180";s:3:"ing";s:3:"181";s:5:"lää";s:3:"182";s:3:"me ";s:3:"183";s:3:"na ";s:3:"184";s:3:"nda";s:3:"185";s:3:"nim";s:3:"186";s:3:"ole";s:3:"187";s:3:"ots";s:3:"188";s:3:"ris";s:3:"189";s:3:"s l";s:3:"190";s:3:"sia";s:3:"191";s:3:"t p";s:3:"192";s:3:" en";s:3:"193";s:3:" mu";s:3:"194";s:3:" ol";s:3:"195";s:4:" põ";s:3:"196";s:3:" su";s:3:"197";s:4:" vä";s:3:"198";s:4:" üh";s:3:"199";s:3:"a l";s:3:"200";s:3:"a p";s:3:"201";s:3:"aga";s:3:"202";s:3:"ale";s:3:"203";s:3:"aps";s:3:"204";s:3:"arv";s:3:"205";s:3:"e a";s:3:"206";s:3:"ela";s:3:"207";s:3:"ika";s:3:"208";s:3:"lle";s:3:"209";s:3:"loo";s:3:"210";s:3:"mal";s:3:"211";s:3:"pet";s:3:"212";s:3:"t k";s:3:"213";s:3:"tee";s:3:"214";s:3:"tis";s:3:"215";s:3:"vat";s:3:"216";s:4:"äne";s:3:"217";s:4:"õnn";s:3:"218";s:3:" es";s:3:"219";s:3:" fi";s:3:"220";s:3:" vi";s:3:"221";s:3:"a i";s:3:"222";s:3:"a o";s:3:"223";s:3:"aab";s:3:"224";s:3:"aap";s:3:"225";s:3:"ala";s:3:"226";s:3:"alt";s:3:"227";s:3:"ama";s:3:"228";s:3:"anu";s:3:"229";s:3:"e p";s:3:"230";s:3:"e t";s:3:"231";s:3:"eal";s:3:"232";s:3:"eli";s:3:"233";s:3:"haa";s:3:"234";s:3:"hin";s:3:"235";s:3:"iva";s:3:"236";s:3:"kon";s:3:"237";s:3:"ku ";s:3:"238";s:3:"lik";s:3:"239";s:3:"lm ";s:3:"240";s:3:"min";s:3:"241";s:3:"n t";s:3:"242";s:3:"odu";s:3:"243";s:3:"oon";s:3:"244";s:3:"psa";s:3:"245";s:3:"ri ";s:3:"246";s:3:"si ";s:3:"247";s:3:"stu";s:3:"248";s:3:"t e";s:3:"249";s:3:"t s";s:3:"250";s:3:"ti ";s:3:"251";s:3:"ule";s:3:"252";s:3:"uur";s:3:"253";s:3:"vas";s:3:"254";s:3:"vee";s:3:"255";s:3:" ki";s:3:"256";s:3:" ni";s:3:"257";s:4:" nä";s:3:"258";s:3:" ra";s:3:"259";s:3:"aig";s:3:"260";s:3:"aka";s:3:"261";s:3:"all";s:3:"262";s:3:"atu";s:3:"263";s:3:"e e";s:3:"264";s:3:"eis";s:3:"265";s:3:"ers";s:3:"266";s:3:"i e";s:3:"267";s:3:"ii ";s:3:"268";s:3:"iis";s:3:"269";s:3:"il ";s:3:"270";s:3:"ima";s:3:"271";s:3:"its";s:3:"272";s:3:"kka";s:3:"273";s:3:"kuh";s:3:"274";s:3:"l k";s:3:"275";s:3:"lat";s:3:"276";s:3:"maj";s:3:"277";s:3:"ndu";s:3:"278";s:3:"ni ";s:3:"279";s:3:"nii";s:3:"280";s:3:"oma";s:3:"281";s:3:"ool";s:3:"282";s:3:"rso";s:3:"283";s:3:"ru ";s:3:"284";s:3:"rva";s:3:"285";s:3:"s t";s:3:"286";s:3:"sek";s:3:"287";s:3:"son";s:3:"288";s:3:"ste";s:3:"289";s:3:"t m";s:3:"290";s:3:"taj";s:3:"291";s:3:"tam";s:3:"292";s:3:"ude";s:3:"293";s:3:"uho";s:3:"294";s:3:"vai";s:3:"295";s:3:" ag";s:3:"296";s:3:" os";s:3:"297";s:3:" pa";s:3:"298";s:3:" re";s:3:"299";}s:5:"farsi";a:300:{s:5:"ان ";s:1:"0";s:5:"ای ";s:1:"1";s:5:"ه ا";s:1:"2";s:5:" اي";s:1:"3";s:5:" در";s:1:"4";s:5:"به ";s:1:"5";s:5:" بر";s:1:"6";s:5:"در ";s:1:"7";s:6:"ران";s:1:"8";s:5:" به";s:1:"9";s:5:"ی ا";s:2:"10";s:5:"از ";s:2:"11";s:5:"ين ";s:2:"12";s:5:"می ";s:2:"13";s:5:" از";s:2:"14";s:5:"ده ";s:2:"15";s:5:"ست ";s:2:"16";s:6:"است";s:2:"17";s:5:" اس";s:2:"18";s:5:" که";s:2:"19";s:5:"که ";s:2:"20";s:6:"اير";s:2:"21";s:5:"ند ";s:2:"22";s:6:"اين";s:2:"23";s:5:" ها";s:2:"24";s:6:"يرا";s:2:"25";s:5:"ود ";s:2:"26";s:5:" را";s:2:"27";s:6:"های";s:2:"28";s:5:" خو";s:2:"29";s:5:"ته ";s:2:"30";s:5:"را ";s:2:"31";s:6:"رای";s:2:"32";s:5:"رد ";s:2:"33";s:5:"ن ب";s:2:"34";s:6:"کرد";s:2:"35";s:4:" و ";s:2:"36";s:5:" کر";s:2:"37";s:5:"ات ";s:2:"38";s:6:"برا";s:2:"39";s:5:"د ک";s:2:"40";s:6:"مان";s:2:"41";s:5:"ی د";s:2:"42";s:5:" ان";s:2:"43";s:6:"خوا";s:2:"44";s:6:"شور";s:2:"45";s:5:" با";s:2:"46";s:5:"ن ا";s:2:"47";s:5:" سا";s:2:"48";s:6:"تمی";s:2:"49";s:5:"ری ";s:2:"50";s:6:"اتم";s:2:"51";s:5:"ا ا";s:2:"52";s:6:"واه";s:2:"53";s:5:" ات";s:2:"54";s:5:" عر";s:2:"55";s:5:"اق ";s:2:"56";s:5:"ر م";s:2:"57";s:6:"راق";s:2:"58";s:6:"عرا";s:2:"59";s:5:"ی ب";s:2:"60";s:5:" تا";s:2:"61";s:5:" تو";s:2:"62";s:5:"ار ";s:2:"63";s:5:"ر ا";s:2:"64";s:5:"ن م";s:2:"65";s:5:"ه ب";s:2:"66";s:5:"ور ";s:2:"67";s:5:"يد ";s:2:"68";s:5:"ی ک";s:2:"69";s:5:" ام";s:2:"70";s:5:" دا";s:2:"71";s:5:" کن";s:2:"72";s:6:"اهد";s:2:"73";s:5:"هد ";s:2:"74";s:5:" آن";s:2:"75";s:5:" می";s:2:"76";s:5:" ني";s:2:"77";s:5:" گف";s:2:"78";s:5:"د ا";s:2:"79";s:6:"گفت";s:2:"80";s:5:" کش";s:2:"81";s:5:"ا ب";s:2:"82";s:5:"نی ";s:2:"83";s:5:"ها ";s:2:"84";s:6:"کشو";s:2:"85";s:5:" رو";s:2:"86";s:5:"ت ک";s:2:"87";s:6:"نيو";s:2:"88";s:5:"ه م";s:2:"89";s:5:"وی ";s:2:"90";s:5:"ی ت";s:2:"91";s:5:" شو";s:2:"92";s:5:"ال ";s:2:"93";s:6:"دار";s:2:"94";s:5:"مه ";s:2:"95";s:5:"ن ک";s:2:"96";s:5:"ه د";s:2:"97";s:5:"يه ";s:2:"98";s:5:" ما";s:2:"99";s:6:"امه";s:3:"100";s:5:"د ب";s:3:"101";s:6:"زار";s:3:"102";s:6:"ورا";s:3:"103";s:6:"گزا";s:3:"104";s:5:" پي";s:3:"105";s:5:"آن ";s:3:"106";s:6:"انت";s:3:"107";s:5:"ت ا";s:3:"108";s:5:"فت ";s:3:"109";s:5:"ه ن";s:3:"110";s:5:"ی خ";s:3:"111";s:6:"اما";s:3:"112";s:6:"بات";s:3:"113";s:5:"ما ";s:3:"114";s:6:"ملل";s:3:"115";s:6:"نام";s:3:"116";s:5:"ير ";s:3:"117";s:5:"ی م";s:3:"118";s:5:"ی ه";s:3:"119";s:5:" آم";s:3:"120";s:5:" ای";s:3:"121";s:5:" من";s:3:"122";s:6:"انس";s:3:"123";s:6:"اني";s:3:"124";s:5:"ت د";s:3:"125";s:6:"رده";s:3:"126";s:6:"ساز";s:3:"127";s:5:"ن د";s:3:"128";s:5:"نه ";s:3:"129";s:6:"ورد";s:3:"130";s:5:" او";s:3:"131";s:5:" بي";s:3:"132";s:5:" سو";s:3:"133";s:5:" شد";s:3:"134";s:6:"اده";s:3:"135";s:6:"اند";s:3:"136";s:5:"با ";s:3:"137";s:5:"ت ب";s:3:"138";s:5:"ر ب";s:3:"139";s:5:"ز ا";s:3:"140";s:6:"زما";s:3:"141";s:6:"سته";s:3:"142";s:5:"ن ر";s:3:"143";s:5:"ه س";s:3:"144";s:6:"وان";s:3:"145";s:5:"وز ";s:3:"146";s:5:"ی ر";s:3:"147";s:5:"ی س";s:3:"148";s:5:" هس";s:3:"149";s:6:"ابا";s:3:"150";s:5:"ام ";s:3:"151";s:6:"اور";s:3:"152";s:6:"تخا";s:3:"153";s:6:"خاب";s:3:"154";s:6:"خود";s:3:"155";s:5:"د د";s:3:"156";s:5:"دن ";s:3:"157";s:6:"رها";s:3:"158";s:6:"روز";s:3:"159";s:6:"رگز";s:3:"160";s:6:"نتخ";s:3:"161";s:5:"ه ش";s:3:"162";s:5:"ه ه";s:3:"163";s:6:"هست";s:3:"164";s:5:"يت ";s:3:"165";s:5:"يم ";s:3:"166";s:5:" دو";s:3:"167";s:5:" دي";s:3:"168";s:5:" مو";s:3:"169";s:5:" نو";s:3:"170";s:5:" هم";s:3:"171";s:5:" کا";s:3:"172";s:5:"اد ";s:3:"173";s:6:"اری";s:3:"174";s:6:"انی";s:3:"175";s:5:"بر ";s:3:"176";s:6:"بود";s:3:"177";s:5:"ت ه";s:3:"178";s:5:"ح ه";s:3:"179";s:6:"حال";s:3:"180";s:5:"رش ";s:3:"181";s:5:"عه ";s:3:"182";s:5:"لی ";s:3:"183";s:5:"وم ";s:3:"184";s:6:"ژان";s:3:"185";s:5:" سل";s:3:"186";s:6:"آمر";s:3:"187";s:5:"اح ";s:3:"188";s:6:"توس";s:3:"189";s:6:"داد";s:3:"190";s:6:"دام";s:3:"191";s:5:"ر د";s:3:"192";s:5:"ره ";s:3:"193";s:6:"ريک";s:3:"194";s:5:"زی ";s:3:"195";s:6:"سلا";s:3:"196";s:6:"شود";s:3:"197";s:6:"لاح";s:3:"198";s:6:"مري";s:3:"199";s:6:"نند";s:3:"200";s:5:"ه ع";s:3:"201";s:6:"يما";s:3:"202";s:6:"يکا";s:3:"203";s:6:"پيم";s:3:"204";s:5:"گر ";s:3:"205";s:5:" آژ";s:3:"206";s:5:" ال";s:3:"207";s:5:" بو";s:3:"208";s:5:" مق";s:3:"209";s:5:" مل";s:3:"210";s:5:" وی";s:3:"211";s:6:"آژا";s:3:"212";s:6:"ازم";s:3:"213";s:6:"ازی";s:3:"214";s:6:"بار";s:3:"215";s:6:"برن";s:3:"216";s:5:"ر آ";s:3:"217";s:5:"ز س";s:3:"218";s:6:"سعه";s:3:"219";s:6:"شته";s:3:"220";s:6:"مات";s:3:"221";s:5:"ن آ";s:3:"222";s:5:"ن پ";s:3:"223";s:5:"نس ";s:3:"224";s:5:"ه گ";s:3:"225";s:6:"وسع";s:3:"226";s:6:"يان";s:3:"227";s:6:"يوم";s:3:"228";s:5:"کا ";s:3:"229";s:6:"کام";s:3:"230";s:6:"کند";s:3:"231";s:5:" خا";s:3:"232";s:5:" سر";s:3:"233";s:6:"آور";s:3:"234";s:6:"ارد";s:3:"235";s:6:"اقد";s:3:"236";s:6:"ايم";s:3:"237";s:6:"ايی";s:3:"238";s:6:"برگ";s:3:"239";s:5:"ت ع";s:3:"240";s:5:"تن ";s:3:"241";s:5:"خت ";s:3:"242";s:5:"د و";s:3:"243";s:5:"ر خ";s:3:"244";s:5:"رک ";s:3:"245";s:6:"زير";s:3:"246";s:6:"فته";s:3:"247";s:6:"قدا";s:3:"248";s:5:"ل ت";s:3:"249";s:6:"مين";s:3:"250";s:5:"ن گ";s:3:"251";s:5:"ه آ";s:3:"252";s:5:"ه خ";s:3:"253";s:5:"ه ک";s:3:"254";s:6:"ورک";s:3:"255";s:6:"ويو";s:3:"256";s:6:"يور";s:3:"257";s:6:"يوي";s:3:"258";s:5:"يی ";s:3:"259";s:5:"ک ت";s:3:"260";s:5:"ی ش";s:3:"261";s:5:" اق";s:3:"262";s:5:" حا";s:3:"263";s:5:" حق";s:3:"264";s:5:" دس";s:3:"265";s:5:" شک";s:3:"266";s:5:" عم";s:3:"267";s:5:" يک";s:3:"268";s:5:"ا ت";s:3:"269";s:5:"ا د";s:3:"270";s:6:"ارج";s:3:"271";s:6:"بين";s:3:"272";s:5:"ت م";s:3:"273";s:5:"ت و";s:3:"274";s:6:"تاي";s:3:"275";s:6:"دست";s:3:"276";s:5:"ر ح";s:3:"277";s:5:"ر س";s:3:"278";s:6:"رنا";s:3:"279";s:5:"ز ب";s:3:"280";s:6:"شکا";s:3:"281";s:5:"لل ";s:3:"282";s:5:"م ک";s:3:"283";s:5:"مز ";s:3:"284";s:6:"ندا";s:3:"285";s:6:"نوا";s:3:"286";s:5:"و ا";s:3:"287";s:6:"وره";s:3:"288";s:5:"ون ";s:3:"289";s:6:"وند";s:3:"290";s:6:"يمز";s:3:"291";s:5:" آو";s:3:"292";s:5:" اع";s:3:"293";s:5:" فر";s:3:"294";s:5:" مت";s:3:"295";s:5:" نه";s:3:"296";s:5:" هر";s:3:"297";s:5:" وز";s:3:"298";s:5:" گز";s:3:"299";}s:7:"finnish";a:300:{s:3:"en ";s:1:"0";s:3:"in ";s:1:"1";s:3:"an ";s:1:"2";s:3:"on ";s:1:"3";s:3:"ist";s:1:"4";s:3:"ta ";s:1:"5";s:3:"ja ";s:1:"6";s:3:"n t";s:1:"7";s:3:"sa ";s:1:"8";s:3:"sta";s:1:"9";s:3:"aan";s:2:"10";s:3:"n p";s:2:"11";s:3:" on";s:2:"12";s:3:"ssa";s:2:"13";s:3:"tta";s:2:"14";s:4:"tä ";s:2:"15";s:3:" ka";s:2:"16";s:3:" pa";s:2:"17";s:3:"si ";s:2:"18";s:3:" ja";s:2:"19";s:3:"n k";s:2:"20";s:3:"lla";s:2:"21";s:4:"än ";s:2:"22";s:3:"een";s:2:"23";s:3:"n v";s:2:"24";s:3:"ksi";s:2:"25";s:3:"ett";s:2:"26";s:3:"nen";s:2:"27";s:3:"taa";s:2:"28";s:4:"ttä";s:2:"29";s:3:" va";s:2:"30";s:3:"ill";s:2:"31";s:3:"itt";s:2:"32";s:3:" jo";s:2:"33";s:3:" ko";s:2:"34";s:3:"n s";s:2:"35";s:3:" tu";s:2:"36";s:3:"ia ";s:2:"37";s:3:" su";s:2:"38";s:3:"a p";s:2:"39";s:3:"aa ";s:2:"40";s:3:"la ";s:2:"41";s:3:"lle";s:2:"42";s:3:"n m";s:2:"43";s:3:"le ";s:2:"44";s:3:"tte";s:2:"45";s:3:"na ";s:2:"46";s:3:" ta";s:2:"47";s:3:" ve";s:2:"48";s:3:"at ";s:2:"49";s:3:" vi";s:2:"50";s:3:"utt";s:2:"51";s:3:" sa";s:2:"52";s:3:"ise";s:2:"53";s:3:"sen";s:2:"54";s:3:" ku";s:2:"55";s:4:" nä";s:2:"56";s:4:" pä";s:2:"57";s:3:"ste";s:2:"58";s:3:" ol";s:2:"59";s:3:"a t";s:2:"60";s:3:"ais";s:2:"61";s:3:"maa";s:2:"62";s:3:"ti ";s:2:"63";s:3:"a o";s:2:"64";s:3:"oit";s:2:"65";s:5:"pää";s:2:"66";s:3:" pi";s:2:"67";s:3:"a v";s:2:"68";s:3:"ala";s:2:"69";s:3:"ine";s:2:"70";s:3:"isi";s:2:"71";s:3:"tel";s:2:"72";s:3:"tti";s:2:"73";s:3:" si";s:2:"74";s:3:"a k";s:2:"75";s:3:"all";s:2:"76";s:3:"iin";s:2:"77";s:3:"kin";s:2:"78";s:4:"stä";s:2:"79";s:3:"uom";s:2:"80";s:3:"vii";s:2:"81";s:3:" ma";s:2:"82";s:3:" se";s:2:"83";s:4:"enä";s:2:"84";s:3:" mu";s:2:"85";s:3:"a s";s:2:"86";s:3:"est";s:2:"87";s:3:"iss";s:2:"88";s:4:"llä";s:2:"89";s:3:"lok";s:2:"90";s:4:"lä ";s:2:"91";s:3:"n j";s:2:"92";s:3:"n o";s:2:"93";s:3:"toi";s:2:"94";s:3:"ven";s:2:"95";s:3:"ytt";s:2:"96";s:3:" li";s:2:"97";s:3:"ain";s:2:"98";s:3:"et ";s:2:"99";s:3:"ina";s:3:"100";s:3:"n a";s:3:"101";s:3:"n n";s:3:"102";s:3:"oll";s:3:"103";s:3:"plo";s:3:"104";s:3:"ten";s:3:"105";s:3:"ust";s:3:"106";s:4:"äll";s:3:"107";s:5:"ään";s:3:"108";s:3:" to";s:3:"109";s:3:"den";s:3:"110";s:3:"men";s:3:"111";s:3:"oki";s:3:"112";s:3:"suo";s:3:"113";s:4:"sä ";s:3:"114";s:5:"tää";s:3:"115";s:3:"uks";s:3:"116";s:3:"vat";s:3:"117";s:3:" al";s:3:"118";s:3:" ke";s:3:"119";s:3:" te";s:3:"120";s:3:"a e";s:3:"121";s:3:"lii";s:3:"122";s:3:"tai";s:3:"123";s:3:"tei";s:3:"124";s:4:"äis";s:3:"125";s:5:"ää ";s:3:"126";s:3:" pl";s:3:"127";s:3:"ell";s:3:"128";s:3:"i t";s:3:"129";s:3:"ide";s:3:"130";s:3:"ikk";s:3:"131";s:3:"ki ";s:3:"132";s:3:"nta";s:3:"133";s:3:"ova";s:3:"134";s:3:"yst";s:3:"135";s:3:"yt ";s:3:"136";s:4:"ä p";s:3:"137";s:4:"äyt";s:3:"138";s:3:" ha";s:3:"139";s:3:" pe";s:3:"140";s:4:" tä";s:3:"141";s:3:"a n";s:3:"142";s:3:"aik";s:3:"143";s:3:"i p";s:3:"144";s:3:"i v";s:3:"145";s:3:"nyt";s:3:"146";s:4:"näy";s:3:"147";s:3:"pal";s:3:"148";s:3:"tee";s:3:"149";s:3:"un ";s:3:"150";s:3:" me";s:3:"151";s:3:"a m";s:3:"152";s:3:"ess";s:3:"153";s:3:"kau";s:3:"154";s:3:"pai";s:3:"155";s:3:"stu";s:3:"156";s:3:"ut ";s:3:"157";s:3:"voi";s:3:"158";s:3:" et";s:3:"159";s:3:"a h";s:3:"160";s:3:"eis";s:3:"161";s:3:"hte";s:3:"162";s:3:"i o";s:3:"163";s:3:"iik";s:3:"164";s:3:"ita";s:3:"165";s:3:"jou";s:3:"166";s:3:"mis";s:3:"167";s:3:"nin";s:3:"168";s:3:"nut";s:3:"169";s:3:"sia";s:3:"170";s:4:"ssä";s:3:"171";s:3:"van";s:3:"172";s:3:" ty";s:3:"173";s:3:" yh";s:3:"174";s:3:"aks";s:3:"175";s:3:"ime";s:3:"176";s:3:"loi";s:3:"177";s:3:"me ";s:3:"178";s:3:"n e";s:3:"179";s:3:"n h";s:3:"180";s:3:"n l";s:3:"181";s:3:"oin";s:3:"182";s:3:"ome";s:3:"183";s:3:"ott";s:3:"184";s:3:"ouk";s:3:"185";s:3:"sit";s:3:"186";s:3:"sti";s:3:"187";s:3:"tet";s:3:"188";s:3:"tie";s:3:"189";s:3:"ukk";s:3:"190";s:4:"ä k";s:3:"191";s:3:" ra";s:3:"192";s:3:" ti";s:3:"193";s:3:"aja";s:3:"194";s:3:"asi";s:3:"195";s:3:"ent";s:3:"196";s:3:"iga";s:3:"197";s:3:"iig";s:3:"198";s:3:"ite";s:3:"199";s:3:"jan";s:3:"200";s:3:"kaa";s:3:"201";s:3:"kse";s:3:"202";s:3:"laa";s:3:"203";s:3:"lan";s:3:"204";s:3:"li ";s:3:"205";s:4:"näj";s:3:"206";s:3:"ole";s:3:"207";s:3:"tii";s:3:"208";s:3:"usi";s:3:"209";s:5:"äjä";s:3:"210";s:3:" ov";s:3:"211";s:3:"a a";s:3:"212";s:3:"ant";s:3:"213";s:3:"ava";s:3:"214";s:3:"ei ";s:3:"215";s:3:"eri";s:3:"216";s:3:"kan";s:3:"217";s:3:"kku";s:3:"218";s:3:"lai";s:3:"219";s:3:"lis";s:3:"220";s:4:"läi";s:3:"221";s:3:"mat";s:3:"222";s:3:"ois";s:3:"223";s:3:"pel";s:3:"224";s:3:"sil";s:3:"225";s:3:"sty";s:3:"226";s:3:"taj";s:3:"227";s:3:"tav";s:3:"228";s:3:"ttu";s:3:"229";s:4:"työ";s:3:"230";s:4:"yös";s:3:"231";s:4:"ä o";s:3:"232";s:3:" ai";s:3:"233";s:3:" pu";s:3:"234";s:3:"a j";s:3:"235";s:3:"a l";s:3:"236";s:3:"aal";s:3:"237";s:3:"arv";s:3:"238";s:3:"ass";s:3:"239";s:3:"ien";s:3:"240";s:3:"imi";s:3:"241";s:3:"imm";s:3:"242";s:4:"itä";s:3:"243";s:3:"ka ";s:3:"244";s:3:"kes";s:3:"245";s:3:"kue";s:3:"246";s:3:"lee";s:3:"247";s:3:"lin";s:3:"248";s:3:"llo";s:3:"249";s:3:"one";s:3:"250";s:3:"ri ";s:3:"251";s:3:"t o";s:3:"252";s:3:"t p";s:3:"253";s:3:"tu ";s:3:"254";s:3:"val";s:3:"255";s:3:"vuo";s:3:"256";s:3:" ei";s:3:"257";s:3:" he";s:3:"258";s:3:" hy";s:3:"259";s:3:" my";s:3:"260";s:3:" vo";s:3:"261";s:3:"ali";s:3:"262";s:3:"alo";s:3:"263";s:3:"ano";s:3:"264";s:3:"ast";s:3:"265";s:3:"att";s:3:"266";s:3:"auk";s:3:"267";s:3:"eli";s:3:"268";s:3:"ely";s:3:"269";s:3:"hti";s:3:"270";s:3:"ika";s:3:"271";s:3:"ken";s:3:"272";s:3:"kki";s:3:"273";s:3:"lys";s:3:"274";s:3:"min";s:3:"275";s:4:"myö";s:3:"276";s:3:"oht";s:3:"277";s:3:"oma";s:3:"278";s:3:"tus";s:3:"279";s:3:"umi";s:3:"280";s:3:"yks";s:3:"281";s:4:"ät ";s:3:"282";s:5:"ääl";s:3:"283";s:4:"ös ";s:3:"284";s:3:" ar";s:3:"285";s:3:" eu";s:3:"286";s:3:" hu";s:3:"287";s:3:" na";s:3:"288";s:3:"aat";s:3:"289";s:3:"alk";s:3:"290";s:3:"alu";s:3:"291";s:3:"ans";s:3:"292";s:3:"arj";s:3:"293";s:3:"enn";s:3:"294";s:3:"han";s:3:"295";s:3:"kuu";s:3:"296";s:3:"n y";s:3:"297";s:3:"set";s:3:"298";s:3:"sim";s:3:"299";}s:6:"french";a:300:{s:3:"es ";s:1:"0";s:3:" de";s:1:"1";s:3:"de ";s:1:"2";s:3:" le";s:1:"3";s:3:"ent";s:1:"4";s:3:"le ";s:1:"5";s:3:"nt ";s:1:"6";s:3:"la ";s:1:"7";s:3:"s d";s:1:"8";s:3:" la";s:1:"9";s:3:"ion";s:2:"10";s:3:"on ";s:2:"11";s:3:"re ";s:2:"12";s:3:" pa";s:2:"13";s:3:"e l";s:2:"14";s:3:"e d";s:2:"15";s:3:" l'";s:2:"16";s:3:"e p";s:2:"17";s:3:" co";s:2:"18";s:3:" pr";s:2:"19";s:3:"tio";s:2:"20";s:3:"ns ";s:2:"21";s:3:" en";s:2:"22";s:3:"ne ";s:2:"23";s:3:"que";s:2:"24";s:3:"r l";s:2:"25";s:3:"les";s:2:"26";s:3:"ur ";s:2:"27";s:3:"en ";s:2:"28";s:3:"ati";s:2:"29";s:3:"ue ";s:2:"30";s:3:" po";s:2:"31";s:3:" d'";s:2:"32";s:3:"par";s:2:"33";s:3:" a ";s:2:"34";s:3:"et ";s:2:"35";s:3:"it ";s:2:"36";s:3:" qu";s:2:"37";s:3:"men";s:2:"38";s:3:"ons";s:2:"39";s:3:"te ";s:2:"40";s:3:" et";s:2:"41";s:3:"t d";s:2:"42";s:3:" re";s:2:"43";s:3:"des";s:2:"44";s:3:" un";s:2:"45";s:3:"ie ";s:2:"46";s:3:"s l";s:2:"47";s:3:" su";s:2:"48";s:3:"pou";s:2:"49";s:3:" au";s:2:"50";s:4:" à ";s:2:"51";s:3:"con";s:2:"52";s:3:"er ";s:2:"53";s:3:" no";s:2:"54";s:3:"ait";s:2:"55";s:3:"e c";s:2:"56";s:3:"se ";s:2:"57";s:4:"té ";s:2:"58";s:3:"du ";s:2:"59";s:3:" du";s:2:"60";s:4:" dé";s:2:"61";s:3:"ce ";s:2:"62";s:3:"e e";s:2:"63";s:3:"is ";s:2:"64";s:3:"n d";s:2:"65";s:3:"s a";s:2:"66";s:3:" so";s:2:"67";s:3:"e r";s:2:"68";s:3:"e s";s:2:"69";s:3:"our";s:2:"70";s:3:"res";s:2:"71";s:3:"ssi";s:2:"72";s:3:"eur";s:2:"73";s:3:" se";s:2:"74";s:3:"eme";s:2:"75";s:3:"est";s:2:"76";s:3:"us ";s:2:"77";s:3:"sur";s:2:"78";s:3:"ant";s:2:"79";s:3:"iqu";s:2:"80";s:3:"s p";s:2:"81";s:3:"une";s:2:"82";s:3:"uss";s:2:"83";s:3:"l'a";s:2:"84";s:3:"pro";s:2:"85";s:3:"ter";s:2:"86";s:3:"tre";s:2:"87";s:3:"end";s:2:"88";s:3:"rs ";s:2:"89";s:3:" ce";s:2:"90";s:3:"e a";s:2:"91";s:3:"t p";s:2:"92";s:3:"un ";s:2:"93";s:3:" ma";s:2:"94";s:3:" ru";s:2:"95";s:4:" ré";s:2:"96";s:3:"ous";s:2:"97";s:3:"ris";s:2:"98";s:3:"rus";s:2:"99";s:3:"sse";s:3:"100";s:3:"ans";s:3:"101";s:3:"ar ";s:3:"102";s:3:"com";s:3:"103";s:3:"e m";s:3:"104";s:3:"ire";s:3:"105";s:3:"nce";s:3:"106";s:3:"nte";s:3:"107";s:3:"t l";s:3:"108";s:3:" av";s:3:"109";s:3:" mo";s:3:"110";s:3:" te";s:3:"111";s:3:"il ";s:3:"112";s:3:"me ";s:3:"113";s:3:"ont";s:3:"114";s:3:"ten";s:3:"115";s:3:"a p";s:3:"116";s:3:"dan";s:3:"117";s:3:"pas";s:3:"118";s:3:"qui";s:3:"119";s:3:"s e";s:3:"120";s:3:"s s";s:3:"121";s:3:" in";s:3:"122";s:3:"ist";s:3:"123";s:3:"lle";s:3:"124";s:3:"nou";s:3:"125";s:4:"pré";s:3:"126";s:3:"'un";s:3:"127";s:3:"air";s:3:"128";s:3:"d'a";s:3:"129";s:3:"ir ";s:3:"130";s:3:"n e";s:3:"131";s:3:"rop";s:3:"132";s:3:"ts ";s:3:"133";s:3:" da";s:3:"134";s:3:"a s";s:3:"135";s:3:"as ";s:3:"136";s:3:"au ";s:3:"137";s:3:"den";s:3:"138";s:3:"mai";s:3:"139";s:3:"mis";s:3:"140";s:3:"ori";s:3:"141";s:3:"out";s:3:"142";s:3:"rme";s:3:"143";s:3:"sio";s:3:"144";s:3:"tte";s:3:"145";s:3:"ux ";s:3:"146";s:3:"a d";s:3:"147";s:3:"ien";s:3:"148";s:3:"n a";s:3:"149";s:3:"ntr";s:3:"150";s:3:"omm";s:3:"151";s:3:"ort";s:3:"152";s:3:"ouv";s:3:"153";s:3:"s c";s:3:"154";s:3:"son";s:3:"155";s:3:"tes";s:3:"156";s:3:"ver";s:3:"157";s:4:"ère";s:3:"158";s:3:" il";s:3:"159";s:3:" m ";s:3:"160";s:3:" sa";s:3:"161";s:3:" ve";s:3:"162";s:3:"a r";s:3:"163";s:3:"ais";s:3:"164";s:3:"ava";s:3:"165";s:3:"di ";s:3:"166";s:3:"n p";s:3:"167";s:3:"sti";s:3:"168";s:3:"ven";s:3:"169";s:3:" mi";s:3:"170";s:3:"ain";s:3:"171";s:3:"enc";s:3:"172";s:3:"for";s:3:"173";s:4:"ité";s:3:"174";s:3:"lar";s:3:"175";s:3:"oir";s:3:"176";s:3:"rem";s:3:"177";s:3:"ren";s:3:"178";s:3:"rro";s:3:"179";s:4:"rés";s:3:"180";s:3:"sie";s:3:"181";s:3:"t a";s:3:"182";s:3:"tur";s:3:"183";s:3:" pe";s:3:"184";s:3:" to";s:3:"185";s:3:"d'u";s:3:"186";s:3:"ell";s:3:"187";s:3:"err";s:3:"188";s:3:"ers";s:3:"189";s:3:"ide";s:3:"190";s:3:"ine";s:3:"191";s:3:"iss";s:3:"192";s:3:"mes";s:3:"193";s:3:"por";s:3:"194";s:3:"ran";s:3:"195";s:3:"sit";s:3:"196";s:3:"st ";s:3:"197";s:3:"t r";s:3:"198";s:3:"uti";s:3:"199";s:3:"vai";s:3:"200";s:4:"é l";s:3:"201";s:4:"ési";s:3:"202";s:3:" di";s:3:"203";s:3:" n'";s:3:"204";s:4:" ét";s:3:"205";s:3:"a c";s:3:"206";s:3:"ass";s:3:"207";s:3:"e t";s:3:"208";s:3:"in ";s:3:"209";s:3:"nde";s:3:"210";s:3:"pre";s:3:"211";s:3:"rat";s:3:"212";s:3:"s m";s:3:"213";s:3:"ste";s:3:"214";s:3:"tai";s:3:"215";s:3:"tch";s:3:"216";s:3:"ui ";s:3:"217";s:3:"uro";s:3:"218";s:4:"ès ";s:3:"219";s:3:" es";s:3:"220";s:3:" fo";s:3:"221";s:3:" tr";s:3:"222";s:3:"'ad";s:3:"223";s:3:"app";s:3:"224";s:3:"aux";s:3:"225";s:4:"e à";s:3:"226";s:3:"ett";s:3:"227";s:3:"iti";s:3:"228";s:3:"lit";s:3:"229";s:3:"nal";s:3:"230";s:4:"opé";s:3:"231";s:3:"r d";s:3:"232";s:3:"ra ";s:3:"233";s:3:"rai";s:3:"234";s:3:"ror";s:3:"235";s:3:"s r";s:3:"236";s:3:"tat";s:3:"237";s:4:"uté";s:3:"238";s:4:"à l";s:3:"239";s:3:" af";s:3:"240";s:3:"anc";s:3:"241";s:3:"ara";s:3:"242";s:3:"art";s:3:"243";s:3:"bre";s:3:"244";s:4:"ché";s:3:"245";s:3:"dre";s:3:"246";s:3:"e f";s:3:"247";s:3:"ens";s:3:"248";s:3:"lem";s:3:"249";s:3:"n r";s:3:"250";s:3:"n t";s:3:"251";s:3:"ndr";s:3:"252";s:3:"nne";s:3:"253";s:3:"onn";s:3:"254";s:3:"pos";s:3:"255";s:3:"s t";s:3:"256";s:3:"tiq";s:3:"257";s:3:"ure";s:3:"258";s:3:" tu";s:3:"259";s:3:"ale";s:3:"260";s:3:"and";s:3:"261";s:3:"ave";s:3:"262";s:3:"cla";s:3:"263";s:3:"cou";s:3:"264";s:3:"e n";s:3:"265";s:3:"emb";s:3:"266";s:3:"ins";s:3:"267";s:3:"jou";s:3:"268";s:3:"mme";s:3:"269";s:3:"rie";s:3:"270";s:4:"rès";s:3:"271";s:3:"sem";s:3:"272";s:3:"str";s:3:"273";s:3:"t i";s:3:"274";s:3:"ues";s:3:"275";s:3:"uni";s:3:"276";s:3:"uve";s:3:"277";s:4:"é d";s:3:"278";s:4:"ée ";s:3:"279";s:3:" ch";s:3:"280";s:3:" do";s:3:"281";s:3:" eu";s:3:"282";s:3:" fa";s:3:"283";s:3:" lo";s:3:"284";s:3:" ne";s:3:"285";s:3:" ra";s:3:"286";s:3:"arl";s:3:"287";s:3:"att";s:3:"288";s:3:"ec ";s:3:"289";s:3:"ica";s:3:"290";s:3:"l a";s:3:"291";s:3:"l'o";s:3:"292";s:4:"l'é";s:3:"293";s:3:"mmi";s:3:"294";s:3:"nta";s:3:"295";s:3:"orm";s:3:"296";s:3:"ou ";s:3:"297";s:3:"r u";s:3:"298";s:3:"rle";s:3:"299";}s:6:"german";a:300:{s:3:"en ";s:1:"0";s:3:"er ";s:1:"1";s:3:" de";s:1:"2";s:3:"der";s:1:"3";s:3:"ie ";s:1:"4";s:3:" di";s:1:"5";s:3:"die";s:1:"6";s:3:"sch";s:1:"7";s:3:"ein";s:1:"8";s:3:"che";s:1:"9";s:3:"ich";s:2:"10";s:3:"den";s:2:"11";s:3:"in ";s:2:"12";s:3:"te ";s:2:"13";s:3:"ch ";s:2:"14";s:3:" ei";s:2:"15";s:3:"ung";s:2:"16";s:3:"n d";s:2:"17";s:3:"nd ";s:2:"18";s:3:" be";s:2:"19";s:3:"ver";s:2:"20";s:3:"es ";s:2:"21";s:3:" zu";s:2:"22";s:3:"eit";s:2:"23";s:3:"gen";s:2:"24";s:3:"und";s:2:"25";s:3:" un";s:2:"26";s:3:" au";s:2:"27";s:3:" in";s:2:"28";s:3:"cht";s:2:"29";s:3:"it ";s:2:"30";s:3:"ten";s:2:"31";s:3:" da";s:2:"32";s:3:"ent";s:2:"33";s:3:" ve";s:2:"34";s:3:"and";s:2:"35";s:3:" ge";s:2:"36";s:3:"ine";s:2:"37";s:3:" mi";s:2:"38";s:3:"r d";s:2:"39";s:3:"hen";s:2:"40";s:3:"ng ";s:2:"41";s:3:"nde";s:2:"42";s:3:" vo";s:2:"43";s:3:"e d";s:2:"44";s:3:"ber";s:2:"45";s:3:"men";s:2:"46";s:3:"ei ";s:2:"47";s:3:"mit";s:2:"48";s:3:" st";s:2:"49";s:3:"ter";s:2:"50";s:3:"ren";s:2:"51";s:3:"t d";s:2:"52";s:3:" er";s:2:"53";s:3:"ere";s:2:"54";s:3:"n s";s:2:"55";s:3:"ste";s:2:"56";s:3:" se";s:2:"57";s:3:"e s";s:2:"58";s:3:"ht ";s:2:"59";s:3:"des";s:2:"60";s:3:"ist";s:2:"61";s:3:"ne ";s:2:"62";s:3:"auf";s:2:"63";s:3:"e a";s:2:"64";s:3:"isc";s:2:"65";s:3:"on ";s:2:"66";s:3:"rte";s:2:"67";s:3:" re";s:2:"68";s:3:" we";s:2:"69";s:3:"ges";s:2:"70";s:3:"uch";s:2:"71";s:4:" fü";s:2:"72";s:3:" so";s:2:"73";s:3:"bei";s:2:"74";s:3:"e e";s:2:"75";s:3:"nen";s:2:"76";s:3:"r s";s:2:"77";s:3:"ach";s:2:"78";s:4:"für";s:2:"79";s:3:"ier";s:2:"80";s:3:"par";s:2:"81";s:4:"ür ";s:2:"82";s:3:" ha";s:2:"83";s:3:"as ";s:2:"84";s:3:"ert";s:2:"85";s:3:" an";s:2:"86";s:3:" pa";s:2:"87";s:3:" sa";s:2:"88";s:3:" sp";s:2:"89";s:3:" wi";s:2:"90";s:3:"for";s:2:"91";s:3:"tag";s:2:"92";s:3:"zu ";s:2:"93";s:3:"das";s:2:"94";s:3:"rei";s:2:"95";s:3:"he ";s:2:"96";s:3:"hre";s:2:"97";s:3:"nte";s:2:"98";s:3:"sen";s:2:"99";s:3:"vor";s:3:"100";s:3:" sc";s:3:"101";s:3:"ech";s:3:"102";s:3:"etz";s:3:"103";s:3:"hei";s:3:"104";s:3:"lan";s:3:"105";s:3:"n a";s:3:"106";s:3:"pd ";s:3:"107";s:3:"st ";s:3:"108";s:3:"sta";s:3:"109";s:3:"ese";s:3:"110";s:3:"lic";s:3:"111";s:3:" ab";s:3:"112";s:3:" si";s:3:"113";s:3:"gte";s:3:"114";s:3:" wa";s:3:"115";s:3:"iti";s:3:"116";s:3:"kei";s:3:"117";s:3:"n e";s:3:"118";s:3:"nge";s:3:"119";s:3:"sei";s:3:"120";s:3:"tra";s:3:"121";s:3:"zen";s:3:"122";s:3:" im";s:3:"123";s:3:" la";s:3:"124";s:3:"art";s:3:"125";s:3:"im ";s:3:"126";s:3:"lle";s:3:"127";s:3:"n w";s:3:"128";s:3:"rde";s:3:"129";s:3:"rec";s:3:"130";s:3:"set";s:3:"131";s:3:"str";s:3:"132";s:3:"tei";s:3:"133";s:3:"tte";s:3:"134";s:3:" ni";s:3:"135";s:3:"e p";s:3:"136";s:3:"ehe";s:3:"137";s:3:"ers";s:3:"138";s:3:"g d";s:3:"139";s:3:"nic";s:3:"140";s:3:"von";s:3:"141";s:3:" al";s:3:"142";s:3:" pr";s:3:"143";s:3:"an ";s:3:"144";s:3:"aus";s:3:"145";s:3:"erf";s:3:"146";s:3:"r e";s:3:"147";s:3:"tze";s:3:"148";s:4:"tür";s:3:"149";s:3:"uf ";s:3:"150";s:3:"ag ";s:3:"151";s:3:"als";s:3:"152";s:3:"ar ";s:3:"153";s:3:"chs";s:3:"154";s:3:"end";s:3:"155";s:3:"ge ";s:3:"156";s:3:"ige";s:3:"157";s:3:"ion";s:3:"158";s:3:"ls ";s:3:"159";s:3:"n m";s:3:"160";s:3:"ngs";s:3:"161";s:3:"nis";s:3:"162";s:3:"nt ";s:3:"163";s:3:"ord";s:3:"164";s:3:"s s";s:3:"165";s:3:"sse";s:3:"166";s:4:" tü";s:3:"167";s:3:"ahl";s:3:"168";s:3:"e b";s:3:"169";s:3:"ede";s:3:"170";s:3:"em ";s:3:"171";s:3:"len";s:3:"172";s:3:"n i";s:3:"173";s:3:"orm";s:3:"174";s:3:"pro";s:3:"175";s:3:"rke";s:3:"176";s:3:"run";s:3:"177";s:3:"s d";s:3:"178";s:3:"wah";s:3:"179";s:3:"wer";s:3:"180";s:4:"ürk";s:3:"181";s:3:" me";s:3:"182";s:3:"age";s:3:"183";s:3:"att";s:3:"184";s:3:"ell";s:3:"185";s:3:"est";s:3:"186";s:3:"hat";s:3:"187";s:3:"n b";s:3:"188";s:3:"oll";s:3:"189";s:3:"raf";s:3:"190";s:3:"s a";s:3:"191";s:3:"tsc";s:3:"192";s:3:" es";s:3:"193";s:3:" fo";s:3:"194";s:3:" gr";s:3:"195";s:3:" ja";s:3:"196";s:3:"abe";s:3:"197";s:3:"auc";s:3:"198";s:3:"ben";s:3:"199";s:3:"e n";s:3:"200";s:3:"ege";s:3:"201";s:3:"lie";s:3:"202";s:3:"n u";s:3:"203";s:3:"r v";s:3:"204";s:3:"re ";s:3:"205";s:3:"rit";s:3:"206";s:3:"sag";s:3:"207";s:3:" am";s:3:"208";s:3:"agt";s:3:"209";s:3:"ahr";s:3:"210";s:3:"bra";s:3:"211";s:3:"de ";s:3:"212";s:3:"erd";s:3:"213";s:3:"her";s:3:"214";s:3:"ite";s:3:"215";s:3:"le ";s:3:"216";s:3:"n p";s:3:"217";s:3:"n v";s:3:"218";s:3:"or ";s:3:"219";s:3:"rbe";s:3:"220";s:3:"rt ";s:3:"221";s:3:"sic";s:3:"222";s:3:"wie";s:3:"223";s:4:"übe";s:3:"224";s:3:" is";s:3:"225";s:4:" üb";s:3:"226";s:3:"cha";s:3:"227";s:3:"chi";s:3:"228";s:3:"e f";s:3:"229";s:3:"e m";s:3:"230";s:3:"eri";s:3:"231";s:3:"ied";s:3:"232";s:3:"mme";s:3:"233";s:3:"ner";s:3:"234";s:3:"r a";s:3:"235";s:3:"sti";s:3:"236";s:3:"t a";s:3:"237";s:3:"t s";s:3:"238";s:3:"tis";s:3:"239";s:3:" ko";s:3:"240";s:3:"arb";s:3:"241";s:3:"ds ";s:3:"242";s:3:"gan";s:3:"243";s:3:"n z";s:3:"244";s:3:"r f";s:3:"245";s:3:"r w";s:3:"246";s:3:"ran";s:3:"247";s:3:"se ";s:3:"248";s:3:"t i";s:3:"249";s:3:"wei";s:3:"250";s:3:"wir";s:3:"251";s:3:" br";s:3:"252";s:3:" np";s:3:"253";s:3:"am ";s:3:"254";s:3:"bes";s:3:"255";s:3:"d d";s:3:"256";s:3:"deu";s:3:"257";s:3:"e g";s:3:"258";s:3:"e k";s:3:"259";s:3:"efo";s:3:"260";s:3:"et ";s:3:"261";s:3:"eut";s:3:"262";s:3:"fen";s:3:"263";s:3:"hse";s:3:"264";s:3:"lte";s:3:"265";s:3:"n r";s:3:"266";s:3:"npd";s:3:"267";s:3:"r b";s:3:"268";s:3:"rhe";s:3:"269";s:3:"t w";s:3:"270";s:3:"tz ";s:3:"271";s:3:" fr";s:3:"272";s:3:" ih";s:3:"273";s:3:" ke";s:3:"274";s:3:" ma";s:3:"275";s:3:"ame";s:3:"276";s:3:"ang";s:3:"277";s:3:"d s";s:3:"278";s:3:"eil";s:3:"279";s:3:"el ";s:3:"280";s:3:"era";s:3:"281";s:3:"erh";s:3:"282";s:3:"h d";s:3:"283";s:3:"i d";s:3:"284";s:3:"kan";s:3:"285";s:3:"n f";s:3:"286";s:3:"n l";s:3:"287";s:3:"nts";s:3:"288";s:3:"och";s:3:"289";s:3:"rag";s:3:"290";s:3:"rd ";s:3:"291";s:3:"spd";s:3:"292";s:3:"spr";s:3:"293";s:3:"tio";s:3:"294";s:3:" ar";s:3:"295";s:3:" en";s:3:"296";s:3:" ka";s:3:"297";s:3:"ark";s:3:"298";s:3:"ass";s:3:"299";}s:5:"hausa";a:300:{s:3:" da";s:1:"0";s:3:"da ";s:1:"1";s:3:"in ";s:1:"2";s:3:"an ";s:1:"3";s:3:"ya ";s:1:"4";s:3:" wa";s:1:"5";s:3:" ya";s:1:"6";s:3:"na ";s:1:"7";s:3:"ar ";s:1:"8";s:3:"a d";s:1:"9";s:3:" ma";s:2:"10";s:3:"wa ";s:2:"11";s:3:"a a";s:2:"12";s:3:"a k";s:2:"13";s:3:"a s";s:2:"14";s:3:" ta";s:2:"15";s:3:"wan";s:2:"16";s:3:" a ";s:2:"17";s:3:" ba";s:2:"18";s:3:" ka";s:2:"19";s:3:"ta ";s:2:"20";s:3:"a y";s:2:"21";s:3:"n d";s:2:"22";s:3:" ha";s:2:"23";s:3:" na";s:2:"24";s:3:" su";s:2:"25";s:3:" sa";s:2:"26";s:3:"kin";s:2:"27";s:3:"sa ";s:2:"28";s:3:"ata";s:2:"29";s:3:" ko";s:2:"30";s:3:"a t";s:2:"31";s:3:"su ";s:2:"32";s:3:" ga";s:2:"33";s:3:"ai ";s:2:"34";s:3:" sh";s:2:"35";s:3:"a m";s:2:"36";s:3:"uwa";s:2:"37";s:3:"iya";s:2:"38";s:3:"ma ";s:2:"39";s:3:"a w";s:2:"40";s:3:"asa";s:2:"41";s:3:"yan";s:2:"42";s:3:"ka ";s:2:"43";s:3:"ani";s:2:"44";s:3:"shi";s:2:"45";s:3:"a b";s:2:"46";s:3:"a h";s:2:"47";s:3:"a c";s:2:"48";s:3:"ama";s:2:"49";s:3:"ba ";s:2:"50";s:3:"nan";s:2:"51";s:3:"n a";s:2:"52";s:3:" mu";s:2:"53";s:3:"ana";s:2:"54";s:3:" yi";s:2:"55";s:3:"a g";s:2:"56";s:3:" za";s:2:"57";s:3:"i d";s:2:"58";s:3:" ku";s:2:"59";s:3:"aka";s:2:"60";s:3:"yi ";s:2:"61";s:3:"n k";s:2:"62";s:3:"ann";s:2:"63";s:3:"ke ";s:2:"64";s:3:"tar";s:2:"65";s:3:" ci";s:2:"66";s:3:"iki";s:2:"67";s:3:"n s";s:2:"68";s:3:"ko ";s:2:"69";s:3:" ra";s:2:"70";s:3:"ki ";s:2:"71";s:3:"ne ";s:2:"72";s:3:"a z";s:2:"73";s:3:"mat";s:2:"74";s:3:"hak";s:2:"75";s:3:"nin";s:2:"76";s:3:"e d";s:2:"77";s:3:"nna";s:2:"78";s:3:"uma";s:2:"79";s:3:"nda";s:2:"80";s:3:"a n";s:2:"81";s:3:"ada";s:2:"82";s:3:"cik";s:2:"83";s:3:"ni ";s:2:"84";s:3:"rin";s:2:"85";s:3:"una";s:2:"86";s:3:"ara";s:2:"87";s:3:"kum";s:2:"88";s:3:"akk";s:2:"89";s:3:" ce";s:2:"90";s:3:" du";s:2:"91";s:3:"man";s:2:"92";s:3:"n y";s:2:"93";s:3:"nci";s:2:"94";s:3:"sar";s:2:"95";s:3:"aki";s:2:"96";s:3:"awa";s:2:"97";s:3:"ci ";s:2:"98";s:3:"kan";s:2:"99";s:3:"kar";s:3:"100";s:3:"ari";s:3:"101";s:3:"n m";s:3:"102";s:3:"and";s:3:"103";s:3:"hi ";s:3:"104";s:3:"n t";s:3:"105";s:3:"ga ";s:3:"106";s:3:"owa";s:3:"107";s:3:"ash";s:3:"108";s:3:"kam";s:3:"109";s:3:"dan";s:3:"110";s:3:"ewa";s:3:"111";s:3:"nsa";s:3:"112";s:3:"ali";s:3:"113";s:3:"ami";s:3:"114";s:3:" ab";s:3:"115";s:3:" do";s:3:"116";s:3:"anc";s:3:"117";s:3:"n r";s:3:"118";s:3:"aya";s:3:"119";s:3:"i n";s:3:"120";s:3:"sun";s:3:"121";s:3:"uka";s:3:"122";s:3:" al";s:3:"123";s:3:" ne";s:3:"124";s:3:"a'a";s:3:"125";s:3:"cew";s:3:"126";s:3:"cin";s:3:"127";s:3:"mas";s:3:"128";s:3:"tak";s:3:"129";s:3:"un ";s:3:"130";s:3:"aba";s:3:"131";s:3:"kow";s:3:"132";s:3:"a r";s:3:"133";s:3:"ra ";s:3:"134";s:3:" ja";s:3:"135";s:4:" ƙa";s:3:"136";s:3:"en ";s:3:"137";s:3:"r d";s:3:"138";s:3:"sam";s:3:"139";s:3:"tsa";s:3:"140";s:3:" ru";s:3:"141";s:3:"ce ";s:3:"142";s:3:"i a";s:3:"143";s:3:"abi";s:3:"144";s:3:"ida";s:3:"145";s:3:"mut";s:3:"146";s:3:"n g";s:3:"147";s:3:"n j";s:3:"148";s:3:"san";s:3:"149";s:4:"a ƙ";s:3:"150";s:3:"har";s:3:"151";s:3:"on ";s:3:"152";s:3:"i m";s:3:"153";s:3:"suk";s:3:"154";s:3:" ak";s:3:"155";s:3:" ji";s:3:"156";s:3:"yar";s:3:"157";s:3:"'ya";s:3:"158";s:3:"kwa";s:3:"159";s:3:"min";s:3:"160";s:3:" 'y";s:3:"161";s:3:"ane";s:3:"162";s:3:"ban";s:3:"163";s:3:"ins";s:3:"164";s:3:"ruw";s:3:"165";s:3:"i k";s:3:"166";s:3:"n h";s:3:"167";s:3:" ad";s:3:"168";s:3:"ake";s:3:"169";s:3:"n w";s:3:"170";s:3:"sha";s:3:"171";s:3:"utu";s:3:"172";s:4:" ƴa";s:3:"173";s:3:"bay";s:3:"174";s:3:"tan";s:3:"175";s:4:"ƴan";s:3:"176";s:3:"bin";s:3:"177";s:3:"duk";s:3:"178";s:3:"e m";s:3:"179";s:3:"n n";s:3:"180";s:3:"oka";s:3:"181";s:3:"yin";s:3:"182";s:4:"ɗan";s:3:"183";s:3:" fa";s:3:"184";s:3:"a i";s:3:"185";s:3:"kki";s:3:"186";s:3:"re ";s:3:"187";s:3:"za ";s:3:"188";s:3:"ala";s:3:"189";s:3:"asu";s:3:"190";s:3:"han";s:3:"191";s:3:"i y";s:3:"192";s:3:"mar";s:3:"193";s:3:"ran";s:3:"194";s:4:"ƙas";s:3:"195";s:3:"add";s:3:"196";s:3:"ars";s:3:"197";s:3:"gab";s:3:"198";s:3:"ira";s:3:"199";s:3:"mma";s:3:"200";s:3:"u d";s:3:"201";s:3:" ts";s:3:"202";s:3:"abb";s:3:"203";s:3:"abu";s:3:"204";s:3:"aga";s:3:"205";s:3:"gar";s:3:"206";s:3:"n b";s:3:"207";s:4:" ɗa";s:3:"208";s:3:"aci";s:3:"209";s:3:"aik";s:3:"210";s:3:"am ";s:3:"211";s:3:"dun";s:3:"212";s:3:"e s";s:3:"213";s:3:"i b";s:3:"214";s:3:"i w";s:3:"215";s:3:"kas";s:3:"216";s:3:"kok";s:3:"217";s:3:"wam";s:3:"218";s:3:" am";s:3:"219";s:3:"amf";s:3:"220";s:3:"bba";s:3:"221";s:3:"din";s:3:"222";s:3:"fan";s:3:"223";s:3:"gwa";s:3:"224";s:3:"i s";s:3:"225";s:3:"wat";s:3:"226";s:3:"ano";s:3:"227";s:3:"are";s:3:"228";s:3:"dai";s:3:"229";s:3:"iri";s:3:"230";s:3:"ma'";s:3:"231";s:3:" la";s:3:"232";s:3:"all";s:3:"233";s:3:"dam";s:3:"234";s:3:"ika";s:3:"235";s:3:"mi ";s:3:"236";s:3:"she";s:3:"237";s:3:"tum";s:3:"238";s:3:"uni";s:3:"239";s:3:" an";s:3:"240";s:3:" ai";s:3:"241";s:3:" ke";s:3:"242";s:3:" ki";s:3:"243";s:3:"dag";s:3:"244";s:3:"mai";s:3:"245";s:3:"mfa";s:3:"246";s:3:"no ";s:3:"247";s:3:"nsu";s:3:"248";s:3:"o d";s:3:"249";s:3:"sak";s:3:"250";s:3:"um ";s:3:"251";s:3:" bi";s:3:"252";s:3:" gw";s:3:"253";s:3:" kw";s:3:"254";s:3:"jam";s:3:"255";s:3:"yya";s:3:"256";s:3:"a j";s:3:"257";s:3:"fa ";s:3:"258";s:3:"uta";s:3:"259";s:3:" hu";s:3:"260";s:3:"'a ";s:3:"261";s:3:"ans";s:3:"262";s:4:"aɗa";s:3:"263";s:3:"dda";s:3:"264";s:3:"hin";s:3:"265";s:3:"niy";s:3:"266";s:3:"r s";s:3:"267";s:3:"bat";s:3:"268";s:3:"dar";s:3:"269";s:3:"gan";s:3:"270";s:3:"i t";s:3:"271";s:3:"nta";s:3:"272";s:3:"oki";s:3:"273";s:3:"omi";s:3:"274";s:3:"sal";s:3:"275";s:3:"a l";s:3:"276";s:3:"kac";s:3:"277";s:3:"lla";s:3:"278";s:3:"wad";s:3:"279";s:3:"war";s:3:"280";s:3:"amm";s:3:"281";s:3:"dom";s:3:"282";s:3:"r m";s:3:"283";s:3:"ras";s:3:"284";s:3:"sai";s:3:"285";s:3:" lo";s:3:"286";s:3:"ats";s:3:"287";s:3:"hal";s:3:"288";s:3:"kat";s:3:"289";s:3:"li ";s:3:"290";s:3:"lok";s:3:"291";s:3:"n c";s:3:"292";s:3:"nar";s:3:"293";s:3:"tin";s:3:"294";s:3:"afa";s:3:"295";s:3:"bub";s:3:"296";s:3:"i g";s:3:"297";s:3:"isa";s:3:"298";s:3:"mak";s:3:"299";}s:8:"hawaiian";a:300:{s:3:" ka";s:1:"0";s:3:"na ";s:1:"1";s:3:" o ";s:1:"2";s:3:"ka ";s:1:"3";s:3:" ma";s:1:"4";s:3:" a ";s:1:"5";s:3:" la";s:1:"6";s:3:"a i";s:1:"7";s:3:"a m";s:1:"8";s:3:" i ";s:1:"9";s:3:"la ";s:2:"10";s:3:"ana";s:2:"11";s:3:"ai ";s:2:"12";s:3:"ia ";s:2:"13";s:3:"a o";s:2:"14";s:3:"a k";s:2:"15";s:3:"a h";s:2:"16";s:3:"o k";s:2:"17";s:3:" ke";s:2:"18";s:3:"a a";s:2:"19";s:3:"i k";s:2:"20";s:3:" ho";s:2:"21";s:3:" ia";s:2:"22";s:3:"ua ";s:2:"23";s:3:" na";s:2:"24";s:3:" me";s:2:"25";s:3:"e k";s:2:"26";s:3:"e a";s:2:"27";s:3:"au ";s:2:"28";s:3:"ke ";s:2:"29";s:3:"ma ";s:2:"30";s:3:"mai";s:2:"31";s:3:"aku";s:2:"32";s:3:" ak";s:2:"33";s:3:"ahi";s:2:"34";s:3:" ha";s:2:"35";s:3:" ko";s:2:"36";s:3:" e ";s:2:"37";s:3:"a l";s:2:"38";s:3:" no";s:2:"39";s:3:"me ";s:2:"40";s:3:"ku ";s:2:"41";s:3:"aka";s:2:"42";s:3:"kan";s:2:"43";s:3:"no ";s:2:"44";s:3:"i a";s:2:"45";s:3:"ho ";s:2:"46";s:3:"ou ";s:2:"47";s:3:" ai";s:2:"48";s:3:"i o";s:2:"49";s:3:"a p";s:2:"50";s:3:"o l";s:2:"51";s:3:"o a";s:2:"52";s:3:"ama";s:2:"53";s:3:"a n";s:2:"54";s:3:" an";s:2:"55";s:3:"i m";s:2:"56";s:3:"han";s:2:"57";s:3:"i i";s:2:"58";s:3:"iho";s:2:"59";s:3:"kou";s:2:"60";s:3:"ne ";s:2:"61";s:3:" ih";s:2:"62";s:3:"o i";s:2:"63";s:3:"iki";s:2:"64";s:3:"ona";s:2:"65";s:3:"hoo";s:2:"66";s:3:"le ";s:2:"67";s:3:"e h";s:2:"68";s:3:" he";s:2:"69";s:3:"ina";s:2:"70";s:3:" wa";s:2:"71";s:3:"ea ";s:2:"72";s:3:"ako";s:2:"73";s:3:"u i";s:2:"74";s:3:"kah";s:2:"75";s:3:"oe ";s:2:"76";s:3:"i l";s:2:"77";s:3:"u a";s:2:"78";s:3:" pa";s:2:"79";s:3:"hoi";s:2:"80";s:3:"e i";s:2:"81";s:3:"era";s:2:"82";s:3:"ko ";s:2:"83";s:3:"u m";s:2:"84";s:3:"kua";s:2:"85";s:3:"mak";s:2:"86";s:3:"oi ";s:2:"87";s:3:"kai";s:2:"88";s:3:"i n";s:2:"89";s:3:"a e";s:2:"90";s:3:"hin";s:2:"91";s:3:"ane";s:2:"92";s:3:" ol";s:2:"93";s:3:"i h";s:2:"94";s:3:"mea";s:2:"95";s:3:"wah";s:2:"96";s:3:"lak";s:2:"97";s:3:"e m";s:2:"98";s:3:"o n";s:2:"99";s:3:"u l";s:3:"100";s:3:"ika";s:3:"101";s:3:"ki ";s:3:"102";s:3:"a w";s:3:"103";s:3:"mal";s:3:"104";s:3:"hi ";s:3:"105";s:3:"e n";s:3:"106";s:3:"u o";s:3:"107";s:3:"hik";s:3:"108";s:3:" ku";s:3:"109";s:3:"e l";s:3:"110";s:3:"ele";s:3:"111";s:3:"ra ";s:3:"112";s:3:"ber";s:3:"113";s:3:"ine";s:3:"114";s:3:"abe";s:3:"115";s:3:"ain";s:3:"116";s:3:"ala";s:3:"117";s:3:"lo ";s:3:"118";s:3:" po";s:3:"119";s:3:"kon";s:3:"120";s:3:" ab";s:3:"121";s:3:"ole";s:3:"122";s:3:"he ";s:3:"123";s:3:"pau";s:3:"124";s:3:"mah";s:3:"125";s:3:"va ";s:3:"126";s:3:"ela";s:3:"127";s:3:"kau";s:3:"128";s:3:"nak";s:3:"129";s:3:" oe";s:3:"130";s:3:"kei";s:3:"131";s:3:"oia";s:3:"132";s:3:" ie";s:3:"133";s:3:"ram";s:3:"134";s:3:" oi";s:3:"135";s:3:"oa ";s:3:"136";s:3:"eho";s:3:"137";s:3:"hov";s:3:"138";s:3:"ieh";s:3:"139";s:3:"ova";s:3:"140";s:3:" ua";s:3:"141";s:3:"una";s:3:"142";s:3:"ara";s:3:"143";s:3:"o s";s:3:"144";s:3:"awa";s:3:"145";s:3:"o o";s:3:"146";s:3:"nau";s:3:"147";s:3:"u n";s:3:"148";s:3:"wa ";s:3:"149";s:3:"wai";s:3:"150";s:3:"hel";s:3:"151";s:3:" ae";s:3:"152";s:3:" al";s:3:"153";s:3:"ae ";s:3:"154";s:3:"ta ";s:3:"155";s:3:"aik";s:3:"156";s:3:" hi";s:3:"157";s:3:"ale";s:3:"158";s:3:"ila";s:3:"159";s:3:"lel";s:3:"160";s:3:"ali";s:3:"161";s:3:"eik";s:3:"162";s:3:"olo";s:3:"163";s:3:"onu";s:3:"164";s:3:" lo";s:3:"165";s:3:"aua";s:3:"166";s:3:"e o";s:3:"167";s:3:"ola";s:3:"168";s:3:"hon";s:3:"169";s:3:"mam";s:3:"170";s:3:"nan";s:3:"171";s:3:" au";s:3:"172";s:3:"aha";s:3:"173";s:3:"lau";s:3:"174";s:3:"nua";s:3:"175";s:3:"oho";s:3:"176";s:3:"oma";s:3:"177";s:3:" ao";s:3:"178";s:3:"ii ";s:3:"179";s:3:"alu";s:3:"180";s:3:"ima";s:3:"181";s:3:"mau";s:3:"182";s:3:"ike";s:3:"183";s:3:"apa";s:3:"184";s:3:"elo";s:3:"185";s:3:"lii";s:3:"186";s:3:"poe";s:3:"187";s:3:"aia";s:3:"188";s:3:"noa";s:3:"189";s:3:" in";s:3:"190";s:3:"o m";s:3:"191";s:3:"oka";s:3:"192";s:3:"'u ";s:3:"193";s:3:"aho";s:3:"194";s:3:"ei ";s:3:"195";s:3:"eka";s:3:"196";s:3:"ha ";s:3:"197";s:3:"lu ";s:3:"198";s:3:"nei";s:3:"199";s:3:"hol";s:3:"200";s:3:"ino";s:3:"201";s:3:"o e";s:3:"202";s:3:"ema";s:3:"203";s:3:"iwa";s:3:"204";s:3:"olu";s:3:"205";s:3:"ada";s:3:"206";s:3:"naa";s:3:"207";s:3:"pa ";s:3:"208";s:3:"u k";s:3:"209";s:3:"ewa";s:3:"210";s:3:"hua";s:3:"211";s:3:"lam";s:3:"212";s:3:"lua";s:3:"213";s:3:"o h";s:3:"214";s:3:"ook";s:3:"215";s:3:"u h";s:3:"216";s:3:" li";s:3:"217";s:3:"ahu";s:3:"218";s:3:"amu";s:3:"219";s:3:"ui ";s:3:"220";s:3:" il";s:3:"221";s:3:" mo";s:3:"222";s:3:" se";s:3:"223";s:3:"eia";s:3:"224";s:3:"law";s:3:"225";s:3:" hu";s:3:"226";s:3:" ik";s:3:"227";s:3:"ail";s:3:"228";s:3:"e p";s:3:"229";s:3:"li ";s:3:"230";s:3:"lun";s:3:"231";s:3:"uli";s:3:"232";s:3:"io ";s:3:"233";s:3:"kik";s:3:"234";s:3:"noh";s:3:"235";s:3:"u e";s:3:"236";s:3:" sa";s:3:"237";s:3:"aaw";s:3:"238";s:3:"awe";s:3:"239";s:3:"ena";s:3:"240";s:3:"hal";s:3:"241";s:3:"kol";s:3:"242";s:3:"lan";s:3:"243";s:3:" le";s:3:"244";s:3:" ne";s:3:"245";s:3:"a'u";s:3:"246";s:3:"ilo";s:3:"247";s:3:"kap";s:3:"248";s:3:"oko";s:3:"249";s:3:"sa ";s:3:"250";s:3:" pe";s:3:"251";s:3:"hop";s:3:"252";s:3:"loa";s:3:"253";s:3:"ope";s:3:"254";s:3:"pe ";s:3:"255";s:3:" ad";s:3:"256";s:3:" pu";s:3:"257";s:3:"ahe";s:3:"258";s:3:"aol";s:3:"259";s:3:"ia'";s:3:"260";s:3:"lai";s:3:"261";s:3:"loh";s:3:"262";s:3:"na'";s:3:"263";s:3:"oom";s:3:"264";s:3:"aau";s:3:"265";s:3:"eri";s:3:"266";s:3:"kul";s:3:"267";s:3:"we ";s:3:"268";s:3:"ake";s:3:"269";s:3:"kek";s:3:"270";s:3:"laa";s:3:"271";s:3:"ri ";s:3:"272";s:3:"iku";s:3:"273";s:3:"kak";s:3:"274";s:3:"lim";s:3:"275";s:3:"nah";s:3:"276";s:3:"ner";s:3:"277";s:3:"nui";s:3:"278";s:3:"ono";s:3:"279";s:3:"a u";s:3:"280";s:3:"dam";s:3:"281";s:3:"kum";s:3:"282";s:3:"lok";s:3:"283";s:3:"mua";s:3:"284";s:3:"uma";s:3:"285";s:3:"wal";s:3:"286";s:3:"wi ";s:3:"287";s:3:"'i ";s:3:"288";s:3:"a'i";s:3:"289";s:3:"aan";s:3:"290";s:3:"alo";s:3:"291";s:3:"eta";s:3:"292";s:3:"mu ";s:3:"293";s:3:"ohe";s:3:"294";s:3:"u p";s:3:"295";s:3:"ula";s:3:"296";s:3:"uwa";s:3:"297";s:3:" nu";s:3:"298";s:3:"amo";s:3:"299";}s:5:"hindi";a:300:{s:7:"ें ";s:1:"0";s:7:" है";s:1:"1";s:9:"में";s:1:"2";s:7:" मे";s:1:"3";s:7:"ने ";s:1:"4";s:7:"की ";s:1:"5";s:7:"के ";s:1:"6";s:7:"है ";s:1:"7";s:7:" के";s:1:"8";s:7:" की";s:1:"9";s:7:" को";s:2:"10";s:7:"ों ";s:2:"11";s:7:"को ";s:2:"12";s:7:"ा ह";s:2:"13";s:7:" का";s:2:"14";s:7:"से ";s:2:"15";s:7:"ा क";s:2:"16";s:7:"े क";s:2:"17";s:7:"ं क";s:2:"18";s:7:"या ";s:2:"19";s:7:" कि";s:2:"20";s:7:" से";s:2:"21";s:7:"का ";s:2:"22";s:7:"ी क";s:2:"23";s:7:" ने";s:2:"24";s:7:" और";s:2:"25";s:7:"और ";s:2:"26";s:7:"ना ";s:2:"27";s:7:"कि ";s:2:"28";s:7:"भी ";s:2:"29";s:7:"ी स";s:2:"30";s:7:" जा";s:2:"31";s:7:" पर";s:2:"32";s:7:"ार ";s:2:"33";s:7:" कर";s:2:"34";s:7:"ी ह";s:2:"35";s:7:" हो";s:2:"36";s:7:"ही ";s:2:"37";s:9:"िया";s:2:"38";s:7:" इस";s:2:"39";s:7:" रह";s:2:"40";s:7:"र क";s:2:"41";s:9:"ुना";s:2:"42";s:7:"ता ";s:2:"43";s:7:"ान ";s:2:"44";s:7:"े स";s:2:"45";s:7:" भी";s:2:"46";s:7:" रा";s:2:"47";s:7:"े ह";s:2:"48";s:7:" चु";s:2:"49";s:7:" पा";s:2:"50";s:7:"पर ";s:2:"51";s:9:"चुन";s:2:"52";s:9:"नाव";s:2:"53";s:7:" कह";s:2:"54";s:9:"प्र";s:2:"55";s:7:" भा";s:2:"56";s:9:"राज";s:2:"57";s:9:"हैं";s:2:"58";s:7:"ा स";s:2:"59";s:7:"ै क";s:2:"60";s:7:"ैं ";s:2:"61";s:7:"नी ";s:2:"62";s:7:"ल क";s:2:"63";s:7:"ीं ";s:2:"64";s:7:"़ी ";s:2:"65";s:7:"था ";s:2:"66";s:7:"री ";s:2:"67";s:7:"ाव ";s:2:"68";s:7:"े ब";s:2:"69";s:7:" प्";s:2:"70";s:9:"क्ष";s:2:"71";s:7:"पा ";s:2:"72";s:7:"ले ";s:2:"73";s:7:" दे";s:2:"74";s:7:"ला ";s:2:"75";s:7:"हा ";s:2:"76";s:9:"ाजप";s:2:"77";s:7:" था";s:2:"78";s:7:" नह";s:2:"79";s:7:"इस ";s:2:"80";s:7:"कर ";s:2:"81";s:9:"जपा";s:2:"82";s:9:"नही";s:2:"83";s:9:"भाज";s:2:"84";s:9:"यों";s:2:"85";s:7:"र स";s:2:"86";s:9:"हीं";s:2:"87";s:7:" अम";s:2:"88";s:7:" बा";s:2:"89";s:7:" मा";s:2:"90";s:7:" वि";s:2:"91";s:9:"रीक";s:2:"92";s:7:"िए ";s:2:"93";s:7:"े प";s:2:"94";s:9:"्या";s:2:"95";s:7:" ही";s:2:"96";s:7:"ं म";s:2:"97";s:9:"कार";s:2:"98";s:7:"ा ज";s:2:"99";s:7:"े ल";s:3:"100";s:7:" ता";s:3:"101";s:7:" दि";s:3:"102";s:7:" सा";s:3:"103";s:7:" हम";s:3:"104";s:7:"ा न";s:3:"105";s:7:"ा म";s:3:"106";s:9:"ाक़";s:3:"107";s:9:"्ता";s:3:"108";s:7:" एक";s:3:"109";s:7:" सं";s:3:"110";s:7:" स्";s:3:"111";s:9:"अमर";s:3:"112";s:9:"क़ी";s:3:"113";s:9:"ताज";s:3:"114";s:9:"मरी";s:3:"115";s:9:"स्थ";s:3:"116";s:7:"ा थ";s:3:"117";s:9:"ार्";s:3:"118";s:7:" हु";s:3:"119";s:9:"इरा";s:3:"120";s:7:"एक ";s:3:"121";s:7:"न क";s:3:"122";s:7:"र म";s:3:"123";s:9:"राक";s:3:"124";s:7:"ी ज";s:3:"125";s:7:"ी न";s:3:"126";s:7:" इर";s:3:"127";s:7:" उन";s:3:"128";s:7:" पह";s:3:"129";s:9:"कहा";s:3:"130";s:7:"ते ";s:3:"131";s:7:"े अ";s:3:"132";s:7:" तो";s:3:"133";s:7:" सु";s:3:"134";s:7:"ति ";s:3:"135";s:7:"ती ";s:3:"136";s:7:"तो ";s:3:"137";s:9:"मिल";s:3:"138";s:7:"िक ";s:3:"139";s:9:"ियो";s:3:"140";s:9:"्रे";s:3:"141";s:7:" अप";s:3:"142";s:7:" फ़";s:3:"143";s:7:" लि";s:3:"144";s:7:" लो";s:3:"145";s:7:" सम";s:3:"146";s:7:"म क";s:3:"147";s:9:"र्ट";s:3:"148";s:7:"हो ";s:3:"149";s:7:"ा च";s:3:"150";s:7:"ाई ";s:3:"151";s:9:"ाने";s:3:"152";s:7:"िन ";s:3:"153";s:7:"्य ";s:3:"154";s:7:" उस";s:3:"155";s:7:" क़";s:3:"156";s:7:" सक";s:3:"157";s:7:" सै";s:3:"158";s:7:"ं प";s:3:"159";s:7:"ं ह";s:3:"160";s:7:"गी ";s:3:"161";s:7:"त क";s:3:"162";s:9:"मान";s:3:"163";s:7:"र न";s:3:"164";s:9:"ष्ट";s:3:"165";s:7:"स क";s:3:"166";s:9:"स्त";s:3:"167";s:7:"ाँ ";s:3:"168";s:7:"ी ब";s:3:"169";s:7:"ी म";s:3:"170";s:9:"्री";s:3:"171";s:7:" दो";s:3:"172";s:7:" मि";s:3:"173";s:7:" मु";s:3:"174";s:7:" ले";s:3:"175";s:7:" शा";s:3:"176";s:7:"ं स";s:3:"177";s:9:"ज़ा";s:3:"178";s:9:"त्र";s:3:"179";s:7:"थी ";s:3:"180";s:9:"लिए";s:3:"181";s:7:"सी ";s:3:"182";s:7:"़ा ";s:3:"183";s:9:"़ार";s:3:"184";s:9:"ांग";s:3:"185";s:7:"े द";s:3:"186";s:7:"े म";s:3:"187";s:7:"्व ";s:3:"188";s:7:" ना";s:3:"189";s:7:" बन";s:3:"190";s:9:"ंग्";s:3:"191";s:9:"कां";s:3:"192";s:7:"गा ";s:3:"193";s:9:"ग्र";s:3:"194";s:7:"जा ";s:3:"195";s:9:"ज्य";s:3:"196";s:7:"दी ";s:3:"197";s:7:"न म";s:3:"198";s:9:"पार";s:3:"199";s:7:"भा ";s:3:"200";s:9:"रही";s:3:"201";s:7:"रे ";s:3:"202";s:9:"रेस";s:3:"203";s:7:"ली ";s:3:"204";s:9:"सभा";s:3:"205";s:7:"ा र";s:3:"206";s:7:"ाल ";s:3:"207";s:7:"ी अ";s:3:"208";s:9:"ीकी";s:3:"209";s:7:"े त";s:3:"210";s:7:"ेश ";s:3:"211";s:7:" अं";s:3:"212";s:7:" तक";s:3:"213";s:7:" या";s:3:"214";s:7:"ई ह";s:3:"215";s:9:"करन";s:3:"216";s:7:"तक ";s:3:"217";s:9:"देश";s:3:"218";s:9:"वर्";s:3:"219";s:9:"ाया";s:3:"220";s:7:"ी भ";s:3:"221";s:7:"ेस ";s:3:"222";s:7:"्ष ";s:3:"223";s:7:" गय";s:3:"224";s:7:" जि";s:3:"225";s:7:" थी";s:3:"226";s:7:" बड";s:3:"227";s:7:" यह";s:3:"228";s:7:" वा";s:3:"229";s:9:"ंतर";s:3:"230";s:9:"अंत";s:3:"231";s:7:"क़ ";s:3:"232";s:9:"गया";s:3:"233";s:7:"टी ";s:3:"234";s:9:"निक";s:3:"235";s:9:"न्ह";s:3:"236";s:9:"पहल";s:3:"237";s:9:"बड़";s:3:"238";s:9:"मार";s:3:"239";s:7:"र प";s:3:"240";s:9:"रने";s:3:"241";s:9:"ाज़";s:3:"242";s:7:"ि इ";s:3:"243";s:7:"ी र";s:3:"244";s:7:"े ज";s:3:"245";s:7:"े व";s:3:"246";s:7:"्ट ";s:3:"247";s:9:"्टी";s:3:"248";s:7:" अब";s:3:"249";s:7:" लग";s:3:"250";s:7:" वर";s:3:"251";s:7:" सी";s:3:"252";s:7:"ं भ";s:3:"253";s:9:"उन्";s:3:"254";s:7:"क क";s:3:"255";s:9:"किय";s:3:"256";s:9:"देख";s:3:"257";s:9:"पूर";s:3:"258";s:9:"फ़्";s:3:"259";s:7:"यह ";s:3:"260";s:9:"यान";s:3:"261";s:9:"रिक";s:3:"262";s:9:"रिय";s:3:"263";s:9:"र्ड";s:3:"264";s:9:"लेक";s:3:"265";s:9:"सकत";s:3:"266";s:9:"हों";s:3:"267";s:9:"होग";s:3:"268";s:7:"ा अ";s:3:"269";s:7:"ा द";s:3:"270";s:7:"ा प";s:3:"271";s:7:"ाद ";s:3:"272";s:9:"ारा";s:3:"273";s:7:"ित ";s:3:"274";s:7:"ी त";s:3:"275";s:7:"ी प";s:3:"276";s:7:"ो क";s:3:"277";s:7:"ो द";s:3:"278";s:7:" ते";s:3:"279";s:7:" नि";s:3:"280";s:7:" सर";s:3:"281";s:7:" हा";s:3:"282";s:7:"ं द";s:3:"283";s:9:"अपन";s:3:"284";s:9:"जान";s:3:"285";s:7:"त म";s:3:"286";s:9:"थित";s:3:"287";s:9:"पनी";s:3:"288";s:9:"महल";s:3:"289";s:7:"र ह";s:3:"290";s:9:"लोग";s:3:"291";s:7:"व क";s:3:"292";s:9:"हना";s:3:"293";s:7:"हल ";s:3:"294";s:9:"हाँ";s:3:"295";s:9:"ाज्";s:3:"296";s:9:"ाना";s:3:"297";s:9:"िक्";s:3:"298";s:9:"िस्";s:3:"299";}s:9:"hungarian";a:300:{s:3:" a ";s:1:"0";s:3:" az";s:1:"1";s:3:" sz";s:1:"2";s:3:"az ";s:1:"3";s:3:" me";s:1:"4";s:3:"en ";s:1:"5";s:3:" el";s:1:"6";s:3:" ho";s:1:"7";s:3:"ek ";s:1:"8";s:3:"gy ";s:1:"9";s:3:"tt ";s:2:"10";s:3:"ett";s:2:"11";s:3:"sze";s:2:"12";s:3:" fe";s:2:"13";s:4:"és ";s:2:"14";s:3:" ki";s:2:"15";s:3:"tet";s:2:"16";s:3:" be";s:2:"17";s:3:"et ";s:2:"18";s:3:"ter";s:2:"19";s:4:" kö";s:2:"20";s:4:" és";s:2:"21";s:3:"hog";s:2:"22";s:3:"meg";s:2:"23";s:3:"ogy";s:2:"24";s:3:"szt";s:2:"25";s:3:"te ";s:2:"26";s:3:"t a";s:2:"27";s:3:"zet";s:2:"28";s:3:"a m";s:2:"29";s:3:"nek";s:2:"30";s:3:"nt ";s:2:"31";s:4:"ség";s:2:"32";s:4:"szá";s:2:"33";s:3:"ak ";s:2:"34";s:3:" va";s:2:"35";s:3:"an ";s:2:"36";s:3:"eze";s:2:"37";s:3:"ra ";s:2:"38";s:3:"ta ";s:2:"39";s:3:" mi";s:2:"40";s:3:"int";s:2:"41";s:4:"köz";s:2:"42";s:3:" is";s:2:"43";s:3:"esz";s:2:"44";s:3:"fel";s:2:"45";s:3:"min";s:2:"46";s:3:"nak";s:2:"47";s:3:"ors";s:2:"48";s:3:"zer";s:2:"49";s:3:" te";s:2:"50";s:3:"a a";s:2:"51";s:3:"a k";s:2:"52";s:3:"is ";s:2:"53";s:3:" cs";s:2:"54";s:3:"ele";s:2:"55";s:3:"er ";s:2:"56";s:3:"men";s:2:"57";s:3:"si ";s:2:"58";s:3:"tek";s:2:"59";s:3:"ti ";s:2:"60";s:3:" ne";s:2:"61";s:3:"csa";s:2:"62";s:3:"ent";s:2:"63";s:3:"z e";s:2:"64";s:3:"a t";s:2:"65";s:3:"ala";s:2:"66";s:3:"ere";s:2:"67";s:3:"es ";s:2:"68";s:3:"lom";s:2:"69";s:3:"lte";s:2:"70";s:3:"mon";s:2:"71";s:3:"ond";s:2:"72";s:3:"rsz";s:2:"73";s:3:"sza";s:2:"74";s:3:"tte";s:2:"75";s:4:"zág";s:2:"76";s:4:"ány";s:2:"77";s:3:" fo";s:2:"78";s:3:" ma";s:2:"79";s:3:"ai ";s:2:"80";s:3:"ben";s:2:"81";s:3:"el ";s:2:"82";s:3:"ene";s:2:"83";s:3:"ik ";s:2:"84";s:3:"jel";s:2:"85";s:4:"tás";s:2:"86";s:4:"áll";s:2:"87";s:3:" ha";s:2:"88";s:3:" le";s:2:"89";s:4:" ál";s:2:"90";s:3:"agy";s:2:"91";s:4:"alá";s:2:"92";s:3:"isz";s:2:"93";s:3:"y a";s:2:"94";s:3:"zte";s:2:"95";s:4:"ás ";s:2:"96";s:3:" al";s:2:"97";s:3:"e a";s:2:"98";s:3:"egy";s:2:"99";s:3:"ely";s:3:"100";s:3:"for";s:3:"101";s:3:"lat";s:3:"102";s:3:"lt ";s:3:"103";s:3:"n a";s:3:"104";s:3:"oga";s:3:"105";s:3:"on ";s:3:"106";s:3:"re ";s:3:"107";s:3:"st ";s:3:"108";s:4:"ság";s:3:"109";s:3:"t m";s:3:"110";s:4:"án ";s:3:"111";s:4:"ét ";s:3:"112";s:4:"ült";s:3:"113";s:3:" je";s:3:"114";s:3:"gi ";s:3:"115";s:3:"k a";s:3:"116";s:4:"kül";s:3:"117";s:3:"lam";s:3:"118";s:3:"len";s:3:"119";s:4:"lás";s:3:"120";s:4:"más";s:3:"121";s:3:"s k";s:3:"122";s:3:"vez";s:3:"123";s:4:"áso";s:3:"124";s:5:"özö";s:3:"125";s:3:" ta";s:3:"126";s:3:"a s";s:3:"127";s:3:"a v";s:3:"128";s:3:"asz";s:3:"129";s:4:"atá";s:3:"130";s:4:"ető";s:3:"131";s:3:"kez";s:3:"132";s:3:"let";s:3:"133";s:3:"mag";s:3:"134";s:3:"nem";s:3:"135";s:4:"szé";s:3:"136";s:3:"z m";s:3:"137";s:4:"át ";s:3:"138";s:4:"éte";s:3:"139";s:4:"ölt";s:3:"140";s:3:" de";s:3:"141";s:3:" gy";s:3:"142";s:4:" ké";s:3:"143";s:3:" mo";s:3:"144";s:4:" vá";s:3:"145";s:4:" ér";s:3:"146";s:3:"a b";s:3:"147";s:3:"a f";s:3:"148";s:3:"ami";s:3:"149";s:3:"at ";s:3:"150";s:3:"ato";s:3:"151";s:3:"att";s:3:"152";s:3:"bef";s:3:"153";s:3:"dta";s:3:"154";s:3:"gya";s:3:"155";s:3:"hat";s:3:"156";s:3:"i s";s:3:"157";s:3:"las";s:3:"158";s:3:"ndt";s:3:"159";s:3:"rt ";s:3:"160";s:3:"szo";s:3:"161";s:3:"t k";s:3:"162";s:4:"tár";s:3:"163";s:4:"tés";s:3:"164";s:3:"van";s:3:"165";s:5:"ásá";s:3:"166";s:4:"ól ";s:3:"167";s:4:" bé";s:3:"168";s:3:" eg";s:3:"169";s:3:" or";s:3:"170";s:4:" pá";s:3:"171";s:4:" pé";s:3:"172";s:3:" ve";s:3:"173";s:3:"ban";s:3:"174";s:3:"eke";s:3:"175";s:4:"ekü";s:3:"176";s:4:"elő";s:3:"177";s:3:"erv";s:3:"178";s:3:"ete";s:3:"179";s:3:"fog";s:3:"180";s:3:"i a";s:3:"181";s:3:"kis";s:3:"182";s:4:"lád";s:3:"183";s:3:"nte";s:3:"184";s:3:"nye";s:3:"185";s:3:"nyi";s:3:"186";s:3:"ok ";s:3:"187";s:4:"omá";s:3:"188";s:3:"os ";s:3:"189";s:4:"rán";s:3:"190";s:4:"rás";s:3:"191";s:3:"sal";s:3:"192";s:3:"t e";s:3:"193";s:4:"vál";s:3:"194";s:3:"yar";s:3:"195";s:4:"ágo";s:3:"196";s:4:"ála";s:3:"197";s:4:"ége";s:3:"198";s:4:"ény";s:3:"199";s:4:"ött";s:3:"200";s:4:" tá";s:3:"201";s:4:"adó";s:3:"202";s:3:"elh";s:3:"203";s:3:"fej";s:3:"204";s:3:"het";s:3:"205";s:3:"hoz";s:3:"206";s:3:"ill";s:3:"207";s:4:"jár";s:3:"208";s:4:"kés";s:3:"209";s:3:"llo";s:3:"210";s:3:"mi ";s:3:"211";s:3:"ny ";s:3:"212";s:3:"ont";s:3:"213";s:3:"ren";s:3:"214";s:3:"res";s:3:"215";s:3:"rin";s:3:"216";s:3:"s a";s:3:"217";s:3:"s e";s:3:"218";s:3:"ssz";s:3:"219";s:3:"zt ";s:3:"220";s:3:" ez";s:3:"221";s:3:" ka";s:3:"222";s:3:" ke";s:3:"223";s:3:" ko";s:3:"224";s:3:" re";s:3:"225";s:3:"a h";s:3:"226";s:3:"a n";s:3:"227";s:3:"den";s:3:"228";s:4:"dó ";s:3:"229";s:3:"efo";s:3:"230";s:3:"gad";s:3:"231";s:3:"gat";s:3:"232";s:3:"gye";s:3:"233";s:3:"hel";s:3:"234";s:3:"k e";s:3:"235";s:3:"ket";s:3:"236";s:3:"les";s:3:"237";s:4:"mán";s:3:"238";s:3:"nde";s:3:"239";s:3:"nis";s:3:"240";s:3:"ozz";s:3:"241";s:3:"t b";s:3:"242";s:3:"t i";s:3:"243";s:4:"t é";s:3:"244";s:3:"tat";s:3:"245";s:3:"tos";s:3:"246";s:3:"val";s:3:"247";s:3:"z o";s:3:"248";s:3:"zak";s:3:"249";s:4:"ád ";s:3:"250";s:4:"ály";s:3:"251";s:4:"ára";s:3:"252";s:4:"ési";s:3:"253";s:4:"ész";s:3:"254";s:3:" ak";s:3:"255";s:3:" am";s:3:"256";s:3:" es";s:3:"257";s:4:" há";s:3:"258";s:3:" ny";s:3:"259";s:4:" tö";s:3:"260";s:3:"aka";s:3:"261";s:3:"art";s:3:"262";s:4:"ató";s:3:"263";s:3:"azt";s:3:"264";s:3:"bbe";s:3:"265";s:3:"ber";s:3:"266";s:4:"ció";s:3:"267";s:3:"cso";s:3:"268";s:3:"em ";s:3:"269";s:3:"eti";s:3:"270";s:4:"eté";s:3:"271";s:3:"gal";s:3:"272";s:3:"i t";s:3:"273";s:3:"ini";s:3:"274";s:3:"ist";s:3:"275";s:3:"ja ";s:3:"276";s:3:"ker";s:3:"277";s:3:"ki ";s:3:"278";s:3:"kor";s:3:"279";s:3:"koz";s:3:"280";s:4:"l é";s:3:"281";s:4:"ljá";s:3:"282";s:3:"lye";s:3:"283";s:3:"n v";s:3:"284";s:3:"ni ";s:3:"285";s:4:"pál";s:3:"286";s:3:"ror";s:3:"287";s:4:"ról";s:3:"288";s:4:"rül";s:3:"289";s:3:"s c";s:3:"290";s:3:"s p";s:3:"291";s:3:"s s";s:3:"292";s:3:"s v";s:3:"293";s:3:"sok";s:3:"294";s:3:"t j";s:3:"295";s:3:"t t";s:3:"296";s:3:"tar";s:3:"297";s:3:"tel";s:3:"298";s:3:"vat";s:3:"299";}s:9:"icelandic";a:300:{s:4:"að ";s:1:"0";s:3:"um ";s:1:"1";s:4:" að";s:1:"2";s:3:"ir ";s:1:"3";s:4:"ið ";s:1:"4";s:3:"ur ";s:1:"5";s:3:" ve";s:1:"6";s:4:" í ";s:1:"7";s:3:"na ";s:1:"8";s:4:" á ";s:1:"9";s:3:" se";s:2:"10";s:3:" er";s:2:"11";s:3:" og";s:2:"12";s:3:"ar ";s:2:"13";s:3:"og ";s:2:"14";s:3:"ver";s:2:"15";s:3:" mi";s:2:"16";s:3:"inn";s:2:"17";s:3:"nn ";s:2:"18";s:3:" fy";s:2:"19";s:3:"er ";s:2:"20";s:3:"fyr";s:2:"21";s:3:" ek";s:2:"22";s:3:" en";s:2:"23";s:3:" ha";s:2:"24";s:3:" he";s:2:"25";s:3:"ekk";s:2:"26";s:3:" st";s:2:"27";s:3:"ki ";s:2:"28";s:3:"st ";s:2:"29";s:4:"ði ";s:2:"30";s:3:" ba";s:2:"31";s:3:" me";s:2:"32";s:3:" vi";s:2:"33";s:3:"ig ";s:2:"34";s:3:"rir";s:2:"35";s:3:"yri";s:2:"36";s:3:" um";s:2:"37";s:3:"g f";s:2:"38";s:3:"leg";s:2:"39";s:3:"lei";s:2:"40";s:3:"ns ";s:2:"41";s:4:"ð s";s:2:"42";s:3:" ei";s:2:"43";s:4:" þa";s:2:"44";s:3:"in ";s:2:"45";s:3:"kki";s:2:"46";s:3:"r h";s:2:"47";s:3:"r s";s:2:"48";s:3:"egi";s:2:"49";s:3:"ein";s:2:"50";s:3:"ga ";s:2:"51";s:3:"ing";s:2:"52";s:3:"ra ";s:2:"53";s:3:"sta";s:2:"54";s:3:" va";s:2:"55";s:4:" þe";s:2:"56";s:3:"ann";s:2:"57";s:3:"en ";s:2:"58";s:3:"mil";s:2:"59";s:3:"sem";s:2:"60";s:4:"tjó";s:2:"61";s:4:"arð";s:2:"62";s:3:"di ";s:2:"63";s:3:"eit";s:2:"64";s:3:"haf";s:2:"65";s:3:"ill";s:2:"66";s:3:"ins";s:2:"67";s:3:"ist";s:2:"68";s:3:"llj";s:2:"69";s:3:"ndi";s:2:"70";s:3:"r a";s:2:"71";s:3:"r e";s:2:"72";s:3:"seg";s:2:"73";s:3:"un ";s:2:"74";s:3:"var";s:2:"75";s:3:" bi";s:2:"76";s:3:" el";s:2:"77";s:3:" fo";s:2:"78";s:3:" ge";s:2:"79";s:3:" yf";s:2:"80";s:3:"and";s:2:"81";s:3:"aug";s:2:"82";s:3:"bau";s:2:"83";s:3:"big";s:2:"84";s:3:"ega";s:2:"85";s:3:"eld";s:2:"86";s:4:"erð";s:2:"87";s:3:"fir";s:2:"88";s:3:"foo";s:2:"89";s:3:"gin";s:2:"90";s:3:"itt";s:2:"91";s:3:"n s";s:2:"92";s:3:"ngi";s:2:"93";s:3:"num";s:2:"94";s:3:"od ";s:2:"95";s:3:"ood";s:2:"96";s:3:"sin";s:2:"97";s:3:"ta ";s:2:"98";s:3:"tt ";s:2:"99";s:4:"við";s:3:"100";s:3:"yfi";s:3:"101";s:4:"ð e";s:3:"102";s:4:"ð f";s:3:"103";s:3:" hr";s:3:"104";s:4:" sé";s:3:"105";s:4:" þv";s:3:"106";s:3:"a e";s:3:"107";s:4:"a á";s:3:"108";s:3:"em ";s:3:"109";s:3:"gi ";s:3:"110";s:3:"i f";s:3:"111";s:3:"jar";s:3:"112";s:4:"jór";s:3:"113";s:3:"lja";s:3:"114";s:3:"m e";s:3:"115";s:4:"r á";s:3:"116";s:3:"rei";s:3:"117";s:3:"rst";s:3:"118";s:4:"rða";s:3:"119";s:4:"rði";s:3:"120";s:4:"rðu";s:3:"121";s:3:"stj";s:3:"122";s:3:"und";s:3:"123";s:3:"veg";s:3:"124";s:4:"ví ";s:3:"125";s:4:"ð v";s:3:"126";s:5:"það";s:3:"127";s:5:"því";s:3:"128";s:3:" fj";s:3:"129";s:3:" ko";s:3:"130";s:3:" sl";s:3:"131";s:3:"eik";s:3:"132";s:3:"end";s:3:"133";s:3:"ert";s:3:"134";s:3:"ess";s:3:"135";s:4:"fjá";s:3:"136";s:3:"fur";s:3:"137";s:3:"gir";s:3:"138";s:4:"hús";s:3:"139";s:4:"jár";s:3:"140";s:3:"n e";s:3:"141";s:3:"ri ";s:3:"142";s:3:"tar";s:3:"143";s:5:"ð þ";s:3:"144";s:4:"ðar";s:3:"145";s:4:"ður";s:3:"146";s:4:"þes";s:3:"147";s:3:" br";s:3:"148";s:4:" hú";s:3:"149";s:3:" kr";s:3:"150";s:3:" le";s:3:"151";s:3:" up";s:3:"152";s:3:"a s";s:3:"153";s:3:"egg";s:3:"154";s:3:"i s";s:3:"155";s:3:"irt";s:3:"156";s:3:"ja ";s:3:"157";s:4:"kið";s:3:"158";s:3:"len";s:3:"159";s:4:"með";s:3:"160";s:3:"mik";s:3:"161";s:3:"n b";s:3:"162";s:3:"nar";s:3:"163";s:3:"nir";s:3:"164";s:3:"nun";s:3:"165";s:3:"r f";s:3:"166";s:3:"r v";s:3:"167";s:4:"rið";s:3:"168";s:3:"rt ";s:3:"169";s:3:"sti";s:3:"170";s:3:"t v";s:3:"171";s:3:"ti ";s:3:"172";s:3:"una";s:3:"173";s:3:"upp";s:3:"174";s:4:"ða ";s:3:"175";s:4:"óna";s:3:"176";s:3:" al";s:3:"177";s:3:" fr";s:3:"178";s:3:" gr";s:3:"179";s:3:"a v";s:3:"180";s:3:"all";s:3:"181";s:3:"an ";s:3:"182";s:3:"da ";s:3:"183";s:4:"eið";s:3:"184";s:4:"eð ";s:3:"185";s:3:"fa ";s:3:"186";s:3:"fra";s:3:"187";s:3:"g e";s:3:"188";s:3:"ger";s:3:"189";s:4:"gið";s:3:"190";s:3:"gt ";s:3:"191";s:3:"han";s:3:"192";s:3:"hef";s:3:"193";s:3:"hel";s:3:"194";s:3:"her";s:3:"195";s:3:"hra";s:3:"196";s:3:"i a";s:3:"197";s:3:"i e";s:3:"198";s:3:"i v";s:3:"199";s:4:"i þ";s:3:"200";s:3:"iki";s:3:"201";s:4:"jón";s:3:"202";s:4:"jör";s:3:"203";s:3:"ka ";s:3:"204";s:4:"kró";s:3:"205";s:4:"lík";s:3:"206";s:3:"m h";s:3:"207";s:3:"n a";s:3:"208";s:3:"nga";s:3:"209";s:3:"r l";s:3:"210";s:3:"ram";s:3:"211";s:3:"ru ";s:3:"212";s:5:"ráð";s:3:"213";s:4:"rón";s:3:"214";s:3:"svo";s:3:"215";s:3:"vin";s:3:"216";s:4:"í b";s:3:"217";s:4:"í h";s:3:"218";s:4:"ð h";s:3:"219";s:4:"ð k";s:3:"220";s:4:"ð m";s:3:"221";s:5:"örð";s:3:"222";s:3:" af";s:3:"223";s:3:" fa";s:3:"224";s:4:" lí";s:3:"225";s:4:" rá";s:3:"226";s:3:" sk";s:3:"227";s:3:" sv";s:3:"228";s:3:" te";s:3:"229";s:3:"a b";s:3:"230";s:3:"a f";s:3:"231";s:3:"a h";s:3:"232";s:3:"a k";s:3:"233";s:3:"a u";s:3:"234";s:3:"afi";s:3:"235";s:3:"agn";s:3:"236";s:3:"arn";s:3:"237";s:3:"ast";s:3:"238";s:3:"ber";s:3:"239";s:3:"efu";s:3:"240";s:3:"enn";s:3:"241";s:3:"erb";s:3:"242";s:3:"erg";s:3:"243";s:3:"fi ";s:3:"244";s:3:"g a";s:3:"245";s:3:"gar";s:3:"246";s:4:"iðs";s:3:"247";s:3:"ker";s:3:"248";s:3:"kke";s:3:"249";s:3:"lan";s:3:"250";s:4:"ljó";s:3:"251";s:3:"llt";s:3:"252";s:3:"ma ";s:3:"253";s:4:"mið";s:3:"254";s:3:"n v";s:3:"255";s:4:"n í";s:3:"256";s:3:"nan";s:3:"257";s:3:"nda";s:3:"258";s:3:"ndu";s:3:"259";s:4:"nið";s:3:"260";s:3:"nna";s:3:"261";s:3:"nnu";s:3:"262";s:3:"nu ";s:3:"263";s:3:"r o";s:3:"264";s:3:"rbe";s:3:"265";s:3:"rgi";s:3:"266";s:4:"slö";s:3:"267";s:4:"sé ";s:3:"268";s:3:"t a";s:3:"269";s:3:"t h";s:3:"270";s:3:"til";s:3:"271";s:3:"tin";s:3:"272";s:3:"ugu";s:3:"273";s:3:"vil";s:3:"274";s:3:"ygg";s:3:"275";s:4:"á s";s:3:"276";s:4:"ð a";s:3:"277";s:4:"ð b";s:3:"278";s:4:"órn";s:3:"279";s:4:"ögn";s:3:"280";s:4:"öku";s:3:"281";s:3:" at";s:3:"282";s:3:" fi";s:3:"283";s:4:" fé";s:3:"284";s:3:" ka";s:3:"285";s:3:" ma";s:3:"286";s:3:" no";s:3:"287";s:3:" sa";s:3:"288";s:3:" si";s:3:"289";s:3:" ti";s:3:"290";s:4:" ák";s:3:"291";s:3:"a m";s:3:"292";s:3:"a t";s:3:"293";s:4:"a í";s:3:"294";s:4:"a þ";s:3:"295";s:3:"afa";s:3:"296";s:3:"afs";s:3:"297";s:3:"ald";s:3:"298";s:3:"arf";s:3:"299";}s:10:"indonesian";a:300:{s:3:"an ";s:1:"0";s:3:" me";s:1:"1";s:3:"kan";s:1:"2";s:3:"ang";s:1:"3";s:3:"ng ";s:1:"4";s:3:" pe";s:1:"5";s:3:"men";s:1:"6";s:3:" di";s:1:"7";s:3:" ke";s:1:"8";s:3:" da";s:1:"9";s:3:" se";s:2:"10";s:3:"eng";s:2:"11";s:3:" be";s:2:"12";s:3:"nga";s:2:"13";s:3:"nya";s:2:"14";s:3:" te";s:2:"15";s:3:"ah ";s:2:"16";s:3:"ber";s:2:"17";s:3:"aka";s:2:"18";s:3:" ya";s:2:"19";s:3:"dan";s:2:"20";s:3:"di ";s:2:"21";s:3:"yan";s:2:"22";s:3:"n p";s:2:"23";s:3:"per";s:2:"24";s:3:"a m";s:2:"25";s:3:"ita";s:2:"26";s:3:" pa";s:2:"27";s:3:"da ";s:2:"28";s:3:"ata";s:2:"29";s:3:"ada";s:2:"30";s:3:"ya ";s:2:"31";s:3:"ta ";s:2:"32";s:3:" in";s:2:"33";s:3:"ala";s:2:"34";s:3:"eri";s:2:"35";s:3:"ia ";s:2:"36";s:3:"a d";s:2:"37";s:3:"n k";s:2:"38";s:3:"am ";s:2:"39";s:3:"ga ";s:2:"40";s:3:"at ";s:2:"41";s:3:"era";s:2:"42";s:3:"n d";s:2:"43";s:3:"ter";s:2:"44";s:3:" ka";s:2:"45";s:3:"a p";s:2:"46";s:3:"ari";s:2:"47";s:3:"emb";s:2:"48";s:3:"n m";s:2:"49";s:3:"ri ";s:2:"50";s:3:" ba";s:2:"51";s:3:"aan";s:2:"52";s:3:"ak ";s:2:"53";s:3:"ra ";s:2:"54";s:3:" it";s:2:"55";s:3:"ara";s:2:"56";s:3:"ela";s:2:"57";s:3:"ni ";s:2:"58";s:3:"ali";s:2:"59";s:3:"ran";s:2:"60";s:3:"ar ";s:2:"61";s:3:"eru";s:2:"62";s:3:"lah";s:2:"63";s:3:"a b";s:2:"64";s:3:"asi";s:2:"65";s:3:"awa";s:2:"66";s:3:"eba";s:2:"67";s:3:"gan";s:2:"68";s:3:"n b";s:2:"69";s:3:" ha";s:2:"70";s:3:"ini";s:2:"71";s:3:"mer";s:2:"72";s:3:" la";s:2:"73";s:3:" mi";s:2:"74";s:3:"and";s:2:"75";s:3:"ena";s:2:"76";s:3:"wan";s:2:"77";s:3:" sa";s:2:"78";s:3:"aha";s:2:"79";s:3:"lam";s:2:"80";s:3:"n i";s:2:"81";s:3:"nda";s:2:"82";s:3:" wa";s:2:"83";s:3:"a i";s:2:"84";s:3:"dua";s:2:"85";s:3:"g m";s:2:"86";s:3:"mi ";s:2:"87";s:3:"n a";s:2:"88";s:3:"rus";s:2:"89";s:3:"tel";s:2:"90";s:3:"yak";s:2:"91";s:3:" an";s:2:"92";s:3:"dal";s:2:"93";s:3:"h d";s:2:"94";s:3:"i s";s:2:"95";s:3:"ing";s:2:"96";s:3:"min";s:2:"97";s:3:"ngg";s:2:"98";s:3:"tak";s:2:"99";s:3:"ami";s:3:"100";s:3:"beb";s:3:"101";s:3:"den";s:3:"102";s:3:"gat";s:3:"103";s:3:"ian";s:3:"104";s:3:"ih ";s:3:"105";s:3:"pad";s:3:"106";s:3:"rga";s:3:"107";s:3:"san";s:3:"108";s:3:"ua ";s:3:"109";s:3:" de";s:3:"110";s:3:"a t";s:3:"111";s:3:"arg";s:3:"112";s:3:"dar";s:3:"113";s:3:"elu";s:3:"114";s:3:"har";s:3:"115";s:3:"i k";s:3:"116";s:3:"i m";s:3:"117";s:3:"i p";s:3:"118";s:3:"ika";s:3:"119";s:3:"in ";s:3:"120";s:3:"iny";s:3:"121";s:3:"itu";s:3:"122";s:3:"mba";s:3:"123";s:3:"n t";s:3:"124";s:3:"ntu";s:3:"125";s:3:"pan";s:3:"126";s:3:"pen";s:3:"127";s:3:"sah";s:3:"128";s:3:"tan";s:3:"129";s:3:"tu ";s:3:"130";s:3:"a k";s:3:"131";s:3:"ban";s:3:"132";s:3:"edu";s:3:"133";s:3:"eka";s:3:"134";s:3:"g d";s:3:"135";s:3:"ka ";s:3:"136";s:3:"ker";s:3:"137";s:3:"nde";s:3:"138";s:3:"nta";s:3:"139";s:3:"ora";s:3:"140";s:3:"usa";s:3:"141";s:3:" du";s:3:"142";s:3:" ma";s:3:"143";s:3:"a s";s:3:"144";s:3:"ai ";s:3:"145";s:3:"ant";s:3:"146";s:3:"bas";s:3:"147";s:3:"end";s:3:"148";s:3:"i d";s:3:"149";s:3:"ira";s:3:"150";s:3:"kam";s:3:"151";s:3:"lan";s:3:"152";s:3:"n s";s:3:"153";s:3:"uli";s:3:"154";s:3:"al ";s:3:"155";s:3:"apa";s:3:"156";s:3:"ere";s:3:"157";s:3:"ert";s:3:"158";s:3:"lia";s:3:"159";s:3:"mem";s:3:"160";s:3:"rka";s:3:"161";s:3:"si ";s:3:"162";s:3:"tal";s:3:"163";s:3:"ung";s:3:"164";s:3:" ak";s:3:"165";s:3:"a a";s:3:"166";s:3:"a w";s:3:"167";s:3:"ani";s:3:"168";s:3:"ask";s:3:"169";s:3:"ent";s:3:"170";s:3:"gar";s:3:"171";s:3:"haa";s:3:"172";s:3:"i i";s:3:"173";s:3:"isa";s:3:"174";s:3:"ked";s:3:"175";s:3:"mbe";s:3:"176";s:3:"ska";s:3:"177";s:3:"tor";s:3:"178";s:3:"uan";s:3:"179";s:3:"uk ";s:3:"180";s:3:"uka";s:3:"181";s:3:" ad";s:3:"182";s:3:" to";s:3:"183";s:3:"asa";s:3:"184";s:3:"aya";s:3:"185";s:3:"bag";s:3:"186";s:3:"dia";s:3:"187";s:3:"dun";s:3:"188";s:3:"erj";s:3:"189";s:3:"mas";s:3:"190";s:3:"na ";s:3:"191";s:3:"rek";s:3:"192";s:3:"rit";s:3:"193";s:3:"sih";s:3:"194";s:3:"us ";s:3:"195";s:3:" bi";s:3:"196";s:3:"a h";s:3:"197";s:3:"ama";s:3:"198";s:3:"dib";s:3:"199";s:3:"ers";s:3:"200";s:3:"g s";s:3:"201";s:3:"han";s:3:"202";s:3:"ik ";s:3:"203";s:3:"kem";s:3:"204";s:3:"ma ";s:3:"205";s:3:"n l";s:3:"206";s:3:"nit";s:3:"207";s:3:"r b";s:3:"208";s:3:"rja";s:3:"209";s:3:"sa ";s:3:"210";s:3:" ju";s:3:"211";s:3:" or";s:3:"212";s:3:" si";s:3:"213";s:3:" ti";s:3:"214";s:3:"a y";s:3:"215";s:3:"aga";s:3:"216";s:3:"any";s:3:"217";s:3:"as ";s:3:"218";s:3:"cul";s:3:"219";s:3:"eme";s:3:"220";s:3:"emu";s:3:"221";s:3:"eny";s:3:"222";s:3:"epa";s:3:"223";s:3:"erb";s:3:"224";s:3:"erl";s:3:"225";s:3:"gi ";s:3:"226";s:3:"h m";s:3:"227";s:3:"i a";s:3:"228";s:3:"kel";s:3:"229";s:3:"li ";s:3:"230";s:3:"mel";s:3:"231";s:3:"nia";s:3:"232";s:3:"opa";s:3:"233";s:3:"rta";s:3:"234";s:3:"sia";s:3:"235";s:3:"tah";s:3:"236";s:3:"ula";s:3:"237";s:3:"un ";s:3:"238";s:3:"unt";s:3:"239";s:3:" at";s:3:"240";s:3:" bu";s:3:"241";s:3:" pu";s:3:"242";s:3:" ta";s:3:"243";s:3:"agi";s:3:"244";s:3:"alu";s:3:"245";s:3:"amb";s:3:"246";s:3:"bah";s:3:"247";s:3:"bis";s:3:"248";s:3:"er ";s:3:"249";s:3:"i t";s:3:"250";s:3:"ibe";s:3:"251";s:3:"ir ";s:3:"252";s:3:"ja ";s:3:"253";s:3:"k m";s:3:"254";s:3:"kar";s:3:"255";s:3:"lai";s:3:"256";s:3:"lal";s:3:"257";s:3:"lu ";s:3:"258";s:3:"mpa";s:3:"259";s:3:"ngk";s:3:"260";s:3:"nja";s:3:"261";s:3:"or ";s:3:"262";s:3:"pa ";s:3:"263";s:3:"pas";s:3:"264";s:3:"pem";s:3:"265";s:3:"rak";s:3:"266";s:3:"rik";s:3:"267";s:3:"seb";s:3:"268";s:3:"tam";s:3:"269";s:3:"tem";s:3:"270";s:3:"top";s:3:"271";s:3:"tuk";s:3:"272";s:3:"uni";s:3:"273";s:3:"war";s:3:"274";s:3:" al";s:3:"275";s:3:" ga";s:3:"276";s:3:" ge";s:3:"277";s:3:" ir";s:3:"278";s:3:" ja";s:3:"279";s:3:" mu";s:3:"280";s:3:" na";s:3:"281";s:3:" pr";s:3:"282";s:3:" su";s:3:"283";s:3:" un";s:3:"284";s:3:"ad ";s:3:"285";s:3:"adi";s:3:"286";s:3:"akt";s:3:"287";s:3:"ann";s:3:"288";s:3:"apo";s:3:"289";s:3:"bel";s:3:"290";s:3:"bul";s:3:"291";s:3:"der";s:3:"292";s:3:"ega";s:3:"293";s:3:"eke";s:3:"294";s:3:"ema";s:3:"295";s:3:"emp";s:3:"296";s:3:"ene";s:3:"297";s:3:"enj";s:3:"298";s:3:"esa";s:3:"299";}s:7:"italian";a:300:{s:3:" di";s:1:"0";s:3:"to ";s:1:"1";s:3:"la ";s:1:"2";s:3:" de";s:1:"3";s:3:"di ";s:1:"4";s:3:"no ";s:1:"5";s:3:" co";s:1:"6";s:3:"re ";s:1:"7";s:3:"ion";s:1:"8";s:3:"e d";s:1:"9";s:3:" e ";s:2:"10";s:3:"le ";s:2:"11";s:3:"del";s:2:"12";s:3:"ne ";s:2:"13";s:3:"ti ";s:2:"14";s:3:"ell";s:2:"15";s:3:" la";s:2:"16";s:3:" un";s:2:"17";s:3:"ni ";s:2:"18";s:3:"i d";s:2:"19";s:3:"per";s:2:"20";s:3:" pe";s:2:"21";s:3:"ent";s:2:"22";s:3:" in";s:2:"23";s:3:"one";s:2:"24";s:3:"he ";s:2:"25";s:3:"ta ";s:2:"26";s:3:"zio";s:2:"27";s:3:"che";s:2:"28";s:3:"o d";s:2:"29";s:3:"a d";s:2:"30";s:3:"na ";s:2:"31";s:3:"ato";s:2:"32";s:3:"e s";s:2:"33";s:3:" so";s:2:"34";s:3:"i s";s:2:"35";s:3:"lla";s:2:"36";s:3:"a p";s:2:"37";s:3:"li ";s:2:"38";s:3:"te ";s:2:"39";s:3:" al";s:2:"40";s:3:" ch";s:2:"41";s:3:"er ";s:2:"42";s:3:" pa";s:2:"43";s:3:" si";s:2:"44";s:3:"con";s:2:"45";s:3:"sta";s:2:"46";s:3:" pr";s:2:"47";s:3:"a c";s:2:"48";s:3:" se";s:2:"49";s:3:"el ";s:2:"50";s:3:"ia ";s:2:"51";s:3:"si ";s:2:"52";s:3:"e p";s:2:"53";s:3:" da";s:2:"54";s:3:"e i";s:2:"55";s:3:"i p";s:2:"56";s:3:"ont";s:2:"57";s:3:"ano";s:2:"58";s:3:"i c";s:2:"59";s:3:"all";s:2:"60";s:3:"azi";s:2:"61";s:3:"nte";s:2:"62";s:3:"on ";s:2:"63";s:3:"nti";s:2:"64";s:3:"o s";s:2:"65";s:3:" ri";s:2:"66";s:3:"i a";s:2:"67";s:3:"o a";s:2:"68";s:3:"un ";s:2:"69";s:3:" an";s:2:"70";s:3:"are";s:2:"71";s:3:"ari";s:2:"72";s:3:"e a";s:2:"73";s:3:"i e";s:2:"74";s:3:"ita";s:2:"75";s:3:"men";s:2:"76";s:3:"ri ";s:2:"77";s:3:" ca";s:2:"78";s:3:" il";s:2:"79";s:3:" no";s:2:"80";s:3:" po";s:2:"81";s:3:"a s";s:2:"82";s:3:"ant";s:2:"83";s:3:"il ";s:2:"84";s:3:"in ";s:2:"85";s:3:"a l";s:2:"86";s:3:"ati";s:2:"87";s:3:"cia";s:2:"88";s:3:"e c";s:2:"89";s:3:"ro ";s:2:"90";s:3:"ann";s:2:"91";s:3:"est";s:2:"92";s:3:"gli";s:2:"93";s:4:"tà ";s:2:"94";s:3:" qu";s:2:"95";s:3:"e l";s:2:"96";s:3:"nta";s:2:"97";s:3:" a ";s:2:"98";s:3:"com";s:2:"99";s:3:"o c";s:3:"100";s:3:"ra ";s:3:"101";s:3:" le";s:3:"102";s:3:" ne";s:3:"103";s:3:"ali";s:3:"104";s:3:"ere";s:3:"105";s:3:"ist";s:3:"106";s:3:" ma";s:3:"107";s:4:" è ";s:3:"108";s:3:"io ";s:3:"109";s:3:"lle";s:3:"110";s:3:"me ";s:3:"111";s:3:"era";s:3:"112";s:3:"ica";s:3:"113";s:3:"ost";s:3:"114";s:3:"pro";s:3:"115";s:3:"tar";s:3:"116";s:3:"una";s:3:"117";s:3:" pi";s:3:"118";s:3:"da ";s:3:"119";s:3:"tat";s:3:"120";s:3:" mi";s:3:"121";s:3:"att";s:3:"122";s:3:"ca ";s:3:"123";s:3:"mo ";s:3:"124";s:3:"non";s:3:"125";s:3:"par";s:3:"126";s:3:"sti";s:3:"127";s:3:" fa";s:3:"128";s:3:" i ";s:3:"129";s:3:" re";s:3:"130";s:3:" su";s:3:"131";s:3:"ess";s:3:"132";s:3:"ini";s:3:"133";s:3:"nto";s:3:"134";s:3:"o l";s:3:"135";s:3:"ssi";s:3:"136";s:3:"tto";s:3:"137";s:3:"a e";s:3:"138";s:3:"ame";s:3:"139";s:3:"col";s:3:"140";s:3:"ei ";s:3:"141";s:3:"ma ";s:3:"142";s:3:"o i";s:3:"143";s:3:"za ";s:3:"144";s:3:" st";s:3:"145";s:3:"a a";s:3:"146";s:3:"ale";s:3:"147";s:3:"anc";s:3:"148";s:3:"ani";s:3:"149";s:3:"i m";s:3:"150";s:3:"ian";s:3:"151";s:3:"o p";s:3:"152";s:3:"oni";s:3:"153";s:3:"sio";s:3:"154";s:3:"tan";s:3:"155";s:3:"tti";s:3:"156";s:3:" lo";s:3:"157";s:3:"i r";s:3:"158";s:3:"oci";s:3:"159";s:3:"oli";s:3:"160";s:3:"ona";s:3:"161";s:3:"ono";s:3:"162";s:3:"tra";s:3:"163";s:3:" l ";s:3:"164";s:3:"a r";s:3:"165";s:3:"eri";s:3:"166";s:3:"ett";s:3:"167";s:3:"lo ";s:3:"168";s:3:"nza";s:3:"169";s:3:"que";s:3:"170";s:3:"str";s:3:"171";s:3:"ter";s:3:"172";s:3:"tta";s:3:"173";s:3:" ba";s:3:"174";s:3:" li";s:3:"175";s:3:" te";s:3:"176";s:3:"ass";s:3:"177";s:3:"e f";s:3:"178";s:3:"enz";s:3:"179";s:3:"for";s:3:"180";s:3:"nno";s:3:"181";s:3:"olo";s:3:"182";s:3:"ori";s:3:"183";s:3:"res";s:3:"184";s:3:"tor";s:3:"185";s:3:" ci";s:3:"186";s:3:" vo";s:3:"187";s:3:"a i";s:3:"188";s:3:"al ";s:3:"189";s:3:"chi";s:3:"190";s:3:"e n";s:3:"191";s:3:"lia";s:3:"192";s:3:"pre";s:3:"193";s:3:"ria";s:3:"194";s:3:"uni";s:3:"195";s:3:"ver";s:3:"196";s:3:" sp";s:3:"197";s:3:"imo";s:3:"198";s:3:"l a";s:3:"199";s:3:"l c";s:3:"200";s:3:"ran";s:3:"201";s:3:"sen";s:3:"202";s:3:"soc";s:3:"203";s:3:"tic";s:3:"204";s:3:" fi";s:3:"205";s:3:" mo";s:3:"206";s:3:"a n";s:3:"207";s:3:"ce ";s:3:"208";s:3:"dei";s:3:"209";s:3:"ggi";s:3:"210";s:3:"gio";s:3:"211";s:3:"iti";s:3:"212";s:3:"l s";s:3:"213";s:3:"lit";s:3:"214";s:3:"ll ";s:3:"215";s:3:"mon";s:3:"216";s:3:"ola";s:3:"217";s:3:"pac";s:3:"218";s:3:"sim";s:3:"219";s:3:"tit";s:3:"220";s:3:"utt";s:3:"221";s:3:"vol";s:3:"222";s:3:" ar";s:3:"223";s:3:" fo";s:3:"224";s:3:" ha";s:3:"225";s:3:" sa";s:3:"226";s:3:"acc";s:3:"227";s:3:"e r";s:3:"228";s:3:"ire";s:3:"229";s:3:"man";s:3:"230";s:3:"ntr";s:3:"231";s:3:"rat";s:3:"232";s:3:"sco";s:3:"233";s:3:"tro";s:3:"234";s:3:"tut";s:3:"235";s:3:"va ";s:3:"236";s:3:" do";s:3:"237";s:3:" gi";s:3:"238";s:3:" me";s:3:"239";s:3:" sc";s:3:"240";s:3:" tu";s:3:"241";s:3:" ve";s:3:"242";s:3:" vi";s:3:"243";s:3:"a m";s:3:"244";s:3:"ber";s:3:"245";s:3:"can";s:3:"246";s:3:"cit";s:3:"247";s:3:"i l";s:3:"248";s:3:"ier";s:3:"249";s:4:"ità";s:3:"250";s:3:"lli";s:3:"251";s:3:"min";s:3:"252";s:3:"n p";s:3:"253";s:3:"nat";s:3:"254";s:3:"nda";s:3:"255";s:3:"o e";s:3:"256";s:3:"o f";s:3:"257";s:3:"o u";s:3:"258";s:3:"ore";s:3:"259";s:3:"oro";s:3:"260";s:3:"ort";s:3:"261";s:3:"sto";s:3:"262";s:3:"ten";s:3:"263";s:3:"tiv";s:3:"264";s:3:"van";s:3:"265";s:3:"art";s:3:"266";s:3:"cco";s:3:"267";s:3:"ci ";s:3:"268";s:3:"cos";s:3:"269";s:3:"dal";s:3:"270";s:3:"e v";s:3:"271";s:3:"i i";s:3:"272";s:3:"ila";s:3:"273";s:3:"ino";s:3:"274";s:3:"l p";s:3:"275";s:3:"n c";s:3:"276";s:3:"nit";s:3:"277";s:3:"ole";s:3:"278";s:3:"ome";s:3:"279";s:3:"po ";s:3:"280";s:3:"rio";s:3:"281";s:3:"sa ";s:3:"282";s:3:" ce";s:3:"283";s:3:" es";s:3:"284";s:3:" tr";s:3:"285";s:3:"a b";s:3:"286";s:3:"and";s:3:"287";s:3:"ata";s:3:"288";s:3:"der";s:3:"289";s:3:"ens";s:3:"290";s:3:"ers";s:3:"291";s:3:"gi ";s:3:"292";s:3:"ial";s:3:"293";s:3:"ina";s:3:"294";s:3:"itt";s:3:"295";s:3:"izi";s:3:"296";s:3:"lan";s:3:"297";s:3:"lor";s:3:"298";s:3:"mil";s:3:"299";}s:6:"kazakh";a:300:{s:5:"ан ";s:1:"0";s:5:"ен ";s:1:"1";s:5:"ың ";s:1:"2";s:5:" қа";s:1:"3";s:5:" ба";s:1:"4";s:5:"ай ";s:1:"5";s:6:"нда";s:1:"6";s:5:"ын ";s:1:"7";s:5:" са";s:1:"8";s:5:" ал";s:1:"9";s:5:"ді ";s:2:"10";s:6:"ары";s:2:"11";s:5:"ды ";s:2:"12";s:5:"ып ";s:2:"13";s:5:" мұ";s:2:"14";s:5:" бі";s:2:"15";s:6:"асы";s:2:"16";s:5:"да ";s:2:"17";s:6:"най";s:2:"18";s:5:" жа";s:2:"19";s:6:"мұн";s:2:"20";s:6:"ста";s:2:"21";s:6:"ған";s:2:"22";s:5:"н б";s:2:"23";s:6:"ұна";s:2:"24";s:5:" бо";s:2:"25";s:6:"ның";s:2:"26";s:5:"ін ";s:2:"27";s:6:"лар";s:2:"28";s:6:"сын";s:2:"29";s:5:" де";s:2:"30";s:6:"аға";s:2:"31";s:6:"тан";s:2:"32";s:5:" кө";s:2:"33";s:6:"бір";s:2:"34";s:5:"ер ";s:2:"35";s:6:"мен";s:2:"36";s:6:"аза";s:2:"37";s:6:"ынд";s:2:"38";s:6:"ыны";s:2:"39";s:5:" ме";s:2:"40";s:6:"анд";s:2:"41";s:6:"ері";s:2:"42";s:6:"бол";s:2:"43";s:6:"дың";s:2:"44";s:6:"қаз";s:2:"45";s:6:"аты";s:2:"46";s:5:"сы ";s:2:"47";s:6:"тын";s:2:"48";s:5:"ғы ";s:2:"49";s:5:" ке";s:2:"50";s:5:"ар ";s:2:"51";s:6:"зақ";s:2:"52";s:5:"ық ";s:2:"53";s:6:"ала";s:2:"54";s:6:"алы";s:2:"55";s:6:"аны";s:2:"56";s:6:"ара";s:2:"57";s:6:"ағы";s:2:"58";s:6:"ген";s:2:"59";s:6:"тар";s:2:"60";s:6:"тер";s:2:"61";s:6:"тыр";s:2:"62";s:6:"айд";s:2:"63";s:6:"ард";s:2:"64";s:5:"де ";s:2:"65";s:5:"ға ";s:2:"66";s:5:" қо";s:2:"67";s:6:"бар";s:2:"68";s:5:"ің ";s:2:"69";s:6:"қан";s:2:"70";s:5:" бе";s:2:"71";s:5:" қы";s:2:"72";s:6:"ақс";s:2:"73";s:6:"гер";s:2:"74";s:6:"дан";s:2:"75";s:6:"дар";s:2:"76";s:6:"лық";s:2:"77";s:6:"лға";s:2:"78";s:6:"ына";s:2:"79";s:5:"ір ";s:2:"80";s:6:"ірі";s:2:"81";s:6:"ғас";s:2:"82";s:5:" та";s:2:"83";s:5:"а б";s:2:"84";s:5:"гі ";s:2:"85";s:6:"еді";s:2:"86";s:6:"еле";s:2:"87";s:6:"йды";s:2:"88";s:5:"н к";s:2:"89";s:5:"н т";s:2:"90";s:6:"ола";s:2:"91";s:6:"рын";s:2:"92";s:5:"іп ";s:2:"93";s:6:"қст";s:2:"94";s:6:"қта";s:2:"95";s:5:"ң б";s:2:"96";s:5:" ай";s:2:"97";s:5:" ол";s:2:"98";s:5:" со";s:2:"99";s:6:"айт";s:3:"100";s:6:"дағ";s:3:"101";s:6:"иге";s:3:"102";s:6:"лер";s:3:"103";s:6:"лып";s:3:"104";s:5:"н а";s:3:"105";s:5:"ік ";s:3:"106";s:6:"ақт";s:3:"107";s:6:"бағ";s:3:"108";s:6:"кен";s:3:"109";s:5:"н қ";s:3:"110";s:5:"ны ";s:3:"111";s:6:"рге";s:3:"112";s:6:"рға";s:3:"113";s:5:"ыр ";s:3:"114";s:5:" ар";s:3:"115";s:6:"алғ";s:3:"116";s:6:"аса";s:3:"117";s:6:"бас";s:3:"118";s:6:"бер";s:3:"119";s:5:"ге ";s:3:"120";s:6:"еті";s:3:"121";s:5:"на ";s:3:"122";s:6:"нде";s:3:"123";s:5:"не ";s:3:"124";s:6:"ниг";s:3:"125";s:6:"рды";s:3:"126";s:5:"ры ";s:3:"127";s:6:"сай";s:3:"128";s:5:" ау";s:3:"129";s:5:" кү";s:3:"130";s:5:" ни";s:3:"131";s:5:" от";s:3:"132";s:5:" өз";s:3:"133";s:6:"ауд";s:3:"134";s:5:"еп ";s:3:"135";s:6:"иял";s:3:"136";s:6:"лты";s:3:"137";s:5:"н ж";s:3:"138";s:5:"н о";s:3:"139";s:6:"осы";s:3:"140";s:6:"оты";s:3:"141";s:6:"рып";s:3:"142";s:5:"рі ";s:3:"143";s:6:"тке";s:3:"144";s:5:"ты ";s:3:"145";s:5:"ы б";s:3:"146";s:5:"ы ж";s:3:"147";s:6:"ылы";s:3:"148";s:6:"ысы";s:3:"149";s:5:"і с";s:3:"150";s:6:"қар";s:3:"151";s:5:" бұ";s:3:"152";s:5:" да";s:3:"153";s:5:" же";s:3:"154";s:5:" тұ";s:3:"155";s:5:" құ";s:3:"156";s:6:"ады";s:3:"157";s:6:"айл";s:3:"158";s:5:"ап ";s:3:"159";s:6:"ата";s:3:"160";s:6:"ені";s:3:"161";s:6:"йла";s:3:"162";s:5:"н м";s:3:"163";s:5:"н с";s:3:"164";s:6:"нды";s:3:"165";s:6:"нді";s:3:"166";s:5:"р м";s:3:"167";s:6:"тай";s:3:"168";s:6:"тін";s:3:"169";s:5:"ы т";s:3:"170";s:5:"ыс ";s:3:"171";s:6:"інд";s:3:"172";s:5:" би";s:3:"173";s:5:"а ж";s:3:"174";s:6:"ауы";s:3:"175";s:6:"деп";s:3:"176";s:6:"дің";s:3:"177";s:6:"еке";s:3:"178";s:6:"ери";s:3:"179";s:6:"йын";s:3:"180";s:6:"кел";s:3:"181";s:6:"лды";s:3:"182";s:5:"ма ";s:3:"183";s:6:"нан";s:3:"184";s:6:"оны";s:3:"185";s:5:"п ж";s:3:"186";s:5:"п о";s:3:"187";s:5:"р б";s:3:"188";s:6:"рия";s:3:"189";s:6:"рла";s:3:"190";s:6:"уда";s:3:"191";s:6:"шыл";s:3:"192";s:5:"ы а";s:3:"193";s:6:"ықт";s:3:"194";s:5:"і а";s:3:"195";s:5:"і б";s:3:"196";s:5:"із ";s:3:"197";s:6:"ілі";s:3:"198";s:5:"ң қ";s:3:"199";s:5:" ас";s:3:"200";s:5:" ек";s:3:"201";s:5:" жо";s:3:"202";s:5:" мә";s:3:"203";s:5:" ос";s:3:"204";s:5:" ре";s:3:"205";s:5:" се";s:3:"206";s:6:"алд";s:3:"207";s:6:"дал";s:3:"208";s:6:"дег";s:3:"209";s:6:"дей";s:3:"210";s:5:"е б";s:3:"211";s:5:"ет ";s:3:"212";s:6:"жас";s:3:"213";s:5:"й б";s:3:"214";s:6:"лау";s:3:"215";s:6:"лда";s:3:"216";s:6:"мет";s:3:"217";s:6:"нын";s:3:"218";s:6:"сар";s:3:"219";s:5:"сі ";s:3:"220";s:5:"ті ";s:3:"221";s:6:"ыры";s:3:"222";s:6:"ыта";s:3:"223";s:6:"ісі";s:3:"224";s:5:"ң а";s:3:"225";s:6:"өте";s:3:"226";s:5:" ат";s:3:"227";s:5:" ел";s:3:"228";s:5:" жү";s:3:"229";s:5:" ма";s:3:"230";s:5:" то";s:3:"231";s:5:" шы";s:3:"232";s:5:"а а";s:3:"233";s:6:"алт";s:3:"234";s:6:"ама";s:3:"235";s:6:"арл";s:3:"236";s:6:"аст";s:3:"237";s:6:"бұл";s:3:"238";s:6:"дай";s:3:"239";s:6:"дық";s:3:"240";s:5:"ек ";s:3:"241";s:6:"ель";s:3:"242";s:6:"есі";s:3:"243";s:6:"зді";s:3:"244";s:6:"көт";s:3:"245";s:6:"лем";s:3:"246";s:5:"ль ";s:3:"247";s:5:"н е";s:3:"248";s:5:"п а";s:3:"249";s:5:"р а";s:3:"250";s:6:"рес";s:3:"251";s:5:"са ";s:3:"252";s:5:"та ";s:3:"253";s:6:"тте";s:3:"254";s:6:"тұр";s:3:"255";s:5:"шы ";s:3:"256";s:5:"ы д";s:3:"257";s:5:"ы қ";s:3:"258";s:5:"ыз ";s:3:"259";s:6:"қыт";s:3:"260";s:5:" ко";s:3:"261";s:5:" не";s:3:"262";s:5:" ой";s:3:"263";s:5:" ор";s:3:"264";s:5:" сұ";s:3:"265";s:5:" тү";s:3:"266";s:6:"аль";s:3:"267";s:6:"аре";s:3:"268";s:6:"атт";s:3:"269";s:6:"дір";s:3:"270";s:5:"ев ";s:3:"271";s:6:"егі";s:3:"272";s:6:"еда";s:3:"273";s:6:"екі";s:3:"274";s:6:"елд";s:3:"275";s:6:"ерг";s:3:"276";s:6:"ерд";s:3:"277";s:6:"ияд";s:3:"278";s:6:"кер";s:3:"279";s:6:"кет";s:3:"280";s:6:"лыс";s:3:"281";s:6:"ліс";s:3:"282";s:6:"мед";s:3:"283";s:6:"мпи";s:3:"284";s:5:"н д";s:3:"285";s:5:"ні ";s:3:"286";s:6:"нін";s:3:"287";s:5:"п т";s:3:"288";s:6:"пек";s:3:"289";s:6:"рел";s:3:"290";s:6:"рта";s:3:"291";s:6:"ріл";s:3:"292";s:6:"рін";s:3:"293";s:6:"сен";s:3:"294";s:6:"тал";s:3:"295";s:6:"шіл";s:3:"296";s:5:"ы к";s:3:"297";s:5:"ы м";s:3:"298";s:6:"ыст";s:3:"299";}s:6:"kyrgyz";a:300:{s:5:"ын ";s:1:"0";s:5:"ан ";s:1:"1";s:5:" жа";s:1:"2";s:5:"ен ";s:1:"3";s:5:"да ";s:1:"4";s:5:" та";s:1:"5";s:5:"ар ";s:1:"6";s:5:"ин ";s:1:"7";s:5:" ка";s:1:"8";s:6:"ары";s:1:"9";s:5:" ал";s:2:"10";s:5:" ба";s:2:"11";s:5:" би";s:2:"12";s:6:"лар";s:2:"13";s:5:" бо";s:2:"14";s:5:" кы";s:2:"15";s:6:"ала";s:2:"16";s:5:"н к";s:2:"17";s:5:" са";s:2:"18";s:6:"нда";s:2:"19";s:6:"ган";s:2:"20";s:6:"тар";s:2:"21";s:5:" де";s:2:"22";s:6:"анд";s:2:"23";s:5:"н б";s:2:"24";s:5:" ке";s:2:"25";s:6:"ард";s:2:"26";s:6:"мен";s:2:"27";s:5:"н т";s:2:"28";s:6:"ара";s:2:"29";s:6:"нын";s:2:"30";s:5:" да";s:2:"31";s:5:" ме";s:2:"32";s:6:"кыр";s:2:"33";s:5:" че";s:2:"34";s:5:"н а";s:2:"35";s:5:"ры ";s:2:"36";s:5:" ко";s:2:"37";s:6:"ген";s:2:"38";s:6:"дар";s:2:"39";s:6:"кен";s:2:"40";s:6:"кта";s:2:"41";s:5:"уу ";s:2:"42";s:6:"ене";s:2:"43";s:6:"ери";s:2:"44";s:5:" ша";s:2:"45";s:6:"алы";s:2:"46";s:5:"ат ";s:2:"47";s:5:"на ";s:2:"48";s:5:" кө";s:2:"49";s:5:" эм";s:2:"50";s:6:"аты";s:2:"51";s:6:"дан";s:2:"52";s:6:"деп";s:2:"53";s:6:"дын";s:2:"54";s:5:"еп ";s:2:"55";s:6:"нен";s:2:"56";s:6:"рын";s:2:"57";s:5:" бе";s:2:"58";s:6:"кан";s:2:"59";s:6:"луу";s:2:"60";s:6:"ргы";s:2:"61";s:6:"тан";s:2:"62";s:6:"шай";s:2:"63";s:6:"ырг";s:2:"64";s:5:"үн ";s:2:"65";s:5:" ар";s:2:"66";s:5:" ма";s:2:"67";s:6:"агы";s:2:"68";s:6:"акт";s:2:"69";s:6:"аны";s:2:"70";s:5:"гы ";s:2:"71";s:6:"гыз";s:2:"72";s:5:"ды ";s:2:"73";s:6:"рда";s:2:"74";s:5:"ай ";s:2:"75";s:6:"бир";s:2:"76";s:6:"бол";s:2:"77";s:5:"ер ";s:2:"78";s:5:"н с";s:2:"79";s:6:"нды";s:2:"80";s:5:"ун ";s:2:"81";s:5:"ча ";s:2:"82";s:6:"ынд";s:2:"83";s:5:"а к";s:2:"84";s:6:"ага";s:2:"85";s:6:"айл";s:2:"86";s:6:"ана";s:2:"87";s:5:"ап ";s:2:"88";s:5:"га ";s:2:"89";s:6:"лге";s:2:"90";s:6:"нча";s:2:"91";s:5:"п к";s:2:"92";s:6:"рды";s:2:"93";s:6:"туу";s:2:"94";s:6:"ыны";s:2:"95";s:5:" ан";s:2:"96";s:5:" өз";s:2:"97";s:6:"ама";s:2:"98";s:6:"ата";s:2:"99";s:6:"дин";s:3:"100";s:5:"йт ";s:3:"101";s:6:"лга";s:3:"102";s:6:"лоо";s:3:"103";s:5:"оо ";s:3:"104";s:5:"ри ";s:3:"105";s:6:"тин";s:3:"106";s:5:"ыз ";s:3:"107";s:5:"ып ";s:3:"108";s:6:"өрү";s:3:"109";s:5:" па";s:3:"110";s:5:" эк";s:3:"111";s:5:"а б";s:3:"112";s:6:"алг";s:3:"113";s:6:"асы";s:3:"114";s:6:"ашт";s:3:"115";s:6:"биз";s:3:"116";s:6:"кел";s:3:"117";s:6:"кте";s:3:"118";s:6:"тал";s:3:"119";s:5:" не";s:3:"120";s:5:" су";s:3:"121";s:6:"акы";s:3:"122";s:6:"ент";s:3:"123";s:6:"инд";s:3:"124";s:5:"ир ";s:3:"125";s:6:"кал";s:3:"126";s:5:"н д";s:3:"127";s:6:"нде";s:3:"128";s:6:"ого";s:3:"129";s:6:"онд";s:3:"130";s:6:"оюн";s:3:"131";s:5:"р б";s:3:"132";s:5:"р м";s:3:"133";s:6:"ран";s:3:"134";s:6:"сал";s:3:"135";s:6:"ста";s:3:"136";s:5:"сы ";s:3:"137";s:6:"ура";s:3:"138";s:6:"ыгы";s:3:"139";s:5:" аш";s:3:"140";s:5:" ми";s:3:"141";s:5:" сы";s:3:"142";s:5:" ту";s:3:"143";s:5:"ал ";s:3:"144";s:6:"арт";s:3:"145";s:6:"бор";s:3:"146";s:6:"елг";s:3:"147";s:6:"ени";s:3:"148";s:5:"ет ";s:3:"149";s:6:"жат";s:3:"150";s:6:"йло";s:3:"151";s:6:"кар";s:3:"152";s:5:"н м";s:3:"153";s:6:"огу";s:3:"154";s:5:"п а";s:3:"155";s:5:"п ж";s:3:"156";s:5:"р э";s:3:"157";s:6:"сын";s:3:"158";s:5:"ык ";s:3:"159";s:6:"юнч";s:3:"160";s:5:" бу";s:3:"161";s:5:" ур";s:3:"162";s:5:"а а";s:3:"163";s:5:"ак ";s:3:"164";s:6:"алд";s:3:"165";s:6:"алу";s:3:"166";s:6:"бар";s:3:"167";s:6:"бер";s:3:"168";s:6:"бою";s:3:"169";s:5:"ге ";s:3:"170";s:6:"дон";s:3:"171";s:6:"еги";s:3:"172";s:6:"ект";s:3:"173";s:6:"ефт";s:3:"174";s:5:"из ";s:3:"175";s:6:"кат";s:3:"176";s:6:"лды";s:3:"177";s:5:"н ч";s:3:"178";s:5:"н э";s:3:"179";s:5:"н ө";s:3:"180";s:6:"ндо";s:3:"181";s:6:"неф";s:3:"182";s:5:"он ";s:3:"183";s:6:"сат";s:3:"184";s:6:"тор";s:3:"185";s:5:"ты ";s:3:"186";s:6:"уда";s:3:"187";s:5:"ул ";s:3:"188";s:6:"ула";s:3:"189";s:6:"ууд";s:3:"190";s:5:"ы б";s:3:"191";s:5:"ы ж";s:3:"192";s:5:"ы к";s:3:"193";s:5:"ыл ";s:3:"194";s:6:"ына";s:3:"195";s:6:"эке";s:3:"196";s:6:"ясы";s:3:"197";s:5:" ат";s:3:"198";s:5:" до";s:3:"199";s:5:" жы";s:3:"200";s:5:" со";s:3:"201";s:5:" чы";s:3:"202";s:6:"аас";s:3:"203";s:6:"айт";s:3:"204";s:6:"аст";s:3:"205";s:6:"баа";s:3:"206";s:6:"баш";s:3:"207";s:6:"гар";s:3:"208";s:6:"гын";s:3:"209";s:5:"дө ";s:3:"210";s:5:"е б";s:3:"211";s:5:"ек ";s:3:"212";s:6:"жыл";s:3:"213";s:5:"и б";s:3:"214";s:5:"ик ";s:3:"215";s:6:"ияс";s:3:"216";s:6:"кыз";s:3:"217";s:6:"лда";s:3:"218";s:6:"лык";s:3:"219";s:6:"мда";s:3:"220";s:5:"н ж";s:3:"221";s:6:"нди";s:3:"222";s:5:"ни ";s:3:"223";s:6:"нин";s:3:"224";s:6:"орд";s:3:"225";s:6:"рдо";s:3:"226";s:6:"сто";s:3:"227";s:5:"та ";s:3:"228";s:6:"тер";s:3:"229";s:6:"тти";s:3:"230";s:6:"тур";s:3:"231";s:6:"тын";s:3:"232";s:5:"уп ";s:3:"233";s:6:"ушу";s:3:"234";s:6:"фти";s:3:"235";s:6:"ыкт";s:3:"236";s:5:"үп ";s:3:"237";s:5:"өн ";s:3:"238";s:5:" ай";s:3:"239";s:5:" бү";s:3:"240";s:5:" ич";s:3:"241";s:5:" иш";s:3:"242";s:5:" мо";s:3:"243";s:5:" пр";s:3:"244";s:5:" ре";s:3:"245";s:5:" өк";s:3:"246";s:5:" өт";s:3:"247";s:5:"а д";s:3:"248";s:5:"а у";s:3:"249";s:5:"а э";s:3:"250";s:6:"айм";s:3:"251";s:6:"амд";s:3:"252";s:6:"атт";s:3:"253";s:6:"бек";s:3:"254";s:6:"бул";s:3:"255";s:6:"гол";s:3:"256";s:6:"дег";s:3:"257";s:6:"еге";s:3:"258";s:6:"ейт";s:3:"259";s:6:"еле";s:3:"260";s:6:"енд";s:3:"261";s:6:"жак";s:3:"262";s:5:"и к";s:3:"263";s:6:"ини";s:3:"264";s:6:"ири";s:3:"265";s:6:"йма";s:3:"266";s:6:"кто";s:3:"267";s:6:"лик";s:3:"268";s:6:"мак";s:3:"269";s:6:"мес";s:3:"270";s:5:"н у";s:3:"271";s:5:"н ш";s:3:"272";s:6:"нтт";s:3:"273";s:5:"ол ";s:3:"274";s:6:"оло";s:3:"275";s:6:"пар";s:3:"276";s:6:"рак";s:3:"277";s:6:"рүү";s:3:"278";s:6:"сыр";s:3:"279";s:5:"ти ";s:3:"280";s:6:"тик";s:3:"281";s:6:"тта";s:3:"282";s:6:"төр";s:3:"283";s:5:"у ж";s:3:"284";s:5:"у с";s:3:"285";s:6:"шка";s:3:"286";s:5:"ы м";s:3:"287";s:6:"ызы";s:3:"288";s:6:"ылд";s:3:"289";s:6:"эме";s:3:"290";s:6:"үрү";s:3:"291";s:6:"өлү";s:3:"292";s:6:"өтө";s:3:"293";s:5:" же";s:3:"294";s:5:" тү";s:3:"295";s:5:" эл";s:3:"296";s:5:" өн";s:3:"297";s:5:"а ж";s:3:"298";s:6:"ады";s:3:"299";}s:5:"latin";a:300:{s:3:"um ";s:1:"0";s:3:"us ";s:1:"1";s:3:"ut ";s:1:"2";s:3:"et ";s:1:"3";s:3:"is ";s:1:"4";s:3:" et";s:1:"5";s:3:" in";s:1:"6";s:3:" qu";s:1:"7";s:3:"tur";s:1:"8";s:3:" pr";s:1:"9";s:3:"est";s:2:"10";s:3:"tio";s:2:"11";s:3:" au";s:2:"12";s:3:"am ";s:2:"13";s:3:"em ";s:2:"14";s:3:"aut";s:2:"15";s:3:" di";s:2:"16";s:3:"ent";s:2:"17";s:3:"in ";s:2:"18";s:3:"dic";s:2:"19";s:3:"t e";s:2:"20";s:3:" es";s:2:"21";s:3:"ur ";s:2:"22";s:3:"ati";s:2:"23";s:3:"ion";s:2:"24";s:3:"st ";s:2:"25";s:3:" ut";s:2:"26";s:3:"ae ";s:2:"27";s:3:"qua";s:2:"28";s:3:" de";s:2:"29";s:3:"nt ";s:2:"30";s:3:" su";s:2:"31";s:3:" si";s:2:"32";s:3:"itu";s:2:"33";s:3:"unt";s:2:"34";s:3:"rum";s:2:"35";s:3:"ia ";s:2:"36";s:3:"es ";s:2:"37";s:3:"ter";s:2:"38";s:3:" re";s:2:"39";s:3:"nti";s:2:"40";s:3:"rae";s:2:"41";s:3:"s e";s:2:"42";s:3:"qui";s:2:"43";s:3:"io ";s:2:"44";s:3:"pro";s:2:"45";s:3:"it ";s:2:"46";s:3:"per";s:2:"47";s:3:"ita";s:2:"48";s:3:"one";s:2:"49";s:3:"ici";s:2:"50";s:3:"ius";s:2:"51";s:3:" co";s:2:"52";s:3:"t d";s:2:"53";s:3:"bus";s:2:"54";s:3:"pra";s:2:"55";s:3:"m e";s:2:"56";s:3:" no";s:2:"57";s:3:"edi";s:2:"58";s:3:"tia";s:2:"59";s:3:"ue ";s:2:"60";s:3:"ibu";s:2:"61";s:3:" se";s:2:"62";s:3:" ad";s:2:"63";s:3:"er ";s:2:"64";s:3:" fi";s:2:"65";s:3:"ili";s:2:"66";s:3:"que";s:2:"67";s:3:"t i";s:2:"68";s:3:"de ";s:2:"69";s:3:"oru";s:2:"70";s:3:" te";s:2:"71";s:3:"ali";s:2:"72";s:3:" pe";s:2:"73";s:3:"aed";s:2:"74";s:3:"cit";s:2:"75";s:3:"m d";s:2:"76";s:3:"t s";s:2:"77";s:3:"tat";s:2:"78";s:3:"tem";s:2:"79";s:3:"tis";s:2:"80";s:3:"t p";s:2:"81";s:3:"sti";s:2:"82";s:3:"te ";s:2:"83";s:3:"cum";s:2:"84";s:3:"ere";s:2:"85";s:3:"ium";s:2:"86";s:3:" ex";s:2:"87";s:3:"rat";s:2:"88";s:3:"ta ";s:2:"89";s:3:"con";s:2:"90";s:3:"cti";s:2:"91";s:3:"oni";s:2:"92";s:3:"ra ";s:2:"93";s:3:"s i";s:2:"94";s:3:" cu";s:2:"95";s:3:" sa";s:2:"96";s:3:"eni";s:2:"97";s:3:"nis";s:2:"98";s:3:"nte";s:2:"99";s:3:"eri";s:3:"100";s:3:"omi";s:3:"101";s:3:"re ";s:3:"102";s:3:"s a";s:3:"103";s:3:"min";s:3:"104";s:3:"os ";s:3:"105";s:3:"ti ";s:3:"106";s:3:"uer";s:3:"107";s:3:" ma";s:3:"108";s:3:" ue";s:3:"109";s:3:"m s";s:3:"110";s:3:"nem";s:3:"111";s:3:"t m";s:3:"112";s:3:" mo";s:3:"113";s:3:" po";s:3:"114";s:3:" ui";s:3:"115";s:3:"gen";s:3:"116";s:3:"ict";s:3:"117";s:3:"m i";s:3:"118";s:3:"ris";s:3:"119";s:3:"s s";s:3:"120";s:3:"t a";s:3:"121";s:3:"uae";s:3:"122";s:3:" do";s:3:"123";s:3:"m a";s:3:"124";s:3:"t c";s:3:"125";s:3:" ge";s:3:"126";s:3:"as ";s:3:"127";s:3:"e i";s:3:"128";s:3:"e p";s:3:"129";s:3:"ne ";s:3:"130";s:3:" ca";s:3:"131";s:3:"ine";s:3:"132";s:3:"quo";s:3:"133";s:3:"s p";s:3:"134";s:3:" al";s:3:"135";s:3:"e e";s:3:"136";s:3:"ntu";s:3:"137";s:3:"ro ";s:3:"138";s:3:"tri";s:3:"139";s:3:"tus";s:3:"140";s:3:"uit";s:3:"141";s:3:"atu";s:3:"142";s:3:"ini";s:3:"143";s:3:"iqu";s:3:"144";s:3:"m p";s:3:"145";s:3:"ost";s:3:"146";s:3:"res";s:3:"147";s:3:"ura";s:3:"148";s:3:" ac";s:3:"149";s:3:" fu";s:3:"150";s:3:"a e";s:3:"151";s:3:"ant";s:3:"152";s:3:"nes";s:3:"153";s:3:"nim";s:3:"154";s:3:"sun";s:3:"155";s:3:"tra";s:3:"156";s:3:"e a";s:3:"157";s:3:"s d";s:3:"158";s:3:" pa";s:3:"159";s:3:" uo";s:3:"160";s:3:"ecu";s:3:"161";s:3:" om";s:3:"162";s:3:" tu";s:3:"163";s:3:"ad ";s:3:"164";s:3:"cut";s:3:"165";s:3:"omn";s:3:"166";s:3:"s q";s:3:"167";s:3:" ei";s:3:"168";s:3:"ex ";s:3:"169";s:3:"icu";s:3:"170";s:3:"tor";s:3:"171";s:3:"uid";s:3:"172";s:3:" ip";s:3:"173";s:3:" me";s:3:"174";s:3:"e s";s:3:"175";s:3:"era";s:3:"176";s:3:"eru";s:3:"177";s:3:"iam";s:3:"178";s:3:"ide";s:3:"179";s:3:"ips";s:3:"180";s:3:" iu";s:3:"181";s:3:"a s";s:3:"182";s:3:"do ";s:3:"183";s:3:"e d";s:3:"184";s:3:"eiu";s:3:"185";s:3:"ica";s:3:"186";s:3:"im ";s:3:"187";s:3:"m c";s:3:"188";s:3:"m u";s:3:"189";s:3:"tiu";s:3:"190";s:3:" ho";s:3:"191";s:3:"cat";s:3:"192";s:3:"ist";s:3:"193";s:3:"nat";s:3:"194";s:3:"on ";s:3:"195";s:3:"pti";s:3:"196";s:3:"reg";s:3:"197";s:3:"rit";s:3:"198";s:3:"s t";s:3:"199";s:3:"sic";s:3:"200";s:3:"spe";s:3:"201";s:3:" en";s:3:"202";s:3:" sp";s:3:"203";s:3:"dis";s:3:"204";s:3:"eli";s:3:"205";s:3:"liq";s:3:"206";s:3:"lis";s:3:"207";s:3:"men";s:3:"208";s:3:"mus";s:3:"209";s:3:"num";s:3:"210";s:3:"pos";s:3:"211";s:3:"sio";s:3:"212";s:3:" an";s:3:"213";s:3:" gr";s:3:"214";s:3:"abi";s:3:"215";s:3:"acc";s:3:"216";s:3:"ect";s:3:"217";s:3:"ri ";s:3:"218";s:3:"uan";s:3:"219";s:3:" le";s:3:"220";s:3:"ecc";s:3:"221";s:3:"ete";s:3:"222";s:3:"gra";s:3:"223";s:3:"non";s:3:"224";s:3:"se ";s:3:"225";s:3:"uen";s:3:"226";s:3:"uis";s:3:"227";s:3:" fa";s:3:"228";s:3:" tr";s:3:"229";s:3:"ate";s:3:"230";s:3:"e c";s:3:"231";s:3:"fil";s:3:"232";s:3:"na ";s:3:"233";s:3:"ni ";s:3:"234";s:3:"pul";s:3:"235";s:3:"s f";s:3:"236";s:3:"ui ";s:3:"237";s:3:"at ";s:3:"238";s:3:"cce";s:3:"239";s:3:"dam";s:3:"240";s:3:"i e";s:3:"241";s:3:"ina";s:3:"242";s:3:"leg";s:3:"243";s:3:"nos";s:3:"244";s:3:"ori";s:3:"245";s:3:"pec";s:3:"246";s:3:"rop";s:3:"247";s:3:"sta";s:3:"248";s:3:"uia";s:3:"249";s:3:"ene";s:3:"250";s:3:"iue";s:3:"251";s:3:"iui";s:3:"252";s:3:"siu";s:3:"253";s:3:"t t";s:3:"254";s:3:"t u";s:3:"255";s:3:"tib";s:3:"256";s:3:"tit";s:3:"257";s:3:" da";s:3:"258";s:3:" ne";s:3:"259";s:3:"a d";s:3:"260";s:3:"and";s:3:"261";s:3:"ege";s:3:"262";s:3:"equ";s:3:"263";s:3:"hom";s:3:"264";s:3:"imu";s:3:"265";s:3:"lor";s:3:"266";s:3:"m m";s:3:"267";s:3:"mni";s:3:"268";s:3:"ndo";s:3:"269";s:3:"ner";s:3:"270";s:3:"o e";s:3:"271";s:3:"r e";s:3:"272";s:3:"sit";s:3:"273";s:3:"tum";s:3:"274";s:3:"utu";s:3:"275";s:3:"a p";s:3:"276";s:3:"bis";s:3:"277";s:3:"bit";s:3:"278";s:3:"cer";s:3:"279";s:3:"cta";s:3:"280";s:3:"dom";s:3:"281";s:3:"fut";s:3:"282";s:3:"i s";s:3:"283";s:3:"ign";s:3:"284";s:3:"int";s:3:"285";s:3:"mod";s:3:"286";s:3:"ndu";s:3:"287";s:3:"nit";s:3:"288";s:3:"rib";s:3:"289";s:3:"rti";s:3:"290";s:3:"tas";s:3:"291";s:3:"und";s:3:"292";s:3:" ab";s:3:"293";s:3:"err";s:3:"294";s:3:"ers";s:3:"295";s:3:"ite";s:3:"296";s:3:"iti";s:3:"297";s:3:"m t";s:3:"298";s:3:"o p";s:3:"299";}s:7:"latvian";a:300:{s:3:"as ";s:1:"0";s:3:" la";s:1:"1";s:3:" pa";s:1:"2";s:3:" ne";s:1:"3";s:3:"es ";s:1:"4";s:3:" un";s:1:"5";s:3:"un ";s:1:"6";s:3:" ka";s:1:"7";s:3:" va";s:1:"8";s:3:"ar ";s:1:"9";s:3:"s p";s:2:"10";s:3:" ar";s:2:"11";s:3:" vi";s:2:"12";s:3:"is ";s:2:"13";s:3:"ai ";s:2:"14";s:3:" no";s:2:"15";s:3:"ja ";s:2:"16";s:3:"ija";s:2:"17";s:3:"iem";s:2:"18";s:3:"em ";s:2:"19";s:3:"tu ";s:2:"20";s:3:"tie";s:2:"21";s:3:"vie";s:2:"22";s:3:"lat";s:2:"23";s:3:"aks";s:2:"24";s:3:"ien";s:2:"25";s:3:"kst";s:2:"26";s:3:"ies";s:2:"27";s:3:"s a";s:2:"28";s:3:"rak";s:2:"29";s:3:"atv";s:2:"30";s:3:"tvi";s:2:"31";s:3:" ja";s:2:"32";s:3:" pi";s:2:"33";s:3:"ka ";s:2:"34";s:3:" ir";s:2:"35";s:3:"ir ";s:2:"36";s:3:"ta ";s:2:"37";s:3:" sa";s:2:"38";s:3:"ts ";s:2:"39";s:4:" kā";s:2:"40";s:4:"ās ";s:2:"41";s:3:" ti";s:2:"42";s:3:"ot ";s:2:"43";s:3:"s n";s:2:"44";s:3:" ie";s:2:"45";s:3:" ta";s:2:"46";s:4:"arī";s:2:"47";s:3:"par";s:2:"48";s:3:"pie";s:2:"49";s:3:" pr";s:2:"50";s:4:"kā ";s:2:"51";s:3:" at";s:2:"52";s:3:" ra";s:2:"53";s:3:"am ";s:2:"54";s:4:"inā";s:2:"55";s:4:"tā ";s:2:"56";s:3:" iz";s:2:"57";s:3:"jas";s:2:"58";s:3:"lai";s:2:"59";s:3:" na";s:2:"60";s:3:"aut";s:2:"61";s:4:"ieš";s:2:"62";s:3:"s s";s:2:"63";s:3:" ap";s:2:"64";s:3:" ko";s:2:"65";s:3:" st";s:2:"66";s:3:"iek";s:2:"67";s:3:"iet";s:2:"68";s:3:"jau";s:2:"69";s:3:"us ";s:2:"70";s:4:"rī ";s:2:"71";s:3:"tik";s:2:"72";s:4:"ība";s:2:"73";s:3:"na ";s:2:"74";s:3:" ga";s:2:"75";s:3:"cij";s:2:"76";s:3:"s i";s:2:"77";s:3:" uz";s:2:"78";s:3:"jum";s:2:"79";s:3:"s v";s:2:"80";s:3:"ms ";s:2:"81";s:3:"var";s:2:"82";s:3:" ku";s:2:"83";s:3:" ma";s:2:"84";s:4:"jā ";s:2:"85";s:3:"sta";s:2:"86";s:3:"s u";s:2:"87";s:4:" tā";s:2:"88";s:3:"die";s:2:"89";s:3:"kai";s:2:"90";s:3:"kas";s:2:"91";s:3:"ska";s:2:"92";s:3:" ci";s:2:"93";s:3:" da";s:2:"94";s:3:"kur";s:2:"95";s:3:"lie";s:2:"96";s:3:"tas";s:2:"97";s:3:"a p";s:2:"98";s:3:"est";s:2:"99";s:4:"stā";s:3:"100";s:4:"šan";s:3:"101";s:3:"nes";s:3:"102";s:3:"nie";s:3:"103";s:3:"s d";s:3:"104";s:3:"s m";s:3:"105";s:3:"val";s:3:"106";s:3:" di";s:3:"107";s:3:" es";s:3:"108";s:3:" re";s:3:"109";s:3:"no ";s:3:"110";s:3:"to ";s:3:"111";s:3:"umu";s:3:"112";s:3:"vai";s:3:"113";s:4:"ši ";s:3:"114";s:4:" vē";s:3:"115";s:3:"kum";s:3:"116";s:3:"nu ";s:3:"117";s:3:"rie";s:3:"118";s:3:"s t";s:3:"119";s:4:"ām ";s:3:"120";s:3:"ad ";s:3:"121";s:3:"et ";s:3:"122";s:3:"mu ";s:3:"123";s:3:"s l";s:3:"124";s:3:" be";s:3:"125";s:3:"aud";s:3:"126";s:3:"tur";s:3:"127";s:3:"vij";s:3:"128";s:4:"viņ";s:3:"129";s:4:"āju";s:3:"130";s:3:"bas";s:3:"131";s:3:"gad";s:3:"132";s:3:"i n";s:3:"133";s:3:"ika";s:3:"134";s:3:"os ";s:3:"135";s:3:"a v";s:3:"136";s:3:"not";s:3:"137";s:3:"oti";s:3:"138";s:3:"sts";s:3:"139";s:3:"aik";s:3:"140";s:3:"u a";s:3:"141";s:4:"ā a";s:3:"142";s:4:"āk ";s:3:"143";s:3:" to";s:3:"144";s:3:"ied";s:3:"145";s:3:"stu";s:3:"146";s:3:"ti ";s:3:"147";s:3:"u p";s:3:"148";s:4:"vēl";s:3:"149";s:4:"āci";s:3:"150";s:4:" šo";s:3:"151";s:3:"gi ";s:3:"152";s:3:"ko ";s:3:"153";s:3:"pro";s:3:"154";s:3:"s r";s:3:"155";s:4:"tāj";s:3:"156";s:3:"u s";s:3:"157";s:3:"u v";s:3:"158";s:3:"vis";s:3:"159";s:3:"aun";s:3:"160";s:3:"ks ";s:3:"161";s:3:"str";s:3:"162";s:3:"zin";s:3:"163";s:3:"a a";s:3:"164";s:4:"adī";s:3:"165";s:3:"da ";s:3:"166";s:3:"dar";s:3:"167";s:3:"ena";s:3:"168";s:3:"ici";s:3:"169";s:3:"kra";s:3:"170";s:3:"nas";s:3:"171";s:4:"stī";s:3:"172";s:4:"šu ";s:3:"173";s:4:" mē";s:3:"174";s:3:"a n";s:3:"175";s:3:"eci";s:3:"176";s:3:"i s";s:3:"177";s:3:"ie ";s:3:"178";s:4:"iņa";s:3:"179";s:3:"ju ";s:3:"180";s:3:"las";s:3:"181";s:3:"r t";s:3:"182";s:3:"ums";s:3:"183";s:4:"šie";s:3:"184";s:3:"bu ";s:3:"185";s:3:"cit";s:3:"186";s:3:"i a";s:3:"187";s:3:"ina";s:3:"188";s:3:"ma ";s:3:"189";s:3:"pus";s:3:"190";s:3:"ra ";s:3:"191";s:3:" au";s:3:"192";s:3:" se";s:3:"193";s:3:" sl";s:3:"194";s:3:"a s";s:3:"195";s:3:"ais";s:3:"196";s:4:"eši";s:3:"197";s:3:"iec";s:3:"198";s:3:"iku";s:3:"199";s:4:"pār";s:3:"200";s:3:"s b";s:3:"201";s:3:"s k";s:3:"202";s:3:"sot";s:3:"203";s:5:"ādā";s:3:"204";s:3:" in";s:3:"205";s:3:" li";s:3:"206";s:3:" tr";s:3:"207";s:3:"ana";s:3:"208";s:3:"eso";s:3:"209";s:3:"ikr";s:3:"210";s:3:"man";s:3:"211";s:3:"ne ";s:3:"212";s:3:"u k";s:3:"213";s:3:" tu";s:3:"214";s:3:"an ";s:3:"215";s:3:"av ";s:3:"216";s:3:"bet";s:3:"217";s:4:"būt";s:3:"218";s:3:"im ";s:3:"219";s:3:"isk";s:3:"220";s:4:"līd";s:3:"221";s:3:"nav";s:3:"222";s:3:"ras";s:3:"223";s:3:"ri ";s:3:"224";s:3:"s g";s:3:"225";s:3:"sti";s:3:"226";s:4:"īdz";s:3:"227";s:3:" ai";s:3:"228";s:3:"arb";s:3:"229";s:3:"cin";s:3:"230";s:3:"das";s:3:"231";s:3:"ent";s:3:"232";s:3:"gal";s:3:"233";s:3:"i p";s:3:"234";s:3:"lik";s:3:"235";s:4:"mā ";s:3:"236";s:3:"nek";s:3:"237";s:3:"pat";s:3:"238";s:4:"rēt";s:3:"239";s:3:"si ";s:3:"240";s:3:"tra";s:3:"241";s:4:"uši";s:3:"242";s:3:"vei";s:3:"243";s:3:" br";s:3:"244";s:3:" pu";s:3:"245";s:3:" sk";s:3:"246";s:3:"als";s:3:"247";s:3:"ama";s:3:"248";s:3:"edz";s:3:"249";s:3:"eka";s:3:"250";s:4:"ešu";s:3:"251";s:3:"ieg";s:3:"252";s:3:"jis";s:3:"253";s:3:"kam";s:3:"254";s:3:"lst";s:3:"255";s:4:"nāk";s:3:"256";s:3:"oli";s:3:"257";s:3:"pre";s:3:"258";s:4:"pēc";s:3:"259";s:3:"rot";s:3:"260";s:4:"tās";s:3:"261";s:3:"usi";s:3:"262";s:4:"ēl ";s:3:"263";s:4:"ēs ";s:3:"264";s:3:" bi";s:3:"265";s:3:" de";s:3:"266";s:3:" me";s:3:"267";s:4:" pā";s:3:"268";s:3:"a i";s:3:"269";s:3:"aid";s:3:"270";s:4:"ajā";s:3:"271";s:3:"ikt";s:3:"272";s:3:"kat";s:3:"273";s:3:"lic";s:3:"274";s:3:"lod";s:3:"275";s:3:"mi ";s:3:"276";s:3:"ni ";s:3:"277";s:3:"pri";s:3:"278";s:4:"rād";s:3:"279";s:4:"rīg";s:3:"280";s:3:"sim";s:3:"281";s:4:"trā";s:3:"282";s:3:"u l";s:3:"283";s:3:"uto";s:3:"284";s:3:"uz ";s:3:"285";s:4:"ēc ";s:3:"286";s:5:"ītā";s:3:"287";s:3:" ce";s:3:"288";s:4:" jā";s:3:"289";s:3:" sv";s:3:"290";s:3:"a t";s:3:"291";s:3:"aga";s:3:"292";s:3:"aiz";s:3:"293";s:3:"atu";s:3:"294";s:3:"ba ";s:3:"295";s:3:"cie";s:3:"296";s:3:"du ";s:3:"297";s:3:"dzi";s:3:"298";s:4:"dzī";s:3:"299";}s:10:"lithuanian";a:300:{s:3:"as ";s:1:"0";s:3:" pa";s:1:"1";s:3:" ka";s:1:"2";s:3:"ai ";s:1:"3";s:3:"us ";s:1:"4";s:3:"os ";s:1:"5";s:3:"is ";s:1:"6";s:3:" ne";s:1:"7";s:3:" ir";s:1:"8";s:3:"ir ";s:1:"9";s:3:"ti ";s:2:"10";s:3:" pr";s:2:"11";s:3:"aus";s:2:"12";s:3:"ini";s:2:"13";s:3:"s p";s:2:"14";s:3:"pas";s:2:"15";s:4:"ių ";s:2:"16";s:3:" ta";s:2:"17";s:3:" vi";s:2:"18";s:3:"iau";s:2:"19";s:3:" ko";s:2:"20";s:3:" su";s:2:"21";s:3:"kai";s:2:"22";s:3:"o p";s:2:"23";s:3:"usi";s:2:"24";s:3:" sa";s:2:"25";s:3:"vo ";s:2:"26";s:3:"tai";s:2:"27";s:3:"ali";s:2:"28";s:4:"tų ";s:2:"29";s:3:"io ";s:2:"30";s:3:"jo ";s:2:"31";s:3:"s k";s:2:"32";s:3:"sta";s:2:"33";s:3:"iai";s:2:"34";s:3:" bu";s:2:"35";s:3:" nu";s:2:"36";s:3:"ius";s:2:"37";s:3:"mo ";s:2:"38";s:3:" po";s:2:"39";s:3:"ien";s:2:"40";s:3:"s s";s:2:"41";s:3:"tas";s:2:"42";s:3:" me";s:2:"43";s:3:"uvo";s:2:"44";s:3:"kad";s:2:"45";s:4:" iš";s:2:"46";s:3:" la";s:2:"47";s:3:"to ";s:2:"48";s:3:"ais";s:2:"49";s:3:"ie ";s:2:"50";s:3:"kur";s:2:"51";s:3:"uri";s:2:"52";s:3:" ku";s:2:"53";s:3:"ijo";s:2:"54";s:4:"čia";s:2:"55";s:3:"au ";s:2:"56";s:3:"met";s:2:"57";s:3:"je ";s:2:"58";s:3:" va";s:2:"59";s:3:"ad ";s:2:"60";s:3:" ap";s:2:"61";s:3:"and";s:2:"62";s:3:" gr";s:2:"63";s:3:" ti";s:2:"64";s:3:"kal";s:2:"65";s:3:"asi";s:2:"66";s:3:"i p";s:2:"67";s:4:"iči";s:2:"68";s:3:"s i";s:2:"69";s:3:"s v";s:2:"70";s:3:"ink";s:2:"71";s:3:"o n";s:2:"72";s:4:"ės ";s:2:"73";s:3:"buv";s:2:"74";s:3:"s a";s:2:"75";s:3:" ga";s:2:"76";s:3:"aip";s:2:"77";s:3:"avi";s:2:"78";s:3:"mas";s:2:"79";s:3:"pri";s:2:"80";s:3:"tik";s:2:"81";s:3:" re";s:2:"82";s:3:"etu";s:2:"83";s:3:"jos";s:2:"84";s:3:" da";s:2:"85";s:3:"ent";s:2:"86";s:3:"oli";s:2:"87";s:3:"par";s:2:"88";s:3:"ant";s:2:"89";s:3:"ara";s:2:"90";s:3:"tar";s:2:"91";s:3:"ama";s:2:"92";s:3:"gal";s:2:"93";s:3:"imo";s:2:"94";s:4:"išk";s:2:"95";s:3:"o s";s:2:"96";s:3:" at";s:2:"97";s:3:" be";s:2:"98";s:4:" į ";s:2:"99";s:3:"min";s:3:"100";s:3:"tin";s:3:"101";s:3:" tu";s:3:"102";s:3:"s n";s:3:"103";s:3:" jo";s:3:"104";s:3:"dar";s:3:"105";s:3:"ip ";s:3:"106";s:3:"rei";s:3:"107";s:3:" te";s:3:"108";s:4:"dži";s:3:"109";s:3:"kas";s:3:"110";s:3:"nin";s:3:"111";s:3:"tei";s:3:"112";s:3:"vie";s:3:"113";s:3:" li";s:3:"114";s:3:" se";s:3:"115";s:3:"cij";s:3:"116";s:3:"gar";s:3:"117";s:3:"lai";s:3:"118";s:3:"art";s:3:"119";s:3:"lau";s:3:"120";s:3:"ras";s:3:"121";s:3:"no ";s:3:"122";s:3:"o k";s:3:"123";s:4:"tą ";s:3:"124";s:3:" ar";s:3:"125";s:4:"ėjo";s:3:"126";s:4:"vič";s:3:"127";s:3:"iga";s:3:"128";s:3:"pra";s:3:"129";s:3:"vis";s:3:"130";s:3:" na";s:3:"131";s:3:"men";s:3:"132";s:3:"oki";s:3:"133";s:4:"raš";s:3:"134";s:3:"s t";s:3:"135";s:3:"iet";s:3:"136";s:3:"ika";s:3:"137";s:3:"int";s:3:"138";s:3:"kom";s:3:"139";s:3:"tam";s:3:"140";s:3:"aug";s:3:"141";s:3:"avo";s:3:"142";s:3:"rie";s:3:"143";s:3:"s b";s:3:"144";s:3:" st";s:3:"145";s:3:"eim";s:3:"146";s:3:"ko ";s:3:"147";s:3:"nus";s:3:"148";s:3:"pol";s:3:"149";s:3:"ria";s:3:"150";s:3:"sau";s:3:"151";s:3:"api";s:3:"152";s:3:"me ";s:3:"153";s:3:"ne ";s:3:"154";s:3:"sik";s:3:"155";s:4:" ši";s:3:"156";s:3:"i n";s:3:"157";s:3:"ia ";s:3:"158";s:3:"ici";s:3:"159";s:3:"oja";s:3:"160";s:3:"sak";s:3:"161";s:3:"sti";s:3:"162";s:3:"ui ";s:3:"163";s:3:"ame";s:3:"164";s:3:"lie";s:3:"165";s:3:"o t";s:3:"166";s:3:"pie";s:3:"167";s:4:"čiu";s:3:"168";s:3:" di";s:3:"169";s:3:" pe";s:3:"170";s:3:"gri";s:3:"171";s:3:"ios";s:3:"172";s:3:"lia";s:3:"173";s:3:"lin";s:3:"174";s:3:"s d";s:3:"175";s:3:"s g";s:3:"176";s:3:"ta ";s:3:"177";s:3:"uot";s:3:"178";s:3:" ja";s:3:"179";s:4:" už";s:3:"180";s:3:"aut";s:3:"181";s:3:"i s";s:3:"182";s:3:"ino";s:3:"183";s:4:"mą ";s:3:"184";s:3:"oje";s:3:"185";s:3:"rav";s:3:"186";s:4:"dėl";s:3:"187";s:3:"nti";s:3:"188";s:3:"o a";s:3:"189";s:3:"toj";s:3:"190";s:4:"ėl ";s:3:"191";s:3:" to";s:3:"192";s:3:" vy";s:3:"193";s:3:"ar ";s:3:"194";s:3:"ina";s:3:"195";s:3:"lic";s:3:"196";s:3:"o v";s:3:"197";s:3:"sei";s:3:"198";s:3:"su ";s:3:"199";s:3:" mi";s:3:"200";s:3:" pi";s:3:"201";s:3:"din";s:3:"202";s:4:"iš ";s:3:"203";s:3:"lan";s:3:"204";s:3:"si ";s:3:"205";s:3:"tus";s:3:"206";s:3:" ba";s:3:"207";s:3:"asa";s:3:"208";s:3:"ata";s:3:"209";s:3:"kla";s:3:"210";s:3:"omi";s:3:"211";s:3:"tat";s:3:"212";s:3:" an";s:3:"213";s:3:" ji";s:3:"214";s:3:"als";s:3:"215";s:3:"ena";s:3:"216";s:4:"jų ";s:3:"217";s:3:"nuo";s:3:"218";s:3:"per";s:3:"219";s:3:"rig";s:3:"220";s:3:"s m";s:3:"221";s:3:"val";s:3:"222";s:3:"yta";s:3:"223";s:4:"čio";s:3:"224";s:3:" ra";s:3:"225";s:3:"i k";s:3:"226";s:3:"lik";s:3:"227";s:3:"net";s:3:"228";s:4:"nė ";s:3:"229";s:3:"tis";s:3:"230";s:3:"tuo";s:3:"231";s:3:"yti";s:3:"232";s:4:"ęs ";s:3:"233";s:4:"ų s";s:3:"234";s:3:"ada";s:3:"235";s:3:"ari";s:3:"236";s:3:"do ";s:3:"237";s:3:"eik";s:3:"238";s:3:"eis";s:3:"239";s:3:"ist";s:3:"240";s:3:"lst";s:3:"241";s:3:"ma ";s:3:"242";s:3:"nes";s:3:"243";s:3:"sav";s:3:"244";s:3:"sio";s:3:"245";s:3:"tau";s:3:"246";s:3:" ki";s:3:"247";s:3:"aik";s:3:"248";s:3:"aud";s:3:"249";s:3:"ies";s:3:"250";s:3:"ori";s:3:"251";s:3:"s r";s:3:"252";s:3:"ska";s:3:"253";s:3:" ge";s:3:"254";s:3:"ast";s:3:"255";s:3:"eig";s:3:"256";s:3:"et ";s:3:"257";s:3:"iam";s:3:"258";s:3:"isa";s:3:"259";s:3:"mis";s:3:"260";s:3:"nam";s:3:"261";s:3:"ome";s:3:"262";s:4:"žia";s:3:"263";s:3:"aba";s:3:"264";s:3:"aul";s:3:"265";s:3:"ikr";s:3:"266";s:4:"ką ";s:3:"267";s:3:"nta";s:3:"268";s:3:"ra ";s:3:"269";s:3:"tur";s:3:"270";s:3:" ma";s:3:"271";s:3:"die";s:3:"272";s:3:"ei ";s:3:"273";s:3:"i t";s:3:"274";s:3:"nas";s:3:"275";s:3:"rin";s:3:"276";s:3:"sto";s:3:"277";s:3:"tie";s:3:"278";s:3:"tuv";s:3:"279";s:3:"vos";s:3:"280";s:4:"ų p";s:3:"281";s:4:" dė";s:3:"282";s:3:"are";s:3:"283";s:3:"ats";s:3:"284";s:4:"enė";s:3:"285";s:3:"ili";s:3:"286";s:3:"ima";s:3:"287";s:3:"kar";s:3:"288";s:3:"ms ";s:3:"289";s:3:"nia";s:3:"290";s:3:"r p";s:3:"291";s:3:"rod";s:3:"292";s:3:"s l";s:3:"293";s:3:" o ";s:3:"294";s:3:"e p";s:3:"295";s:3:"es ";s:3:"296";s:3:"ide";s:3:"297";s:3:"ik ";s:3:"298";s:3:"ja ";s:3:"299";}s:10:"macedonian";a:300:{s:5:"на ";s:1:"0";s:5:" на";s:1:"1";s:5:"та ";s:1:"2";s:6:"ата";s:1:"3";s:6:"ија";s:1:"4";s:5:" пр";s:1:"5";s:5:"то ";s:1:"6";s:5:"ја ";s:1:"7";s:5:" за";s:1:"8";s:5:"а н";s:1:"9";s:4:" и ";s:2:"10";s:5:"а с";s:2:"11";s:5:"те ";s:2:"12";s:6:"ите";s:2:"13";s:5:" ко";s:2:"14";s:5:"от ";s:2:"15";s:5:" де";s:2:"16";s:5:" по";s:2:"17";s:5:"а д";s:2:"18";s:5:"во ";s:2:"19";s:5:"за ";s:2:"20";s:5:" во";s:2:"21";s:5:" од";s:2:"22";s:5:" се";s:2:"23";s:5:" не";s:2:"24";s:5:"се ";s:2:"25";s:5:" до";s:2:"26";s:5:"а в";s:2:"27";s:5:"ка ";s:2:"28";s:6:"ање";s:2:"29";s:5:"а п";s:2:"30";s:5:"о п";s:2:"31";s:6:"ува";s:2:"32";s:6:"циј";s:2:"33";s:5:"а о";s:2:"34";s:6:"ици";s:2:"35";s:6:"ето";s:2:"36";s:5:"о н";s:2:"37";s:6:"ани";s:2:"38";s:5:"ни ";s:2:"39";s:5:" вл";s:2:"40";s:6:"дек";s:2:"41";s:6:"ека";s:2:"42";s:6:"њет";s:2:"43";s:5:"ќе ";s:2:"44";s:4:" е ";s:2:"45";s:5:"а з";s:2:"46";s:5:"а и";s:2:"47";s:5:"ат ";s:2:"48";s:6:"вла";s:2:"49";s:5:"го ";s:2:"50";s:5:"е н";s:2:"51";s:5:"од ";s:2:"52";s:6:"пре";s:2:"53";s:5:" го";s:2:"54";s:5:" да";s:2:"55";s:5:" ма";s:2:"56";s:5:" ре";s:2:"57";s:5:" ќе";s:2:"58";s:6:"али";s:2:"59";s:5:"и д";s:2:"60";s:5:"и н";s:2:"61";s:6:"иот";s:2:"62";s:6:"нат";s:2:"63";s:6:"ово";s:2:"64";s:5:" па";s:2:"65";s:5:" ра";s:2:"66";s:5:" со";s:2:"67";s:6:"ове";s:2:"68";s:6:"пра";s:2:"69";s:6:"што";s:2:"70";s:5:"ње ";s:2:"71";s:5:"а е";s:2:"72";s:5:"да ";s:2:"73";s:6:"дат";s:2:"74";s:6:"дон";s:2:"75";s:5:"е в";s:2:"76";s:5:"е д";s:2:"77";s:5:"е з";s:2:"78";s:5:"е с";s:2:"79";s:6:"кон";s:2:"80";s:6:"нит";s:2:"81";s:5:"но ";s:2:"82";s:6:"они";s:2:"83";s:6:"ото";s:2:"84";s:6:"пар";s:2:"85";s:6:"при";s:2:"86";s:6:"ста";s:2:"87";s:5:"т н";s:2:"88";s:5:" шт";s:2:"89";s:5:"а к";s:2:"90";s:6:"аци";s:2:"91";s:5:"ва ";s:2:"92";s:6:"вањ";s:2:"93";s:5:"е п";s:2:"94";s:6:"ени";s:2:"95";s:5:"ла ";s:2:"96";s:6:"лад";s:2:"97";s:6:"мак";s:2:"98";s:6:"нес";s:2:"99";s:6:"нос";s:3:"100";s:6:"про";s:3:"101";s:6:"рен";s:3:"102";s:6:"јат";s:3:"103";s:5:" ин";s:3:"104";s:5:" ме";s:3:"105";s:5:" то";s:3:"106";s:5:"а г";s:3:"107";s:5:"а м";s:3:"108";s:5:"а р";s:3:"109";s:6:"аке";s:3:"110";s:6:"ако";s:3:"111";s:6:"вор";s:3:"112";s:6:"гов";s:3:"113";s:6:"едо";s:3:"114";s:6:"ена";s:3:"115";s:5:"и и";s:3:"116";s:6:"ира";s:3:"117";s:6:"кед";s:3:"118";s:5:"не ";s:3:"119";s:6:"ниц";s:3:"120";s:6:"ниј";s:3:"121";s:6:"ост";s:3:"122";s:5:"ра ";s:3:"123";s:6:"рат";s:3:"124";s:6:"ред";s:3:"125";s:6:"ска";s:3:"126";s:6:"тен";s:3:"127";s:5:" ка";s:3:"128";s:5:" сп";s:3:"129";s:5:" ја";s:3:"130";s:5:"а т";s:3:"131";s:6:"аде";s:3:"132";s:6:"арт";s:3:"133";s:5:"е г";s:3:"134";s:5:"е и";s:3:"135";s:6:"кат";s:3:"136";s:6:"лас";s:3:"137";s:6:"нио";s:3:"138";s:5:"о с";s:3:"139";s:5:"ри ";s:3:"140";s:5:" ба";s:3:"141";s:5:" би";s:3:"142";s:6:"ава";s:3:"143";s:6:"ате";s:3:"144";s:6:"вни";s:3:"145";s:5:"д н";s:3:"146";s:6:"ден";s:3:"147";s:6:"дов";s:3:"148";s:6:"држ";s:3:"149";s:6:"дув";s:3:"150";s:5:"е о";s:3:"151";s:5:"ен ";s:3:"152";s:6:"ере";s:3:"153";s:6:"ери";s:3:"154";s:5:"и п";s:3:"155";s:5:"и с";s:3:"156";s:6:"ина";s:3:"157";s:6:"кој";s:3:"158";s:6:"нци";s:3:"159";s:5:"о м";s:3:"160";s:5:"о о";s:3:"161";s:6:"одн";s:3:"162";s:6:"пор";s:3:"163";s:6:"ски";s:3:"164";s:6:"спо";s:3:"165";s:6:"ств";s:3:"166";s:6:"сти";s:3:"167";s:6:"тво";s:3:"168";s:5:"ти ";s:3:"169";s:5:" об";s:3:"170";s:5:" ов";s:3:"171";s:5:"а б";s:3:"172";s:6:"алн";s:3:"173";s:6:"ара";s:3:"174";s:6:"бар";s:3:"175";s:5:"е к";s:3:"176";s:5:"ед ";s:3:"177";s:6:"ент";s:3:"178";s:6:"еѓу";s:3:"179";s:5:"и о";s:3:"180";s:5:"ии ";s:3:"181";s:6:"меѓ";s:3:"182";s:5:"о д";s:3:"183";s:6:"оја";s:3:"184";s:6:"пот";s:3:"185";s:6:"раз";s:3:"186";s:6:"раш";s:3:"187";s:6:"спр";s:3:"188";s:6:"сто";s:3:"189";s:5:"т д";s:3:"190";s:5:"ци ";s:3:"191";s:5:" бе";s:3:"192";s:5:" гр";s:3:"193";s:5:" др";s:3:"194";s:5:" из";s:3:"195";s:5:" ст";s:3:"196";s:5:"аа ";s:3:"197";s:6:"бид";s:3:"198";s:6:"вед";s:3:"199";s:6:"гла";s:3:"200";s:6:"еко";s:3:"201";s:6:"енд";s:3:"202";s:6:"есе";s:3:"203";s:6:"етс";s:3:"204";s:6:"зац";s:3:"205";s:5:"и т";s:3:"206";s:6:"иза";s:3:"207";s:6:"инс";s:3:"208";s:6:"ист";s:3:"209";s:5:"ки ";s:3:"210";s:6:"ков";s:3:"211";s:6:"кол";s:3:"212";s:5:"ку ";s:3:"213";s:6:"лиц";s:3:"214";s:5:"о з";s:3:"215";s:5:"о и";s:3:"216";s:6:"ова";s:3:"217";s:6:"олк";s:3:"218";s:6:"оре";s:3:"219";s:6:"ори";s:3:"220";s:6:"под";s:3:"221";s:6:"рањ";s:3:"222";s:6:"реф";s:3:"223";s:6:"ржа";s:3:"224";s:6:"ров";s:3:"225";s:6:"рти";s:3:"226";s:5:"со ";s:3:"227";s:6:"тор";s:3:"228";s:6:"фер";s:3:"229";s:6:"цен";s:3:"230";s:6:"цит";s:3:"231";s:4:" а ";s:3:"232";s:5:" вр";s:3:"233";s:5:" гл";s:3:"234";s:5:" дп";s:3:"235";s:5:" мо";s:3:"236";s:5:" ни";s:3:"237";s:5:" но";s:3:"238";s:5:" оп";s:3:"239";s:5:" от";s:3:"240";s:5:"а ќ";s:3:"241";s:6:"або";s:3:"242";s:6:"ада";s:3:"243";s:6:"аса";s:3:"244";s:6:"аша";s:3:"245";s:5:"ба ";s:3:"246";s:6:"бот";s:3:"247";s:6:"ваа";s:3:"248";s:6:"ват";s:3:"249";s:6:"вот";s:3:"250";s:5:"ги ";s:3:"251";s:6:"гра";s:3:"252";s:5:"де ";s:3:"253";s:6:"дин";s:3:"254";s:6:"дум";s:3:"255";s:6:"евр";s:3:"256";s:6:"еду";s:3:"257";s:6:"ено";s:3:"258";s:6:"ера";s:3:"259";s:5:"ес ";s:3:"260";s:6:"ење";s:3:"261";s:5:"же ";s:3:"262";s:6:"зак";s:3:"263";s:5:"и в";s:3:"264";s:6:"ила";s:3:"265";s:6:"иту";s:3:"266";s:6:"коа";s:3:"267";s:6:"кои";s:3:"268";s:6:"лан";s:3:"269";s:6:"лку";s:3:"270";s:6:"лож";s:3:"271";s:6:"мот";s:3:"272";s:6:"нду";s:3:"273";s:6:"нст";s:3:"274";s:5:"о в";s:3:"275";s:5:"оа ";s:3:"276";s:6:"оал";s:3:"277";s:6:"обр";s:3:"278";s:5:"ов ";s:3:"279";s:6:"ови";s:3:"280";s:6:"овн";s:3:"281";s:5:"ои ";s:3:"282";s:5:"ор ";s:3:"283";s:6:"орм";s:3:"284";s:5:"ој ";s:3:"285";s:6:"рет";s:3:"286";s:6:"сед";s:3:"287";s:5:"ст ";s:3:"288";s:6:"тер";s:3:"289";s:6:"тиј";s:3:"290";s:6:"тоа";s:3:"291";s:6:"фор";s:3:"292";s:6:"ции";s:3:"293";s:5:"ѓу ";s:3:"294";s:5:" ал";s:3:"295";s:5:" ве";s:3:"296";s:5:" вм";s:3:"297";s:5:" ги";s:3:"298";s:5:" ду";s:3:"299";}s:9:"mongolian";a:300:{s:5:"ын ";s:1:"0";s:5:" ба";s:1:"1";s:5:"йн ";s:1:"2";s:6:"бай";s:1:"3";s:6:"ийн";s:1:"4";s:6:"уул";s:1:"5";s:5:" ул";s:1:"6";s:6:"улс";s:1:"7";s:5:"ан ";s:1:"8";s:5:" ха";s:1:"9";s:6:"ний";s:2:"10";s:5:"н х";s:2:"11";s:6:"гаа";s:2:"12";s:6:"сын";s:2:"13";s:5:"ий ";s:2:"14";s:6:"лсы";s:2:"15";s:5:" бо";s:2:"16";s:5:"й б";s:2:"17";s:5:"эн ";s:2:"18";s:5:"ах ";s:2:"19";s:6:"бол";s:2:"20";s:5:"ол ";s:2:"21";s:5:"н б";s:2:"22";s:6:"оло";s:2:"23";s:5:" хэ";s:2:"24";s:6:"онг";s:2:"25";s:6:"гол";s:2:"26";s:6:"гуу";s:2:"27";s:6:"нго";s:2:"28";s:5:"ыг ";s:2:"29";s:6:"жил";s:2:"30";s:5:" мо";s:2:"31";s:6:"лаг";s:2:"32";s:6:"лла";s:2:"33";s:6:"мон";s:2:"34";s:5:" тє";s:2:"35";s:5:" ху";s:2:"36";s:6:"айд";s:2:"37";s:5:"ны ";s:2:"38";s:5:"он ";s:2:"39";s:6:"сан";s:2:"40";s:6:"хий";s:2:"41";s:5:" аж";s:2:"42";s:5:" ор";s:2:"43";s:5:"л у";s:2:"44";s:5:"н т";s:2:"45";s:6:"улг";s:2:"46";s:6:"айг";s:2:"47";s:6:"длы";s:2:"48";s:5:"йг ";s:2:"49";s:5:" за";s:2:"50";s:6:"дэс";s:2:"51";s:5:"н а";s:2:"52";s:6:"ндэ";s:2:"53";s:6:"ула";s:2:"54";s:5:"ээ ";s:2:"55";s:6:"ага";s:2:"56";s:6:"ийг";s:2:"57";s:4:"vй ";s:2:"58";s:5:"аа ";s:2:"59";s:5:"й а";s:2:"60";s:6:"лын";s:2:"61";s:5:"н з";s:2:"62";s:5:" аю";s:2:"63";s:5:" зє";s:2:"64";s:6:"аар";s:2:"65";s:5:"ад ";s:2:"66";s:5:"ар ";s:2:"67";s:5:"гvй";s:2:"68";s:6:"зєв";s:2:"69";s:6:"ажи";s:2:"70";s:5:"ал ";s:2:"71";s:6:"аюу";s:2:"72";s:5:"г х";s:2:"73";s:5:"лгv";s:2:"74";s:5:"лж ";s:2:"75";s:6:"сни";s:2:"76";s:6:"эсн";s:2:"77";s:6:"юул";s:2:"78";s:6:"йдл";s:2:"79";s:6:"лыг";s:2:"80";s:6:"нхи";s:2:"81";s:6:"ууд";s:2:"82";s:6:"хам";s:2:"83";s:5:" нэ";s:2:"84";s:5:" са";s:2:"85";s:6:"гий";s:2:"86";s:6:"лах";s:2:"87";s:6:"лєл";s:2:"88";s:6:"рєн";s:2:"89";s:6:"єгч";s:2:"90";s:5:" та";s:2:"91";s:6:"илл";s:2:"92";s:6:"лий";s:2:"93";s:6:"лэх";s:2:"94";s:6:"рий";s:2:"95";s:5:"эх ";s:2:"96";s:5:" ер";s:2:"97";s:5:" эр";s:2:"98";s:6:"влє";s:2:"99";s:6:"ерє";s:3:"100";s:6:"ийл";s:3:"101";s:6:"лон";s:3:"102";s:6:"лєг";s:3:"103";s:6:"євл";s:3:"104";s:6:"єнх";s:3:"105";s:5:" хо";s:3:"106";s:6:"ари";s:3:"107";s:5:"их ";s:3:"108";s:6:"хан";s:3:"109";s:5:"эр ";s:3:"110";s:5:"єн ";s:3:"111";s:4:"vvл";s:3:"112";s:5:"ж б";s:3:"113";s:6:"тэй";s:3:"114";s:5:"х х";s:3:"115";s:6:"эрх";s:3:"116";s:4:" vн";s:3:"117";s:5:" нь";s:3:"118";s:5:"vнд";s:3:"119";s:6:"алт";s:3:"120";s:6:"йлє";s:3:"121";s:5:"нь ";s:3:"122";s:6:"тєр";s:3:"123";s:5:" га";s:3:"124";s:5:" су";s:3:"125";s:6:"аан";s:3:"126";s:6:"даа";s:3:"127";s:6:"илц";s:3:"128";s:6:"йгу";s:3:"129";s:5:"л а";s:3:"130";s:6:"лаа";s:3:"131";s:5:"н н";s:3:"132";s:6:"руу";s:3:"133";s:5:"эй ";s:3:"134";s:5:" то";s:3:"135";s:5:"н с";s:3:"136";s:6:"рил";s:3:"137";s:6:"єри";s:3:"138";s:6:"ааг";s:3:"139";s:5:"гч ";s:3:"140";s:6:"лээ";s:3:"141";s:5:"н о";s:3:"142";s:6:"рэг";s:3:"143";s:6:"суу";s:3:"144";s:6:"эрэ";s:3:"145";s:6:"їїл";s:3:"146";s:4:" yн";s:3:"147";s:5:" бу";s:3:"148";s:5:" дэ";s:3:"149";s:5:" ол";s:3:"150";s:5:" ту";s:3:"151";s:5:" ши";s:3:"152";s:5:"yнд";s:3:"153";s:6:"аши";s:3:"154";s:5:"г т";s:3:"155";s:5:"иг ";s:3:"156";s:5:"йл ";s:3:"157";s:6:"хар";s:3:"158";s:6:"шин";s:3:"159";s:5:"эг ";s:3:"160";s:5:"єр ";s:3:"161";s:5:" их";s:3:"162";s:5:" хє";s:3:"163";s:5:" хї";s:3:"164";s:5:"ам ";s:3:"165";s:6:"анг";s:3:"166";s:5:"ин ";s:3:"167";s:6:"йга";s:3:"168";s:6:"лса";s:3:"169";s:4:"н v";s:3:"170";s:5:"н е";s:3:"171";s:6:"нал";s:3:"172";s:5:"нд ";s:3:"173";s:6:"хуу";s:3:"174";s:6:"цаа";s:3:"175";s:5:"эд ";s:3:"176";s:6:"ээр";s:3:"177";s:5:"єл ";s:3:"178";s:5:"vйл";s:3:"179";s:6:"ада";s:3:"180";s:6:"айн";s:3:"181";s:6:"ала";s:3:"182";s:6:"амт";s:3:"183";s:6:"гах";s:3:"184";s:5:"д х";s:3:"185";s:6:"дал";s:3:"186";s:6:"зар";s:3:"187";s:5:"л б";s:3:"188";s:6:"лан";s:3:"189";s:5:"н д";s:3:"190";s:6:"сэн";s:3:"191";s:6:"улл";s:3:"192";s:5:"х б";s:3:"193";s:6:"хэр";s:3:"194";s:4:" бv";s:3:"195";s:5:" да";s:3:"196";s:5:" зо";s:3:"197";s:5:"vрэ";s:3:"198";s:6:"аад";s:3:"199";s:6:"гээ";s:3:"200";s:6:"лэн";s:3:"201";s:5:"н и";s:3:"202";s:5:"н э";s:3:"203";s:6:"нга";s:3:"204";s:5:"нэ ";s:3:"205";s:6:"тал";s:3:"206";s:6:"тын";s:3:"207";s:6:"хур";s:3:"208";s:5:"эл ";s:3:"209";s:5:" на";s:3:"210";s:5:" ни";s:3:"211";s:5:" он";s:3:"212";s:5:"vлэ";s:3:"213";s:5:"аг ";s:3:"214";s:5:"аж ";s:3:"215";s:5:"ай ";s:3:"216";s:6:"ата";s:3:"217";s:6:"бар";s:3:"218";s:5:"г б";s:3:"219";s:6:"гад";s:3:"220";s:6:"гїй";s:3:"221";s:5:"й х";s:3:"222";s:5:"лт ";s:3:"223";s:5:"н м";s:3:"224";s:5:"на ";s:3:"225";s:6:"оро";s:3:"226";s:6:"уль";s:3:"227";s:6:"чин";s:3:"228";s:5:"эж ";s:3:"229";s:6:"энэ";s:3:"230";s:6:"ээд";s:3:"231";s:5:"їй ";s:3:"232";s:6:"їлэ";s:3:"233";s:5:" би";s:3:"234";s:5:" тэ";s:3:"235";s:5:" эн";s:3:"236";s:6:"аны";s:3:"237";s:6:"дий";s:3:"238";s:6:"дээ";s:3:"239";s:6:"лал";s:3:"240";s:6:"лга";s:3:"241";s:5:"лд ";s:3:"242";s:6:"лог";s:3:"243";s:5:"ль ";s:3:"244";s:5:"н у";s:3:"245";s:5:"н ї";s:3:"246";s:5:"р б";s:3:"247";s:6:"рал";s:3:"248";s:6:"сон";s:3:"249";s:6:"тай";s:3:"250";s:6:"удл";s:3:"251";s:6:"элт";s:3:"252";s:6:"эрг";s:3:"253";s:6:"єлє";s:3:"254";s:4:" vй";s:3:"255";s:4:" в ";s:3:"256";s:5:" гэ";s:3:"257";s:4:" хv";s:3:"258";s:6:"ара";s:3:"259";s:5:"бvр";s:3:"260";s:5:"д н";s:3:"261";s:5:"д о";s:3:"262";s:5:"л х";s:3:"263";s:5:"лс ";s:3:"264";s:6:"лты";s:3:"265";s:5:"н г";s:3:"266";s:6:"нэг";s:3:"267";s:6:"огт";s:3:"268";s:6:"олы";s:3:"269";s:6:"оёр";s:3:"270";s:5:"р т";s:3:"271";s:6:"рээ";s:3:"272";s:6:"тав";s:3:"273";s:6:"тог";s:3:"274";s:6:"уур";s:3:"275";s:6:"хоё";s:3:"276";s:6:"хэл";s:3:"277";s:6:"хээ";s:3:"278";s:6:"элэ";s:3:"279";s:5:"ёр ";s:3:"280";s:5:" ав";s:3:"281";s:5:" ас";s:3:"282";s:5:" аш";s:3:"283";s:5:" ду";s:3:"284";s:5:" со";s:3:"285";s:5:" чи";s:3:"286";s:5:" эв";s:3:"287";s:5:" єр";s:3:"288";s:6:"аал";s:3:"289";s:6:"алд";s:3:"290";s:6:"амж";s:3:"291";s:6:"анд";s:3:"292";s:6:"асу";s:3:"293";s:6:"вэр";s:3:"294";s:5:"г у";s:3:"295";s:6:"двэ";s:3:"296";s:4:"жvv";s:3:"297";s:6:"лца";s:3:"298";s:6:"лэл";s:3:"299";}s:6:"nepali";a:300:{s:7:"को ";s:1:"0";s:7:"का ";s:1:"1";s:7:"मा ";s:1:"2";s:9:"हरु";s:1:"3";s:7:" ने";s:1:"4";s:9:"नेप";s:1:"5";s:9:"पाल";s:1:"6";s:9:"ेपा";s:1:"7";s:7:" सम";s:1:"8";s:7:"ले ";s:1:"9";s:7:" प्";s:2:"10";s:9:"प्र";s:2:"11";s:9:"कार";s:2:"12";s:7:"ा स";s:2:"13";s:9:"एको";s:2:"14";s:7:" भए";s:2:"15";s:5:" छ ";s:2:"16";s:7:" भा";s:2:"17";s:9:"्रम";s:2:"18";s:7:" गर";s:2:"19";s:9:"रुक";s:2:"20";s:5:" र ";s:2:"21";s:9:"भार";s:2:"22";s:9:"ारत";s:2:"23";s:7:" का";s:2:"24";s:7:" वि";s:2:"25";s:9:"भएक";s:2:"26";s:9:"ाली";s:2:"27";s:7:"ली ";s:2:"28";s:7:"ा प";s:2:"29";s:9:"ीहर";s:2:"30";s:9:"ार्";s:2:"31";s:7:"ो छ";s:2:"32";s:7:"ना ";s:2:"33";s:7:"रु ";s:2:"34";s:9:"ालक";s:2:"35";s:9:"्या";s:2:"36";s:7:" बा";s:2:"37";s:9:"एका";s:2:"38";s:7:"ने ";s:2:"39";s:9:"न्त";s:2:"40";s:7:"ा ब";s:2:"41";s:9:"ाको";s:2:"42";s:7:"ार ";s:2:"43";s:7:"ा भ";s:2:"44";s:9:"ाहर";s:2:"45";s:9:"्रो";s:2:"46";s:9:"क्ष";s:2:"47";s:7:"न् ";s:2:"48";s:9:"ारी";s:2:"49";s:7:" नि";s:2:"50";s:7:"ा न";s:2:"51";s:7:"ी स";s:2:"52";s:7:" डु";s:2:"53";s:9:"क्र";s:2:"54";s:9:"जना";s:2:"55";s:7:"यो ";s:2:"56";s:7:"ा छ";s:2:"57";s:9:"ेवा";s:2:"58";s:9:"्ता";s:2:"59";s:7:" रा";s:2:"60";s:9:"त्य";s:2:"61";s:9:"न्द";s:2:"62";s:9:"हुन";s:2:"63";s:7:"ा क";s:2:"64";s:9:"ामा";s:2:"65";s:7:"ी न";s:2:"66";s:9:"्दा";s:2:"67";s:7:" से";s:2:"68";s:9:"छन्";s:2:"69";s:9:"म्ब";s:2:"70";s:9:"रोत";s:2:"71";s:9:"सेव";s:2:"72";s:9:"स्त";s:2:"73";s:9:"स्र";s:2:"74";s:9:"ेका";s:2:"75";s:7:"्त ";s:2:"76";s:7:" बी";s:2:"77";s:7:" हु";s:2:"78";s:9:"क्त";s:2:"79";s:9:"त्र";s:2:"80";s:7:"रत ";s:2:"81";s:9:"र्न";s:2:"82";s:9:"र्य";s:2:"83";s:7:"ा र";s:2:"84";s:9:"ाका";s:2:"85";s:9:"ुको";s:2:"86";s:7:" एक";s:2:"87";s:7:" सं";s:2:"88";s:7:" सु";s:2:"89";s:9:"बीब";s:2:"90";s:9:"बीस";s:2:"91";s:9:"लको";s:2:"92";s:9:"स्य";s:2:"93";s:9:"ीबी";s:2:"94";s:9:"ीसी";s:2:"95";s:9:"ेको";s:2:"96";s:7:"ो स";s:2:"97";s:9:"्यक";s:2:"98";s:7:" छन";s:2:"99";s:7:" जन";s:3:"100";s:7:" बि";s:3:"101";s:7:" मु";s:3:"102";s:7:" स्";s:3:"103";s:9:"गर्";s:3:"104";s:9:"ताह";s:3:"105";s:9:"न्ध";s:3:"106";s:9:"बार";s:3:"107";s:9:"मन्";s:3:"108";s:9:"मस्";s:3:"109";s:9:"रुल";s:3:"110";s:9:"लाई";s:3:"111";s:7:"ा व";s:3:"112";s:7:"ाई ";s:3:"113";s:7:"ाल ";s:3:"114";s:9:"िका";s:3:"115";s:7:" त्";s:3:"116";s:7:" मा";s:3:"117";s:7:" यस";s:3:"118";s:7:" रु";s:3:"119";s:9:"ताक";s:3:"120";s:9:"बन्";s:3:"121";s:7:"र ब";s:3:"122";s:7:"रण ";s:3:"123";s:9:"रुप";s:3:"124";s:9:"रेक";s:3:"125";s:9:"ष्ट";s:3:"126";s:9:"सम्";s:3:"127";s:7:"सी ";s:3:"128";s:9:"ाएक";s:3:"129";s:9:"ुका";s:3:"130";s:9:"ुक्";s:3:"131";s:7:" अध";s:3:"132";s:7:" अन";s:3:"133";s:7:" तथ";s:3:"134";s:7:" थि";s:3:"135";s:7:" दे";s:3:"136";s:7:" पर";s:3:"137";s:7:" बै";s:3:"138";s:9:"तथा";s:3:"139";s:7:"ता ";s:3:"140";s:7:"दा ";s:3:"141";s:9:"द्द";s:3:"142";s:7:"नी ";s:3:"143";s:9:"बाट";s:3:"144";s:9:"यक्";s:3:"145";s:7:"री ";s:3:"146";s:9:"रीह";s:3:"147";s:9:"र्म";s:3:"148";s:9:"लका";s:3:"149";s:9:"समस";s:3:"150";s:7:"ा अ";s:3:"151";s:7:"ा ए";s:3:"152";s:7:"ाट ";s:3:"153";s:7:"िय ";s:3:"154";s:7:"ो प";s:3:"155";s:7:"ो म";s:3:"156";s:7:"्न ";s:3:"157";s:9:"्ने";s:3:"158";s:9:"्षा";s:3:"159";s:7:" पा";s:3:"160";s:7:" यो";s:3:"161";s:7:" हा";s:3:"162";s:9:"अधि";s:3:"163";s:9:"डुव";s:3:"164";s:7:"त भ";s:3:"165";s:7:"त स";s:3:"166";s:7:"था ";s:3:"167";s:9:"धिक";s:3:"168";s:9:"पमा";s:3:"169";s:9:"बैठ";s:3:"170";s:9:"मुद";s:3:"171";s:7:"या ";s:3:"172";s:9:"युक";s:3:"173";s:7:"र न";s:3:"174";s:9:"रति";s:3:"175";s:9:"वान";s:3:"176";s:9:"सार";s:3:"177";s:7:"ा आ";s:3:"178";s:7:"ा ज";s:3:"179";s:7:"ा ह";s:3:"180";s:9:"ुद्";s:3:"181";s:9:"ुपम";s:3:"182";s:9:"ुले";s:3:"183";s:9:"ुवा";s:3:"184";s:9:"ैठक";s:3:"185";s:7:"ो ब";s:3:"186";s:9:"्तर";s:3:"187";s:7:"्य ";s:3:"188";s:9:"्यस";s:3:"189";s:7:" क्";s:3:"190";s:7:" मन";s:3:"191";s:7:" रह";s:3:"192";s:9:"चार";s:3:"193";s:9:"तिय";s:3:"194";s:7:"दै ";s:3:"195";s:9:"निर";s:3:"196";s:7:"नु ";s:3:"197";s:9:"पर्";s:3:"198";s:9:"रक्";s:3:"199";s:9:"र्द";s:3:"200";s:9:"समा";s:3:"201";s:9:"सुर";s:3:"202";s:9:"ाउन";s:3:"203";s:7:"ान ";s:3:"204";s:9:"ानम";s:3:"205";s:9:"ारण";s:3:"206";s:9:"ाले";s:3:"207";s:7:"ि ब";s:3:"208";s:9:"ियो";s:3:"209";s:9:"ुन्";s:3:"210";s:9:"ुरक";s:3:"211";s:9:"्त्";s:3:"212";s:9:"्बन";s:3:"213";s:9:"्रा";s:3:"214";s:7:"्ष ";s:3:"215";s:7:" आर";s:3:"216";s:7:" जल";s:3:"217";s:7:" बे";s:3:"218";s:7:" या";s:3:"219";s:7:" सा";s:3:"220";s:9:"आएक";s:3:"221";s:7:"एक ";s:3:"222";s:9:"कर्";s:3:"223";s:9:"जलस";s:3:"224";s:9:"णका";s:3:"225";s:7:"त र";s:3:"226";s:9:"द्र";s:3:"227";s:9:"धान";s:3:"228";s:7:"धि ";s:3:"229";s:9:"नका";s:3:"230";s:9:"नमा";s:3:"231";s:7:"नि ";s:3:"232";s:9:"ममा";s:3:"233";s:7:"रम ";s:3:"234";s:9:"रहे";s:3:"235";s:9:"राज";s:3:"236";s:9:"लस्";s:3:"237";s:7:"ला ";s:3:"238";s:9:"वार";s:3:"239";s:9:"सका";s:3:"240";s:9:"हिल";s:3:"241";s:9:"हेक";s:3:"242";s:7:"ा त";s:3:"243";s:9:"ारे";s:3:"244";s:9:"िन्";s:3:"245";s:9:"िस्";s:3:"246";s:7:"े स";s:3:"247";s:7:"ो न";s:3:"248";s:7:"ो र";s:3:"249";s:7:"ोत ";s:3:"250";s:9:"्धि";s:3:"251";s:9:"्मी";s:3:"252";s:9:"्रस";s:3:"253";s:7:" दु";s:3:"254";s:7:" पन";s:3:"255";s:7:" बत";s:3:"256";s:7:" बन";s:3:"257";s:7:" भन";s:3:"258";s:9:"ंयु";s:3:"259";s:9:"आरम";s:3:"260";s:7:"खि ";s:3:"261";s:9:"ण्ड";s:3:"262";s:9:"तका";s:3:"263";s:9:"ताल";s:3:"264";s:7:"दी ";s:3:"265";s:9:"देख";s:3:"266";s:9:"निय";s:3:"267";s:9:"पनि";s:3:"268";s:9:"प्त";s:3:"269";s:9:"बता";s:3:"270";s:7:"मी ";s:3:"271";s:9:"म्भ";s:3:"272";s:7:"र स";s:3:"273";s:9:"रम्";s:3:"274";s:9:"लमा";s:3:"275";s:9:"विश";s:3:"276";s:9:"षाक";s:3:"277";s:9:"संय";s:3:"278";s:7:"ा ड";s:3:"279";s:7:"ा म";s:3:"280";s:9:"ानक";s:3:"281";s:9:"ालम";s:3:"282";s:7:"ि भ";s:3:"283";s:7:"ित ";s:3:"284";s:7:"ी प";s:3:"285";s:7:"ी र";s:3:"286";s:7:"ु भ";s:3:"287";s:9:"ुने";s:3:"288";s:7:"े ग";s:3:"289";s:9:"ेखि";s:3:"290";s:7:"ेर ";s:3:"291";s:7:"ो भ";s:3:"292";s:7:"ो व";s:3:"293";s:7:"ो ह";s:3:"294";s:7:"्भ ";s:3:"295";s:7:"्र ";s:3:"296";s:7:" ता";s:3:"297";s:7:" नम";s:3:"298";s:7:" ना";s:3:"299";}s:9:"norwegian";a:300:{s:3:"er ";s:1:"0";s:3:"en ";s:1:"1";s:3:"et ";s:1:"2";s:3:" de";s:1:"3";s:3:"det";s:1:"4";s:3:" i ";s:1:"5";s:3:"for";s:1:"6";s:3:"il ";s:1:"7";s:3:" fo";s:1:"8";s:3:" me";s:1:"9";s:3:"ing";s:2:"10";s:3:"om ";s:2:"11";s:3:" ha";s:2:"12";s:3:" og";s:2:"13";s:3:"ter";s:2:"14";s:3:" er";s:2:"15";s:3:" ti";s:2:"16";s:3:" st";s:2:"17";s:3:"og ";s:2:"18";s:3:"til";s:2:"19";s:3:"ne ";s:2:"20";s:3:" vi";s:2:"21";s:3:"re ";s:2:"22";s:3:" en";s:2:"23";s:3:" se";s:2:"24";s:3:"te ";s:2:"25";s:3:"or ";s:2:"26";s:3:"de ";s:2:"27";s:3:"kke";s:2:"28";s:3:"ke ";s:2:"29";s:3:"ar ";s:2:"30";s:3:"ng ";s:2:"31";s:3:"r s";s:2:"32";s:3:"ene";s:2:"33";s:3:" so";s:2:"34";s:3:"e s";s:2:"35";s:3:"der";s:2:"36";s:3:"an ";s:2:"37";s:3:"som";s:2:"38";s:3:"ste";s:2:"39";s:3:"at ";s:2:"40";s:3:"ed ";s:2:"41";s:3:"r i";s:2:"42";s:3:" av";s:2:"43";s:3:" in";s:2:"44";s:3:"men";s:2:"45";s:3:" at";s:2:"46";s:3:" ko";s:2:"47";s:4:" på";s:2:"48";s:3:"har";s:2:"49";s:3:" si";s:2:"50";s:3:"ere";s:2:"51";s:4:"på ";s:2:"52";s:3:"nde";s:2:"53";s:3:"and";s:2:"54";s:3:"els";s:2:"55";s:3:"ett";s:2:"56";s:3:"tte";s:2:"57";s:3:"lig";s:2:"58";s:3:"t s";s:2:"59";s:3:"den";s:2:"60";s:3:"t i";s:2:"61";s:3:"ikk";s:2:"62";s:3:"med";s:2:"63";s:3:"n s";s:2:"64";s:3:"rt ";s:2:"65";s:3:"ser";s:2:"66";s:3:"ska";s:2:"67";s:3:"t e";s:2:"68";s:3:"ker";s:2:"69";s:3:"sen";s:2:"70";s:3:"av ";s:2:"71";s:3:"ler";s:2:"72";s:3:"r a";s:2:"73";s:3:"ten";s:2:"74";s:3:"e f";s:2:"75";s:3:"r e";s:2:"76";s:3:"r t";s:2:"77";s:3:"ede";s:2:"78";s:3:"ig ";s:2:"79";s:3:" re";s:2:"80";s:3:"han";s:2:"81";s:3:"lle";s:2:"82";s:3:"ner";s:2:"83";s:3:" bl";s:2:"84";s:3:" fr";s:2:"85";s:3:"le ";s:2:"86";s:3:" ve";s:2:"87";s:3:"e t";s:2:"88";s:3:"lan";s:2:"89";s:3:"mme";s:2:"90";s:3:"nge";s:2:"91";s:3:" be";s:2:"92";s:3:" ik";s:2:"93";s:3:" om";s:2:"94";s:4:" å ";s:2:"95";s:3:"ell";s:2:"96";s:3:"sel";s:2:"97";s:3:"sta";s:2:"98";s:3:"ver";s:2:"99";s:3:" et";s:3:"100";s:3:" sk";s:3:"101";s:3:"nte";s:3:"102";s:3:"one";s:3:"103";s:3:"ore";s:3:"104";s:3:"r d";s:3:"105";s:3:"ske";s:3:"106";s:3:" an";s:3:"107";s:3:" la";s:3:"108";s:3:"del";s:3:"109";s:3:"gen";s:3:"110";s:3:"nin";s:3:"111";s:3:"r f";s:3:"112";s:3:"r v";s:3:"113";s:3:"se ";s:3:"114";s:3:" po";s:3:"115";s:3:"ir ";s:3:"116";s:3:"jon";s:3:"117";s:3:"mer";s:3:"118";s:3:"nen";s:3:"119";s:3:"omm";s:3:"120";s:3:"sjo";s:3:"121";s:3:" fl";s:3:"122";s:3:" sa";s:3:"123";s:3:"ern";s:3:"124";s:3:"kom";s:3:"125";s:3:"r m";s:3:"126";s:3:"r o";s:3:"127";s:3:"ren";s:3:"128";s:3:"vil";s:3:"129";s:3:"ale";s:3:"130";s:3:"es ";s:3:"131";s:3:"n a";s:3:"132";s:3:"t f";s:3:"133";s:3:" le";s:3:"134";s:3:"bli";s:3:"135";s:3:"e e";s:3:"136";s:3:"e i";s:3:"137";s:3:"e v";s:3:"138";s:3:"het";s:3:"139";s:3:"ye ";s:3:"140";s:3:" ir";s:3:"141";s:3:"al ";s:3:"142";s:3:"e o";s:3:"143";s:3:"ide";s:3:"144";s:3:"iti";s:3:"145";s:3:"lit";s:3:"146";s:3:"nne";s:3:"147";s:3:"ran";s:3:"148";s:3:"t o";s:3:"149";s:3:"tal";s:3:"150";s:3:"tat";s:3:"151";s:3:"tt ";s:3:"152";s:3:" ka";s:3:"153";s:3:"ans";s:3:"154";s:3:"asj";s:3:"155";s:3:"ge ";s:3:"156";s:3:"inn";s:3:"157";s:3:"kon";s:3:"158";s:3:"lse";s:3:"159";s:3:"pet";s:3:"160";s:3:"t d";s:3:"161";s:3:"vi ";s:3:"162";s:3:" ut";s:3:"163";s:3:"ent";s:3:"164";s:3:"eri";s:3:"165";s:3:"oli";s:3:"166";s:3:"r p";s:3:"167";s:3:"ret";s:3:"168";s:3:"ris";s:3:"169";s:3:"sto";s:3:"170";s:3:"str";s:3:"171";s:3:"t a";s:3:"172";s:3:" ga";s:3:"173";s:3:"all";s:3:"174";s:3:"ape";s:3:"175";s:3:"g s";s:3:"176";s:3:"ill";s:3:"177";s:3:"ira";s:3:"178";s:3:"kap";s:3:"179";s:3:"nn ";s:3:"180";s:3:"opp";s:3:"181";s:3:"r h";s:3:"182";s:3:"rin";s:3:"183";s:3:" br";s:3:"184";s:3:" op";s:3:"185";s:3:"e m";s:3:"186";s:3:"ert";s:3:"187";s:3:"ger";s:3:"188";s:3:"ion";s:3:"189";s:3:"kal";s:3:"190";s:3:"lsk";s:3:"191";s:3:"nes";s:3:"192";s:3:" gj";s:3:"193";s:3:" mi";s:3:"194";s:3:" pr";s:3:"195";s:3:"ang";s:3:"196";s:3:"e h";s:3:"197";s:3:"e r";s:3:"198";s:3:"elt";s:3:"199";s:3:"enn";s:3:"200";s:3:"i s";s:3:"201";s:3:"ist";s:3:"202";s:3:"jen";s:3:"203";s:3:"kan";s:3:"204";s:3:"lt ";s:3:"205";s:3:"nal";s:3:"206";s:3:"res";s:3:"207";s:3:"tor";s:3:"208";s:3:"ass";s:3:"209";s:3:"dre";s:3:"210";s:3:"e b";s:3:"211";s:3:"e p";s:3:"212";s:3:"mel";s:3:"213";s:3:"n t";s:3:"214";s:3:"nse";s:3:"215";s:3:"ort";s:3:"216";s:3:"per";s:3:"217";s:3:"reg";s:3:"218";s:3:"sje";s:3:"219";s:3:"t p";s:3:"220";s:3:"t v";s:3:"221";s:3:" hv";s:3:"222";s:4:" nå";s:3:"223";s:3:" va";s:3:"224";s:3:"ann";s:3:"225";s:3:"ato";s:3:"226";s:3:"e a";s:3:"227";s:3:"est";s:3:"228";s:3:"ise";s:3:"229";s:3:"isk";s:3:"230";s:3:"oil";s:3:"231";s:3:"ord";s:3:"232";s:3:"pol";s:3:"233";s:3:"ra ";s:3:"234";s:3:"rak";s:3:"235";s:3:"sse";s:3:"236";s:3:"toi";s:3:"237";s:3:" gr";s:3:"238";s:3:"ak ";s:3:"239";s:3:"eg ";s:3:"240";s:3:"ele";s:3:"241";s:3:"g a";s:3:"242";s:3:"ige";s:3:"243";s:3:"igh";s:3:"244";s:3:"m e";s:3:"245";s:3:"n f";s:3:"246";s:3:"n v";s:3:"247";s:3:"ndr";s:3:"248";s:3:"nsk";s:3:"249";s:3:"rer";s:3:"250";s:3:"t m";s:3:"251";s:3:"und";s:3:"252";s:3:"var";s:3:"253";s:4:"år ";s:3:"254";s:3:" he";s:3:"255";s:3:" no";s:3:"256";s:3:" ny";s:3:"257";s:3:"end";s:3:"258";s:3:"ete";s:3:"259";s:3:"fly";s:3:"260";s:3:"g i";s:3:"261";s:3:"ghe";s:3:"262";s:3:"ier";s:3:"263";s:3:"ind";s:3:"264";s:3:"int";s:3:"265";s:3:"lin";s:3:"266";s:3:"n d";s:3:"267";s:3:"n p";s:3:"268";s:3:"rne";s:3:"269";s:3:"sak";s:3:"270";s:3:"sie";s:3:"271";s:3:"t b";s:3:"272";s:3:"tid";s:3:"273";s:3:" al";s:3:"274";s:3:" pa";s:3:"275";s:3:" tr";s:3:"276";s:3:"ag ";s:3:"277";s:3:"dig";s:3:"278";s:3:"e d";s:3:"279";s:3:"e k";s:3:"280";s:3:"ess";s:3:"281";s:3:"hol";s:3:"282";s:3:"i d";s:3:"283";s:3:"lag";s:3:"284";s:3:"led";s:3:"285";s:3:"n e";s:3:"286";s:3:"n i";s:3:"287";s:3:"n o";s:3:"288";s:3:"pri";s:3:"289";s:3:"r b";s:3:"290";s:3:"st ";s:3:"291";s:3:" fe";s:3:"292";s:3:" li";s:3:"293";s:3:" ry";s:3:"294";s:3:"air";s:3:"295";s:3:"ake";s:3:"296";s:3:"d s";s:3:"297";s:3:"eas";s:3:"298";s:3:"egi";s:3:"299";}s:6:"pashto";a:300:{s:4:" د ";s:1:"0";s:5:"اؤ ";s:1:"1";s:5:" اؤ";s:1:"2";s:5:"نو ";s:1:"3";s:5:"ې د";s:1:"4";s:5:"ره ";s:1:"5";s:5:" په";s:1:"6";s:5:"نه ";s:1:"7";s:5:"چې ";s:1:"8";s:5:" چې";s:1:"9";s:5:"په ";s:2:"10";s:5:"ه د";s:2:"11";s:5:"ته ";s:2:"12";s:5:"و ا";s:2:"13";s:6:"ونو";s:2:"14";s:5:"و د";s:2:"15";s:5:" او";s:2:"16";s:6:"انو";s:2:"17";s:6:"ونه";s:2:"18";s:5:"ه ک";s:2:"19";s:5:" دا";s:2:"20";s:5:"ه ا";s:2:"21";s:5:"دې ";s:2:"22";s:5:"ښې ";s:2:"23";s:5:" کې";s:2:"24";s:5:"ان ";s:2:"25";s:5:"لو ";s:2:"26";s:5:"هم ";s:2:"27";s:5:"و م";s:2:"28";s:6:"کښې";s:2:"29";s:5:"ه م";s:2:"30";s:5:"ى ا";s:2:"31";s:5:" نو";s:2:"32";s:5:" ته";s:2:"33";s:5:" کښ";s:2:"34";s:6:"رون";s:2:"35";s:5:"کې ";s:2:"36";s:5:"ده ";s:2:"37";s:5:"له ";s:2:"38";s:5:"به ";s:2:"39";s:5:"رو ";s:2:"40";s:5:" هم";s:2:"41";s:5:"ه و";s:2:"42";s:5:"وى ";s:2:"43";s:5:"او ";s:2:"44";s:6:"تون";s:2:"45";s:5:"دا ";s:2:"46";s:5:" کو";s:2:"47";s:5:" کړ";s:2:"48";s:6:"قام";s:2:"49";s:5:" تر";s:2:"50";s:6:"ران";s:2:"51";s:5:"ه پ";s:2:"52";s:5:"ې و";s:2:"53";s:5:"ې پ";s:2:"54";s:5:" به";s:2:"55";s:5:" خو";s:2:"56";s:5:"تو ";s:2:"57";s:5:"د د";s:2:"58";s:5:"د ا";s:2:"59";s:5:"ه ت";s:2:"60";s:5:"و پ";s:2:"61";s:5:"يا ";s:2:"62";s:5:" خپ";s:2:"63";s:5:" دو";s:2:"64";s:5:" را";s:2:"65";s:5:" مش";s:2:"66";s:5:" پر";s:2:"67";s:6:"ارو";s:2:"68";s:5:"رې ";s:2:"69";s:5:"م د";s:2:"70";s:6:"مشر";s:2:"71";s:5:" شو";s:2:"72";s:5:" ور";s:2:"73";s:5:"ار ";s:2:"74";s:5:"دى ";s:2:"75";s:5:" اد";s:2:"76";s:5:" دى";s:2:"77";s:5:" مو";s:2:"78";s:5:"د پ";s:2:"79";s:5:"لي ";s:2:"80";s:5:"و ک";s:2:"81";s:5:" مق";s:2:"82";s:5:" يو";s:2:"83";s:5:"ؤ د";s:2:"84";s:6:"خپل";s:2:"85";s:6:"سره";s:2:"86";s:5:"ه چ";s:2:"87";s:5:"ور ";s:2:"88";s:5:" تا";s:2:"89";s:5:" دې";s:2:"90";s:5:" رو";s:2:"91";s:5:" سر";s:2:"92";s:5:" مل";s:2:"93";s:5:" کا";s:2:"94";s:5:"ؤ ا";s:2:"95";s:6:"اره";s:2:"96";s:6:"برو";s:2:"97";s:5:"مه ";s:2:"98";s:5:"ه ب";s:2:"99";s:5:"و ت";s:3:"100";s:6:"پښت";s:3:"101";s:5:" با";s:3:"102";s:5:" دغ";s:3:"103";s:5:" قب";s:3:"104";s:5:" له";s:3:"105";s:5:" وا";s:3:"106";s:5:" پا";s:3:"107";s:5:" پښ";s:3:"108";s:5:"د م";s:3:"109";s:5:"د ه";s:3:"110";s:5:"لې ";s:3:"111";s:6:"مات";s:3:"112";s:5:"مو ";s:3:"113";s:5:"ه ه";s:3:"114";s:5:"وي ";s:3:"115";s:5:"ې ب";s:3:"116";s:5:"ې ک";s:3:"117";s:5:" ده";s:3:"118";s:5:" قا";s:3:"119";s:5:"ال ";s:3:"120";s:6:"اما";s:3:"121";s:5:"د ن";s:3:"122";s:6:"قبر";s:3:"123";s:5:"ه ن";s:3:"124";s:6:"پار";s:3:"125";s:5:" اث";s:3:"126";s:5:" بي";s:3:"127";s:5:" لا";s:3:"128";s:5:" لر";s:3:"129";s:6:"اثا";s:3:"130";s:5:"د خ";s:3:"131";s:6:"دار";s:3:"132";s:6:"ريخ";s:3:"133";s:6:"شرا";s:3:"134";s:6:"مقا";s:3:"135";s:5:"نۍ ";s:3:"136";s:5:"ه ر";s:3:"137";s:5:"ه ل";s:3:"138";s:6:"ولو";s:3:"139";s:5:"يو ";s:3:"140";s:6:"کوم";s:3:"141";s:5:" دد";s:3:"142";s:5:" لو";s:3:"143";s:5:" مح";s:3:"144";s:5:" مر";s:3:"145";s:5:" وو";s:3:"146";s:6:"اتو";s:3:"147";s:6:"اري";s:3:"148";s:6:"الو";s:3:"149";s:6:"اند";s:3:"150";s:6:"خان";s:3:"151";s:5:"د ت";s:3:"152";s:5:"سې ";s:3:"153";s:5:"لى ";s:3:"154";s:6:"نور";s:3:"155";s:5:"و ل";s:3:"156";s:5:"ي چ";s:3:"157";s:5:"ړي ";s:3:"158";s:6:"ښتو";s:3:"159";s:5:"ې ل";s:3:"160";s:5:" جو";s:3:"161";s:5:" سي";s:3:"162";s:5:"ام ";s:3:"163";s:6:"بان";s:3:"164";s:6:"تار";s:3:"165";s:5:"تر ";s:3:"166";s:6:"ثار";s:3:"167";s:5:"خو ";s:3:"168";s:5:"دو ";s:3:"169";s:5:"ر ک";s:3:"170";s:5:"ل د";s:3:"171";s:6:"مون";s:3:"172";s:6:"ندې";s:3:"173";s:5:"و ن";s:3:"174";s:5:"ول ";s:3:"175";s:5:"وه ";s:3:"176";s:5:"ى و";s:3:"177";s:5:"ي د";s:3:"178";s:5:"ې ا";s:3:"179";s:5:"ې ت";s:3:"180";s:5:"ې ي";s:3:"181";s:5:" حک";s:3:"182";s:5:" خب";s:3:"183";s:5:" نه";s:3:"184";s:5:" پو";s:3:"185";s:5:"ا د";s:3:"186";s:5:"تې ";s:3:"187";s:6:"جوړ";s:3:"188";s:6:"حکم";s:3:"189";s:6:"حکو";s:3:"190";s:6:"خبر";s:3:"191";s:6:"دان";s:3:"192";s:5:"ر د";s:3:"193";s:5:"غه ";s:3:"194";s:6:"قاف";s:3:"195";s:6:"محک";s:3:"196";s:6:"وال";s:3:"197";s:6:"ومت";s:3:"198";s:6:"ويل";s:3:"199";s:5:"ى د";s:3:"200";s:5:"ى م";s:3:"201";s:6:"يره";s:3:"202";s:5:"پر ";s:3:"203";s:6:"کول";s:3:"204";s:5:"ې ه";s:3:"205";s:5:" تي";s:3:"206";s:5:" خا";s:3:"207";s:5:" وک";s:3:"208";s:5:" يا";s:3:"209";s:5:" ځا";s:3:"210";s:5:"ؤ ق";s:3:"211";s:6:"انۍ";s:3:"212";s:5:"بى ";s:3:"213";s:5:"غو ";s:3:"214";s:5:"ه خ";s:3:"215";s:5:"و ب";s:3:"216";s:6:"ودا";s:3:"217";s:6:"يدو";s:3:"218";s:5:"ړې ";s:3:"219";s:6:"کال";s:3:"220";s:5:" بر";s:3:"221";s:5:" قد";s:3:"222";s:5:" مي";s:3:"223";s:5:" وي";s:3:"224";s:5:" کر";s:3:"225";s:5:"ؤ م";s:3:"226";s:5:"ات ";s:3:"227";s:6:"ايي";s:3:"228";s:5:"تى ";s:3:"229";s:6:"تيا";s:3:"230";s:6:"تير";s:3:"231";s:6:"خوا";s:3:"232";s:6:"دغو";s:3:"233";s:5:"دم ";s:3:"234";s:6:"ديم";s:3:"235";s:5:"ر و";s:3:"236";s:6:"قدي";s:3:"237";s:5:"م خ";s:3:"238";s:6:"مان";s:3:"239";s:5:"مې ";s:3:"240";s:6:"نيو";s:3:"241";s:5:"نږ ";s:3:"242";s:5:"ه ي";s:3:"243";s:5:"و س";s:3:"244";s:5:"و چ";s:3:"245";s:6:"وان";s:3:"246";s:6:"ورو";s:3:"247";s:6:"ونږ";s:3:"248";s:6:"پور";s:3:"249";s:5:"ړه ";s:3:"250";s:5:"ړو ";s:3:"251";s:5:"ۍ د";s:3:"252";s:5:"ې ن";s:3:"253";s:5:" اه";s:3:"254";s:5:" زي";s:3:"255";s:5:" سو";s:3:"256";s:5:" شي";s:3:"257";s:5:" هر";s:3:"258";s:5:" هغ";s:3:"259";s:5:" ښا";s:3:"260";s:6:"اتل";s:3:"261";s:5:"اق ";s:3:"262";s:6:"اني";s:3:"263";s:6:"بري";s:3:"264";s:5:"بې ";s:3:"265";s:5:"ت ا";s:3:"266";s:5:"د ب";s:3:"267";s:5:"د س";s:3:"268";s:5:"ر م";s:3:"269";s:5:"رى ";s:3:"270";s:6:"عرا";s:3:"271";s:6:"لان";s:3:"272";s:5:"مى ";s:3:"273";s:5:"نى ";s:3:"274";s:5:"و خ";s:3:"275";s:5:"وئ ";s:3:"276";s:6:"ورک";s:3:"277";s:6:"ورې";s:3:"278";s:5:"ون ";s:3:"279";s:6:"وکړ";s:3:"280";s:5:"ى چ";s:3:"281";s:6:"يمه";s:3:"282";s:5:"يې ";s:3:"283";s:6:"ښتن";s:3:"284";s:5:"که ";s:3:"285";s:6:"کړي";s:3:"286";s:5:"ې خ";s:3:"287";s:5:"ے ش";s:3:"288";s:5:" تح";s:3:"289";s:5:" تو";s:3:"290";s:5:" در";s:3:"291";s:5:" دپ";s:3:"292";s:5:" صو";s:3:"293";s:5:" عر";s:3:"294";s:5:" ول";s:3:"295";s:5:" يؤ";s:3:"296";s:5:" پۀ";s:3:"297";s:5:" څو";s:3:"298";s:5:"ا ا";s:3:"299";}s:6:"pidgin";a:300:{s:3:" de";s:1:"0";s:3:" we";s:1:"1";s:3:" di";s:1:"2";s:3:"di ";s:1:"3";s:3:"dem";s:1:"4";s:3:"em ";s:1:"5";s:3:"ay ";s:1:"6";s:3:" sa";s:1:"7";s:3:"or ";s:1:"8";s:3:"say";s:1:"9";s:3:"ke ";s:2:"10";s:3:"ey ";s:2:"11";s:3:" an";s:2:"12";s:3:" go";s:2:"13";s:3:" e ";s:2:"14";s:3:" to";s:2:"15";s:3:" ma";s:2:"16";s:3:"e d";s:2:"17";s:3:"wey";s:2:"18";s:3:"for";s:2:"19";s:3:"nd ";s:2:"20";s:3:"to ";s:2:"21";s:3:" be";s:2:"22";s:3:" fo";s:2:"23";s:3:"ake";s:2:"24";s:3:"im ";s:2:"25";s:3:" pe";s:2:"26";s:3:"le ";s:2:"27";s:3:"go ";s:2:"28";s:3:"ll ";s:2:"29";s:3:"de ";s:2:"30";s:3:"e s";s:2:"31";s:3:"on ";s:2:"32";s:3:"get";s:2:"33";s:3:"ght";s:2:"34";s:3:"igh";s:2:"35";s:3:" ri";s:2:"36";s:3:"et ";s:2:"37";s:3:"rig";s:2:"38";s:3:" ge";s:2:"39";s:3:"y d";s:2:"40";s:3:" na";s:2:"41";s:3:"mak";s:2:"42";s:3:"t t";s:2:"43";s:3:" no";s:2:"44";s:3:"and";s:2:"45";s:3:"tin";s:2:"46";s:3:"ing";s:2:"47";s:3:"eve";s:2:"48";s:3:"ri ";s:2:"49";s:3:" im";s:2:"50";s:3:" am";s:2:"51";s:3:" or";s:2:"52";s:3:"am ";s:2:"53";s:3:"be ";s:2:"54";s:3:" ev";s:2:"55";s:3:" ta";s:2:"56";s:3:"ht ";s:2:"57";s:3:"e w";s:2:"58";s:3:" li";s:2:"59";s:3:"eri";s:2:"60";s:3:"ng ";s:2:"61";s:3:"ver";s:2:"62";s:3:"all";s:2:"63";s:3:"e f";s:2:"64";s:3:"ers";s:2:"65";s:3:"ntr";s:2:"66";s:3:"ont";s:2:"67";s:3:" do";s:2:"68";s:3:"r d";s:2:"69";s:3:" ko";s:2:"70";s:3:" ti";s:2:"71";s:3:"an ";s:2:"72";s:3:"kon";s:2:"73";s:3:"per";s:2:"74";s:3:"tri";s:2:"75";s:3:"y e";s:2:"76";s:3:"rso";s:2:"77";s:3:"son";s:2:"78";s:3:"no ";s:2:"79";s:3:"ome";s:2:"80";s:3:"is ";s:2:"81";s:3:"do ";s:2:"82";s:3:"ne ";s:2:"83";s:3:"one";s:2:"84";s:3:"ion";s:2:"85";s:3:"m g";s:2:"86";s:3:"i k";s:2:"87";s:3:" al";s:2:"88";s:3:"bod";s:2:"89";s:3:"i w";s:2:"90";s:3:"odi";s:2:"91";s:3:" so";s:2:"92";s:3:" wo";s:2:"93";s:3:"o d";s:2:"94";s:3:"st ";s:2:"95";s:3:"t r";s:2:"96";s:3:" of";s:2:"97";s:3:"aim";s:2:"98";s:3:"e g";s:2:"99";s:3:"nai";s:3:"100";s:3:" co";s:3:"101";s:3:"dis";s:3:"102";s:3:"me ";s:3:"103";s:3:"of ";s:3:"104";s:3:" wa";s:3:"105";s:3:"e t";s:3:"106";s:3:" ar";s:3:"107";s:3:"e l";s:3:"108";s:3:"ike";s:3:"109";s:3:"lik";s:3:"110";s:3:"t a";s:3:"111";s:3:"wor";s:3:"112";s:3:"alk";s:3:"113";s:3:"ell";s:3:"114";s:3:"eop";s:3:"115";s:3:"lk ";s:3:"116";s:3:"opl";s:3:"117";s:3:"peo";s:3:"118";s:3:"ple";s:3:"119";s:3:"re ";s:3:"120";s:3:"tal";s:3:"121";s:3:"any";s:3:"122";s:3:"e a";s:3:"123";s:3:"o g";s:3:"124";s:3:"art";s:3:"125";s:3:"cle";s:3:"126";s:3:"i p";s:3:"127";s:3:"icl";s:3:"128";s:3:"rti";s:3:"129";s:3:"the";s:3:"130";s:3:"tic";s:3:"131";s:3:"we ";s:3:"132";s:3:"f d";s:3:"133";s:3:"in ";s:3:"134";s:3:" mu";s:3:"135";s:3:"e n";s:3:"136";s:3:"e o";s:3:"137";s:3:"mus";s:3:"138";s:3:"n d";s:3:"139";s:3:"na ";s:3:"140";s:3:"o m";s:3:"141";s:3:"ust";s:3:"142";s:3:"wel";s:3:"143";s:3:"e e";s:3:"144";s:3:"her";s:3:"145";s:3:"m d";s:3:"146";s:3:"nt ";s:3:"147";s:3:" fi";s:3:"148";s:3:"at ";s:3:"149";s:3:"e b";s:3:"150";s:3:"it ";s:3:"151";s:3:"m w";s:3:"152";s:3:"o t";s:3:"153";s:3:"wan";s:3:"154";s:3:"com";s:3:"155";s:3:"da ";s:3:"156";s:3:"fit";s:3:"157";s:3:"m b";s:3:"158";s:3:"so ";s:3:"159";s:3:" fr";s:3:"160";s:3:"ce ";s:3:"161";s:3:"er ";s:3:"162";s:3:"o a";s:3:"163";s:3:" if";s:3:"164";s:3:" on";s:3:"165";s:3:"ent";s:3:"166";s:3:"if ";s:3:"167";s:3:"ind";s:3:"168";s:3:"kin";s:3:"169";s:3:"l d";s:3:"170";s:3:"man";s:3:"171";s:3:"o s";s:3:"172";s:3:" se";s:3:"173";s:3:"y a";s:3:"174";s:3:"y m";s:3:"175";s:3:" re";s:3:"176";s:3:"ee ";s:3:"177";s:3:"k a";s:3:"178";s:3:"t s";s:3:"179";s:3:"ve ";s:3:"180";s:3:"y w";s:3:"181";s:3:" ki";s:3:"182";s:3:"eti";s:3:"183";s:3:"men";s:3:"184";s:3:"ta ";s:3:"185";s:3:"y n";s:3:"186";s:3:"d t";s:3:"187";s:3:"dey";s:3:"188";s:3:"e c";s:3:"189";s:3:"i o";s:3:"190";s:3:"ibo";s:3:"191";s:3:"ld ";s:3:"192";s:3:"m t";s:3:"193";s:3:"n b";s:3:"194";s:3:"o b";s:3:"195";s:3:"ow ";s:3:"196";s:3:"ree";s:3:"197";s:3:"rio";s:3:"198";s:3:"t d";s:3:"199";s:3:" hu";s:3:"200";s:3:" su";s:3:"201";s:3:"en ";s:3:"202";s:3:"hts";s:3:"203";s:3:"ive";s:3:"204";s:3:"m n";s:3:"205";s:3:"n g";s:3:"206";s:3:"ny ";s:3:"207";s:3:"oth";s:3:"208";s:3:"ts ";s:3:"209";s:3:" as";s:3:"210";s:3:" wh";s:3:"211";s:3:"as ";s:3:"212";s:3:"gom";s:3:"213";s:3:"hum";s:3:"214";s:3:"k s";s:3:"215";s:3:"oda";s:3:"216";s:3:"ork";s:3:"217";s:3:"se ";s:3:"218";s:3:"uma";s:3:"219";s:3:"ut ";s:3:"220";s:3:" ba";s:3:"221";s:3:" ot";s:3:"222";s:3:"ano";s:3:"223";s:3:"m a";s:3:"224";s:3:"m s";s:3:"225";s:3:"nod";s:3:"226";s:3:"om ";s:3:"227";s:3:"r a";s:3:"228";s:3:"r i";s:3:"229";s:3:"rk ";s:3:"230";s:3:" fa";s:3:"231";s:3:" si";s:3:"232";s:3:" th";s:3:"233";s:3:"ad ";s:3:"234";s:3:"e m";s:3:"235";s:3:"eac";s:3:"236";s:3:"m m";s:3:"237";s:3:"n w";s:3:"238";s:3:"nob";s:3:"239";s:3:"orl";s:3:"240";s:3:"out";s:3:"241";s:3:"own";s:3:"242";s:3:"r s";s:3:"243";s:3:"r w";s:3:"244";s:3:"rib";s:3:"245";s:3:"rld";s:3:"246";s:3:"s w";s:3:"247";s:3:"ure";s:3:"248";s:3:"wn ";s:3:"249";s:3:" ow";s:3:"250";s:3:"a d";s:3:"251";s:3:"bad";s:3:"252";s:3:"ch ";s:3:"253";s:3:"fre";s:3:"254";s:3:"gs ";s:3:"255";s:3:"m k";s:3:"256";s:3:"nce";s:3:"257";s:3:"ngs";s:3:"258";s:3:"o f";s:3:"259";s:3:"obo";s:3:"260";s:3:"rea";s:3:"261";s:3:"sur";s:3:"262";s:3:"y o";s:3:"263";s:3:" ab";s:3:"264";s:3:" un";s:3:"265";s:3:"abo";s:3:"266";s:3:"ach";s:3:"267";s:3:"bou";s:3:"268";s:3:"d m";s:3:"269";s:3:"dat";s:3:"270";s:3:"e p";s:3:"271";s:3:"g w";s:3:"272";s:3:"hol";s:3:"273";s:3:"i m";s:3:"274";s:3:"i r";s:3:"275";s:3:"m f";s:3:"276";s:3:"m o";s:3:"277";s:3:"n o";s:3:"278";s:3:"now";s:3:"279";s:3:"ry ";s:3:"280";s:3:"s a";s:3:"281";s:3:"t o";s:3:"282";s:3:"tay";s:3:"283";s:3:"wet";s:3:"284";s:3:" ag";s:3:"285";s:3:" bo";s:3:"286";s:3:" da";s:3:"287";s:3:" pr";s:3:"288";s:3:"arr";s:3:"289";s:3:"ati";s:3:"290";s:3:"d d";s:3:"291";s:3:"d p";s:3:"292";s:3:"i g";s:3:"293";s:3:"i t";s:3:"294";s:3:"liv";s:3:"295";s:3:"ly ";s:3:"296";s:3:"n a";s:3:"297";s:3:"od ";s:3:"298";s:3:"ok ";s:3:"299";}s:6:"polish";a:300:{s:3:"ie ";s:1:"0";s:3:"nie";s:1:"1";s:3:"em ";s:1:"2";s:3:" ni";s:1:"3";s:3:" po";s:1:"4";s:3:" pr";s:1:"5";s:3:"dzi";s:1:"6";s:3:" na";s:1:"7";s:4:"że ";s:1:"8";s:3:"rze";s:1:"9";s:3:"na ";s:2:"10";s:4:"łem";s:2:"11";s:3:"wie";s:2:"12";s:3:" w ";s:2:"13";s:4:" że";s:2:"14";s:3:"go ";s:2:"15";s:3:" by";s:2:"16";s:3:"prz";s:2:"17";s:3:"owa";s:2:"18";s:4:"ię ";s:2:"19";s:3:" do";s:2:"20";s:3:" si";s:2:"21";s:3:"owi";s:2:"22";s:3:" pa";s:2:"23";s:3:" za";s:2:"24";s:3:"ch ";s:2:"25";s:3:"ego";s:2:"26";s:4:"ał ";s:2:"27";s:4:"się";s:2:"28";s:3:"ej ";s:2:"29";s:4:"wał";s:2:"30";s:3:"ym ";s:2:"31";s:3:"ani";s:2:"32";s:4:"ałe";s:2:"33";s:3:"to ";s:2:"34";s:3:" i ";s:2:"35";s:3:" to";s:2:"36";s:3:" te";s:2:"37";s:3:"e p";s:2:"38";s:3:" je";s:2:"39";s:3:" z ";s:2:"40";s:3:"czy";s:2:"41";s:4:"był";s:2:"42";s:3:"pan";s:2:"43";s:3:"sta";s:2:"44";s:3:"kie";s:2:"45";s:3:" ja";s:2:"46";s:3:"do ";s:2:"47";s:3:" ch";s:2:"48";s:3:" cz";s:2:"49";s:3:" wi";s:2:"50";s:4:"iał";s:2:"51";s:3:"a p";s:2:"52";s:3:"pow";s:2:"53";s:3:" mi";s:2:"54";s:3:"li ";s:2:"55";s:3:"eni";s:2:"56";s:3:"zie";s:2:"57";s:3:" ta";s:2:"58";s:3:" wa";s:2:"59";s:4:"ło ";s:2:"60";s:4:"ać ";s:2:"61";s:3:"dy ";s:2:"62";s:3:"ak ";s:2:"63";s:3:"e w";s:2:"64";s:3:" a ";s:2:"65";s:3:" od";s:2:"66";s:3:" st";s:2:"67";s:3:"nia";s:2:"68";s:3:"rzy";s:2:"69";s:3:"ied";s:2:"70";s:3:" kt";s:2:"71";s:3:"odz";s:2:"72";s:3:"cie";s:2:"73";s:3:"cze";s:2:"74";s:3:"ia ";s:2:"75";s:3:"iel";s:2:"76";s:4:"któ";s:2:"77";s:3:"o p";s:2:"78";s:4:"tór";s:2:"79";s:4:"ści";s:2:"80";s:3:" sp";s:2:"81";s:3:" wy";s:2:"82";s:3:"jak";s:2:"83";s:3:"tak";s:2:"84";s:3:"zy ";s:2:"85";s:3:" mo";s:2:"86";s:5:"ałę";s:2:"87";s:3:"pro";s:2:"88";s:3:"ski";s:2:"89";s:3:"tem";s:2:"90";s:5:"łęs";s:2:"91";s:3:" tr";s:2:"92";s:3:"e m";s:2:"93";s:3:"jes";s:2:"94";s:3:"my ";s:2:"95";s:3:" ro";s:2:"96";s:3:"edz";s:2:"97";s:3:"eli";s:2:"98";s:3:"iej";s:2:"99";s:3:" rz";s:3:"100";s:3:"a n";s:3:"101";s:3:"ale";s:3:"102";s:3:"an ";s:3:"103";s:3:"e s";s:3:"104";s:3:"est";s:3:"105";s:3:"le ";s:3:"106";s:3:"o s";s:3:"107";s:3:"i p";s:3:"108";s:3:"ki ";s:3:"109";s:3:" co";s:3:"110";s:3:"ada";s:3:"111";s:3:"czn";s:3:"112";s:3:"e t";s:3:"113";s:3:"e z";s:3:"114";s:3:"ent";s:3:"115";s:3:"ny ";s:3:"116";s:3:"pre";s:3:"117";s:4:"rzą";s:3:"118";s:3:"y s";s:3:"119";s:3:" ko";s:3:"120";s:3:" o ";s:3:"121";s:3:"ach";s:3:"122";s:3:"am ";s:3:"123";s:3:"e n";s:3:"124";s:3:"o t";s:3:"125";s:3:"oli";s:3:"126";s:3:"pod";s:3:"127";s:3:"zia";s:3:"128";s:3:" go";s:3:"129";s:3:" ka";s:3:"130";s:3:"by ";s:3:"131";s:3:"ieg";s:3:"132";s:3:"ier";s:3:"133";s:4:"noś";s:3:"134";s:3:"roz";s:3:"135";s:3:"spo";s:3:"136";s:3:"ych";s:3:"137";s:4:"ząd";s:3:"138";s:3:" mn";s:3:"139";s:3:"acz";s:3:"140";s:3:"adz";s:3:"141";s:3:"bie";s:3:"142";s:3:"cho";s:3:"143";s:3:"mni";s:3:"144";s:3:"o n";s:3:"145";s:3:"ost";s:3:"146";s:3:"pra";s:3:"147";s:3:"ze ";s:3:"148";s:4:"ła ";s:3:"149";s:3:" so";s:3:"150";s:3:"a m";s:3:"151";s:3:"cza";s:3:"152";s:3:"iem";s:3:"153";s:4:"ić ";s:3:"154";s:3:"obi";s:3:"155";s:4:"ył ";s:3:"156";s:4:"yło";s:3:"157";s:3:" mu";s:3:"158";s:4:" mó";s:3:"159";s:3:"a t";s:3:"160";s:3:"acj";s:3:"161";s:3:"ci ";s:3:"162";s:3:"e b";s:3:"163";s:3:"ich";s:3:"164";s:3:"kan";s:3:"165";s:3:"mi ";s:3:"166";s:3:"mie";s:3:"167";s:4:"ośc";s:3:"168";s:3:"row";s:3:"169";s:3:"zen";s:3:"170";s:3:"zyd";s:3:"171";s:3:" al";s:3:"172";s:3:" re";s:3:"173";s:3:"a w";s:3:"174";s:3:"den";s:3:"175";s:3:"edy";s:3:"176";s:4:"ił ";s:3:"177";s:3:"ko ";s:3:"178";s:3:"o w";s:3:"179";s:3:"rac";s:3:"180";s:4:"śmy";s:3:"181";s:3:" ma";s:3:"182";s:3:" ra";s:3:"183";s:3:" sz";s:3:"184";s:3:" ty";s:3:"185";s:3:"e j";s:3:"186";s:3:"isk";s:3:"187";s:3:"ji ";s:3:"188";s:3:"ka ";s:3:"189";s:3:"m s";s:3:"190";s:3:"no ";s:3:"191";s:3:"o z";s:3:"192";s:3:"rez";s:3:"193";s:3:"wa ";s:3:"194";s:4:"ów ";s:3:"195";s:4:"łow";s:3:"196";s:5:"ść ";s:3:"197";s:3:" ob";s:3:"198";s:3:"ech";s:3:"199";s:3:"ecz";s:3:"200";s:3:"ezy";s:3:"201";s:3:"i w";s:3:"202";s:3:"ja ";s:3:"203";s:3:"kon";s:3:"204";s:4:"mów";s:3:"205";s:3:"ne ";s:3:"206";s:3:"ni ";s:3:"207";s:3:"now";s:3:"208";s:3:"nym";s:3:"209";s:3:"pol";s:3:"210";s:3:"pot";s:3:"211";s:3:"yde";s:3:"212";s:3:" dl";s:3:"213";s:3:" sy";s:3:"214";s:3:"a s";s:3:"215";s:3:"aki";s:3:"216";s:3:"ali";s:3:"217";s:3:"dla";s:3:"218";s:3:"icz";s:3:"219";s:3:"ku ";s:3:"220";s:3:"ocz";s:3:"221";s:3:"st ";s:3:"222";s:3:"str";s:3:"223";s:3:"szy";s:3:"224";s:3:"trz";s:3:"225";s:3:"wia";s:3:"226";s:3:"y p";s:3:"227";s:3:"za ";s:3:"228";s:3:" wt";s:3:"229";s:3:"chc";s:3:"230";s:3:"esz";s:3:"231";s:3:"iec";s:3:"232";s:3:"im ";s:3:"233";s:3:"la ";s:3:"234";s:3:"o m";s:3:"235";s:3:"sa ";s:3:"236";s:4:"wać";s:3:"237";s:3:"y n";s:3:"238";s:3:"zac";s:3:"239";s:3:"zec";s:3:"240";s:3:" gd";s:3:"241";s:3:"a z";s:3:"242";s:3:"ard";s:3:"243";s:3:"co ";s:3:"244";s:3:"dar";s:3:"245";s:3:"e r";s:3:"246";s:3:"ien";s:3:"247";s:3:"m n";s:3:"248";s:3:"m w";s:3:"249";s:3:"mia";s:3:"250";s:4:"moż";s:3:"251";s:3:"raw";s:3:"252";s:3:"rdz";s:3:"253";s:3:"tan";s:3:"254";s:3:"ted";s:3:"255";s:3:"teg";s:3:"256";s:4:"wił";s:3:"257";s:3:"wte";s:3:"258";s:3:"y z";s:3:"259";s:3:"zna";s:3:"260";s:4:"zło";s:3:"261";s:3:"a r";s:3:"262";s:3:"awi";s:3:"263";s:3:"bar";s:3:"264";s:3:"cji";s:3:"265";s:4:"czą";s:3:"266";s:3:"dow";s:3:"267";s:4:"eż ";s:3:"268";s:3:"gdy";s:3:"269";s:3:"iek";s:3:"270";s:3:"je ";s:3:"271";s:3:"o d";s:3:"272";s:4:"tał";s:3:"273";s:3:"wal";s:3:"274";s:3:"wsz";s:3:"275";s:3:"zed";s:3:"276";s:4:"ówi";s:3:"277";s:4:"ęsa";s:3:"278";s:3:" ba";s:3:"279";s:3:" lu";s:3:"280";s:3:" wo";s:3:"281";s:3:"aln";s:3:"282";s:3:"arn";s:3:"283";s:3:"ba ";s:3:"284";s:3:"dzo";s:3:"285";s:3:"e c";s:3:"286";s:3:"hod";s:3:"287";s:3:"igi";s:3:"288";s:3:"lig";s:3:"289";s:3:"m p";s:3:"290";s:4:"myś";s:3:"291";s:3:"o c";s:3:"292";s:3:"oni";s:3:"293";s:3:"rel";s:3:"294";s:3:"sku";s:3:"295";s:3:"ste";s:3:"296";s:3:"y w";s:3:"297";s:3:"yst";s:3:"298";s:3:"z w";s:3:"299";}s:10:"portuguese";a:300:{s:3:"de ";s:1:"0";s:3:" de";s:1:"1";s:3:"os ";s:1:"2";s:3:"as ";s:1:"3";s:3:"que";s:1:"4";s:3:" co";s:1:"5";s:4:"ão ";s:1:"6";s:3:"o d";s:1:"7";s:3:" qu";s:1:"8";s:3:"ue ";s:1:"9";s:3:" a ";s:2:"10";s:3:"do ";s:2:"11";s:3:"ent";s:2:"12";s:3:" se";s:2:"13";s:3:"a d";s:2:"14";s:3:"s d";s:2:"15";s:3:"e a";s:2:"16";s:3:"es ";s:2:"17";s:3:" pr";s:2:"18";s:3:"ra ";s:2:"19";s:3:"da ";s:2:"20";s:3:" es";s:2:"21";s:3:" pa";s:2:"22";s:3:"to ";s:2:"23";s:3:" o ";s:2:"24";s:3:"em ";s:2:"25";s:3:"con";s:2:"26";s:3:"o p";s:2:"27";s:3:" do";s:2:"28";s:3:"est";s:2:"29";s:3:"nte";s:2:"30";s:5:"ção";s:2:"31";s:3:" da";s:2:"32";s:3:" re";s:2:"33";s:3:"ma ";s:2:"34";s:3:"par";s:2:"35";s:3:" te";s:2:"36";s:3:"ara";s:2:"37";s:3:"ida";s:2:"38";s:3:" e ";s:2:"39";s:3:"ade";s:2:"40";s:3:"is ";s:2:"41";s:3:" um";s:2:"42";s:3:" po";s:2:"43";s:3:"a a";s:2:"44";s:3:"a p";s:2:"45";s:3:"dad";s:2:"46";s:3:"no ";s:2:"47";s:3:"te ";s:2:"48";s:3:" no";s:2:"49";s:5:"açã";s:2:"50";s:3:"pro";s:2:"51";s:3:"al ";s:2:"52";s:3:"com";s:2:"53";s:3:"e d";s:2:"54";s:3:"s a";s:2:"55";s:3:" as";s:2:"56";s:3:"a c";s:2:"57";s:3:"er ";s:2:"58";s:3:"men";s:2:"59";s:3:"s e";s:2:"60";s:3:"ais";s:2:"61";s:3:"nto";s:2:"62";s:3:"res";s:2:"63";s:3:"a s";s:2:"64";s:3:"ado";s:2:"65";s:3:"ist";s:2:"66";s:3:"s p";s:2:"67";s:3:"tem";s:2:"68";s:3:"e c";s:2:"69";s:3:"e s";s:2:"70";s:3:"ia ";s:2:"71";s:3:"o s";s:2:"72";s:3:"o a";s:2:"73";s:3:"o c";s:2:"74";s:3:"e p";s:2:"75";s:3:"sta";s:2:"76";s:3:"ta ";s:2:"77";s:3:"tra";s:2:"78";s:3:"ura";s:2:"79";s:3:" di";s:2:"80";s:3:" pe";s:2:"81";s:3:"ar ";s:2:"82";s:3:"e e";s:2:"83";s:3:"ser";s:2:"84";s:3:"uma";s:2:"85";s:3:"mos";s:2:"86";s:3:"se ";s:2:"87";s:3:" ca";s:2:"88";s:3:"o e";s:2:"89";s:3:" na";s:2:"90";s:3:"a e";s:2:"91";s:3:"des";s:2:"92";s:3:"ont";s:2:"93";s:3:"por";s:2:"94";s:3:" in";s:2:"95";s:3:" ma";s:2:"96";s:3:"ect";s:2:"97";s:3:"o q";s:2:"98";s:3:"ria";s:2:"99";s:3:"s c";s:3:"100";s:3:"ste";s:3:"101";s:3:"ver";s:3:"102";s:3:"cia";s:3:"103";s:3:"dos";s:3:"104";s:3:"ica";s:3:"105";s:3:"str";s:3:"106";s:3:" ao";s:3:"107";s:3:" em";s:3:"108";s:3:"das";s:3:"109";s:3:"e t";s:3:"110";s:3:"ito";s:3:"111";s:3:"iza";s:3:"112";s:3:"pre";s:3:"113";s:3:"tos";s:3:"114";s:4:" nã";s:3:"115";s:3:"ada";s:3:"116";s:4:"não";s:3:"117";s:3:"ess";s:3:"118";s:3:"eve";s:3:"119";s:3:"or ";s:3:"120";s:3:"ran";s:3:"121";s:3:"s n";s:3:"122";s:3:"s t";s:3:"123";s:3:"tur";s:3:"124";s:3:" ac";s:3:"125";s:3:" fa";s:3:"126";s:3:"a r";s:3:"127";s:3:"ens";s:3:"128";s:3:"eri";s:3:"129";s:3:"na ";s:3:"130";s:3:"sso";s:3:"131";s:3:" si";s:3:"132";s:4:" é ";s:3:"133";s:3:"bra";s:3:"134";s:3:"esp";s:3:"135";s:3:"mo ";s:3:"136";s:3:"nos";s:3:"137";s:3:"ro ";s:3:"138";s:3:"um ";s:3:"139";s:3:"a n";s:3:"140";s:3:"ao ";s:3:"141";s:3:"ico";s:3:"142";s:3:"liz";s:3:"143";s:3:"min";s:3:"144";s:3:"o n";s:3:"145";s:3:"ons";s:3:"146";s:3:"pri";s:3:"147";s:3:"ten";s:3:"148";s:3:"tic";s:3:"149";s:4:"ões";s:3:"150";s:3:" tr";s:3:"151";s:3:"a m";s:3:"152";s:3:"aga";s:3:"153";s:3:"e n";s:3:"154";s:3:"ili";s:3:"155";s:3:"ime";s:3:"156";s:3:"m a";s:3:"157";s:3:"nci";s:3:"158";s:3:"nha";s:3:"159";s:3:"nta";s:3:"160";s:3:"spe";s:3:"161";s:3:"tiv";s:3:"162";s:3:"am ";s:3:"163";s:3:"ano";s:3:"164";s:3:"arc";s:3:"165";s:3:"ass";s:3:"166";s:3:"cer";s:3:"167";s:3:"e o";s:3:"168";s:3:"ece";s:3:"169";s:3:"emo";s:3:"170";s:3:"ga ";s:3:"171";s:3:"o m";s:3:"172";s:3:"rag";s:3:"173";s:3:"so ";s:3:"174";s:4:"são";s:3:"175";s:3:" au";s:3:"176";s:3:" os";s:3:"177";s:3:" sa";s:3:"178";s:3:"ali";s:3:"179";s:3:"ca ";s:3:"180";s:3:"ema";s:3:"181";s:3:"emp";s:3:"182";s:3:"ici";s:3:"183";s:3:"ido";s:3:"184";s:3:"inh";s:3:"185";s:3:"iss";s:3:"186";s:3:"l d";s:3:"187";s:3:"la ";s:3:"188";s:3:"lic";s:3:"189";s:3:"m c";s:3:"190";s:3:"mai";s:3:"191";s:3:"onc";s:3:"192";s:3:"pec";s:3:"193";s:3:"ram";s:3:"194";s:3:"s q";s:3:"195";s:3:" ci";s:3:"196";s:3:" en";s:3:"197";s:3:" fo";s:3:"198";s:3:"a o";s:3:"199";s:3:"ame";s:3:"200";s:3:"car";s:3:"201";s:3:"co ";s:3:"202";s:3:"der";s:3:"203";s:3:"eir";s:3:"204";s:3:"ho ";s:3:"205";s:3:"io ";s:3:"206";s:3:"om ";s:3:"207";s:3:"ora";s:3:"208";s:3:"r a";s:3:"209";s:3:"sen";s:3:"210";s:3:"ter";s:3:"211";s:3:" br";s:3:"212";s:3:" ex";s:3:"213";s:3:"a u";s:3:"214";s:3:"cul";s:3:"215";s:3:"dev";s:3:"216";s:3:"e u";s:3:"217";s:3:"ha ";s:3:"218";s:3:"mpr";s:3:"219";s:3:"nce";s:3:"220";s:3:"oca";s:3:"221";s:3:"ove";s:3:"222";s:3:"rio";s:3:"223";s:3:"s o";s:3:"224";s:3:"sa ";s:3:"225";s:3:"sem";s:3:"226";s:3:"tes";s:3:"227";s:3:"uni";s:3:"228";s:3:"ven";s:3:"229";s:4:"zaç";s:3:"230";s:5:"çõe";s:3:"231";s:3:" ad";s:3:"232";s:3:" al";s:3:"233";s:3:" an";s:3:"234";s:3:" mi";s:3:"235";s:3:" mo";s:3:"236";s:3:" ve";s:3:"237";s:4:" à ";s:3:"238";s:3:"a i";s:3:"239";s:3:"a q";s:3:"240";s:3:"ala";s:3:"241";s:3:"amo";s:3:"242";s:3:"bli";s:3:"243";s:3:"cen";s:3:"244";s:3:"col";s:3:"245";s:3:"cos";s:3:"246";s:3:"cto";s:3:"247";s:3:"e m";s:3:"248";s:3:"e v";s:3:"249";s:3:"ede";s:3:"250";s:4:"gás";s:3:"251";s:3:"ias";s:3:"252";s:3:"ita";s:3:"253";s:3:"iva";s:3:"254";s:3:"ndo";s:3:"255";s:3:"o t";s:3:"256";s:3:"ore";s:3:"257";s:3:"r d";s:3:"258";s:3:"ral";s:3:"259";s:3:"rea";s:3:"260";s:3:"s f";s:3:"261";s:3:"sid";s:3:"262";s:3:"tro";s:3:"263";s:3:"vel";s:3:"264";s:3:"vid";s:3:"265";s:4:"ás ";s:3:"266";s:3:" ap";s:3:"267";s:3:" ar";s:3:"268";s:3:" ce";s:3:"269";s:3:" ou";s:3:"270";s:4:" pú";s:3:"271";s:3:" so";s:3:"272";s:3:" vi";s:3:"273";s:3:"a f";s:3:"274";s:3:"act";s:3:"275";s:3:"arr";s:3:"276";s:3:"bil";s:3:"277";s:3:"cam";s:3:"278";s:3:"e f";s:3:"279";s:3:"e i";s:3:"280";s:3:"el ";s:3:"281";s:3:"for";s:3:"282";s:3:"lem";s:3:"283";s:3:"lid";s:3:"284";s:3:"lo ";s:3:"285";s:3:"m d";s:3:"286";s:3:"mar";s:3:"287";s:3:"nde";s:3:"288";s:3:"o o";s:3:"289";s:3:"omo";s:3:"290";s:3:"ort";s:3:"291";s:3:"per";s:3:"292";s:4:"púb";s:3:"293";s:3:"r u";s:3:"294";s:3:"rei";s:3:"295";s:3:"rem";s:3:"296";s:3:"ros";s:3:"297";s:3:"rre";s:3:"298";s:3:"ssi";s:3:"299";}s:8:"romanian";a:300:{s:3:" de";s:1:"0";s:4:" în";s:1:"1";s:3:"de ";s:1:"2";s:3:" a ";s:1:"3";s:3:"ul ";s:1:"4";s:3:" co";s:1:"5";s:4:"în ";s:1:"6";s:3:"re ";s:1:"7";s:3:"e d";s:1:"8";s:3:"ea ";s:1:"9";s:3:" di";s:2:"10";s:3:" pr";s:2:"11";s:3:"le ";s:2:"12";s:4:"şi ";s:2:"13";s:3:"are";s:2:"14";s:3:"at ";s:2:"15";s:3:"con";s:2:"16";s:3:"ui ";s:2:"17";s:4:" şi";s:2:"18";s:3:"i d";s:2:"19";s:3:"ii ";s:2:"20";s:3:" cu";s:2:"21";s:3:"e a";s:2:"22";s:3:"lui";s:2:"23";s:3:"ern";s:2:"24";s:3:"te ";s:2:"25";s:3:"cu ";s:2:"26";s:3:" la";s:2:"27";s:3:"a c";s:2:"28";s:4:"că ";s:2:"29";s:3:"din";s:2:"30";s:3:"e c";s:2:"31";s:3:"or ";s:2:"32";s:3:"ulu";s:2:"33";s:3:"ne ";s:2:"34";s:3:"ter";s:2:"35";s:3:"la ";s:2:"36";s:4:"să ";s:2:"37";s:3:"tat";s:2:"38";s:3:"tre";s:2:"39";s:3:" ac";s:2:"40";s:4:" să";s:2:"41";s:3:"est";s:2:"42";s:3:"st ";s:2:"43";s:4:"tă ";s:2:"44";s:3:" ca";s:2:"45";s:3:" ma";s:2:"46";s:3:" pe";s:2:"47";s:3:"cur";s:2:"48";s:3:"ist";s:2:"49";s:4:"mân";s:2:"50";s:3:"a d";s:2:"51";s:3:"i c";s:2:"52";s:3:"nat";s:2:"53";s:3:" ce";s:2:"54";s:3:"i a";s:2:"55";s:3:"ia ";s:2:"56";s:3:"in ";s:2:"57";s:3:"scu";s:2:"58";s:3:" mi";s:2:"59";s:3:"ato";s:2:"60";s:4:"aţi";s:2:"61";s:3:"ie ";s:2:"62";s:3:" re";s:2:"63";s:3:" se";s:2:"64";s:3:"a a";s:2:"65";s:3:"int";s:2:"66";s:3:"ntr";s:2:"67";s:3:"tru";s:2:"68";s:3:"uri";s:2:"69";s:4:"ă a";s:2:"70";s:3:" fo";s:2:"71";s:3:" pa";s:2:"72";s:3:"ate";s:2:"73";s:3:"ini";s:2:"74";s:3:"tul";s:2:"75";s:3:"ent";s:2:"76";s:3:"min";s:2:"77";s:3:"pre";s:2:"78";s:3:"pro";s:2:"79";s:3:"a p";s:2:"80";s:3:"e p";s:2:"81";s:3:"e s";s:2:"82";s:3:"ei ";s:2:"83";s:4:"nă ";s:2:"84";s:3:"par";s:2:"85";s:3:"rna";s:2:"86";s:3:"rul";s:2:"87";s:3:"tor";s:2:"88";s:3:" in";s:2:"89";s:3:" ro";s:2:"90";s:3:" tr";s:2:"91";s:3:" un";s:2:"92";s:3:"al ";s:2:"93";s:3:"ale";s:2:"94";s:3:"art";s:2:"95";s:3:"ce ";s:2:"96";s:3:"e e";s:2:"97";s:4:"e î";s:2:"98";s:3:"fos";s:2:"99";s:3:"ita";s:3:"100";s:3:"nte";s:3:"101";s:4:"omâ";s:3:"102";s:3:"ost";s:3:"103";s:3:"rom";s:3:"104";s:3:"ru ";s:3:"105";s:3:"str";s:3:"106";s:3:"ver";s:3:"107";s:3:" ex";s:3:"108";s:3:" na";s:3:"109";s:3:"a f";s:3:"110";s:3:"lor";s:3:"111";s:3:"nis";s:3:"112";s:3:"rea";s:3:"113";s:3:"rit";s:3:"114";s:3:" al";s:3:"115";s:3:" eu";s:3:"116";s:3:" no";s:3:"117";s:3:"ace";s:3:"118";s:3:"cer";s:3:"119";s:3:"ile";s:3:"120";s:3:"nal";s:3:"121";s:3:"pri";s:3:"122";s:3:"ri ";s:3:"123";s:3:"sta";s:3:"124";s:3:"ste";s:3:"125";s:4:"ţie";s:3:"126";s:3:" au";s:3:"127";s:3:" da";s:3:"128";s:3:" ju";s:3:"129";s:3:" po";s:3:"130";s:3:"ar ";s:3:"131";s:3:"au ";s:3:"132";s:3:"ele";s:3:"133";s:3:"ere";s:3:"134";s:3:"eri";s:3:"135";s:3:"ina";s:3:"136";s:3:"n a";s:3:"137";s:3:"n c";s:3:"138";s:3:"res";s:3:"139";s:3:"se ";s:3:"140";s:3:"t a";s:3:"141";s:3:"tea";s:3:"142";s:4:" că";s:3:"143";s:3:" do";s:3:"144";s:3:" fi";s:3:"145";s:3:"a s";s:3:"146";s:4:"ată";s:3:"147";s:3:"com";s:3:"148";s:4:"e ş";s:3:"149";s:3:"eur";s:3:"150";s:3:"guv";s:3:"151";s:3:"i s";s:3:"152";s:3:"ice";s:3:"153";s:3:"ili";s:3:"154";s:3:"na ";s:3:"155";s:3:"rec";s:3:"156";s:3:"rep";s:3:"157";s:3:"ril";s:3:"158";s:3:"rne";s:3:"159";s:3:"rti";s:3:"160";s:3:"uro";s:3:"161";s:3:"uve";s:3:"162";s:4:"ă p";s:3:"163";s:3:" ar";s:3:"164";s:3:" o ";s:3:"165";s:3:" su";s:3:"166";s:3:" vi";s:3:"167";s:3:"dec";s:3:"168";s:3:"dre";s:3:"169";s:3:"oar";s:3:"170";s:3:"ons";s:3:"171";s:3:"pe ";s:3:"172";s:3:"rii";s:3:"173";s:3:" ad";s:3:"174";s:3:" ge";s:3:"175";s:3:"a m";s:3:"176";s:3:"a r";s:3:"177";s:3:"ain";s:3:"178";s:3:"ali";s:3:"179";s:3:"car";s:3:"180";s:3:"cat";s:3:"181";s:3:"ecu";s:3:"182";s:3:"ene";s:3:"183";s:3:"ept";s:3:"184";s:3:"ext";s:3:"185";s:3:"ilo";s:3:"186";s:3:"iu ";s:3:"187";s:3:"n p";s:3:"188";s:3:"ori";s:3:"189";s:3:"sec";s:3:"190";s:3:"u p";s:3:"191";s:3:"une";s:3:"192";s:4:"ă c";s:3:"193";s:4:"şti";s:3:"194";s:4:"ţia";s:3:"195";s:3:" ch";s:3:"196";s:3:" gu";s:3:"197";s:3:"ai ";s:3:"198";s:3:"ani";s:3:"199";s:3:"cea";s:3:"200";s:3:"e f";s:3:"201";s:3:"isc";s:3:"202";s:3:"l a";s:3:"203";s:3:"lic";s:3:"204";s:3:"liu";s:3:"205";s:3:"mar";s:3:"206";s:3:"nic";s:3:"207";s:3:"nt ";s:3:"208";s:3:"nul";s:3:"209";s:3:"ris";s:3:"210";s:3:"t c";s:3:"211";s:3:"t p";s:3:"212";s:3:"tic";s:3:"213";s:3:"tid";s:3:"214";s:3:"u a";s:3:"215";s:3:"ucr";s:3:"216";s:3:" as";s:3:"217";s:3:" dr";s:3:"218";s:3:" fa";s:3:"219";s:3:" nu";s:3:"220";s:3:" pu";s:3:"221";s:3:" to";s:3:"222";s:3:"cra";s:3:"223";s:3:"dis";s:3:"224";s:4:"enţ";s:3:"225";s:3:"esc";s:3:"226";s:3:"gen";s:3:"227";s:3:"it ";s:3:"228";s:3:"ivi";s:3:"229";s:3:"l d";s:3:"230";s:3:"n d";s:3:"231";s:3:"nd ";s:3:"232";s:3:"nu ";s:3:"233";s:3:"ond";s:3:"234";s:3:"pen";s:3:"235";s:3:"ral";s:3:"236";s:3:"riv";s:3:"237";s:3:"rte";s:3:"238";s:3:"sti";s:3:"239";s:3:"t d";s:3:"240";s:3:"ta ";s:3:"241";s:3:"to ";s:3:"242";s:3:"uni";s:3:"243";s:3:"xte";s:3:"244";s:4:"ând";s:3:"245";s:4:"îns";s:3:"246";s:4:"ă s";s:3:"247";s:3:" bl";s:3:"248";s:3:" st";s:3:"249";s:3:" uc";s:3:"250";s:3:"a b";s:3:"251";s:3:"a i";s:3:"252";s:3:"a l";s:3:"253";s:3:"air";s:3:"254";s:3:"ast";s:3:"255";s:3:"bla";s:3:"256";s:3:"bri";s:3:"257";s:3:"che";s:3:"258";s:3:"duc";s:3:"259";s:3:"dul";s:3:"260";s:3:"e m";s:3:"261";s:3:"eas";s:3:"262";s:3:"edi";s:3:"263";s:3:"esp";s:3:"264";s:3:"i l";s:3:"265";s:3:"i p";s:3:"266";s:3:"ica";s:3:"267";s:4:"ică";s:3:"268";s:3:"ir ";s:3:"269";s:3:"iun";s:3:"270";s:3:"jud";s:3:"271";s:3:"lai";s:3:"272";s:3:"lul";s:3:"273";s:3:"mai";s:3:"274";s:3:"men";s:3:"275";s:3:"ni ";s:3:"276";s:3:"pus";s:3:"277";s:3:"put";s:3:"278";s:3:"ra ";s:3:"279";s:3:"rai";s:3:"280";s:3:"rop";s:3:"281";s:3:"sil";s:3:"282";s:3:"ti ";s:3:"283";s:3:"tra";s:3:"284";s:3:"u s";s:3:"285";s:3:"ua ";s:3:"286";s:3:"ude";s:3:"287";s:3:"urs";s:3:"288";s:4:"ân ";s:3:"289";s:4:"înt";s:3:"290";s:5:"ţă ";s:3:"291";s:3:" lu";s:3:"292";s:3:" mo";s:3:"293";s:3:" s ";s:3:"294";s:3:" sa";s:3:"295";s:3:" sc";s:3:"296";s:3:"a u";s:3:"297";s:3:"an ";s:3:"298";s:3:"atu";s:3:"299";}s:7:"russian";a:300:{s:5:" на";s:1:"0";s:5:" пр";s:1:"1";s:5:"то ";s:1:"2";s:5:" не";s:1:"3";s:5:"ли ";s:1:"4";s:5:" по";s:1:"5";s:5:"но ";s:1:"6";s:4:" в ";s:1:"7";s:5:"на ";s:1:"8";s:5:"ть ";s:1:"9";s:5:"не ";s:2:"10";s:4:" и ";s:2:"11";s:5:" ко";s:2:"12";s:5:"ом ";s:2:"13";s:6:"про";s:2:"14";s:5:" то";s:2:"15";s:5:"их ";s:2:"16";s:5:" ка";s:2:"17";s:6:"ать";s:2:"18";s:6:"ото";s:2:"19";s:5:" за";s:2:"20";s:5:"ие ";s:2:"21";s:6:"ова";s:2:"22";s:6:"тел";s:2:"23";s:6:"тор";s:2:"24";s:5:" де";s:2:"25";s:5:"ой ";s:2:"26";s:6:"сти";s:2:"27";s:5:" от";s:2:"28";s:5:"ах ";s:2:"29";s:5:"ми ";s:2:"30";s:6:"стр";s:2:"31";s:5:" бе";s:2:"32";s:5:" во";s:2:"33";s:5:" ра";s:2:"34";s:5:"ая ";s:2:"35";s:6:"ват";s:2:"36";s:5:"ей ";s:2:"37";s:5:"ет ";s:2:"38";s:5:"же ";s:2:"39";s:6:"иче";s:2:"40";s:5:"ия ";s:2:"41";s:5:"ов ";s:2:"42";s:6:"сто";s:2:"43";s:5:" об";s:2:"44";s:6:"вер";s:2:"45";s:5:"го ";s:2:"46";s:5:"и в";s:2:"47";s:5:"и п";s:2:"48";s:5:"и с";s:2:"49";s:5:"ии ";s:2:"50";s:6:"ист";s:2:"51";s:5:"о в";s:2:"52";s:6:"ост";s:2:"53";s:6:"тра";s:2:"54";s:5:" те";s:2:"55";s:6:"ели";s:2:"56";s:6:"ере";s:2:"57";s:6:"кот";s:2:"58";s:6:"льн";s:2:"59";s:6:"ник";s:2:"60";s:6:"нти";s:2:"61";s:5:"о с";s:2:"62";s:6:"рор";s:2:"63";s:6:"ств";s:2:"64";s:6:"чес";s:2:"65";s:5:" бо";s:2:"66";s:5:" ве";s:2:"67";s:5:" да";s:2:"68";s:5:" ин";s:2:"69";s:5:" но";s:2:"70";s:4:" с ";s:2:"71";s:5:" со";s:2:"72";s:5:" сп";s:2:"73";s:5:" ст";s:2:"74";s:5:" чт";s:2:"75";s:6:"али";s:2:"76";s:6:"ами";s:2:"77";s:6:"вид";s:2:"78";s:6:"дет";s:2:"79";s:5:"е н";s:2:"80";s:6:"ель";s:2:"81";s:6:"еск";s:2:"82";s:6:"ест";s:2:"83";s:6:"зал";s:2:"84";s:5:"и н";s:2:"85";s:6:"ива";s:2:"86";s:6:"кон";s:2:"87";s:6:"ого";s:2:"88";s:6:"одн";s:2:"89";s:6:"ожн";s:2:"90";s:6:"оль";s:2:"91";s:6:"ори";s:2:"92";s:6:"ров";s:2:"93";s:6:"ско";s:2:"94";s:5:"ся ";s:2:"95";s:6:"тер";s:2:"96";s:6:"что";s:2:"97";s:5:" мо";s:2:"98";s:5:" са";s:2:"99";s:5:" эт";s:3:"100";s:6:"ант";s:3:"101";s:6:"все";s:3:"102";s:6:"ерр";s:3:"103";s:6:"есл";s:3:"104";s:6:"иде";s:3:"105";s:6:"ина";s:3:"106";s:6:"ино";s:3:"107";s:6:"иро";s:3:"108";s:6:"ите";s:3:"109";s:5:"ка ";s:3:"110";s:5:"ко ";s:3:"111";s:6:"кол";s:3:"112";s:6:"ком";s:3:"113";s:5:"ла ";s:3:"114";s:6:"ния";s:3:"115";s:5:"о т";s:3:"116";s:6:"оло";s:3:"117";s:6:"ран";s:3:"118";s:6:"ред";s:3:"119";s:5:"сь ";s:3:"120";s:6:"тив";s:3:"121";s:6:"тич";s:3:"122";s:5:"ых ";s:3:"123";s:5:" ви";s:3:"124";s:5:" вс";s:3:"125";s:5:" го";s:3:"126";s:5:" ма";s:3:"127";s:5:" сл";s:3:"128";s:6:"ако";s:3:"129";s:6:"ани";s:3:"130";s:6:"аст";s:3:"131";s:6:"без";s:3:"132";s:6:"дел";s:3:"133";s:5:"е д";s:3:"134";s:5:"е п";s:3:"135";s:5:"ем ";s:3:"136";s:6:"жно";s:3:"137";s:5:"и д";s:3:"138";s:6:"ика";s:3:"139";s:6:"каз";s:3:"140";s:6:"как";s:3:"141";s:5:"ки ";s:3:"142";s:6:"нос";s:3:"143";s:5:"о н";s:3:"144";s:6:"опа";s:3:"145";s:6:"при";s:3:"146";s:6:"рро";s:3:"147";s:6:"ски";s:3:"148";s:5:"ти ";s:3:"149";s:6:"тов";s:3:"150";s:5:"ые ";s:3:"151";s:5:" вы";s:3:"152";s:5:" до";s:3:"153";s:5:" ме";s:3:"154";s:5:" ни";s:3:"155";s:5:" од";s:3:"156";s:5:" ро";s:3:"157";s:5:" св";s:3:"158";s:5:" чи";s:3:"159";s:5:"а н";s:3:"160";s:6:"ает";s:3:"161";s:6:"аза";s:3:"162";s:6:"ате";s:3:"163";s:6:"бес";s:3:"164";s:5:"в п";s:3:"165";s:5:"ва ";s:3:"166";s:5:"е в";s:3:"167";s:5:"е м";s:3:"168";s:5:"е с";s:3:"169";s:5:"ез ";s:3:"170";s:6:"ени";s:3:"171";s:5:"за ";s:3:"172";s:6:"зна";s:3:"173";s:6:"ини";s:3:"174";s:6:"кам";s:3:"175";s:6:"ках";s:3:"176";s:6:"кто";s:3:"177";s:6:"лов";s:3:"178";s:6:"мер";s:3:"179";s:6:"мож";s:3:"180";s:6:"нал";s:3:"181";s:6:"ниц";s:3:"182";s:5:"ны ";s:3:"183";s:6:"ным";s:3:"184";s:6:"ора";s:3:"185";s:6:"оро";s:3:"186";s:5:"от ";s:3:"187";s:6:"пор";s:3:"188";s:6:"рав";s:3:"189";s:6:"рес";s:3:"190";s:6:"рис";s:3:"191";s:6:"рос";s:3:"192";s:6:"ска";s:3:"193";s:5:"т н";s:3:"194";s:6:"том";s:3:"195";s:6:"чит";s:3:"196";s:6:"шко";s:3:"197";s:5:" бы";s:3:"198";s:4:" о ";s:3:"199";s:5:" тр";s:3:"200";s:5:" уж";s:3:"201";s:5:" чу";s:3:"202";s:5:" шк";s:3:"203";s:5:"а б";s:3:"204";s:5:"а в";s:3:"205";s:5:"а р";s:3:"206";s:6:"аби";s:3:"207";s:6:"ала";s:3:"208";s:6:"ало";s:3:"209";s:6:"аль";s:3:"210";s:6:"анн";s:3:"211";s:6:"ати";s:3:"212";s:6:"бин";s:3:"213";s:6:"вес";s:3:"214";s:6:"вно";s:3:"215";s:5:"во ";s:3:"216";s:6:"вши";s:3:"217";s:6:"дал";s:3:"218";s:6:"дат";s:3:"219";s:6:"дно";s:3:"220";s:5:"е з";s:3:"221";s:6:"его";s:3:"222";s:6:"еле";s:3:"223";s:6:"енн";s:3:"224";s:6:"ент";s:3:"225";s:6:"ете";s:3:"226";s:5:"и о";s:3:"227";s:6:"или";s:3:"228";s:6:"ись";s:3:"229";s:5:"ит ";s:3:"230";s:6:"ици";s:3:"231";s:6:"ков";s:3:"232";s:6:"лен";s:3:"233";s:6:"льк";s:3:"234";s:6:"мен";s:3:"235";s:5:"мы ";s:3:"236";s:6:"нет";s:3:"237";s:5:"ни ";s:3:"238";s:6:"нны";s:3:"239";s:6:"ног";s:3:"240";s:6:"ной";s:3:"241";s:6:"ном";s:3:"242";s:5:"о п";s:3:"243";s:6:"обн";s:3:"244";s:6:"ове";s:3:"245";s:6:"овн";s:3:"246";s:6:"оры";s:3:"247";s:6:"пер";s:3:"248";s:5:"по ";s:3:"249";s:6:"пра";s:3:"250";s:6:"пре";s:3:"251";s:6:"раз";s:3:"252";s:6:"роп";s:3:"253";s:5:"ры ";s:3:"254";s:5:"се ";s:3:"255";s:6:"сли";s:3:"256";s:6:"сов";s:3:"257";s:6:"тре";s:3:"258";s:6:"тся";s:3:"259";s:6:"уро";s:3:"260";s:6:"цел";s:3:"261";s:6:"чно";s:3:"262";s:5:"ь в";s:3:"263";s:6:"ько";s:3:"264";s:6:"ьно";s:3:"265";s:6:"это";s:3:"266";s:5:"ют ";s:3:"267";s:5:"я н";s:3:"268";s:5:" ан";s:3:"269";s:5:" ес";s:3:"270";s:5:" же";s:3:"271";s:5:" из";s:3:"272";s:5:" кт";s:3:"273";s:5:" ми";s:3:"274";s:5:" мы";s:3:"275";s:5:" пе";s:3:"276";s:5:" се";s:3:"277";s:5:" це";s:3:"278";s:5:"а м";s:3:"279";s:5:"а п";s:3:"280";s:5:"а т";s:3:"281";s:6:"авш";s:3:"282";s:6:"аже";s:3:"283";s:5:"ак ";s:3:"284";s:5:"ал ";s:3:"285";s:6:"але";s:3:"286";s:6:"ане";s:3:"287";s:6:"ачи";s:3:"288";s:6:"ают";s:3:"289";s:6:"бна";s:3:"290";s:6:"бол";s:3:"291";s:5:"бы ";s:3:"292";s:5:"в и";s:3:"293";s:5:"в с";s:3:"294";s:6:"ван";s:3:"295";s:6:"гра";s:3:"296";s:6:"даж";s:3:"297";s:6:"ден";s:3:"298";s:5:"е к";s:3:"299";}s:7:"serbian";a:300:{s:5:" на";s:1:"0";s:5:" је";s:1:"1";s:5:" по";s:1:"2";s:5:"је ";s:1:"3";s:4:" и ";s:1:"4";s:5:" не";s:1:"5";s:5:" пр";s:1:"6";s:5:"га ";s:1:"7";s:5:" св";s:1:"8";s:5:"ог ";s:1:"9";s:5:"а с";s:2:"10";s:5:"их ";s:2:"11";s:5:"на ";s:2:"12";s:6:"кој";s:2:"13";s:6:"ога";s:2:"14";s:4:" у ";s:2:"15";s:5:"а п";s:2:"16";s:5:"не ";s:2:"17";s:5:"ни ";s:2:"18";s:5:"ти ";s:2:"19";s:5:" да";s:2:"20";s:5:"ом ";s:2:"21";s:5:" ве";s:2:"22";s:5:" ср";s:2:"23";s:5:"и с";s:2:"24";s:6:"ско";s:2:"25";s:5:" об";s:2:"26";s:5:"а н";s:2:"27";s:5:"да ";s:2:"28";s:5:"е н";s:2:"29";s:5:"но ";s:2:"30";s:6:"ног";s:2:"31";s:5:"о ј";s:2:"32";s:5:"ој ";s:2:"33";s:5:" за";s:2:"34";s:5:"ва ";s:2:"35";s:5:"е с";s:2:"36";s:5:"и п";s:2:"37";s:5:"ма ";s:2:"38";s:6:"ник";s:2:"39";s:6:"обр";s:2:"40";s:6:"ова";s:2:"41";s:5:" ко";s:2:"42";s:5:"а и";s:2:"43";s:6:"диј";s:2:"44";s:5:"е п";s:2:"45";s:5:"ка ";s:2:"46";s:5:"ко ";s:2:"47";s:6:"ког";s:2:"48";s:6:"ост";s:2:"49";s:6:"све";s:2:"50";s:6:"ств";s:2:"51";s:6:"сти";s:2:"52";s:6:"тра";s:2:"53";s:6:"еди";s:2:"54";s:6:"има";s:2:"55";s:6:"пок";s:2:"56";s:6:"пра";s:2:"57";s:6:"раз";s:2:"58";s:5:"те ";s:2:"59";s:5:" бо";s:2:"60";s:5:" ви";s:2:"61";s:5:" са";s:2:"62";s:6:"аво";s:2:"63";s:6:"бра";s:2:"64";s:6:"гос";s:2:"65";s:5:"е и";s:2:"66";s:6:"ели";s:2:"67";s:6:"ени";s:2:"68";s:5:"за ";s:2:"69";s:6:"ики";s:2:"70";s:5:"ио ";s:2:"71";s:6:"пре";s:2:"72";s:6:"рав";s:2:"73";s:6:"рад";s:2:"74";s:5:"у с";s:2:"75";s:5:"ју ";s:2:"76";s:5:"ња ";s:2:"77";s:5:" би";s:2:"78";s:5:" до";s:2:"79";s:5:" ст";s:2:"80";s:6:"аст";s:2:"81";s:6:"бој";s:2:"82";s:6:"ебо";s:2:"83";s:5:"и н";s:2:"84";s:5:"им ";s:2:"85";s:5:"ку ";s:2:"86";s:6:"лан";s:2:"87";s:6:"неб";s:2:"88";s:6:"ово";s:2:"89";s:6:"ого";s:2:"90";s:6:"осл";s:2:"91";s:6:"ојш";s:2:"92";s:6:"пед";s:2:"93";s:6:"стр";s:2:"94";s:6:"час";s:2:"95";s:5:" го";s:2:"96";s:5:" кр";s:2:"97";s:5:" мо";s:2:"98";s:5:" чл";s:2:"99";s:5:"а м";s:3:"100";s:5:"а о";s:3:"101";s:6:"ако";s:3:"102";s:6:"ача";s:3:"103";s:6:"вел";s:3:"104";s:6:"вет";s:3:"105";s:6:"вог";s:3:"106";s:6:"еда";s:3:"107";s:6:"ист";s:3:"108";s:6:"ити";s:3:"109";s:6:"ије";s:3:"110";s:6:"око";s:3:"111";s:6:"сло";s:3:"112";s:6:"срб";s:3:"113";s:6:"чла";s:3:"114";s:5:" бе";s:3:"115";s:5:" ос";s:3:"116";s:5:" от";s:3:"117";s:5:" ре";s:3:"118";s:5:" се";s:3:"119";s:5:"а в";s:3:"120";s:5:"ан ";s:3:"121";s:6:"бог";s:3:"122";s:6:"бро";s:3:"123";s:6:"вен";s:3:"124";s:6:"гра";s:3:"125";s:5:"е о";s:3:"126";s:6:"ика";s:3:"127";s:6:"ија";s:3:"128";s:6:"ких";s:3:"129";s:6:"ком";s:3:"130";s:5:"ли ";s:3:"131";s:5:"ну ";s:3:"132";s:6:"ота";s:3:"133";s:6:"ојн";s:3:"134";s:6:"под";s:3:"135";s:6:"рбс";s:3:"136";s:6:"ред";s:3:"137";s:6:"рој";s:3:"138";s:5:"са ";s:3:"139";s:6:"сни";s:3:"140";s:6:"тач";s:3:"141";s:6:"тва";s:3:"142";s:5:"ја ";s:3:"143";s:5:"ји ";s:3:"144";s:5:" ка";s:3:"145";s:5:" ов";s:3:"146";s:5:" тр";s:3:"147";s:5:"а ј";s:3:"148";s:6:"ави";s:3:"149";s:5:"аз ";s:3:"150";s:6:"ано";s:3:"151";s:6:"био";s:3:"152";s:6:"вик";s:3:"153";s:5:"во ";s:3:"154";s:6:"гов";s:3:"155";s:6:"дни";s:3:"156";s:5:"е ч";s:3:"157";s:6:"его";s:3:"158";s:5:"и о";s:3:"159";s:6:"ива";s:3:"160";s:6:"иво";s:3:"161";s:5:"ик ";s:3:"162";s:6:"ине";s:3:"163";s:6:"ини";s:3:"164";s:6:"ипе";s:3:"165";s:6:"кип";s:3:"166";s:6:"лик";s:3:"167";s:5:"ло ";s:3:"168";s:6:"наш";s:3:"169";s:6:"нос";s:3:"170";s:5:"о т";s:3:"171";s:5:"од ";s:3:"172";s:6:"оди";s:3:"173";s:6:"она";s:3:"174";s:6:"оји";s:3:"175";s:6:"поч";s:3:"176";s:6:"про";s:3:"177";s:5:"ра ";s:3:"178";s:6:"рис";s:3:"179";s:6:"род";s:3:"180";s:6:"рст";s:3:"181";s:5:"се ";s:3:"182";s:6:"спо";s:3:"183";s:6:"ста";s:3:"184";s:6:"тић";s:3:"185";s:5:"у д";s:3:"186";s:5:"у н";s:3:"187";s:5:"у о";s:3:"188";s:6:"чин";s:3:"189";s:5:"ша ";s:3:"190";s:6:"јед";s:3:"191";s:6:"јни";s:3:"192";s:5:"ће ";s:3:"193";s:4:" м ";s:3:"194";s:5:" ме";s:3:"195";s:5:" ни";s:3:"196";s:5:" он";s:3:"197";s:5:" па";s:3:"198";s:5:" сл";s:3:"199";s:5:" те";s:3:"200";s:5:"а у";s:3:"201";s:6:"ава";s:3:"202";s:6:"аве";s:3:"203";s:6:"авн";s:3:"204";s:6:"ана";s:3:"205";s:5:"ао ";s:3:"206";s:6:"ати";s:3:"207";s:6:"аци";s:3:"208";s:6:"ају";s:3:"209";s:6:"ања";s:3:"210";s:6:"бск";s:3:"211";s:6:"вор";s:3:"212";s:6:"вос";s:3:"213";s:6:"вск";s:3:"214";s:6:"дин";s:3:"215";s:5:"е у";s:3:"216";s:6:"едн";s:3:"217";s:6:"ези";s:3:"218";s:6:"ека";s:3:"219";s:6:"ено";s:3:"220";s:6:"ето";s:3:"221";s:6:"ења";s:3:"222";s:6:"жив";s:3:"223";s:5:"и г";s:3:"224";s:5:"и и";s:3:"225";s:5:"и к";s:3:"226";s:5:"и т";s:3:"227";s:6:"ику";s:3:"228";s:6:"ичк";s:3:"229";s:5:"ки ";s:3:"230";s:6:"крс";s:3:"231";s:5:"ла ";s:3:"232";s:6:"лав";s:3:"233";s:6:"лит";s:3:"234";s:5:"ме ";s:3:"235";s:6:"мен";s:3:"236";s:6:"нац";s:3:"237";s:5:"о н";s:3:"238";s:5:"о п";s:3:"239";s:5:"о у";s:3:"240";s:6:"одн";s:3:"241";s:6:"оли";s:3:"242";s:6:"орн";s:3:"243";s:6:"осн";s:3:"244";s:6:"осп";s:3:"245";s:6:"оче";s:3:"246";s:6:"пск";s:3:"247";s:6:"реч";s:3:"248";s:6:"рпс";s:3:"249";s:6:"сво";s:3:"250";s:6:"ски";s:3:"251";s:6:"сла";s:3:"252";s:6:"срп";s:3:"253";s:5:"су ";s:3:"254";s:5:"та ";s:3:"255";s:6:"тав";s:3:"256";s:6:"тве";s:3:"257";s:5:"у б";s:3:"258";s:6:"јез";s:3:"259";s:5:"ћи ";s:3:"260";s:5:" ен";s:3:"261";s:5:" жи";s:3:"262";s:5:" им";s:3:"263";s:5:" му";s:3:"264";s:5:" од";s:3:"265";s:5:" су";s:3:"266";s:5:" та";s:3:"267";s:5:" хр";s:3:"268";s:5:" ча";s:3:"269";s:5:" шт";s:3:"270";s:5:" ње";s:3:"271";s:5:"а д";s:3:"272";s:5:"а з";s:3:"273";s:5:"а к";s:3:"274";s:5:"а т";s:3:"275";s:6:"аду";s:3:"276";s:6:"ало";s:3:"277";s:6:"ани";s:3:"278";s:6:"асо";s:3:"279";s:6:"ван";s:3:"280";s:6:"вач";s:3:"281";s:6:"вањ";s:3:"282";s:6:"вед";s:3:"283";s:5:"ви ";s:3:"284";s:6:"вно";s:3:"285";s:6:"вот";s:3:"286";s:6:"вој";s:3:"287";s:5:"ву ";s:3:"288";s:6:"доб";s:3:"289";s:6:"дру";s:3:"290";s:6:"дсе";s:3:"291";s:5:"ду ";s:3:"292";s:5:"е б";s:3:"293";s:5:"е д";s:3:"294";s:5:"е м";s:3:"295";s:5:"ем ";s:3:"296";s:6:"ема";s:3:"297";s:6:"ент";s:3:"298";s:6:"енц";s:3:"299";}s:6:"slovak";a:300:{s:3:" pr";s:1:"0";s:3:" po";s:1:"1";s:3:" ne";s:1:"2";s:3:" a ";s:1:"3";s:3:"ch ";s:1:"4";s:3:" na";s:1:"5";s:3:" je";s:1:"6";s:4:"ní ";s:1:"7";s:3:"je ";s:1:"8";s:3:" do";s:1:"9";s:3:"na ";s:2:"10";s:3:"ova";s:2:"11";s:3:" v ";s:2:"12";s:3:"to ";s:2:"13";s:3:"ho ";s:2:"14";s:3:"ou ";s:2:"15";s:3:" to";s:2:"16";s:3:"ick";s:2:"17";s:3:"ter";s:2:"18";s:4:"že ";s:2:"19";s:3:" st";s:2:"20";s:3:" za";s:2:"21";s:3:"ost";s:2:"22";s:4:"ých";s:2:"23";s:3:" se";s:2:"24";s:3:"pro";s:2:"25";s:3:" te";s:2:"26";s:3:"e s";s:2:"27";s:4:" že";s:2:"28";s:3:"a p";s:2:"29";s:3:" kt";s:2:"30";s:3:"pre";s:2:"31";s:3:" by";s:2:"32";s:3:" o ";s:2:"33";s:3:"se ";s:2:"34";s:3:"kon";s:2:"35";s:4:" př";s:2:"36";s:3:"a s";s:2:"37";s:4:"né ";s:2:"38";s:4:"ně ";s:2:"39";s:3:"sti";s:2:"40";s:3:"ako";s:2:"41";s:3:"ist";s:2:"42";s:3:"mu ";s:2:"43";s:3:"ame";s:2:"44";s:3:"ent";s:2:"45";s:3:"ky ";s:2:"46";s:3:"la ";s:2:"47";s:3:"pod";s:2:"48";s:3:" ve";s:2:"49";s:3:" ob";s:2:"50";s:3:"om ";s:2:"51";s:3:"vat";s:2:"52";s:3:" ko";s:2:"53";s:3:"sta";s:2:"54";s:3:"em ";s:2:"55";s:3:"le ";s:2:"56";s:3:"a v";s:2:"57";s:3:"by ";s:2:"58";s:3:"e p";s:2:"59";s:3:"ko ";s:2:"60";s:3:"eri";s:2:"61";s:3:"kte";s:2:"62";s:3:"sa ";s:2:"63";s:4:"ého";s:2:"64";s:3:"e v";s:2:"65";s:3:"mer";s:2:"66";s:3:"tel";s:2:"67";s:3:" ak";s:2:"68";s:3:" sv";s:2:"69";s:4:" zá";s:2:"70";s:3:"hla";s:2:"71";s:3:"las";s:2:"72";s:3:"lo ";s:2:"73";s:3:" ta";s:2:"74";s:3:"a n";s:2:"75";s:3:"ej ";s:2:"76";s:3:"li ";s:2:"77";s:3:"ne ";s:2:"78";s:3:" sa";s:2:"79";s:3:"ak ";s:2:"80";s:3:"ani";s:2:"81";s:3:"ate";s:2:"82";s:3:"ia ";s:2:"83";s:3:"sou";s:2:"84";s:3:" so";s:2:"85";s:4:"ení";s:2:"86";s:3:"ie ";s:2:"87";s:3:" re";s:2:"88";s:3:"ce ";s:2:"89";s:3:"e n";s:2:"90";s:3:"ori";s:2:"91";s:3:"tic";s:2:"92";s:3:" vy";s:2:"93";s:3:"a t";s:2:"94";s:4:"ké ";s:2:"95";s:3:"nos";s:2:"96";s:3:"o s";s:2:"97";s:3:"str";s:2:"98";s:3:"ti ";s:2:"99";s:3:"uje";s:3:"100";s:3:" sp";s:3:"101";s:3:"lov";s:3:"102";s:3:"o p";s:3:"103";s:3:"oli";s:3:"104";s:4:"ová";s:3:"105";s:4:" ná";s:3:"106";s:3:"ale";s:3:"107";s:3:"den";s:3:"108";s:3:"e o";s:3:"109";s:3:"ku ";s:3:"110";s:3:"val";s:3:"111";s:3:" am";s:3:"112";s:3:" ro";s:3:"113";s:3:" si";s:3:"114";s:3:"nie";s:3:"115";s:3:"pol";s:3:"116";s:3:"tra";s:3:"117";s:3:" al";s:3:"118";s:3:"ali";s:3:"119";s:3:"o v";s:3:"120";s:3:"tor";s:3:"121";s:3:" mo";s:3:"122";s:3:" ni";s:3:"123";s:3:"ci ";s:3:"124";s:3:"o n";s:3:"125";s:4:"ím ";s:3:"126";s:3:" le";s:3:"127";s:3:" pa";s:3:"128";s:3:" s ";s:3:"129";s:3:"al ";s:3:"130";s:3:"ati";s:3:"131";s:3:"ero";s:3:"132";s:3:"ove";s:3:"133";s:3:"rov";s:3:"134";s:4:"ván";s:3:"135";s:4:"ích";s:3:"136";s:3:" ja";s:3:"137";s:3:" z ";s:3:"138";s:4:"cké";s:3:"139";s:3:"e z";s:3:"140";s:3:" od";s:3:"141";s:3:"byl";s:3:"142";s:3:"de ";s:3:"143";s:3:"dob";s:3:"144";s:3:"nep";s:3:"145";s:3:"pra";s:3:"146";s:3:"ric";s:3:"147";s:3:"spo";s:3:"148";s:3:"tak";s:3:"149";s:4:" vš";s:3:"150";s:3:"a a";s:3:"151";s:3:"e t";s:3:"152";s:3:"lit";s:3:"153";s:3:"me ";s:3:"154";s:3:"nej";s:3:"155";s:3:"no ";s:3:"156";s:4:"nýc";s:3:"157";s:3:"o t";s:3:"158";s:3:"a j";s:3:"159";s:3:"e a";s:3:"160";s:3:"en ";s:3:"161";s:3:"est";s:3:"162";s:4:"jí ";s:3:"163";s:3:"mi ";s:3:"164";s:3:"slo";s:3:"165";s:4:"stá";s:3:"166";s:3:"u v";s:3:"167";s:3:"for";s:3:"168";s:3:"nou";s:3:"169";s:3:"pos";s:3:"170";s:4:"pře";s:3:"171";s:3:"si ";s:3:"172";s:3:"tom";s:3:"173";s:3:" vl";s:3:"174";s:3:"a z";s:3:"175";s:3:"ly ";s:3:"176";s:3:"orm";s:3:"177";s:3:"ris";s:3:"178";s:3:"za ";s:3:"179";s:4:"zák";s:3:"180";s:3:" k ";s:3:"181";s:3:"at ";s:3:"182";s:4:"cký";s:3:"183";s:3:"dno";s:3:"184";s:3:"dos";s:3:"185";s:3:"dy ";s:3:"186";s:3:"jak";s:3:"187";s:3:"kov";s:3:"188";s:3:"ny ";s:3:"189";s:3:"res";s:3:"190";s:3:"ror";s:3:"191";s:3:"sto";s:3:"192";s:3:"van";s:3:"193";s:3:" op";s:3:"194";s:3:"da ";s:3:"195";s:3:"do ";s:3:"196";s:3:"e j";s:3:"197";s:3:"hod";s:3:"198";s:3:"len";s:3:"199";s:4:"ný ";s:3:"200";s:3:"o z";s:3:"201";s:3:"poz";s:3:"202";s:3:"pri";s:3:"203";s:3:"ran";s:3:"204";s:3:"u s";s:3:"205";s:3:" ab";s:3:"206";s:3:"aj ";s:3:"207";s:3:"ast";s:3:"208";s:3:"it ";s:3:"209";s:3:"kto";s:3:"210";s:3:"o o";s:3:"211";s:3:"oby";s:3:"212";s:3:"odo";s:3:"213";s:3:"u p";s:3:"214";s:3:"va ";s:3:"215";s:5:"ání";s:3:"216";s:4:"í p";s:3:"217";s:4:"ým ";s:3:"218";s:3:" in";s:3:"219";s:3:" mi";s:3:"220";s:4:"ať ";s:3:"221";s:3:"dov";s:3:"222";s:3:"ka ";s:3:"223";s:3:"nsk";s:3:"224";s:4:"áln";s:3:"225";s:3:" an";s:3:"226";s:3:" bu";s:3:"227";s:3:" sl";s:3:"228";s:3:" tr";s:3:"229";s:3:"e m";s:3:"230";s:3:"ech";s:3:"231";s:3:"edn";s:3:"232";s:3:"i n";s:3:"233";s:4:"kýc";s:3:"234";s:4:"níc";s:3:"235";s:3:"ov ";s:3:"236";s:5:"pří";s:3:"237";s:4:"í a";s:3:"238";s:3:" aj";s:3:"239";s:3:" bo";s:3:"240";s:3:"a d";s:3:"241";s:3:"ide";s:3:"242";s:3:"o a";s:3:"243";s:3:"o d";s:3:"244";s:3:"och";s:3:"245";s:3:"pov";s:3:"246";s:3:"svo";s:3:"247";s:4:"é s";s:3:"248";s:3:" kd";s:3:"249";s:3:" vo";s:3:"250";s:4:" vý";s:3:"251";s:3:"bud";s:3:"252";s:3:"ich";s:3:"253";s:3:"il ";s:3:"254";s:3:"ili";s:3:"255";s:3:"ni ";s:3:"256";s:4:"ním";s:3:"257";s:3:"od ";s:3:"258";s:3:"osl";s:3:"259";s:3:"ouh";s:3:"260";s:3:"rav";s:3:"261";s:3:"roz";s:3:"262";s:3:"st ";s:3:"263";s:3:"stv";s:3:"264";s:3:"tu ";s:3:"265";s:3:"u a";s:3:"266";s:4:"vál";s:3:"267";s:3:"y s";s:3:"268";s:4:"í s";s:3:"269";s:4:"í v";s:3:"270";s:3:" hl";s:3:"271";s:3:" li";s:3:"272";s:3:" me";s:3:"273";s:3:"a m";s:3:"274";s:3:"e b";s:3:"275";s:3:"h s";s:3:"276";s:3:"i p";s:3:"277";s:3:"i s";s:3:"278";s:3:"iti";s:3:"279";s:4:"lád";s:3:"280";s:3:"nem";s:3:"281";s:3:"nov";s:3:"282";s:3:"opo";s:3:"283";s:3:"uhl";s:3:"284";s:3:"eno";s:3:"285";s:3:"ens";s:3:"286";s:3:"men";s:3:"287";s:3:"nes";s:3:"288";s:3:"obo";s:3:"289";s:3:"te ";s:3:"290";s:3:"ved";s:3:"291";s:4:"vlá";s:3:"292";s:3:"y n";s:3:"293";s:3:" ma";s:3:"294";s:3:" mu";s:3:"295";s:4:" vá";s:3:"296";s:3:"bez";s:3:"297";s:3:"byv";s:3:"298";s:3:"cho";s:3:"299";}s:7:"slovene";a:300:{s:3:"je ";s:1:"0";s:3:" pr";s:1:"1";s:3:" po";s:1:"2";s:3:" je";s:1:"3";s:3:" v ";s:1:"4";s:3:" za";s:1:"5";s:3:" na";s:1:"6";s:3:"pre";s:1:"7";s:3:"da ";s:1:"8";s:3:" da";s:1:"9";s:3:"ki ";s:2:"10";s:3:"ti ";s:2:"11";s:3:"ja ";s:2:"12";s:3:"ne ";s:2:"13";s:3:" in";s:2:"14";s:3:"in ";s:2:"15";s:3:"li ";s:2:"16";s:3:"no ";s:2:"17";s:3:"na ";s:2:"18";s:3:"ni ";s:2:"19";s:3:" bi";s:2:"20";s:3:"jo ";s:2:"21";s:3:" ne";s:2:"22";s:3:"nje";s:2:"23";s:3:"e p";s:2:"24";s:3:"i p";s:2:"25";s:3:"pri";s:2:"26";s:3:"o p";s:2:"27";s:3:"red";s:2:"28";s:3:" do";s:2:"29";s:3:"anj";s:2:"30";s:3:"em ";s:2:"31";s:3:"ih ";s:2:"32";s:3:" bo";s:2:"33";s:3:" ki";s:2:"34";s:3:" iz";s:2:"35";s:3:" se";s:2:"36";s:3:" so";s:2:"37";s:3:"al ";s:2:"38";s:3:" de";s:2:"39";s:3:"e v";s:2:"40";s:3:"i s";s:2:"41";s:3:"ko ";s:2:"42";s:3:"bil";s:2:"43";s:3:"ira";s:2:"44";s:3:"ove";s:2:"45";s:3:" br";s:2:"46";s:3:" ob";s:2:"47";s:3:"e b";s:2:"48";s:3:"i n";s:2:"49";s:3:"ova";s:2:"50";s:3:"se ";s:2:"51";s:3:"za ";s:2:"52";s:3:"la ";s:2:"53";s:3:" ja";s:2:"54";s:3:"ati";s:2:"55";s:3:"so ";s:2:"56";s:3:"ter";s:2:"57";s:3:" ta";s:2:"58";s:3:"a s";s:2:"59";s:3:"del";s:2:"60";s:3:"e d";s:2:"61";s:3:" dr";s:2:"62";s:3:" od";s:2:"63";s:3:"a n";s:2:"64";s:3:"ar ";s:2:"65";s:3:"jal";s:2:"66";s:3:"ji ";s:2:"67";s:3:"rit";s:2:"68";s:3:" ka";s:2:"69";s:3:" ko";s:2:"70";s:3:" pa";s:2:"71";s:3:"a b";s:2:"72";s:3:"ani";s:2:"73";s:3:"e s";s:2:"74";s:3:"er ";s:2:"75";s:3:"ili";s:2:"76";s:3:"lov";s:2:"77";s:3:"o v";s:2:"78";s:3:"tov";s:2:"79";s:3:" ir";s:2:"80";s:3:" ni";s:2:"81";s:3:" vo";s:2:"82";s:3:"a j";s:2:"83";s:3:"bi ";s:2:"84";s:3:"bri";s:2:"85";s:3:"iti";s:2:"86";s:3:"let";s:2:"87";s:3:"o n";s:2:"88";s:3:"tan";s:2:"89";s:4:"še ";s:2:"90";s:3:" le";s:2:"91";s:3:" te";s:2:"92";s:3:"eni";s:2:"93";s:3:"eri";s:2:"94";s:3:"ita";s:2:"95";s:3:"kat";s:2:"96";s:3:"por";s:2:"97";s:3:"pro";s:2:"98";s:3:"ali";s:2:"99";s:3:"ke ";s:3:"100";s:3:"oli";s:3:"101";s:3:"ov ";s:3:"102";s:3:"pra";s:3:"103";s:3:"ri ";s:3:"104";s:3:"uar";s:3:"105";s:3:"ve ";s:3:"106";s:3:" to";s:3:"107";s:3:"a i";s:3:"108";s:3:"a v";s:3:"109";s:3:"ako";s:3:"110";s:3:"arj";s:3:"111";s:3:"ate";s:3:"112";s:3:"di ";s:3:"113";s:3:"do ";s:3:"114";s:3:"ga ";s:3:"115";s:3:"le ";s:3:"116";s:3:"lo ";s:3:"117";s:3:"mer";s:3:"118";s:3:"o s";s:3:"119";s:3:"oda";s:3:"120";s:3:"oro";s:3:"121";s:3:"pod";s:3:"122";s:3:" ma";s:3:"123";s:3:" mo";s:3:"124";s:3:" si";s:3:"125";s:3:"a p";s:3:"126";s:3:"bod";s:3:"127";s:3:"e n";s:3:"128";s:3:"ega";s:3:"129";s:3:"ju ";s:3:"130";s:3:"ka ";s:3:"131";s:3:"lje";s:3:"132";s:3:"rav";s:3:"133";s:3:"ta ";s:3:"134";s:3:"a o";s:3:"135";s:3:"e t";s:3:"136";s:3:"e z";s:3:"137";s:3:"i d";s:3:"138";s:3:"i v";s:3:"139";s:3:"ila";s:3:"140";s:3:"lit";s:3:"141";s:3:"nih";s:3:"142";s:3:"odo";s:3:"143";s:3:"sti";s:3:"144";s:3:"to ";s:3:"145";s:3:"var";s:3:"146";s:3:"ved";s:3:"147";s:3:"vol";s:3:"148";s:3:" la";s:3:"149";s:3:" no";s:3:"150";s:3:" vs";s:3:"151";s:3:"a d";s:3:"152";s:3:"agu";s:3:"153";s:3:"aja";s:3:"154";s:3:"dej";s:3:"155";s:3:"dnj";s:3:"156";s:3:"eda";s:3:"157";s:3:"gov";s:3:"158";s:3:"gua";s:3:"159";s:3:"jag";s:3:"160";s:3:"jem";s:3:"161";s:3:"kon";s:3:"162";s:3:"ku ";s:3:"163";s:3:"nij";s:3:"164";s:3:"omo";s:3:"165";s:4:"oči";s:3:"166";s:3:"pov";s:3:"167";s:3:"rak";s:3:"168";s:3:"rja";s:3:"169";s:3:"sta";s:3:"170";s:3:"tev";s:3:"171";s:3:"a t";s:3:"172";s:3:"aj ";s:3:"173";s:3:"ed ";s:3:"174";s:3:"eja";s:3:"175";s:3:"ent";s:3:"176";s:3:"ev ";s:3:"177";s:3:"i i";s:3:"178";s:3:"i o";s:3:"179";s:3:"ijo";s:3:"180";s:3:"ist";s:3:"181";s:3:"ost";s:3:"182";s:3:"ske";s:3:"183";s:3:"str";s:3:"184";s:3:" ra";s:3:"185";s:3:" s ";s:3:"186";s:3:" tr";s:3:"187";s:4:" še";s:3:"188";s:3:"arn";s:3:"189";s:3:"bo ";s:3:"190";s:4:"drž";s:3:"191";s:3:"i j";s:3:"192";s:3:"ilo";s:3:"193";s:3:"izv";s:3:"194";s:3:"jen";s:3:"195";s:3:"lja";s:3:"196";s:3:"nsk";s:3:"197";s:3:"o d";s:3:"198";s:3:"o i";s:3:"199";s:3:"om ";s:3:"200";s:3:"ora";s:3:"201";s:3:"ovo";s:3:"202";s:3:"raz";s:3:"203";s:4:"rža";s:3:"204";s:3:"tak";s:3:"205";s:3:"va ";s:3:"206";s:3:"ven";s:3:"207";s:4:"žav";s:3:"208";s:3:" me";s:3:"209";s:4:" če";s:3:"210";s:3:"ame";s:3:"211";s:3:"avi";s:3:"212";s:3:"e i";s:3:"213";s:3:"e o";s:3:"214";s:3:"eka";s:3:"215";s:3:"gre";s:3:"216";s:3:"i t";s:3:"217";s:3:"ija";s:3:"218";s:3:"il ";s:3:"219";s:3:"ite";s:3:"220";s:3:"kra";s:3:"221";s:3:"lju";s:3:"222";s:3:"mor";s:3:"223";s:3:"nik";s:3:"224";s:3:"o t";s:3:"225";s:3:"obi";s:3:"226";s:3:"odn";s:3:"227";s:3:"ran";s:3:"228";s:3:"re ";s:3:"229";s:3:"sto";s:3:"230";s:3:"stv";s:3:"231";s:3:"udi";s:3:"232";s:3:"v i";s:3:"233";s:3:"van";s:3:"234";s:3:" am";s:3:"235";s:3:" sp";s:3:"236";s:3:" st";s:3:"237";s:3:" tu";s:3:"238";s:3:" ve";s:3:"239";s:4:" že";s:3:"240";s:3:"ajo";s:3:"241";s:3:"ale";s:3:"242";s:3:"apo";s:3:"243";s:3:"dal";s:3:"244";s:3:"dru";s:3:"245";s:3:"e j";s:3:"246";s:3:"edn";s:3:"247";s:3:"ejo";s:3:"248";s:3:"elo";s:3:"249";s:3:"est";s:3:"250";s:3:"etj";s:3:"251";s:3:"eva";s:3:"252";s:3:"iji";s:3:"253";s:3:"ik ";s:3:"254";s:3:"im ";s:3:"255";s:3:"itv";s:3:"256";s:3:"mob";s:3:"257";s:3:"nap";s:3:"258";s:3:"nek";s:3:"259";s:3:"pol";s:3:"260";s:3:"pos";s:3:"261";s:3:"rat";s:3:"262";s:3:"ski";s:3:"263";s:4:"tič";s:3:"264";s:3:"tom";s:3:"265";s:3:"ton";s:3:"266";s:3:"tra";s:3:"267";s:3:"tud";s:3:"268";s:3:"tve";s:3:"269";s:3:"v b";s:3:"270";s:3:"vil";s:3:"271";s:3:"vse";s:3:"272";s:4:"čit";s:3:"273";s:3:" av";s:3:"274";s:3:" gr";s:3:"275";s:3:"a z";s:3:"276";s:3:"ans";s:3:"277";s:3:"ast";s:3:"278";s:3:"avt";s:3:"279";s:3:"dan";s:3:"280";s:3:"e m";s:3:"281";s:3:"eds";s:3:"282";s:3:"for";s:3:"283";s:3:"i z";s:3:"284";s:3:"kot";s:3:"285";s:3:"mi ";s:3:"286";s:3:"nim";s:3:"287";s:3:"o b";s:3:"288";s:3:"o o";s:3:"289";s:3:"od ";s:3:"290";s:3:"odl";s:3:"291";s:3:"oiz";s:3:"292";s:3:"ot ";s:3:"293";s:3:"par";s:3:"294";s:3:"pot";s:3:"295";s:3:"rje";s:3:"296";s:3:"roi";s:3:"297";s:3:"tem";s:3:"298";s:3:"val";s:3:"299";}s:6:"somali";a:300:{s:3:"ka ";s:1:"0";s:3:"ay ";s:1:"1";s:3:"da ";s:1:"2";s:3:" ay";s:1:"3";s:3:"aal";s:1:"4";s:3:"oo ";s:1:"5";s:3:"aan";s:1:"6";s:3:" ka";s:1:"7";s:3:"an ";s:1:"8";s:3:"in ";s:1:"9";s:3:" in";s:2:"10";s:3:"ada";s:2:"11";s:3:"maa";s:2:"12";s:3:"aba";s:2:"13";s:3:" so";s:2:"14";s:3:"ali";s:2:"15";s:3:"bad";s:2:"16";s:3:"add";s:2:"17";s:3:"soo";s:2:"18";s:3:" na";s:2:"19";s:3:"aha";s:2:"20";s:3:"ku ";s:2:"21";s:3:"ta ";s:2:"22";s:3:" wa";s:2:"23";s:3:"yo ";s:2:"24";s:3:"a s";s:2:"25";s:3:"oma";s:2:"26";s:3:"yaa";s:2:"27";s:3:" ba";s:2:"28";s:3:" ku";s:2:"29";s:3:" la";s:2:"30";s:3:" oo";s:2:"31";s:3:"iya";s:2:"32";s:3:"sha";s:2:"33";s:3:"a a";s:2:"34";s:3:"dda";s:2:"35";s:3:"nab";s:2:"36";s:3:"nta";s:2:"37";s:3:" da";s:2:"38";s:3:" ma";s:2:"39";s:3:"nka";s:2:"40";s:3:"uu ";s:2:"41";s:3:"y i";s:2:"42";s:3:"aya";s:2:"43";s:3:"ha ";s:2:"44";s:3:"raa";s:2:"45";s:3:" dh";s:2:"46";s:3:" qa";s:2:"47";s:3:"a k";s:2:"48";s:3:"ala";s:2:"49";s:3:"baa";s:2:"50";s:3:"doo";s:2:"51";s:3:"had";s:2:"52";s:3:"liy";s:2:"53";s:3:"oom";s:2:"54";s:3:" ha";s:2:"55";s:3:" sh";s:2:"56";s:3:"a d";s:2:"57";s:3:"a i";s:2:"58";s:3:"a n";s:2:"59";s:3:"aar";s:2:"60";s:3:"ee ";s:2:"61";s:3:"ey ";s:2:"62";s:3:"y k";s:2:"63";s:3:"ya ";s:2:"64";s:3:" ee";s:2:"65";s:3:" iy";s:2:"66";s:3:"aa ";s:2:"67";s:3:"aaq";s:2:"68";s:3:"gaa";s:2:"69";s:3:"lam";s:2:"70";s:3:" bu";s:2:"71";s:3:"a b";s:2:"72";s:3:"a m";s:2:"73";s:3:"ad ";s:2:"74";s:3:"aga";s:2:"75";s:3:"ama";s:2:"76";s:3:"iyo";s:2:"77";s:3:"la ";s:2:"78";s:3:"a c";s:2:"79";s:3:"a l";s:2:"80";s:3:"een";s:2:"81";s:3:"int";s:2:"82";s:3:"she";s:2:"83";s:3:"wax";s:2:"84";s:3:"yee";s:2:"85";s:3:" si";s:2:"86";s:3:" uu";s:2:"87";s:3:"a h";s:2:"88";s:3:"aas";s:2:"89";s:3:"alk";s:2:"90";s:3:"dha";s:2:"91";s:3:"gu ";s:2:"92";s:3:"hee";s:2:"93";s:3:"ii ";s:2:"94";s:3:"ira";s:2:"95";s:3:"mad";s:2:"96";s:3:"o a";s:2:"97";s:3:"o k";s:2:"98";s:3:"qay";s:2:"99";s:3:" ah";s:3:"100";s:3:" ca";s:3:"101";s:3:" wu";s:3:"102";s:3:"ank";s:3:"103";s:3:"ash";s:3:"104";s:3:"axa";s:3:"105";s:3:"eed";s:3:"106";s:3:"en ";s:3:"107";s:3:"ga ";s:3:"108";s:3:"haa";s:3:"109";s:3:"n a";s:3:"110";s:3:"n s";s:3:"111";s:3:"naa";s:3:"112";s:3:"nay";s:3:"113";s:3:"o d";s:3:"114";s:3:"taa";s:3:"115";s:3:"u b";s:3:"116";s:3:"uxu";s:3:"117";s:3:"wux";s:3:"118";s:3:"xuu";s:3:"119";s:3:" ci";s:3:"120";s:3:" do";s:3:"121";s:3:" ho";s:3:"122";s:3:" ta";s:3:"123";s:3:"a g";s:3:"124";s:3:"a u";s:3:"125";s:3:"ana";s:3:"126";s:3:"ayo";s:3:"127";s:3:"dhi";s:3:"128";s:3:"iin";s:3:"129";s:3:"lag";s:3:"130";s:3:"lin";s:3:"131";s:3:"lka";s:3:"132";s:3:"o i";s:3:"133";s:3:"san";s:3:"134";s:3:"u s";s:3:"135";s:3:"una";s:3:"136";s:3:"uun";s:3:"137";s:3:" ga";s:3:"138";s:3:" xa";s:3:"139";s:3:" xu";s:3:"140";s:3:"aab";s:3:"141";s:3:"abt";s:3:"142";s:3:"aq ";s:3:"143";s:3:"aqa";s:3:"144";s:3:"ara";s:3:"145";s:3:"arl";s:3:"146";s:3:"caa";s:3:"147";s:3:"cir";s:3:"148";s:3:"eeg";s:3:"149";s:3:"eel";s:3:"150";s:3:"isa";s:3:"151";s:3:"kal";s:3:"152";s:3:"lah";s:3:"153";s:3:"ney";s:3:"154";s:3:"qaa";s:3:"155";s:3:"rla";s:3:"156";s:3:"sad";s:3:"157";s:3:"sii";s:3:"158";s:3:"u d";s:3:"159";s:3:"wad";s:3:"160";s:3:" ad";s:3:"161";s:3:" ar";s:3:"162";s:3:" di";s:3:"163";s:3:" jo";s:3:"164";s:3:" ra";s:3:"165";s:3:" sa";s:3:"166";s:3:" u ";s:3:"167";s:3:" yi";s:3:"168";s:3:"a j";s:3:"169";s:3:"a q";s:3:"170";s:3:"aad";s:3:"171";s:3:"aat";s:3:"172";s:3:"aay";s:3:"173";s:3:"ah ";s:3:"174";s:3:"ale";s:3:"175";s:3:"amk";s:3:"176";s:3:"ari";s:3:"177";s:3:"as ";s:3:"178";s:3:"aye";s:3:"179";s:3:"bus";s:3:"180";s:3:"dal";s:3:"181";s:3:"ddu";s:3:"182";s:3:"dii";s:3:"183";s:3:"du ";s:3:"184";s:3:"duu";s:3:"185";s:3:"ed ";s:3:"186";s:3:"ege";s:3:"187";s:3:"gey";s:3:"188";s:3:"hay";s:3:"189";s:3:"hii";s:3:"190";s:3:"ida";s:3:"191";s:3:"ine";s:3:"192";s:3:"joo";s:3:"193";s:3:"laa";s:3:"194";s:3:"lay";s:3:"195";s:3:"mar";s:3:"196";s:3:"mee";s:3:"197";s:3:"n b";s:3:"198";s:3:"n d";s:3:"199";s:3:"n m";s:3:"200";s:3:"no ";s:3:"201";s:3:"o b";s:3:"202";s:3:"o l";s:3:"203";s:3:"oog";s:3:"204";s:3:"oon";s:3:"205";s:3:"rga";s:3:"206";s:3:"sh ";s:3:"207";s:3:"sid";s:3:"208";s:3:"u q";s:3:"209";s:3:"unk";s:3:"210";s:3:"ush";s:3:"211";s:3:"xa ";s:3:"212";s:3:"y d";s:3:"213";s:3:" bi";s:3:"214";s:3:" gu";s:3:"215";s:3:" is";s:3:"216";s:3:" ke";s:3:"217";s:3:" lo";s:3:"218";s:3:" me";s:3:"219";s:3:" mu";s:3:"220";s:3:" qo";s:3:"221";s:3:" ug";s:3:"222";s:3:"a e";s:3:"223";s:3:"a o";s:3:"224";s:3:"a w";s:3:"225";s:3:"adi";s:3:"226";s:3:"ado";s:3:"227";s:3:"agu";s:3:"228";s:3:"al ";s:3:"229";s:3:"ant";s:3:"230";s:3:"ark";s:3:"231";s:3:"asa";s:3:"232";s:3:"awi";s:3:"233";s:3:"bta";s:3:"234";s:3:"bul";s:3:"235";s:3:"d a";s:3:"236";s:3:"dag";s:3:"237";s:3:"dan";s:3:"238";s:3:"do ";s:3:"239";s:3:"e s";s:3:"240";s:3:"gal";s:3:"241";s:3:"gay";s:3:"242";s:3:"guu";s:3:"243";s:3:"h e";s:3:"244";s:3:"hal";s:3:"245";s:3:"iga";s:3:"246";s:3:"ihi";s:3:"247";s:3:"iri";s:3:"248";s:3:"iye";s:3:"249";s:3:"ken";s:3:"250";s:3:"lad";s:3:"251";s:3:"lid";s:3:"252";s:3:"lsh";s:3:"253";s:3:"mag";s:3:"254";s:3:"mun";s:3:"255";s:3:"n h";s:3:"256";s:3:"n i";s:3:"257";s:3:"na ";s:3:"258";s:3:"o n";s:3:"259";s:3:"o w";s:3:"260";s:3:"ood";s:3:"261";s:3:"oor";s:3:"262";s:3:"ora";s:3:"263";s:3:"qab";s:3:"264";s:3:"qor";s:3:"265";s:3:"rab";s:3:"266";s:3:"rit";s:3:"267";s:3:"rta";s:3:"268";s:3:"s o";s:3:"269";s:3:"sab";s:3:"270";s:3:"ska";s:3:"271";s:3:"to ";s:3:"272";s:3:"u a";s:3:"273";s:3:"u h";s:3:"274";s:3:"u u";s:3:"275";s:3:"ud ";s:3:"276";s:3:"ugu";s:3:"277";s:3:"uls";s:3:"278";s:3:"uud";s:3:"279";s:3:"waa";s:3:"280";s:3:"xus";s:3:"281";s:3:"y b";s:3:"282";s:3:"y q";s:3:"283";s:3:"y s";s:3:"284";s:3:"yad";s:3:"285";s:3:"yay";s:3:"286";s:3:"yih";s:3:"287";s:3:" aa";s:3:"288";s:3:" bo";s:3:"289";s:3:" br";s:3:"290";s:3:" go";s:3:"291";s:3:" ji";s:3:"292";s:3:" mi";s:3:"293";s:3:" of";s:3:"294";s:3:" ti";s:3:"295";s:3:" um";s:3:"296";s:3:" wi";s:3:"297";s:3:" xo";s:3:"298";s:3:"a x";s:3:"299";}s:7:"spanish";a:300:{s:3:" de";s:1:"0";s:3:"de ";s:1:"1";s:3:" la";s:1:"2";s:3:"os ";s:1:"3";s:3:"la ";s:1:"4";s:3:"el ";s:1:"5";s:3:"es ";s:1:"6";s:3:" qu";s:1:"7";s:3:" co";s:1:"8";s:3:"e l";s:1:"9";s:3:"as ";s:2:"10";s:3:"que";s:2:"11";s:3:" el";s:2:"12";s:3:"ue ";s:2:"13";s:3:"en ";s:2:"14";s:3:"ent";s:2:"15";s:3:" en";s:2:"16";s:3:" se";s:2:"17";s:3:"nte";s:2:"18";s:3:"res";s:2:"19";s:3:"con";s:2:"20";s:3:"est";s:2:"21";s:3:" es";s:2:"22";s:3:"s d";s:2:"23";s:3:" lo";s:2:"24";s:3:" pr";s:2:"25";s:3:"los";s:2:"26";s:3:" y ";s:2:"27";s:3:"do ";s:2:"28";s:4:"ón ";s:2:"29";s:4:"ión";s:2:"30";s:3:" un";s:2:"31";s:4:"ció";s:2:"32";s:3:"del";s:2:"33";s:3:"o d";s:2:"34";s:3:" po";s:2:"35";s:3:"a d";s:2:"36";s:3:"aci";s:2:"37";s:3:"sta";s:2:"38";s:3:"te ";s:2:"39";s:3:"ado";s:2:"40";s:3:"pre";s:2:"41";s:3:"to ";s:2:"42";s:3:"par";s:2:"43";s:3:"a e";s:2:"44";s:3:"a l";s:2:"45";s:3:"ra ";s:2:"46";s:3:"al ";s:2:"47";s:3:"e e";s:2:"48";s:3:"se ";s:2:"49";s:3:"pro";s:2:"50";s:3:"ar ";s:2:"51";s:3:"ia ";s:2:"52";s:3:"o e";s:2:"53";s:3:" re";s:2:"54";s:3:"ida";s:2:"55";s:3:"dad";s:2:"56";s:3:"tra";s:2:"57";s:3:"por";s:2:"58";s:3:"s p";s:2:"59";s:3:" a ";s:2:"60";s:3:"a p";s:2:"61";s:3:"ara";s:2:"62";s:3:"cia";s:2:"63";s:3:" pa";s:2:"64";s:3:"com";s:2:"65";s:3:"no ";s:2:"66";s:3:" di";s:2:"67";s:3:" in";s:2:"68";s:3:"ien";s:2:"69";s:3:"n l";s:2:"70";s:3:"ad ";s:2:"71";s:3:"ant";s:2:"72";s:3:"e s";s:2:"73";s:3:"men";s:2:"74";s:3:"a c";s:2:"75";s:3:"on ";s:2:"76";s:3:"un ";s:2:"77";s:3:"las";s:2:"78";s:3:"nci";s:2:"79";s:3:" tr";s:2:"80";s:3:"cio";s:2:"81";s:3:"ier";s:2:"82";s:3:"nto";s:2:"83";s:3:"tiv";s:2:"84";s:3:"n d";s:2:"85";s:3:"n e";s:2:"86";s:3:"or ";s:2:"87";s:3:"s c";s:2:"88";s:3:"enc";s:2:"89";s:3:"ern";s:2:"90";s:3:"io ";s:2:"91";s:3:"a s";s:2:"92";s:3:"ici";s:2:"93";s:3:"s e";s:2:"94";s:3:" ma";s:2:"95";s:3:"dos";s:2:"96";s:3:"e a";s:2:"97";s:3:"e c";s:2:"98";s:3:"emp";s:2:"99";s:3:"ica";s:3:"100";s:3:"ivo";s:3:"101";s:3:"l p";s:3:"102";s:3:"n c";s:3:"103";s:3:"r e";s:3:"104";s:3:"ta ";s:3:"105";s:3:"ter";s:3:"106";s:3:"e d";s:3:"107";s:3:"esa";s:3:"108";s:3:"ez ";s:3:"109";s:3:"mpr";s:3:"110";s:3:"o a";s:3:"111";s:3:"s a";s:3:"112";s:3:" ca";s:3:"113";s:3:" su";s:3:"114";s:3:"ion";s:3:"115";s:3:" cu";s:3:"116";s:3:" ju";s:3:"117";s:3:"an ";s:3:"118";s:3:"da ";s:3:"119";s:3:"ene";s:3:"120";s:3:"ero";s:3:"121";s:3:"na ";s:3:"122";s:3:"rec";s:3:"123";s:3:"ro ";s:3:"124";s:3:"tar";s:3:"125";s:3:" al";s:3:"126";s:3:" an";s:3:"127";s:3:"bie";s:3:"128";s:3:"e p";s:3:"129";s:3:"er ";s:3:"130";s:3:"l c";s:3:"131";s:3:"n p";s:3:"132";s:3:"omp";s:3:"133";s:3:"ten";s:3:"134";s:3:" em";s:3:"135";s:3:"ist";s:3:"136";s:3:"nes";s:3:"137";s:3:"nta";s:3:"138";s:3:"o c";s:3:"139";s:3:"so ";s:3:"140";s:3:"tes";s:3:"141";s:3:"era";s:3:"142";s:3:"l d";s:3:"143";s:3:"l m";s:3:"144";s:3:"les";s:3:"145";s:3:"ntr";s:3:"146";s:3:"o s";s:3:"147";s:3:"ore";s:3:"148";s:4:"rá ";s:3:"149";s:3:"s q";s:3:"150";s:3:"s y";s:3:"151";s:3:"sto";s:3:"152";s:3:"a a";s:3:"153";s:3:"a r";s:3:"154";s:3:"ari";s:3:"155";s:3:"des";s:3:"156";s:3:"e q";s:3:"157";s:3:"ivi";s:3:"158";s:3:"lic";s:3:"159";s:3:"lo ";s:3:"160";s:3:"n a";s:3:"161";s:3:"one";s:3:"162";s:3:"ora";s:3:"163";s:3:"per";s:3:"164";s:3:"pue";s:3:"165";s:3:"r l";s:3:"166";s:3:"re ";s:3:"167";s:3:"ren";s:3:"168";s:3:"una";s:3:"169";s:4:"ía ";s:3:"170";s:3:"ada";s:3:"171";s:3:"cas";s:3:"172";s:3:"ere";s:3:"173";s:3:"ide";s:3:"174";s:3:"min";s:3:"175";s:3:"n s";s:3:"176";s:3:"ndo";s:3:"177";s:3:"ran";s:3:"178";s:3:"rno";s:3:"179";s:3:" ac";s:3:"180";s:3:" ex";s:3:"181";s:3:" go";s:3:"182";s:3:" no";s:3:"183";s:3:"a t";s:3:"184";s:3:"aba";s:3:"185";s:3:"ble";s:3:"186";s:3:"ece";s:3:"187";s:3:"ect";s:3:"188";s:3:"l a";s:3:"189";s:3:"l g";s:3:"190";s:3:"lid";s:3:"191";s:3:"nsi";s:3:"192";s:3:"ons";s:3:"193";s:3:"rac";s:3:"194";s:3:"rio";s:3:"195";s:3:"str";s:3:"196";s:3:"uer";s:3:"197";s:3:"ust";s:3:"198";s:3:" ha";s:3:"199";s:3:" le";s:3:"200";s:3:" mi";s:3:"201";s:3:" mu";s:3:"202";s:3:" ob";s:3:"203";s:3:" pe";s:3:"204";s:3:" pu";s:3:"205";s:3:" so";s:3:"206";s:3:"a i";s:3:"207";s:3:"ale";s:3:"208";s:3:"ca ";s:3:"209";s:3:"cto";s:3:"210";s:3:"e i";s:3:"211";s:3:"e u";s:3:"212";s:3:"eso";s:3:"213";s:3:"fer";s:3:"214";s:3:"fic";s:3:"215";s:3:"gob";s:3:"216";s:3:"jo ";s:3:"217";s:3:"ma ";s:3:"218";s:3:"mpl";s:3:"219";s:3:"o p";s:3:"220";s:3:"obi";s:3:"221";s:3:"s m";s:3:"222";s:3:"sa ";s:3:"223";s:3:"sep";s:3:"224";s:3:"ste";s:3:"225";s:3:"sti";s:3:"226";s:3:"tad";s:3:"227";s:3:"tod";s:3:"228";s:3:"y s";s:3:"229";s:3:" ci";s:3:"230";s:3:"and";s:3:"231";s:3:"ces";s:3:"232";s:4:"có ";s:3:"233";s:3:"dor";s:3:"234";s:3:"e m";s:3:"235";s:3:"eci";s:3:"236";s:3:"eco";s:3:"237";s:3:"esi";s:3:"238";s:3:"int";s:3:"239";s:3:"iza";s:3:"240";s:3:"l e";s:3:"241";s:3:"lar";s:3:"242";s:3:"mie";s:3:"243";s:3:"ner";s:3:"244";s:3:"orc";s:3:"245";s:3:"rci";s:3:"246";s:3:"ria";s:3:"247";s:3:"tic";s:3:"248";s:3:"tor";s:3:"249";s:3:" as";s:3:"250";s:3:" si";s:3:"251";s:3:"ce ";s:3:"252";s:3:"den";s:3:"253";s:3:"e r";s:3:"254";s:3:"e t";s:3:"255";s:3:"end";s:3:"256";s:3:"eri";s:3:"257";s:3:"esp";s:3:"258";s:3:"ial";s:3:"259";s:3:"ido";s:3:"260";s:3:"ina";s:3:"261";s:3:"inc";s:3:"262";s:3:"mit";s:3:"263";s:3:"o l";s:3:"264";s:3:"ome";s:3:"265";s:3:"pli";s:3:"266";s:3:"ras";s:3:"267";s:3:"s t";s:3:"268";s:3:"sid";s:3:"269";s:3:"sup";s:3:"270";s:3:"tab";s:3:"271";s:3:"uen";s:3:"272";s:3:"ues";s:3:"273";s:3:"ura";s:3:"274";s:3:"vo ";s:3:"275";s:3:"vor";s:3:"276";s:3:" sa";s:3:"277";s:3:" ti";s:3:"278";s:3:"abl";s:3:"279";s:3:"ali";s:3:"280";s:3:"aso";s:3:"281";s:3:"ast";s:3:"282";s:3:"cor";s:3:"283";s:3:"cti";s:3:"284";s:3:"cue";s:3:"285";s:3:"div";s:3:"286";s:3:"duc";s:3:"287";s:3:"ens";s:3:"288";s:3:"eti";s:3:"289";s:3:"imi";s:3:"290";s:3:"ini";s:3:"291";s:3:"lec";s:3:"292";s:3:"o q";s:3:"293";s:3:"oce";s:3:"294";s:3:"ort";s:3:"295";s:3:"ral";s:3:"296";s:3:"rma";s:3:"297";s:3:"roc";s:3:"298";s:3:"rod";s:3:"299";}s:7:"swahili";a:300:{s:3:" wa";s:1:"0";s:3:"wa ";s:1:"1";s:3:"a k";s:1:"2";s:3:"a m";s:1:"3";s:3:" ku";s:1:"4";s:3:" ya";s:1:"5";s:3:"a w";s:1:"6";s:3:"ya ";s:1:"7";s:3:"ni ";s:1:"8";s:3:" ma";s:1:"9";s:3:"ka ";s:2:"10";s:3:"a u";s:2:"11";s:3:"na ";s:2:"12";s:3:"za ";s:2:"13";s:3:"ia ";s:2:"14";s:3:" na";s:2:"15";s:3:"ika";s:2:"16";s:3:"ma ";s:2:"17";s:3:"ali";s:2:"18";s:3:"a n";s:2:"19";s:3:" am";s:2:"20";s:3:"ili";s:2:"21";s:3:"kwa";s:2:"22";s:3:" kw";s:2:"23";s:3:"ini";s:2:"24";s:3:" ha";s:2:"25";s:3:"ame";s:2:"26";s:3:"ana";s:2:"27";s:3:"i n";s:2:"28";s:3:" za";s:2:"29";s:3:"a h";s:2:"30";s:3:"ema";s:2:"31";s:3:"i m";s:2:"32";s:3:"i y";s:2:"33";s:3:"kuw";s:2:"34";s:3:"la ";s:2:"35";s:3:"o w";s:2:"36";s:3:"a y";s:2:"37";s:3:"ata";s:2:"38";s:3:"sem";s:2:"39";s:3:" la";s:2:"40";s:3:"ati";s:2:"41";s:3:"chi";s:2:"42";s:3:"i w";s:2:"43";s:3:"uwa";s:2:"44";s:3:"aki";s:2:"45";s:3:"li ";s:2:"46";s:3:"eka";s:2:"47";s:3:"ira";s:2:"48";s:3:" nc";s:2:"49";s:3:"a s";s:2:"50";s:3:"iki";s:2:"51";s:3:"kat";s:2:"52";s:3:"nch";s:2:"53";s:3:" ka";s:2:"54";s:3:" ki";s:2:"55";s:3:"a b";s:2:"56";s:3:"aji";s:2:"57";s:3:"amb";s:2:"58";s:3:"ra ";s:2:"59";s:3:"ri ";s:2:"60";s:3:"rik";s:2:"61";s:3:"ada";s:2:"62";s:3:"mat";s:2:"63";s:3:"mba";s:2:"64";s:3:"mes";s:2:"65";s:3:"yo ";s:2:"66";s:3:"zi ";s:2:"67";s:3:"da ";s:2:"68";s:3:"hi ";s:2:"69";s:3:"i k";s:2:"70";s:3:"ja ";s:2:"71";s:3:"kut";s:2:"72";s:3:"tek";s:2:"73";s:3:"wan";s:2:"74";s:3:" bi";s:2:"75";s:3:"a a";s:2:"76";s:3:"aka";s:2:"77";s:3:"ao ";s:2:"78";s:3:"asi";s:2:"79";s:3:"cha";s:2:"80";s:3:"ese";s:2:"81";s:3:"eza";s:2:"82";s:3:"ke ";s:2:"83";s:3:"moj";s:2:"84";s:3:"oja";s:2:"85";s:3:" hi";s:2:"86";s:3:"a z";s:2:"87";s:3:"end";s:2:"88";s:3:"ha ";s:2:"89";s:3:"ji ";s:2:"90";s:3:"mu ";s:2:"91";s:3:"shi";s:2:"92";s:3:"wat";s:2:"93";s:3:" bw";s:2:"94";s:3:"ake";s:2:"95";s:3:"ara";s:2:"96";s:3:"bw ";s:2:"97";s:3:"i h";s:2:"98";s:3:"imb";s:2:"99";s:3:"tik";s:3:"100";s:3:"wak";s:3:"101";s:3:"wal";s:3:"102";s:3:" hu";s:3:"103";s:3:" mi";s:3:"104";s:3:" mk";s:3:"105";s:3:" ni";s:3:"106";s:3:" ra";s:3:"107";s:3:" um";s:3:"108";s:3:"a l";s:3:"109";s:3:"ate";s:3:"110";s:3:"esh";s:3:"111";s:3:"ina";s:3:"112";s:3:"ish";s:3:"113";s:3:"kim";s:3:"114";s:3:"o k";s:3:"115";s:3:" ir";s:3:"116";s:3:"a i";s:3:"117";s:3:"ala";s:3:"118";s:3:"ani";s:3:"119";s:3:"aq ";s:3:"120";s:3:"azi";s:3:"121";s:3:"hin";s:3:"122";s:3:"i a";s:3:"123";s:3:"idi";s:3:"124";s:3:"ima";s:3:"125";s:3:"ita";s:3:"126";s:3:"rai";s:3:"127";s:3:"raq";s:3:"128";s:3:"sha";s:3:"129";s:3:" ms";s:3:"130";s:3:" se";s:3:"131";s:3:"afr";s:3:"132";s:3:"ama";s:3:"133";s:3:"ano";s:3:"134";s:3:"ea ";s:3:"135";s:3:"ele";s:3:"136";s:3:"fri";s:3:"137";s:3:"go ";s:3:"138";s:3:"i i";s:3:"139";s:3:"ifa";s:3:"140";s:3:"iwa";s:3:"141";s:3:"iyo";s:3:"142";s:3:"kus";s:3:"143";s:3:"lia";s:3:"144";s:3:"lio";s:3:"145";s:3:"maj";s:3:"146";s:3:"mku";s:3:"147";s:3:"no ";s:3:"148";s:3:"tan";s:3:"149";s:3:"uli";s:3:"150";s:3:"uta";s:3:"151";s:3:"wen";s:3:"152";s:3:" al";s:3:"153";s:3:"a j";s:3:"154";s:3:"aad";s:3:"155";s:3:"aid";s:3:"156";s:3:"ari";s:3:"157";s:3:"awa";s:3:"158";s:3:"ba ";s:3:"159";s:3:"fa ";s:3:"160";s:3:"nde";s:3:"161";s:3:"nge";s:3:"162";s:3:"nya";s:3:"163";s:3:"o y";s:3:"164";s:3:"u w";s:3:"165";s:3:"ua ";s:3:"166";s:3:"umo";s:3:"167";s:3:"waz";s:3:"168";s:3:"ye ";s:3:"169";s:3:" ut";s:3:"170";s:3:" vi";s:3:"171";s:3:"a d";s:3:"172";s:3:"a t";s:3:"173";s:3:"aif";s:3:"174";s:3:"di ";s:3:"175";s:3:"ere";s:3:"176";s:3:"ing";s:3:"177";s:3:"kin";s:3:"178";s:3:"nda";s:3:"179";s:3:"o n";s:3:"180";s:3:"oa ";s:3:"181";s:3:"tai";s:3:"182";s:3:"toa";s:3:"183";s:3:"usa";s:3:"184";s:3:"uto";s:3:"185";s:3:"was";s:3:"186";s:3:"yak";s:3:"187";s:3:"zo ";s:3:"188";s:3:" ji";s:3:"189";s:3:" mw";s:3:"190";s:3:"a p";s:3:"191";s:3:"aia";s:3:"192";s:3:"amu";s:3:"193";s:3:"ang";s:3:"194";s:3:"bik";s:3:"195";s:3:"bo ";s:3:"196";s:3:"del";s:3:"197";s:3:"e w";s:3:"198";s:3:"ene";s:3:"199";s:3:"eng";s:3:"200";s:3:"ich";s:3:"201";s:3:"iri";s:3:"202";s:3:"iti";s:3:"203";s:3:"ito";s:3:"204";s:3:"ki ";s:3:"205";s:3:"kir";s:3:"206";s:3:"ko ";s:3:"207";s:3:"kuu";s:3:"208";s:3:"mar";s:3:"209";s:3:"mbo";s:3:"210";s:3:"mil";s:3:"211";s:3:"ngi";s:3:"212";s:3:"ngo";s:3:"213";s:3:"o l";s:3:"214";s:3:"ong";s:3:"215";s:3:"si ";s:3:"216";s:3:"ta ";s:3:"217";s:3:"tak";s:3:"218";s:3:"u y";s:3:"219";s:3:"umu";s:3:"220";s:3:"usi";s:3:"221";s:3:"uu ";s:3:"222";s:3:"wam";s:3:"223";s:3:" af";s:3:"224";s:3:" ba";s:3:"225";s:3:" li";s:3:"226";s:3:" si";s:3:"227";s:3:" zi";s:3:"228";s:3:"a v";s:3:"229";s:3:"ami";s:3:"230";s:3:"atu";s:3:"231";s:3:"awi";s:3:"232";s:3:"eri";s:3:"233";s:3:"fan";s:3:"234";s:3:"fur";s:3:"235";s:3:"ger";s:3:"236";s:3:"i z";s:3:"237";s:3:"isi";s:3:"238";s:3:"izo";s:3:"239";s:3:"lea";s:3:"240";s:3:"mbi";s:3:"241";s:3:"mwa";s:3:"242";s:3:"nye";s:3:"243";s:3:"o h";s:3:"244";s:3:"o m";s:3:"245";s:3:"oni";s:3:"246";s:3:"rez";s:3:"247";s:3:"saa";s:3:"248";s:3:"ser";s:3:"249";s:3:"sin";s:3:"250";s:3:"tat";s:3:"251";s:3:"tis";s:3:"252";s:3:"tu ";s:3:"253";s:3:"uin";s:3:"254";s:3:"uki";s:3:"255";s:3:"ur ";s:3:"256";s:3:"wi ";s:3:"257";s:3:"yar";s:3:"258";s:3:" da";s:3:"259";s:3:" en";s:3:"260";s:3:" mp";s:3:"261";s:3:" ny";s:3:"262";s:3:" ta";s:3:"263";s:3:" ul";s:3:"264";s:3:" we";s:3:"265";s:3:"a c";s:3:"266";s:3:"a f";s:3:"267";s:3:"ais";s:3:"268";s:3:"apo";s:3:"269";s:3:"ayo";s:3:"270";s:3:"bar";s:3:"271";s:3:"dhi";s:3:"272";s:3:"e a";s:3:"273";s:3:"eke";s:3:"274";s:3:"eny";s:3:"275";s:3:"eon";s:3:"276";s:3:"hai";s:3:"277";s:3:"han";s:3:"278";s:3:"hiy";s:3:"279";s:3:"hur";s:3:"280";s:3:"i s";s:3:"281";s:3:"imw";s:3:"282";s:3:"kal";s:3:"283";s:3:"kwe";s:3:"284";s:3:"lak";s:3:"285";s:3:"lam";s:3:"286";s:3:"mak";s:3:"287";s:3:"msa";s:3:"288";s:3:"ne ";s:3:"289";s:3:"ngu";s:3:"290";s:3:"ru ";s:3:"291";s:3:"sal";s:3:"292";s:3:"swa";s:3:"293";s:3:"te ";s:3:"294";s:3:"ti ";s:3:"295";s:3:"uku";s:3:"296";s:3:"uma";s:3:"297";s:3:"una";s:3:"298";s:3:"uru";s:3:"299";}s:7:"swedish";a:300:{s:3:"en ";s:1:"0";s:3:" de";s:1:"1";s:3:"et ";s:1:"2";s:3:"er ";s:1:"3";s:3:"tt ";s:1:"4";s:3:"om ";s:1:"5";s:4:"för";s:1:"6";s:3:"ar ";s:1:"7";s:3:"de ";s:1:"8";s:3:"att";s:1:"9";s:4:" fö";s:2:"10";s:3:"ing";s:2:"11";s:3:" in";s:2:"12";s:3:" at";s:2:"13";s:3:" i ";s:2:"14";s:3:"det";s:2:"15";s:3:"ch ";s:2:"16";s:3:"an ";s:2:"17";s:3:"gen";s:2:"18";s:3:" an";s:2:"19";s:3:"t s";s:2:"20";s:3:"som";s:2:"21";s:3:"te ";s:2:"22";s:3:" oc";s:2:"23";s:3:"ter";s:2:"24";s:3:" ha";s:2:"25";s:3:"lle";s:2:"26";s:3:"och";s:2:"27";s:3:" sk";s:2:"28";s:3:" so";s:2:"29";s:3:"ra ";s:2:"30";s:3:"r a";s:2:"31";s:3:" me";s:2:"32";s:3:"var";s:2:"33";s:3:"nde";s:2:"34";s:4:"är ";s:2:"35";s:3:" ko";s:2:"36";s:3:"on ";s:2:"37";s:3:"ans";s:2:"38";s:3:"int";s:2:"39";s:3:"n s";s:2:"40";s:3:"na ";s:2:"41";s:3:" en";s:2:"42";s:3:" fr";s:2:"43";s:4:" på";s:2:"44";s:3:" st";s:2:"45";s:3:" va";s:2:"46";s:3:"and";s:2:"47";s:3:"nte";s:2:"48";s:4:"på ";s:2:"49";s:3:"ska";s:2:"50";s:3:"ta ";s:2:"51";s:3:" vi";s:2:"52";s:3:"der";s:2:"53";s:4:"äll";s:2:"54";s:4:"örs";s:2:"55";s:3:" om";s:2:"56";s:3:"da ";s:2:"57";s:3:"kri";s:2:"58";s:3:"ka ";s:2:"59";s:3:"nst";s:2:"60";s:3:" ho";s:2:"61";s:3:"as ";s:2:"62";s:4:"stä";s:2:"63";s:3:"r d";s:2:"64";s:3:"t f";s:2:"65";s:3:"upp";s:2:"66";s:3:" be";s:2:"67";s:3:"nge";s:2:"68";s:3:"r s";s:2:"69";s:3:"tal";s:2:"70";s:4:"täl";s:2:"71";s:4:"ör ";s:2:"72";s:3:" av";s:2:"73";s:3:"ger";s:2:"74";s:3:"ill";s:2:"75";s:3:"ng ";s:2:"76";s:3:"e s";s:2:"77";s:3:"ekt";s:2:"78";s:3:"ade";s:2:"79";s:3:"era";s:2:"80";s:3:"ers";s:2:"81";s:3:"har";s:2:"82";s:3:"ll ";s:2:"83";s:3:"lld";s:2:"84";s:3:"rin";s:2:"85";s:3:"rna";s:2:"86";s:4:"säk";s:2:"87";s:3:"und";s:2:"88";s:3:"inn";s:2:"89";s:3:"lig";s:2:"90";s:3:"ns ";s:2:"91";s:3:" ma";s:2:"92";s:3:" pr";s:2:"93";s:3:" up";s:2:"94";s:3:"age";s:2:"95";s:3:"av ";s:2:"96";s:3:"iva";s:2:"97";s:3:"kti";s:2:"98";s:3:"lda";s:2:"99";s:3:"orn";s:3:"100";s:3:"son";s:3:"101";s:3:"ts ";s:3:"102";s:3:"tta";s:3:"103";s:4:"äkr";s:3:"104";s:3:" sj";s:3:"105";s:3:" ti";s:3:"106";s:3:"avt";s:3:"107";s:3:"ber";s:3:"108";s:3:"els";s:3:"109";s:3:"eta";s:3:"110";s:3:"kol";s:3:"111";s:3:"men";s:3:"112";s:3:"n d";s:3:"113";s:3:"t k";s:3:"114";s:3:"vta";s:3:"115";s:4:"år ";s:3:"116";s:3:"juk";s:3:"117";s:3:"man";s:3:"118";s:3:"n f";s:3:"119";s:3:"nin";s:3:"120";s:3:"r i";s:3:"121";s:4:"rsä";s:3:"122";s:3:"sju";s:3:"123";s:3:"sso";s:3:"124";s:4:" är";s:3:"125";s:3:"a s";s:3:"126";s:3:"ach";s:3:"127";s:3:"ag ";s:3:"128";s:3:"bac";s:3:"129";s:3:"den";s:3:"130";s:3:"ett";s:3:"131";s:3:"fte";s:3:"132";s:3:"hor";s:3:"133";s:3:"nba";s:3:"134";s:3:"oll";s:3:"135";s:3:"rnb";s:3:"136";s:3:"ste";s:3:"137";s:3:"til";s:3:"138";s:3:" ef";s:3:"139";s:3:" si";s:3:"140";s:3:"a a";s:3:"141";s:3:"e h";s:3:"142";s:3:"ed ";s:3:"143";s:3:"eft";s:3:"144";s:3:"ga ";s:3:"145";s:3:"ig ";s:3:"146";s:3:"it ";s:3:"147";s:3:"ler";s:3:"148";s:3:"med";s:3:"149";s:3:"n i";s:3:"150";s:3:"nd ";s:3:"151";s:4:"så ";s:3:"152";s:3:"tiv";s:3:"153";s:3:" bl";s:3:"154";s:3:" et";s:3:"155";s:3:" fi";s:3:"156";s:4:" sä";s:3:"157";s:3:"at ";s:3:"158";s:3:"des";s:3:"159";s:3:"e a";s:3:"160";s:3:"gar";s:3:"161";s:3:"get";s:3:"162";s:3:"lan";s:3:"163";s:3:"lss";s:3:"164";s:3:"ost";s:3:"165";s:3:"r b";s:3:"166";s:3:"r e";s:3:"167";s:3:"re ";s:3:"168";s:3:"ret";s:3:"169";s:3:"sta";s:3:"170";s:3:"t i";s:3:"171";s:3:" ge";s:3:"172";s:3:" he";s:3:"173";s:3:" re";s:3:"174";s:3:"a f";s:3:"175";s:3:"all";s:3:"176";s:3:"bos";s:3:"177";s:3:"ets";s:3:"178";s:3:"lek";s:3:"179";s:3:"let";s:3:"180";s:3:"ner";s:3:"181";s:3:"nna";s:3:"182";s:3:"nne";s:3:"183";s:3:"r f";s:3:"184";s:3:"rit";s:3:"185";s:3:"s s";s:3:"186";s:3:"sen";s:3:"187";s:3:"sto";s:3:"188";s:3:"tor";s:3:"189";s:3:"vav";s:3:"190";s:3:"ygg";s:3:"191";s:3:" ka";s:3:"192";s:4:" så";s:3:"193";s:3:" tr";s:3:"194";s:3:" ut";s:3:"195";s:3:"ad ";s:3:"196";s:3:"al ";s:3:"197";s:3:"are";s:3:"198";s:3:"e o";s:3:"199";s:3:"gon";s:3:"200";s:3:"kom";s:3:"201";s:3:"n a";s:3:"202";s:3:"n h";s:3:"203";s:3:"nga";s:3:"204";s:3:"r h";s:3:"205";s:3:"ren";s:3:"206";s:3:"t d";s:3:"207";s:3:"tag";s:3:"208";s:3:"tar";s:3:"209";s:3:"tre";s:3:"210";s:4:"ätt";s:3:"211";s:4:" få";s:3:"212";s:4:" hä";s:3:"213";s:3:" se";s:3:"214";s:3:"a d";s:3:"215";s:3:"a i";s:3:"216";s:3:"a p";s:3:"217";s:3:"ale";s:3:"218";s:3:"ann";s:3:"219";s:3:"ara";s:3:"220";s:3:"byg";s:3:"221";s:3:"gt ";s:3:"222";s:3:"han";s:3:"223";s:3:"igt";s:3:"224";s:3:"kan";s:3:"225";s:3:"la ";s:3:"226";s:3:"n o";s:3:"227";s:3:"nom";s:3:"228";s:3:"nsk";s:3:"229";s:3:"omm";s:3:"230";s:3:"r k";s:3:"231";s:3:"r p";s:3:"232";s:3:"r v";s:3:"233";s:3:"s f";s:3:"234";s:3:"s k";s:3:"235";s:3:"t a";s:3:"236";s:3:"t p";s:3:"237";s:3:"ver";s:3:"238";s:3:" bo";s:3:"239";s:3:" br";s:3:"240";s:3:" ku";s:3:"241";s:4:" nå";s:3:"242";s:3:"a b";s:3:"243";s:3:"a e";s:3:"244";s:3:"del";s:3:"245";s:3:"ens";s:3:"246";s:3:"es ";s:3:"247";s:3:"fin";s:3:"248";s:3:"ige";s:3:"249";s:3:"m s";s:3:"250";s:3:"n p";s:3:"251";s:4:"någ";s:3:"252";s:3:"or ";s:3:"253";s:3:"r o";s:3:"254";s:3:"rbe";s:3:"255";s:3:"rs ";s:3:"256";s:3:"rt ";s:3:"257";s:3:"s a";s:3:"258";s:3:"s n";s:3:"259";s:3:"skr";s:3:"260";s:3:"t o";s:3:"261";s:3:"ten";s:3:"262";s:3:"tio";s:3:"263";s:3:"ven";s:3:"264";s:3:" al";s:3:"265";s:3:" ja";s:3:"266";s:3:" p ";s:3:"267";s:3:" r ";s:3:"268";s:3:" sa";s:3:"269";s:3:"a h";s:3:"270";s:3:"bet";s:3:"271";s:3:"cke";s:3:"272";s:3:"dra";s:3:"273";s:3:"e f";s:3:"274";s:3:"e i";s:3:"275";s:3:"eda";s:3:"276";s:3:"eno";s:3:"277";s:4:"erä";s:3:"278";s:3:"ess";s:3:"279";s:3:"ion";s:3:"280";s:3:"jag";s:3:"281";s:3:"m f";s:3:"282";s:3:"ne ";s:3:"283";s:3:"nns";s:3:"284";s:3:"pro";s:3:"285";s:3:"r t";s:3:"286";s:3:"rar";s:3:"287";s:3:"riv";s:3:"288";s:4:"rät";s:3:"289";s:3:"t e";s:3:"290";s:3:"t t";s:3:"291";s:3:"ust";s:3:"292";s:3:"vad";s:3:"293";s:4:"öre";s:3:"294";s:3:" ar";s:3:"295";s:3:" by";s:3:"296";s:3:" kr";s:3:"297";s:3:" mi";s:3:"298";s:3:"arb";s:3:"299";}s:7:"tagalog";a:300:{s:3:"ng ";s:1:"0";s:3:"ang";s:1:"1";s:3:" na";s:1:"2";s:3:" sa";s:1:"3";s:3:"an ";s:1:"4";s:3:"nan";s:1:"5";s:3:"sa ";s:1:"6";s:3:"na ";s:1:"7";s:3:" ma";s:1:"8";s:3:" ca";s:1:"9";s:3:"ay ";s:2:"10";s:3:"n g";s:2:"11";s:3:" an";s:2:"12";s:3:"ong";s:2:"13";s:3:" ga";s:2:"14";s:3:"at ";s:2:"15";s:3:" pa";s:2:"16";s:3:"ala";s:2:"17";s:3:" si";s:2:"18";s:3:"a n";s:2:"19";s:3:"ga ";s:2:"20";s:3:"g n";s:2:"21";s:3:"g m";s:2:"22";s:3:"ito";s:2:"23";s:3:"g c";s:2:"24";s:3:"man";s:2:"25";s:3:"san";s:2:"26";s:3:"g s";s:2:"27";s:3:"ing";s:2:"28";s:3:"to ";s:2:"29";s:3:"ila";s:2:"30";s:3:"ina";s:2:"31";s:3:" di";s:2:"32";s:3:" ta";s:2:"33";s:3:"aga";s:2:"34";s:3:"iya";s:2:"35";s:3:"aca";s:2:"36";s:3:"g t";s:2:"37";s:3:" at";s:2:"38";s:3:"aya";s:2:"39";s:3:"ama";s:2:"40";s:3:"lan";s:2:"41";s:3:"a a";s:2:"42";s:3:"qui";s:2:"43";s:3:"a c";s:2:"44";s:3:"a s";s:2:"45";s:3:"nag";s:2:"46";s:3:" ba";s:2:"47";s:3:"g i";s:2:"48";s:3:"tan";s:2:"49";s:3:"'t ";s:2:"50";s:3:" cu";s:2:"51";s:3:"aua";s:2:"52";s:3:"g p";s:2:"53";s:3:" ni";s:2:"54";s:3:"os ";s:2:"55";s:3:"'y ";s:2:"56";s:3:"a m";s:2:"57";s:3:" n ";s:2:"58";s:3:"la ";s:2:"59";s:3:" la";s:2:"60";s:3:"o n";s:2:"61";s:3:"yan";s:2:"62";s:3:" ay";s:2:"63";s:3:"usa";s:2:"64";s:3:"cay";s:2:"65";s:3:"on ";s:2:"66";s:3:"ya ";s:2:"67";s:3:" it";s:2:"68";s:3:"al ";s:2:"69";s:3:"apa";s:2:"70";s:3:"ata";s:2:"71";s:3:"t n";s:2:"72";s:3:"uan";s:2:"73";s:3:"aha";s:2:"74";s:3:"asa";s:2:"75";s:3:"pag";s:2:"76";s:3:" gu";s:2:"77";s:3:"g l";s:2:"78";s:3:"di ";s:2:"79";s:3:"mag";s:2:"80";s:3:"aba";s:2:"81";s:3:"g a";s:2:"82";s:3:"ara";s:2:"83";s:3:"a p";s:2:"84";s:3:"in ";s:2:"85";s:3:"ana";s:2:"86";s:3:"it ";s:2:"87";s:3:"si ";s:2:"88";s:3:"cus";s:2:"89";s:3:"g b";s:2:"90";s:3:"uin";s:2:"91";s:3:"a t";s:2:"92";s:3:"as ";s:2:"93";s:3:"n n";s:2:"94";s:3:"hin";s:2:"95";s:3:" hi";s:2:"96";s:3:"a't";s:2:"97";s:3:"ali";s:2:"98";s:3:" bu";s:2:"99";s:3:"gan";s:3:"100";s:3:"uma";s:3:"101";s:3:"a d";s:3:"102";s:3:"agc";s:3:"103";s:3:"aqu";s:3:"104";s:3:"g d";s:3:"105";s:3:" tu";s:3:"106";s:3:"aon";s:3:"107";s:3:"ari";s:3:"108";s:3:"cas";s:3:"109";s:3:"i n";s:3:"110";s:3:"niy";s:3:"111";s:3:"pin";s:3:"112";s:3:"a i";s:3:"113";s:3:"gca";s:3:"114";s:3:"siy";s:3:"115";s:3:"a'y";s:3:"116";s:3:"yao";s:3:"117";s:3:"ag ";s:3:"118";s:3:"ca ";s:3:"119";s:3:"han";s:3:"120";s:3:"ili";s:3:"121";s:3:"pan";s:3:"122";s:3:"sin";s:3:"123";s:3:"ual";s:3:"124";s:3:"n s";s:3:"125";s:3:"nam";s:3:"126";s:3:" lu";s:3:"127";s:3:"can";s:3:"128";s:3:"dit";s:3:"129";s:3:"gui";s:3:"130";s:3:"y n";s:3:"131";s:3:"gal";s:3:"132";s:3:"hat";s:3:"133";s:3:"nal";s:3:"134";s:3:" is";s:3:"135";s:3:"bag";s:3:"136";s:3:"fra";s:3:"137";s:3:" fr";s:3:"138";s:3:" su";s:3:"139";s:3:"a l";s:3:"140";s:3:" co";s:3:"141";s:3:"ani";s:3:"142";s:3:" bi";s:3:"143";s:3:" da";s:3:"144";s:3:"alo";s:3:"145";s:3:"isa";s:3:"146";s:3:"ita";s:3:"147";s:3:"may";s:3:"148";s:3:"o s";s:3:"149";s:3:"sil";s:3:"150";s:3:"una";s:3:"151";s:3:" in";s:3:"152";s:3:" pi";s:3:"153";s:3:"l n";s:3:"154";s:3:"nil";s:3:"155";s:3:"o a";s:3:"156";s:3:"pat";s:3:"157";s:3:"sac";s:3:"158";s:3:"t s";s:3:"159";s:3:" ua";s:3:"160";s:3:"agu";s:3:"161";s:3:"ail";s:3:"162";s:3:"bin";s:3:"163";s:3:"dal";s:3:"164";s:3:"g h";s:3:"165";s:3:"ndi";s:3:"166";s:3:"oon";s:3:"167";s:3:"ua ";s:3:"168";s:3:" ha";s:3:"169";s:3:"ind";s:3:"170";s:3:"ran";s:3:"171";s:3:"s n";s:3:"172";s:3:"tin";s:3:"173";s:3:"ulo";s:3:"174";s:3:"eng";s:3:"175";s:3:"g f";s:3:"176";s:3:"ini";s:3:"177";s:3:"lah";s:3:"178";s:3:"lo ";s:3:"179";s:3:"rai";s:3:"180";s:3:"rin";s:3:"181";s:3:"ton";s:3:"182";s:3:"g u";s:3:"183";s:3:"inu";s:3:"184";s:3:"lon";s:3:"185";s:3:"o'y";s:3:"186";s:3:"t a";s:3:"187";s:3:" ar";s:3:"188";s:3:"a b";s:3:"189";s:3:"ad ";s:3:"190";s:3:"bay";s:3:"191";s:3:"cal";s:3:"192";s:3:"gya";s:3:"193";s:3:"ile";s:3:"194";s:3:"mat";s:3:"195";s:3:"n a";s:3:"196";s:3:"pau";s:3:"197";s:3:"ra ";s:3:"198";s:3:"tay";s:3:"199";s:3:"y m";s:3:"200";s:3:"ant";s:3:"201";s:3:"ban";s:3:"202";s:3:"i m";s:3:"203";s:3:"nas";s:3:"204";s:3:"nay";s:3:"205";s:3:"no ";s:3:"206";s:3:"sti";s:3:"207";s:3:" ti";s:3:"208";s:3:"ags";s:3:"209";s:3:"g g";s:3:"210";s:3:"ta ";s:3:"211";s:3:"uit";s:3:"212";s:3:"uno";s:3:"213";s:3:" ib";s:3:"214";s:3:" ya";s:3:"215";s:3:"a u";s:3:"216";s:3:"abi";s:3:"217";s:3:"ati";s:3:"218";s:3:"cap";s:3:"219";s:3:"ig ";s:3:"220";s:3:"is ";s:3:"221";s:3:"la'";s:3:"222";s:3:" do";s:3:"223";s:3:" pu";s:3:"224";s:3:"api";s:3:"225";s:3:"ayo";s:3:"226";s:3:"gos";s:3:"227";s:3:"gul";s:3:"228";s:3:"lal";s:3:"229";s:3:"tag";s:3:"230";s:3:"til";s:3:"231";s:3:"tun";s:3:"232";s:3:"y c";s:3:"233";s:3:"y s";s:3:"234";s:3:"yon";s:3:"235";s:3:"ano";s:3:"236";s:3:"bur";s:3:"237";s:3:"iba";s:3:"238";s:3:"isi";s:3:"239";s:3:"lam";s:3:"240";s:3:"nac";s:3:"241";s:3:"nat";s:3:"242";s:3:"ni ";s:3:"243";s:3:"nto";s:3:"244";s:3:"od ";s:3:"245";s:3:"pa ";s:3:"246";s:3:"rgo";s:3:"247";s:3:"urg";s:3:"248";s:3:" m ";s:3:"249";s:3:"adr";s:3:"250";s:3:"ast";s:3:"251";s:3:"cag";s:3:"252";s:3:"gay";s:3:"253";s:3:"gsi";s:3:"254";s:3:"i p";s:3:"255";s:3:"ino";s:3:"256";s:3:"len";s:3:"257";s:3:"lin";s:3:"258";s:3:"m g";s:3:"259";s:3:"mar";s:3:"260";s:3:"nah";s:3:"261";s:3:"to'";s:3:"262";s:3:" de";s:3:"263";s:3:"a h";s:3:"264";s:3:"cat";s:3:"265";s:3:"cau";s:3:"266";s:3:"con";s:3:"267";s:3:"iqu";s:3:"268";s:3:"lac";s:3:"269";s:3:"mab";s:3:"270";s:3:"min";s:3:"271";s:3:"og ";s:3:"272";s:3:"par";s:3:"273";s:3:"sal";s:3:"274";s:3:" za";s:3:"275";s:3:"ao ";s:3:"276";s:3:"doo";s:3:"277";s:3:"ipi";s:3:"278";s:3:"nod";s:3:"279";s:3:"nte";s:3:"280";s:3:"uha";s:3:"281";s:3:"ula";s:3:"282";s:3:" re";s:3:"283";s:3:"ill";s:3:"284";s:3:"lit";s:3:"285";s:3:"mac";s:3:"286";s:3:"nit";s:3:"287";s:3:"o't";s:3:"288";s:3:"or ";s:3:"289";s:3:"ora";s:3:"290";s:3:"sum";s:3:"291";s:3:"y p";s:3:"292";s:3:" al";s:3:"293";s:3:" mi";s:3:"294";s:3:" um";s:3:"295";s:3:"aco";s:3:"296";s:3:"ada";s:3:"297";s:3:"agd";s:3:"298";s:3:"cab";s:3:"299";}s:7:"turkish";a:300:{s:3:"lar";s:1:"0";s:3:"en ";s:1:"1";s:3:"ler";s:1:"2";s:3:"an ";s:1:"3";s:3:"in ";s:1:"4";s:3:" bi";s:1:"5";s:3:" ya";s:1:"6";s:3:"eri";s:1:"7";s:3:"de ";s:1:"8";s:3:" ka";s:1:"9";s:3:"ir ";s:2:"10";s:4:"arı";s:2:"11";s:3:" ba";s:2:"12";s:3:" de";s:2:"13";s:3:" ha";s:2:"14";s:4:"ın ";s:2:"15";s:3:"ara";s:2:"16";s:3:"bir";s:2:"17";s:3:" ve";s:2:"18";s:3:" sa";s:2:"19";s:3:"ile";s:2:"20";s:3:"le ";s:2:"21";s:3:"nde";s:2:"22";s:3:"da ";s:2:"23";s:3:" bu";s:2:"24";s:3:"ana";s:2:"25";s:3:"ini";s:2:"26";s:5:"ını";s:2:"27";s:3:"er ";s:2:"28";s:3:"ve ";s:2:"29";s:4:" yı";s:2:"30";s:3:"lma";s:2:"31";s:4:"yıl";s:2:"32";s:3:" ol";s:2:"33";s:3:"ar ";s:2:"34";s:3:"n b";s:2:"35";s:3:"nda";s:2:"36";s:3:"aya";s:2:"37";s:3:"li ";s:2:"38";s:4:"ası";s:2:"39";s:3:" ge";s:2:"40";s:3:"ind";s:2:"41";s:3:"n k";s:2:"42";s:3:"esi";s:2:"43";s:3:"lan";s:2:"44";s:3:"nla";s:2:"45";s:3:"ak ";s:2:"46";s:4:"anı";s:2:"47";s:3:"eni";s:2:"48";s:3:"ni ";s:2:"49";s:4:"nı ";s:2:"50";s:4:"rın";s:2:"51";s:3:"san";s:2:"52";s:3:" ko";s:2:"53";s:3:" ye";s:2:"54";s:3:"maz";s:2:"55";s:4:"baş";s:2:"56";s:3:"ili";s:2:"57";s:3:"rin";s:2:"58";s:4:"alı";s:2:"59";s:3:"az ";s:2:"60";s:3:"hal";s:2:"61";s:4:"ınd";s:2:"62";s:3:" da";s:2:"63";s:4:" gü";s:2:"64";s:3:"ele";s:2:"65";s:4:"ılm";s:2:"66";s:6:"ığı";s:2:"67";s:3:"eki";s:2:"68";s:4:"gün";s:2:"69";s:3:"i b";s:2:"70";s:4:"içi";s:2:"71";s:3:"den";s:2:"72";s:3:"kar";s:2:"73";s:3:"si ";s:2:"74";s:3:" il";s:2:"75";s:3:"e y";s:2:"76";s:3:"na ";s:2:"77";s:3:"yor";s:2:"78";s:3:"ek ";s:2:"79";s:3:"n s";s:2:"80";s:4:" iç";s:2:"81";s:3:"bu ";s:2:"82";s:3:"e b";s:2:"83";s:3:"im ";s:2:"84";s:3:"ki ";s:2:"85";s:3:"len";s:2:"86";s:3:"ri ";s:2:"87";s:4:"sın";s:2:"88";s:3:" so";s:2:"89";s:4:"ün ";s:2:"90";s:3:" ta";s:2:"91";s:3:"nin";s:2:"92";s:4:"iği";s:2:"93";s:3:"tan";s:2:"94";s:3:"yan";s:2:"95";s:3:" si";s:2:"96";s:3:"nat";s:2:"97";s:4:"nın";s:2:"98";s:3:"kan";s:2:"99";s:4:"rı ";s:3:"100";s:4:"çin";s:3:"101";s:5:"ğı ";s:3:"102";s:3:"eli";s:3:"103";s:3:"n a";s:3:"104";s:4:"ır ";s:3:"105";s:3:" an";s:3:"106";s:3:"ine";s:3:"107";s:3:"n y";s:3:"108";s:3:"ola";s:3:"109";s:3:" ar";s:3:"110";s:3:"al ";s:3:"111";s:3:"e s";s:3:"112";s:3:"lik";s:3:"113";s:3:"n d";s:3:"114";s:3:"sin";s:3:"115";s:3:" al";s:3:"116";s:4:" dü";s:3:"117";s:3:"anl";s:3:"118";s:3:"ne ";s:3:"119";s:3:"ya ";s:3:"120";s:4:"ım ";s:3:"121";s:4:"ına";s:3:"122";s:3:" be";s:3:"123";s:3:"ada";s:3:"124";s:3:"ala";s:3:"125";s:3:"ama";s:3:"126";s:3:"ilm";s:3:"127";s:3:"or ";s:3:"128";s:4:"sı ";s:3:"129";s:3:"yen";s:3:"130";s:3:" me";s:3:"131";s:4:"atı";s:3:"132";s:3:"di ";s:3:"133";s:3:"eti";s:3:"134";s:3:"ken";s:3:"135";s:3:"la ";s:3:"136";s:4:"lı ";s:3:"137";s:3:"oru";s:3:"138";s:4:" gö";s:3:"139";s:3:" in";s:3:"140";s:3:"and";s:3:"141";s:3:"e d";s:3:"142";s:3:"men";s:3:"143";s:3:"un ";s:3:"144";s:4:"öne";s:3:"145";s:3:"a d";s:3:"146";s:3:"at ";s:3:"147";s:3:"e a";s:3:"148";s:3:"e g";s:3:"149";s:3:"yar";s:3:"150";s:3:" ku";s:3:"151";s:4:"ayı";s:3:"152";s:3:"dan";s:3:"153";s:3:"edi";s:3:"154";s:3:"iri";s:3:"155";s:5:"ünü";s:3:"156";s:4:"ği ";s:3:"157";s:5:"ılı";s:3:"158";s:3:"eme";s:3:"159";s:4:"eği";s:3:"160";s:3:"i k";s:3:"161";s:3:"i y";s:3:"162";s:4:"ıla";s:3:"163";s:4:" ça";s:3:"164";s:3:"a y";s:3:"165";s:3:"alk";s:3:"166";s:4:"dı ";s:3:"167";s:3:"ede";s:3:"168";s:3:"el ";s:3:"169";s:4:"ndı";s:3:"170";s:3:"ra ";s:3:"171";s:4:"üne";s:3:"172";s:4:" sü";s:3:"173";s:4:"dır";s:3:"174";s:3:"e k";s:3:"175";s:3:"ere";s:3:"176";s:3:"ik ";s:3:"177";s:3:"imi";s:3:"178";s:4:"işi";s:3:"179";s:3:"mas";s:3:"180";s:3:"n h";s:3:"181";s:4:"sür";s:3:"182";s:3:"yle";s:3:"183";s:3:" ad";s:3:"184";s:3:" fi";s:3:"185";s:3:" gi";s:3:"186";s:3:" se";s:3:"187";s:3:"a k";s:3:"188";s:3:"arl";s:3:"189";s:5:"aşı";s:3:"190";s:3:"iyo";s:3:"191";s:3:"kla";s:3:"192";s:5:"lığ";s:3:"193";s:3:"nem";s:3:"194";s:3:"ney";s:3:"195";s:3:"rme";s:3:"196";s:3:"ste";s:3:"197";s:4:"tı ";s:3:"198";s:3:"unl";s:3:"199";s:3:"ver";s:3:"200";s:4:" sı";s:3:"201";s:3:" te";s:3:"202";s:3:" to";s:3:"203";s:3:"a s";s:3:"204";s:4:"aşk";s:3:"205";s:3:"ekl";s:3:"206";s:3:"end";s:3:"207";s:3:"kal";s:3:"208";s:4:"liğ";s:3:"209";s:3:"min";s:3:"210";s:4:"tır";s:3:"211";s:3:"ulu";s:3:"212";s:3:"unu";s:3:"213";s:3:"yap";s:3:"214";s:3:"ye ";s:3:"215";s:4:"ı i";s:3:"216";s:4:"şka";s:3:"217";s:5:"ştı";s:3:"218";s:4:" bü";s:3:"219";s:3:" ke";s:3:"220";s:3:" ki";s:3:"221";s:3:"ard";s:3:"222";s:3:"art";s:3:"223";s:4:"aşa";s:3:"224";s:3:"n i";s:3:"225";s:3:"ndi";s:3:"226";s:3:"ti ";s:3:"227";s:3:"top";s:3:"228";s:4:"ı b";s:3:"229";s:3:" va";s:3:"230";s:4:" ön";s:3:"231";s:3:"aki";s:3:"232";s:3:"cak";s:3:"233";s:3:"ey ";s:3:"234";s:3:"fil";s:3:"235";s:3:"isi";s:3:"236";s:3:"kle";s:3:"237";s:3:"kur";s:3:"238";s:3:"man";s:3:"239";s:3:"nce";s:3:"240";s:3:"nle";s:3:"241";s:3:"nun";s:3:"242";s:3:"rak";s:3:"243";s:4:"ık ";s:3:"244";s:3:" en";s:3:"245";s:3:" yo";s:3:"246";s:3:"a g";s:3:"247";s:3:"lis";s:3:"248";s:3:"mak";s:3:"249";s:3:"n g";s:3:"250";s:3:"tir";s:3:"251";s:3:"yas";s:3:"252";s:4:" iş";s:3:"253";s:4:" yö";s:3:"254";s:3:"ale";s:3:"255";s:3:"bil";s:3:"256";s:3:"bul";s:3:"257";s:3:"et ";s:3:"258";s:3:"i d";s:3:"259";s:3:"iye";s:3:"260";s:3:"kil";s:3:"261";s:3:"ma ";s:3:"262";s:3:"n e";s:3:"263";s:3:"n t";s:3:"264";s:3:"nu ";s:3:"265";s:3:"olu";s:3:"266";s:3:"rla";s:3:"267";s:3:"te ";s:3:"268";s:4:"yön";s:3:"269";s:5:"çık";s:3:"270";s:3:" ay";s:3:"271";s:4:" mü";s:3:"272";s:4:" ço";s:3:"273";s:5:" çı";s:3:"274";s:3:"a a";s:3:"275";s:3:"a b";s:3:"276";s:3:"ata";s:3:"277";s:3:"der";s:3:"278";s:3:"gel";s:3:"279";s:3:"i g";s:3:"280";s:3:"i i";s:3:"281";s:3:"ill";s:3:"282";s:3:"ist";s:3:"283";s:4:"ldı";s:3:"284";s:3:"lu ";s:3:"285";s:3:"mek";s:3:"286";s:3:"mle";s:3:"287";s:4:"n ç";s:3:"288";s:3:"onu";s:3:"289";s:3:"opl";s:3:"290";s:3:"ran";s:3:"291";s:3:"rat";s:3:"292";s:4:"rdı";s:3:"293";s:3:"rke";s:3:"294";s:3:"siy";s:3:"295";s:3:"son";s:3:"296";s:3:"ta ";s:3:"297";s:5:"tçı";s:3:"298";s:4:"tın";s:3:"299";}s:9:"ukrainian";a:300:{s:5:" на";s:1:"0";s:5:" за";s:1:"1";s:6:"ння";s:1:"2";s:5:"ня ";s:1:"3";s:5:"на ";s:1:"4";s:5:" пр";s:1:"5";s:6:"ого";s:1:"6";s:5:"го ";s:1:"7";s:6:"ськ";s:1:"8";s:5:" по";s:1:"9";s:4:" у ";s:2:"10";s:6:"від";s:2:"11";s:6:"ере";s:2:"12";s:5:" мі";s:2:"13";s:5:" не";s:2:"14";s:5:"их ";s:2:"15";s:5:"ть ";s:2:"16";s:6:"пер";s:2:"17";s:5:" ві";s:2:"18";s:5:"ів ";s:2:"19";s:5:" пе";s:2:"20";s:5:" що";s:2:"21";s:6:"льн";s:2:"22";s:5:"ми ";s:2:"23";s:5:"ні ";s:2:"24";s:5:"не ";s:2:"25";s:5:"ти ";s:2:"26";s:6:"ати";s:2:"27";s:6:"енн";s:2:"28";s:6:"міс";s:2:"29";s:6:"пра";s:2:"30";s:6:"ува";s:2:"31";s:6:"ник";s:2:"32";s:6:"про";s:2:"33";s:6:"рав";s:2:"34";s:6:"івн";s:2:"35";s:5:" та";s:2:"36";s:6:"буд";s:2:"37";s:6:"влі";s:2:"38";s:6:"рів";s:2:"39";s:5:" ко";s:2:"40";s:5:" рі";s:2:"41";s:6:"аль";s:2:"42";s:5:"но ";s:2:"43";s:6:"ому";s:2:"44";s:5:"що ";s:2:"45";s:5:" ви";s:2:"46";s:5:"му ";s:2:"47";s:6:"рев";s:2:"48";s:5:"ся ";s:2:"49";s:6:"інн";s:2:"50";s:5:" до";s:2:"51";s:5:" уп";s:2:"52";s:6:"авл";s:2:"53";s:6:"анн";s:2:"54";s:6:"ком";s:2:"55";s:5:"ли ";s:2:"56";s:6:"лін";s:2:"57";s:6:"ног";s:2:"58";s:6:"упр";s:2:"59";s:5:" бу";s:2:"60";s:4:" з ";s:2:"61";s:5:" ро";s:2:"62";s:5:"за ";s:2:"63";s:5:"и н";s:2:"64";s:6:"нов";s:2:"65";s:6:"оро";s:2:"66";s:6:"ост";s:2:"67";s:6:"ста";s:2:"68";s:5:"ті ";s:2:"69";s:6:"ють";s:2:"70";s:5:" мо";s:2:"71";s:5:" ні";s:2:"72";s:5:" як";s:2:"73";s:6:"бор";s:2:"74";s:5:"ва ";s:2:"75";s:6:"ван";s:2:"76";s:6:"ень";s:2:"77";s:5:"и п";s:2:"78";s:5:"нь ";s:2:"79";s:6:"ові";s:2:"80";s:6:"рон";s:2:"81";s:6:"сті";s:2:"82";s:5:"та ";s:2:"83";s:5:"у в";s:2:"84";s:6:"ько";s:2:"85";s:6:"іст";s:2:"86";s:4:" в ";s:2:"87";s:5:" ре";s:2:"88";s:5:"до ";s:2:"89";s:5:"е п";s:2:"90";s:6:"заб";s:2:"91";s:5:"ий ";s:2:"92";s:6:"нсь";s:2:"93";s:5:"о в";s:2:"94";s:5:"о п";s:2:"95";s:6:"при";s:2:"96";s:5:"і п";s:2:"97";s:5:" ку";s:2:"98";s:5:" пі";s:2:"99";s:5:" сп";s:3:"100";s:5:"а п";s:3:"101";s:6:"або";s:3:"102";s:6:"анс";s:3:"103";s:6:"аці";s:3:"104";s:6:"ват";s:3:"105";s:6:"вни";s:3:"106";s:5:"и в";s:3:"107";s:6:"ими";s:3:"108";s:5:"ка ";s:3:"109";s:6:"нен";s:3:"110";s:6:"ніч";s:3:"111";s:6:"она";s:3:"112";s:5:"ої ";s:3:"113";s:6:"пов";s:3:"114";s:6:"ьки";s:3:"115";s:6:"ьно";s:3:"116";s:6:"ізн";s:3:"117";s:6:"ічн";s:3:"118";s:5:" ав";s:3:"119";s:5:" ма";s:3:"120";s:5:" ор";s:3:"121";s:5:" су";s:3:"122";s:5:" чи";s:3:"123";s:5:" ін";s:3:"124";s:5:"а з";s:3:"125";s:5:"ам ";s:3:"126";s:5:"ає ";s:3:"127";s:6:"вне";s:3:"128";s:6:"вто";s:3:"129";s:6:"дом";s:3:"130";s:6:"ент";s:3:"131";s:6:"жит";s:3:"132";s:6:"зни";s:3:"133";s:5:"им ";s:3:"134";s:6:"итл";s:3:"135";s:5:"ла ";s:3:"136";s:6:"них";s:3:"137";s:6:"ниц";s:3:"138";s:6:"ова";s:3:"139";s:6:"ови";s:3:"140";s:5:"ом ";s:3:"141";s:6:"пор";s:3:"142";s:6:"тьс";s:3:"143";s:5:"у р";s:3:"144";s:6:"ься";s:3:"145";s:6:"ідо";s:3:"146";s:6:"іль";s:3:"147";s:6:"ісь";s:3:"148";s:5:" ва";s:3:"149";s:5:" ді";s:3:"150";s:5:" жи";s:3:"151";s:5:" че";s:3:"152";s:4:" і ";s:3:"153";s:5:"а в";s:3:"154";s:5:"а н";s:3:"155";s:6:"али";s:3:"156";s:6:"вез";s:3:"157";s:6:"вно";s:3:"158";s:6:"еве";s:3:"159";s:6:"езе";s:3:"160";s:6:"зен";s:3:"161";s:6:"ицт";s:3:"162";s:5:"ки ";s:3:"163";s:6:"ких";s:3:"164";s:6:"кон";s:3:"165";s:5:"ку ";s:3:"166";s:6:"лас";s:3:"167";s:5:"ля ";s:3:"168";s:6:"мож";s:3:"169";s:6:"нач";s:3:"170";s:6:"ним";s:3:"171";s:6:"ної";s:3:"172";s:5:"о б";s:3:"173";s:6:"ову";s:3:"174";s:6:"оди";s:3:"175";s:5:"ою ";s:3:"176";s:5:"ро ";s:3:"177";s:6:"рок";s:3:"178";s:6:"сно";s:3:"179";s:6:"спо";s:3:"180";s:6:"так";s:3:"181";s:6:"тва";s:3:"182";s:5:"ту ";s:3:"183";s:5:"у п";s:3:"184";s:6:"цтв";s:3:"185";s:6:"ьни";s:3:"186";s:5:"я з";s:3:"187";s:5:"і м";s:3:"188";s:5:"ії ";s:3:"189";s:5:" вс";s:3:"190";s:5:" гр";s:3:"191";s:5:" де";s:3:"192";s:5:" но";s:3:"193";s:5:" па";s:3:"194";s:5:" се";s:3:"195";s:5:" ук";s:3:"196";s:5:" їх";s:3:"197";s:5:"а о";s:3:"198";s:6:"авт";s:3:"199";s:6:"аст";s:3:"200";s:6:"ают";s:3:"201";s:6:"вар";s:3:"202";s:6:"ден";s:3:"203";s:5:"ди ";s:3:"204";s:5:"ду ";s:3:"205";s:6:"зна";s:3:"206";s:5:"и з";s:3:"207";s:6:"ико";s:3:"208";s:6:"ися";s:3:"209";s:6:"ити";s:3:"210";s:6:"ког";s:3:"211";s:6:"мен";s:3:"212";s:6:"ном";s:3:"213";s:5:"ну ";s:3:"214";s:5:"о н";s:3:"215";s:5:"о с";s:3:"216";s:6:"обу";s:3:"217";s:6:"ово";s:3:"218";s:6:"пла";s:3:"219";s:6:"ран";s:3:"220";s:6:"рив";s:3:"221";s:6:"роб";s:3:"222";s:6:"ска";s:3:"223";s:6:"тан";s:3:"224";s:6:"тим";s:3:"225";s:6:"тис";s:3:"226";s:5:"то ";s:3:"227";s:6:"тра";s:3:"228";s:6:"удо";s:3:"229";s:6:"чин";s:3:"230";s:6:"чни";s:3:"231";s:5:"і в";s:3:"232";s:5:"ію ";s:3:"233";s:4:" а ";s:3:"234";s:5:" во";s:3:"235";s:5:" да";s:3:"236";s:5:" кв";s:3:"237";s:5:" ме";s:3:"238";s:5:" об";s:3:"239";s:5:" ск";s:3:"240";s:5:" ти";s:3:"241";s:5:" фі";s:3:"242";s:4:" є ";s:3:"243";s:5:"а р";s:3:"244";s:5:"а с";s:3:"245";s:5:"а у";s:3:"246";s:5:"ак ";s:3:"247";s:6:"ані";s:3:"248";s:6:"арт";s:3:"249";s:6:"асн";s:3:"250";s:5:"в у";s:3:"251";s:6:"вик";s:3:"252";s:6:"віз";s:3:"253";s:6:"дов";s:3:"254";s:6:"дпо";s:3:"255";s:6:"дів";s:3:"256";s:6:"еві";s:3:"257";s:6:"енс";s:3:"258";s:5:"же ";s:3:"259";s:5:"и м";s:3:"260";s:5:"и с";s:3:"261";s:6:"ика";s:3:"262";s:6:"ичн";s:3:"263";s:5:"кі ";s:3:"264";s:6:"ків";s:3:"265";s:6:"між";s:3:"266";s:6:"нан";s:3:"267";s:6:"нос";s:3:"268";s:5:"о у";s:3:"269";s:6:"обл";s:3:"270";s:6:"одн";s:3:"271";s:5:"ок ";s:3:"272";s:6:"оло";s:3:"273";s:6:"отр";s:3:"274";s:6:"рен";s:3:"275";s:6:"рим";s:3:"276";s:6:"роз";s:3:"277";s:5:"сь ";s:3:"278";s:5:"сі ";s:3:"279";s:6:"тла";s:3:"280";s:6:"тів";s:3:"281";s:5:"у з";s:3:"282";s:6:"уго";s:3:"283";s:6:"уді";s:3:"284";s:5:"чи ";s:3:"285";s:5:"ше ";s:3:"286";s:5:"я н";s:3:"287";s:5:"я у";s:3:"288";s:6:"ідп";s:3:"289";s:5:"ій ";s:3:"290";s:6:"іна";s:3:"291";s:5:"ія ";s:3:"292";s:5:" ка";s:3:"293";s:5:" ни";s:3:"294";s:5:" ос";s:3:"295";s:5:" си";s:3:"296";s:5:" то";s:3:"297";s:5:" тр";s:3:"298";s:5:" уг";s:3:"299";}s:4:"urdu";a:300:{s:5:"یں ";s:1:"0";s:5:" کی";s:1:"1";s:5:"کے ";s:1:"2";s:5:" کے";s:1:"3";s:5:"نے ";s:1:"4";s:5:" کہ";s:1:"5";s:5:"ے ک";s:1:"6";s:5:"کی ";s:1:"7";s:6:"میں";s:1:"8";s:5:" می";s:1:"9";s:5:"ہے ";s:2:"10";s:5:"وں ";s:2:"11";s:5:"کہ ";s:2:"12";s:5:" ہے";s:2:"13";s:5:"ان ";s:2:"14";s:6:"ہیں";s:2:"15";s:5:"ور ";s:2:"16";s:5:" کو";s:2:"17";s:5:"یا ";s:2:"18";s:5:" ان";s:2:"19";s:5:" نے";s:2:"20";s:5:"سے ";s:2:"21";s:5:" سے";s:2:"22";s:5:" کر";s:2:"23";s:6:"ستا";s:2:"24";s:5:" او";s:2:"25";s:6:"اور";s:2:"26";s:6:"تان";s:2:"27";s:5:"ر ک";s:2:"28";s:5:"ی ک";s:2:"29";s:5:" اس";s:2:"30";s:5:"ے ا";s:2:"31";s:5:" پا";s:2:"32";s:5:" ہو";s:2:"33";s:5:" پر";s:2:"34";s:5:"رف ";s:2:"35";s:5:" کا";s:2:"36";s:5:"ا ک";s:2:"37";s:5:"ی ا";s:2:"38";s:5:" ہی";s:2:"39";s:5:"در ";s:2:"40";s:5:"کو ";s:2:"41";s:5:" ای";s:2:"42";s:5:"ں ک";s:2:"43";s:5:" مش";s:2:"44";s:5:" مل";s:2:"45";s:5:"ات ";s:2:"46";s:6:"صدر";s:2:"47";s:6:"اکس";s:2:"48";s:6:"شرف";s:2:"49";s:6:"مشر";s:2:"50";s:6:"پاک";s:2:"51";s:6:"کست";s:2:"52";s:5:"ی م";s:2:"53";s:5:" دی";s:2:"54";s:5:" صد";s:2:"55";s:5:" یہ";s:2:"56";s:5:"ا ہ";s:2:"57";s:5:"ن ک";s:2:"58";s:6:"وال";s:2:"59";s:5:"یہ ";s:2:"60";s:5:"ے و";s:2:"61";s:5:" بھ";s:2:"62";s:5:" دو";s:2:"63";s:5:"اس ";s:2:"64";s:5:"ر ا";s:2:"65";s:6:"نہی";s:2:"66";s:5:"کا ";s:2:"67";s:5:"ے س";s:2:"68";s:5:"ئی ";s:2:"69";s:5:"ہ ا";s:2:"70";s:5:"یت ";s:2:"71";s:5:"ے ہ";s:2:"72";s:5:"ت ک";s:2:"73";s:5:" سا";s:2:"74";s:5:"لے ";s:2:"75";s:5:"ہا ";s:2:"76";s:5:"ے ب";s:2:"77";s:5:" وا";s:2:"78";s:5:"ار ";s:2:"79";s:5:"نی ";s:2:"80";s:6:"کہا";s:2:"81";s:5:"ی ہ";s:2:"82";s:5:"ے م";s:2:"83";s:5:" سی";s:2:"84";s:5:" لی";s:2:"85";s:6:"انہ";s:2:"86";s:6:"انی";s:2:"87";s:5:"ر م";s:2:"88";s:5:"ر پ";s:2:"89";s:6:"ریت";s:2:"90";s:5:"ن م";s:2:"91";s:5:"ھا ";s:2:"92";s:5:"یر ";s:2:"93";s:5:" جا";s:2:"94";s:5:" جن";s:2:"95";s:5:"ئے ";s:2:"96";s:5:"پر ";s:2:"97";s:5:"ں ن";s:2:"98";s:5:"ہ ک";s:2:"99";s:5:"ی و";s:3:"100";s:5:"ے د";s:3:"101";s:5:" تو";s:3:"102";s:5:" تھ";s:3:"103";s:5:" گی";s:3:"104";s:6:"ایک";s:3:"105";s:5:"ل ک";s:3:"106";s:5:"نا ";s:3:"107";s:5:"کر ";s:3:"108";s:5:"ں م";s:3:"109";s:5:"یک ";s:3:"110";s:5:" با";s:3:"111";s:5:"ا ت";s:3:"112";s:5:"دی ";s:3:"113";s:5:"ن س";s:3:"114";s:6:"کیا";s:3:"115";s:6:"یوں";s:3:"116";s:5:"ے ج";s:3:"117";s:5:"ال ";s:3:"118";s:5:"تو ";s:3:"119";s:5:"ں ا";s:3:"120";s:5:"ے پ";s:3:"121";s:5:" چا";s:3:"122";s:5:"ام ";s:3:"123";s:6:"بھی";s:3:"124";s:5:"تی ";s:3:"125";s:5:"تے ";s:3:"126";s:6:"دوس";s:3:"127";s:5:"س ک";s:3:"128";s:6:"ملک";s:3:"129";s:5:"ن ا";s:3:"130";s:6:"ہور";s:3:"131";s:5:"یے ";s:3:"132";s:5:" مو";s:3:"133";s:5:" وک";s:3:"134";s:6:"ائی";s:3:"135";s:6:"ارت";s:3:"136";s:6:"الے";s:3:"137";s:6:"بھا";s:3:"138";s:6:"ردی";s:3:"139";s:5:"ری ";s:3:"140";s:5:"وہ ";s:3:"141";s:6:"ویز";s:3:"142";s:5:"ں د";s:3:"143";s:5:"ھی ";s:3:"144";s:5:"ی س";s:3:"145";s:5:" رہ";s:3:"146";s:5:" من";s:3:"147";s:5:" نہ";s:3:"148";s:5:" ور";s:3:"149";s:5:" وہ";s:3:"150";s:5:" ہن";s:3:"151";s:5:"ا ا";s:3:"152";s:6:"است";s:3:"153";s:5:"ت ا";s:3:"154";s:5:"ت پ";s:3:"155";s:5:"د ک";s:3:"156";s:5:"ز م";s:3:"157";s:5:"ند ";s:3:"158";s:6:"ورد";s:3:"159";s:6:"وکل";s:3:"160";s:5:"گی ";s:3:"161";s:6:"گیا";s:3:"162";s:5:"ہ پ";s:3:"163";s:5:"یز ";s:3:"164";s:5:"ے ت";s:3:"165";s:5:" اع";s:3:"166";s:5:" اپ";s:3:"167";s:5:" جس";s:3:"168";s:5:" جم";s:3:"169";s:5:" جو";s:3:"170";s:5:" سر";s:3:"171";s:6:"اپن";s:3:"172";s:6:"اکث";s:3:"173";s:6:"تھا";s:3:"174";s:6:"ثری";s:3:"175";s:6:"دیا";s:3:"176";s:5:"ر د";s:3:"177";s:5:"رت ";s:3:"178";s:6:"روی";s:3:"179";s:5:"سی ";s:3:"180";s:6:"ملا";s:3:"181";s:6:"ندو";s:3:"182";s:6:"وست";s:3:"183";s:6:"پرو";s:3:"184";s:6:"چاہ";s:3:"185";s:6:"کثر";s:3:"186";s:6:"کلا";s:3:"187";s:5:"ہ ہ";s:3:"188";s:6:"ہند";s:3:"189";s:5:"ہو ";s:3:"190";s:5:"ے ل";s:3:"191";s:5:" اک";s:3:"192";s:5:" دا";s:3:"193";s:5:" سن";s:3:"194";s:5:" وز";s:3:"195";s:5:" پی";s:3:"196";s:5:"ا چ";s:3:"197";s:5:"اء ";s:3:"198";s:6:"اتھ";s:3:"199";s:6:"اقا";s:3:"200";s:5:"اہ ";s:3:"201";s:5:"تھ ";s:3:"202";s:5:"دو ";s:3:"203";s:5:"ر ب";s:3:"204";s:6:"روا";s:3:"205";s:5:"رے ";s:3:"206";s:6:"سات";s:3:"207";s:5:"ف ک";s:3:"208";s:6:"قات";s:3:"209";s:5:"لا ";s:3:"210";s:6:"لاء";s:3:"211";s:5:"م م";s:3:"212";s:5:"م ک";s:3:"213";s:5:"من ";s:3:"214";s:6:"نوں";s:3:"215";s:5:"و ا";s:3:"216";s:6:"کرن";s:3:"217";s:5:"ں ہ";s:3:"218";s:6:"ھار";s:3:"219";s:6:"ہوئ";s:3:"220";s:5:"ہی ";s:3:"221";s:5:"یش ";s:3:"222";s:5:" ام";s:3:"223";s:5:" لا";s:3:"224";s:5:" مس";s:3:"225";s:5:" پو";s:3:"226";s:5:" پہ";s:3:"227";s:6:"انے";s:3:"228";s:5:"ت م";s:3:"229";s:5:"ت ہ";s:3:"230";s:5:"ج ک";s:3:"231";s:6:"دون";s:3:"232";s:6:"زیر";s:3:"233";s:5:"س س";s:3:"234";s:5:"ش ک";s:3:"235";s:5:"ف ن";s:3:"236";s:5:"ل ہ";s:3:"237";s:6:"لاق";s:3:"238";s:5:"لی ";s:3:"239";s:6:"وری";s:3:"240";s:6:"وزی";s:3:"241";s:6:"ونو";s:3:"242";s:6:"کھن";s:3:"243";s:5:"گا ";s:3:"244";s:5:"ں س";s:3:"245";s:5:"ں گ";s:3:"246";s:6:"ھنے";s:3:"247";s:5:"ھے ";s:3:"248";s:5:"ہ ب";s:3:"249";s:5:"ہ ج";s:3:"250";s:5:"ہر ";s:3:"251";s:5:"ی آ";s:3:"252";s:5:"ی پ";s:3:"253";s:5:" حا";s:3:"254";s:5:" وف";s:3:"255";s:5:" گا";s:3:"256";s:5:"ا ج";s:3:"257";s:5:"ا گ";s:3:"258";s:5:"اد ";s:3:"259";s:6:"ادی";s:3:"260";s:6:"اعظ";s:3:"261";s:6:"اہت";s:3:"262";s:5:"جس ";s:3:"263";s:6:"جمہ";s:3:"264";s:5:"جو ";s:3:"265";s:5:"ر س";s:3:"266";s:5:"ر ہ";s:3:"267";s:6:"رنے";s:3:"268";s:5:"س م";s:3:"269";s:5:"سا ";s:3:"270";s:6:"سند";s:3:"271";s:6:"سنگ";s:3:"272";s:5:"ظم ";s:3:"273";s:6:"عظم";s:3:"274";s:5:"ل م";s:3:"275";s:6:"لیے";s:3:"276";s:5:"مل ";s:3:"277";s:6:"موہ";s:3:"278";s:6:"مہو";s:3:"279";s:6:"نگھ";s:3:"280";s:5:"و ص";s:3:"281";s:6:"ورٹ";s:3:"282";s:6:"وہن";s:3:"283";s:5:"کن ";s:3:"284";s:5:"گھ ";s:3:"285";s:5:"گے ";s:3:"286";s:5:"ں ج";s:3:"287";s:5:"ں و";s:3:"288";s:5:"ں ی";s:3:"289";s:5:"ہ د";s:3:"290";s:5:"ہن ";s:3:"291";s:6:"ہوں";s:3:"292";s:5:"ے ح";s:3:"293";s:5:"ے گ";s:3:"294";s:5:"ے ی";s:3:"295";s:5:" اگ";s:3:"296";s:5:" بع";s:3:"297";s:5:" رو";s:3:"298";s:5:" شا";s:3:"299";}s:5:"uzbek";a:300:{s:5:"ан ";s:1:"0";s:6:"ган";s:1:"1";s:6:"лар";s:1:"2";s:5:"га ";s:1:"3";s:5:"нг ";s:1:"4";s:6:"инг";s:1:"5";s:6:"нин";s:1:"6";s:5:"да ";s:1:"7";s:5:"ни ";s:1:"8";s:6:"ида";s:1:"9";s:6:"ари";s:2:"10";s:6:"ига";s:2:"11";s:6:"ини";s:2:"12";s:5:"ар ";s:2:"13";s:5:"ди ";s:2:"14";s:5:" би";s:2:"15";s:6:"ани";s:2:"16";s:5:" бо";s:2:"17";s:6:"дан";s:2:"18";s:6:"лга";s:2:"19";s:5:" ҳа";s:2:"20";s:5:" ва";s:2:"21";s:5:" са";s:2:"22";s:5:"ги ";s:2:"23";s:6:"ила";s:2:"24";s:5:"н б";s:2:"25";s:5:"и б";s:2:"26";s:5:" кў";s:2:"27";s:5:" та";s:2:"28";s:5:"ир ";s:2:"29";s:5:" ма";s:2:"30";s:6:"ага";s:2:"31";s:6:"ала";s:2:"32";s:6:"бир";s:2:"33";s:5:"ри ";s:2:"34";s:6:"тга";s:2:"35";s:6:"лан";s:2:"36";s:6:"лик";s:2:"37";s:5:"а к";s:2:"38";s:6:"аги";s:2:"39";s:6:"ати";s:2:"40";s:5:"та ";s:2:"41";s:6:"ади";s:2:"42";s:6:"даг";s:2:"43";s:6:"рга";s:2:"44";s:5:" йи";s:2:"45";s:5:" ми";s:2:"46";s:5:" па";s:2:"47";s:5:" бў";s:2:"48";s:5:" қа";s:2:"49";s:5:" қи";s:2:"50";s:5:"а б";s:2:"51";s:6:"илл";s:2:"52";s:5:"ли ";s:2:"53";s:6:"аси";s:2:"54";s:5:"и т";s:2:"55";s:5:"ик ";s:2:"56";s:6:"или";s:2:"57";s:6:"лла";s:2:"58";s:6:"ард";s:2:"59";s:6:"вчи";s:2:"60";s:5:"ва ";s:2:"61";s:5:"иб ";s:2:"62";s:6:"ири";s:2:"63";s:6:"лиг";s:2:"64";s:6:"нга";s:2:"65";s:6:"ран";s:2:"66";s:5:" ке";s:2:"67";s:5:" ўз";s:2:"68";s:5:"а с";s:2:"69";s:6:"ахт";s:2:"70";s:6:"бўл";s:2:"71";s:6:"иги";s:2:"72";s:6:"кўр";s:2:"73";s:6:"рда";s:2:"74";s:6:"рни";s:2:"75";s:5:"са ";s:2:"76";s:5:" бе";s:2:"77";s:5:" бу";s:2:"78";s:5:" да";s:2:"79";s:5:" жа";s:2:"80";s:5:"а т";s:2:"81";s:6:"ази";s:2:"82";s:6:"ери";s:2:"83";s:5:"и а";s:2:"84";s:6:"илг";s:2:"85";s:6:"йил";s:2:"86";s:6:"ман";s:2:"87";s:6:"пах";s:2:"88";s:6:"рид";s:2:"89";s:5:"ти ";s:2:"90";s:6:"увч";s:2:"91";s:6:"хта";s:2:"92";s:5:" не";s:2:"93";s:5:" со";s:2:"94";s:5:" уч";s:2:"95";s:6:"айт";s:2:"96";s:6:"лли";s:2:"97";s:6:"тла";s:2:"98";s:5:" ай";s:2:"99";s:5:" фр";s:3:"100";s:5:" эт";s:3:"101";s:5:" ҳо";s:3:"102";s:5:"а қ";s:3:"103";s:6:"али";s:3:"104";s:6:"аро";s:3:"105";s:6:"бер";s:3:"106";s:6:"бил";s:3:"107";s:6:"бор";s:3:"108";s:6:"ими";s:3:"109";s:6:"ист";s:3:"110";s:5:"он ";s:3:"111";s:6:"рин";s:3:"112";s:6:"тер";s:3:"113";s:6:"тил";s:3:"114";s:5:"ун ";s:3:"115";s:6:"фра";s:3:"116";s:6:"қил";s:3:"117";s:5:" ба";s:3:"118";s:5:" ол";s:3:"119";s:6:"анс";s:3:"120";s:6:"ефт";s:3:"121";s:6:"зир";s:3:"122";s:6:"кат";s:3:"123";s:6:"мил";s:3:"124";s:6:"неф";s:3:"125";s:6:"саг";s:3:"126";s:5:"чи ";s:3:"127";s:6:"ўра";s:3:"128";s:5:" на";s:3:"129";s:5:" те";s:3:"130";s:5:" эн";s:3:"131";s:5:"а э";s:3:"132";s:5:"ам ";s:3:"133";s:6:"арн";s:3:"134";s:5:"ат ";s:3:"135";s:5:"иш ";s:3:"136";s:5:"ма ";s:3:"137";s:6:"нла";s:3:"138";s:6:"рли";s:3:"139";s:6:"чил";s:3:"140";s:6:"шга";s:3:"141";s:5:" иш";s:3:"142";s:5:" му";s:3:"143";s:5:" ўқ";s:3:"144";s:6:"ара";s:3:"145";s:6:"ваз";s:3:"146";s:5:"и у";s:3:"147";s:5:"иқ ";s:3:"148";s:6:"моқ";s:3:"149";s:6:"рим";s:3:"150";s:6:"учу";s:3:"151";s:6:"чун";s:3:"152";s:5:"ши ";s:3:"153";s:6:"энг";s:3:"154";s:6:"қув";s:3:"155";s:6:"ҳам";s:3:"156";s:5:" сў";s:3:"157";s:5:" ши";s:3:"158";s:6:"бар";s:3:"159";s:6:"бек";s:3:"160";s:6:"дам";s:3:"161";s:5:"и ҳ";s:3:"162";s:6:"иши";s:3:"163";s:6:"лад";s:3:"164";s:6:"оли";s:3:"165";s:6:"олл";s:3:"166";s:6:"ори";s:3:"167";s:6:"оқд";s:3:"168";s:5:"р б";s:3:"169";s:5:"ра ";s:3:"170";s:6:"рла";s:3:"171";s:6:"уни";s:3:"172";s:5:"фт ";s:3:"173";s:6:"ўлг";s:3:"174";s:6:"ўқу";s:3:"175";s:5:" де";s:3:"176";s:5:" ка";s:3:"177";s:5:" қў";s:3:"178";s:5:"а ў";s:3:"179";s:6:"аба";s:3:"180";s:6:"амм";s:3:"181";s:6:"атл";s:3:"182";s:5:"б к";s:3:"183";s:6:"бош";s:3:"184";s:6:"збе";s:3:"185";s:5:"и в";s:3:"186";s:5:"им ";s:3:"187";s:5:"ин ";s:3:"188";s:6:"ишл";s:3:"189";s:6:"лаб";s:3:"190";s:6:"лей";s:3:"191";s:6:"мин";s:3:"192";s:5:"н д";s:3:"193";s:6:"нда";s:3:"194";s:5:"оқ ";s:3:"195";s:5:"р м";s:3:"196";s:6:"рил";s:3:"197";s:6:"сид";s:3:"198";s:6:"тал";s:3:"199";s:6:"тан";s:3:"200";s:6:"тид";s:3:"201";s:6:"тон";s:3:"202";s:6:"ўзб";s:3:"203";s:5:" ам";s:3:"204";s:5:" ки";s:3:"205";s:5:"а ҳ";s:3:"206";s:6:"анг";s:3:"207";s:6:"анд";s:3:"208";s:6:"арт";s:3:"209";s:6:"аёт";s:3:"210";s:6:"дир";s:3:"211";s:6:"ент";s:3:"212";s:5:"и д";s:3:"213";s:5:"и м";s:3:"214";s:5:"и о";s:3:"215";s:5:"и э";s:3:"216";s:6:"иро";s:3:"217";s:6:"йти";s:3:"218";s:6:"нсу";s:3:"219";s:6:"оди";s:3:"220";s:5:"ор ";s:3:"221";s:5:"си ";s:3:"222";s:6:"тиш";s:3:"223";s:6:"тоб";s:3:"224";s:6:"эти";s:3:"225";s:6:"қар";s:3:"226";s:6:"қда";s:3:"227";s:5:" бл";s:3:"228";s:5:" ге";s:3:"229";s:5:" до";s:3:"230";s:5:" ду";s:3:"231";s:5:" но";s:3:"232";s:5:" пр";s:3:"233";s:5:" ра";s:3:"234";s:5:" фо";s:3:"235";s:5:" қо";s:3:"236";s:5:"а м";s:3:"237";s:5:"а о";s:3:"238";s:6:"айд";s:3:"239";s:6:"ало";s:3:"240";s:6:"ама";s:3:"241";s:6:"бле";s:3:"242";s:5:"г н";s:3:"243";s:6:"дол";s:3:"244";s:6:"ейр";s:3:"245";s:5:"ек ";s:3:"246";s:6:"ерг";s:3:"247";s:6:"жар";s:3:"248";s:6:"зид";s:3:"249";s:5:"и к";s:3:"250";s:5:"и ф";s:3:"251";s:5:"ий ";s:3:"252";s:6:"ило";s:3:"253";s:6:"лди";s:3:"254";s:6:"либ";s:3:"255";s:6:"лин";s:3:"256";s:5:"ми ";s:3:"257";s:6:"мма";s:3:"258";s:5:"н в";s:3:"259";s:5:"н к";s:3:"260";s:5:"н ў";s:3:"261";s:5:"н ҳ";s:3:"262";s:6:"ози";s:3:"263";s:6:"ора";s:3:"264";s:6:"оси";s:3:"265";s:6:"рас";s:3:"266";s:6:"риш";s:3:"267";s:6:"рка";s:3:"268";s:6:"роқ";s:3:"269";s:6:"сто";s:3:"270";s:6:"тин";s:3:"271";s:6:"хат";s:3:"272";s:6:"шир";s:3:"273";s:5:" ав";s:3:"274";s:5:" рў";s:3:"275";s:5:" ту";s:3:"276";s:5:" ўт";s:3:"277";s:5:"а п";s:3:"278";s:6:"авт";s:3:"279";s:6:"ада";s:3:"280";s:6:"аза";s:3:"281";s:6:"анл";s:3:"282";s:5:"б б";s:3:"283";s:6:"бой";s:3:"284";s:5:"бу ";s:3:"285";s:6:"вто";s:3:"286";s:5:"г э";s:3:"287";s:6:"гин";s:3:"288";s:6:"дар";s:3:"289";s:6:"ден";s:3:"290";s:6:"дун";s:3:"291";s:6:"иде";s:3:"292";s:6:"ион";s:3:"293";s:6:"ирл";s:3:"294";s:6:"ишг";s:3:"295";s:6:"йха";s:3:"296";s:6:"кел";s:3:"297";s:6:"кўп";s:3:"298";s:6:"лио";s:3:"299";}s:10:"vietnamese";a:300:{s:3:"ng ";s:1:"0";s:3:" th";s:1:"1";s:3:" ch";s:1:"2";s:3:"g t";s:1:"3";s:3:" nh";s:1:"4";s:4:"ông";s:1:"5";s:3:" kh";s:1:"6";s:3:" tr";s:1:"7";s:3:"nh ";s:1:"8";s:4:" cô";s:1:"9";s:4:"côn";s:2:"10";s:3:" ty";s:2:"11";s:3:"ty ";s:2:"12";s:3:"i t";s:2:"13";s:3:"n t";s:2:"14";s:3:" ng";s:2:"15";s:5:"ại ";s:2:"16";s:3:" ti";s:2:"17";s:3:"ch ";s:2:"18";s:3:"y l";s:2:"19";s:5:"ền ";s:2:"20";s:5:" đư";s:2:"21";s:3:"hi ";s:2:"22";s:5:" gở";s:2:"23";s:5:"gởi";s:2:"24";s:5:"iền";s:2:"25";s:5:"tiề";s:2:"26";s:5:"ởi ";s:2:"27";s:3:" gi";s:2:"28";s:3:" le";s:2:"29";s:3:" vi";s:2:"30";s:3:"cho";s:2:"31";s:3:"ho ";s:2:"32";s:4:"khá";s:2:"33";s:4:" và";s:2:"34";s:4:"hác";s:2:"35";s:3:" ph";s:2:"36";s:3:"am ";s:2:"37";s:4:"hàn";s:2:"38";s:4:"ách";s:2:"39";s:4:"ôi ";s:2:"40";s:3:"i n";s:2:"41";s:6:"ược";s:2:"42";s:5:"ợc ";s:2:"43";s:4:" tô";s:2:"44";s:4:"chú";s:2:"45";s:5:"iệt";s:2:"46";s:4:"tôi";s:2:"47";s:4:"ên ";s:2:"48";s:4:"úng";s:2:"49";s:5:"ệt ";s:2:"50";s:4:" có";s:2:"51";s:3:"c t";s:2:"52";s:4:"có ";s:2:"53";s:4:"hún";s:2:"54";s:5:"việ";s:2:"55";s:7:"đượ";s:2:"56";s:3:" na";s:2:"57";s:3:"g c";s:2:"58";s:3:"i c";s:2:"59";s:3:"n c";s:2:"60";s:3:"n n";s:2:"61";s:3:"t n";s:2:"62";s:4:"và ";s:2:"63";s:3:"n l";s:2:"64";s:4:"n đ";s:2:"65";s:4:"àng";s:2:"66";s:4:"ác ";s:2:"67";s:5:"ất ";s:2:"68";s:3:"h l";s:2:"69";s:3:"nam";s:2:"70";s:4:"ân ";s:2:"71";s:4:"ăm ";s:2:"72";s:4:" hà";s:2:"73";s:4:" là";s:2:"74";s:4:" nă";s:2:"75";s:3:" qu";s:2:"76";s:5:" tạ";s:2:"77";s:3:"g m";s:2:"78";s:4:"năm";s:2:"79";s:5:"tại";s:2:"80";s:5:"ới ";s:2:"81";s:5:" lẹ";s:2:"82";s:3:"ay ";s:2:"83";s:3:"e g";s:2:"84";s:3:"h h";s:2:"85";s:3:"i v";s:2:"86";s:4:"i đ";s:2:"87";s:3:"le ";s:2:"88";s:5:"lẹ ";s:2:"89";s:5:"ều ";s:2:"90";s:5:"ời ";s:2:"91";s:4:"hân";s:2:"92";s:3:"nhi";s:2:"93";s:3:"t t";s:2:"94";s:5:" củ";s:2:"95";s:5:" mộ";s:2:"96";s:5:" về";s:2:"97";s:4:" đi";s:2:"98";s:3:"an ";s:2:"99";s:5:"của";s:3:"100";s:4:"là ";s:3:"101";s:5:"một";s:3:"102";s:5:"về ";s:3:"103";s:4:"ành";s:3:"104";s:5:"ết ";s:3:"105";s:5:"ột ";s:3:"106";s:5:"ủa ";s:3:"107";s:3:" bi";s:3:"108";s:4:" cá";s:3:"109";s:3:"a c";s:3:"110";s:3:"anh";s:3:"111";s:4:"các";s:3:"112";s:3:"h c";s:3:"113";s:5:"iều";s:3:"114";s:3:"m t";s:3:"115";s:5:"ện ";s:3:"116";s:3:" ho";s:3:"117";s:3:"'s ";s:3:"118";s:3:"ave";s:3:"119";s:3:"e's";s:3:"120";s:3:"el ";s:3:"121";s:3:"g n";s:3:"122";s:3:"le'";s:3:"123";s:3:"n v";s:3:"124";s:3:"o c";s:3:"125";s:3:"rav";s:3:"126";s:3:"s t";s:3:"127";s:3:"thi";s:3:"128";s:3:"tra";s:3:"129";s:3:"vel";s:3:"130";s:5:"ận ";s:3:"131";s:5:"ến ";s:3:"132";s:3:" ba";s:3:"133";s:3:" cu";s:3:"134";s:3:" sa";s:3:"135";s:5:" đó";s:3:"136";s:6:" đế";s:3:"137";s:3:"c c";s:3:"138";s:3:"chu";s:3:"139";s:5:"hiề";s:3:"140";s:3:"huy";s:3:"141";s:3:"khi";s:3:"142";s:4:"nhâ";s:3:"143";s:4:"như";s:3:"144";s:3:"ong";s:3:"145";s:3:"ron";s:3:"146";s:3:"thu";s:3:"147";s:4:"thư";s:3:"148";s:3:"tro";s:3:"149";s:3:"y c";s:3:"150";s:4:"ày ";s:3:"151";s:6:"đến";s:3:"152";s:6:"ười";s:3:"153";s:6:"ườn";s:3:"154";s:5:"ề v";s:3:"155";s:5:"ờng";s:3:"156";s:5:" vớ";s:3:"157";s:5:"cuộ";s:3:"158";s:4:"g đ";s:3:"159";s:5:"iết";s:3:"160";s:5:"iện";s:3:"161";s:4:"ngà";s:3:"162";s:3:"o t";s:3:"163";s:3:"u c";s:3:"164";s:5:"uộc";s:3:"165";s:5:"với";s:3:"166";s:4:"à c";s:3:"167";s:4:"ài ";s:3:"168";s:4:"ơng";s:3:"169";s:5:"ươn";s:3:"170";s:5:"ải ";s:3:"171";s:5:"ộc ";s:3:"172";s:5:"ức ";s:3:"173";s:3:" an";s:3:"174";s:5:" lậ";s:3:"175";s:3:" ra";s:3:"176";s:5:" sẽ";s:3:"177";s:5:" số";s:3:"178";s:5:" tổ";s:3:"179";s:3:"a k";s:3:"180";s:5:"biế";s:3:"181";s:3:"c n";s:3:"182";s:4:"c đ";s:3:"183";s:5:"chứ";s:3:"184";s:3:"g v";s:3:"185";s:3:"gia";s:3:"186";s:4:"gày";s:3:"187";s:4:"hán";s:3:"188";s:4:"hôn";s:3:"189";s:4:"hư ";s:3:"190";s:5:"hức";s:3:"191";s:3:"i g";s:3:"192";s:3:"i h";s:3:"193";s:3:"i k";s:3:"194";s:3:"i p";s:3:"195";s:4:"iên";s:3:"196";s:4:"khô";s:3:"197";s:5:"lập";s:3:"198";s:3:"n k";s:3:"199";s:3:"ra ";s:3:"200";s:4:"rên";s:3:"201";s:5:"sẽ ";s:3:"202";s:3:"t c";s:3:"203";s:4:"thà";s:3:"204";s:4:"trê";s:3:"205";s:5:"tổ ";s:3:"206";s:3:"u n";s:3:"207";s:3:"y t";s:3:"208";s:4:"ình";s:3:"209";s:5:"ấy ";s:3:"210";s:5:"ập ";s:3:"211";s:5:"ổ c";s:3:"212";s:4:" má";s:3:"213";s:6:" để";s:3:"214";s:3:"ai ";s:3:"215";s:3:"c s";s:3:"216";s:6:"gườ";s:3:"217";s:3:"h v";s:3:"218";s:3:"hoa";s:3:"219";s:5:"hoạ";s:3:"220";s:3:"inh";s:3:"221";s:3:"m n";s:3:"222";s:4:"máy";s:3:"223";s:3:"n g";s:3:"224";s:4:"ngư";s:3:"225";s:5:"nhậ";s:3:"226";s:3:"o n";s:3:"227";s:3:"oa ";s:3:"228";s:4:"oàn";s:3:"229";s:3:"p c";s:3:"230";s:5:"số ";s:3:"231";s:4:"t đ";s:3:"232";s:3:"y v";s:3:"233";s:4:"ào ";s:3:"234";s:4:"áy ";s:3:"235";s:4:"ăn ";s:3:"236";s:5:"đó ";s:3:"237";s:6:"để ";s:3:"238";s:6:"ước";s:3:"239";s:5:"ần ";s:3:"240";s:5:"ển ";s:3:"241";s:5:"ớc ";s:3:"242";s:4:" bá";s:3:"243";s:4:" cơ";s:3:"244";s:5:" cả";s:3:"245";s:5:" cầ";s:3:"246";s:5:" họ";s:3:"247";s:5:" kỳ";s:3:"248";s:3:" li";s:3:"249";s:5:" mạ";s:3:"250";s:5:" sở";s:3:"251";s:5:" tặ";s:3:"252";s:4:" vé";s:3:"253";s:5:" vụ";s:3:"254";s:6:" đạ";s:3:"255";s:4:"a đ";s:3:"256";s:3:"bay";s:3:"257";s:4:"cơ ";s:3:"258";s:3:"g s";s:3:"259";s:3:"han";s:3:"260";s:5:"hươ";s:3:"261";s:3:"i s";s:3:"262";s:5:"kỳ ";s:3:"263";s:3:"m c";s:3:"264";s:3:"n m";s:3:"265";s:3:"n p";s:3:"266";s:3:"o b";s:3:"267";s:5:"oại";s:3:"268";s:3:"qua";s:3:"269";s:5:"sở ";s:3:"270";s:3:"tha";s:3:"271";s:4:"thá";s:3:"272";s:5:"tặn";s:3:"273";s:4:"vào";s:3:"274";s:4:"vé ";s:3:"275";s:5:"vụ ";s:3:"276";s:3:"y b";s:3:"277";s:4:"àn ";s:3:"278";s:4:"áng";s:3:"279";s:4:"ơ s";s:3:"280";s:5:"ầu ";s:3:"281";s:5:"ật ";s:3:"282";s:5:"ặng";s:3:"283";s:5:"ọc ";s:3:"284";s:5:"ở t";s:3:"285";s:5:"ững";s:3:"286";s:3:" du";s:3:"287";s:3:" lu";s:3:"288";s:3:" ta";s:3:"289";s:3:" to";s:3:"290";s:5:" từ";s:3:"291";s:5:" ở ";s:3:"292";s:3:"a v";s:3:"293";s:3:"ao ";s:3:"294";s:3:"c v";s:3:"295";s:5:"cả ";s:3:"296";s:3:"du ";s:3:"297";s:3:"g l";s:3:"298";s:5:"giả";s:3:"299";}s:5:"welsh";a:300:{s:3:"yn ";s:1:"0";s:3:"dd ";s:1:"1";s:3:" yn";s:1:"2";s:3:" y ";s:1:"3";s:3:"ydd";s:1:"4";s:3:"eth";s:1:"5";s:3:"th ";s:1:"6";s:3:" i ";s:1:"7";s:3:"aet";s:1:"8";s:3:"d y";s:1:"9";s:3:"ch ";s:2:"10";s:3:"od ";s:2:"11";s:3:"ol ";s:2:"12";s:3:"edd";s:2:"13";s:3:" ga";s:2:"14";s:3:" gw";s:2:"15";s:3:"'r ";s:2:"16";s:3:"au ";s:2:"17";s:3:"ddi";s:2:"18";s:3:"ad ";s:2:"19";s:3:" cy";s:2:"20";s:3:" gy";s:2:"21";s:3:" ei";s:2:"22";s:3:" o ";s:2:"23";s:3:"iad";s:2:"24";s:3:"yr ";s:2:"25";s:3:"an ";s:2:"26";s:3:"bod";s:2:"27";s:3:"wed";s:2:"28";s:3:" bo";s:2:"29";s:3:" dd";s:2:"30";s:3:"el ";s:2:"31";s:3:"n y";s:2:"32";s:3:" am";s:2:"33";s:3:"di ";s:2:"34";s:3:"edi";s:2:"35";s:3:"on ";s:2:"36";s:3:" we";s:2:"37";s:3:" ym";s:2:"38";s:3:" ar";s:2:"39";s:3:" rh";s:2:"40";s:3:"odd";s:2:"41";s:3:" ca";s:2:"42";s:3:" ma";s:2:"43";s:3:"ael";s:2:"44";s:3:"oed";s:2:"45";s:3:"dae";s:2:"46";s:3:"n a";s:2:"47";s:3:"dda";s:2:"48";s:3:"er ";s:2:"49";s:3:"h y";s:2:"50";s:3:"all";s:2:"51";s:3:"ei ";s:2:"52";s:3:" ll";s:2:"53";s:3:"am ";s:2:"54";s:3:"eu ";s:2:"55";s:3:"fod";s:2:"56";s:3:"fyd";s:2:"57";s:3:"l y";s:2:"58";s:3:"n g";s:2:"59";s:3:"wyn";s:2:"60";s:3:"d a";s:2:"61";s:3:"i g";s:2:"62";s:3:"mae";s:2:"63";s:3:"neu";s:2:"64";s:3:"os ";s:2:"65";s:3:" ne";s:2:"66";s:3:"d i";s:2:"67";s:3:"dod";s:2:"68";s:3:"dol";s:2:"69";s:3:"n c";s:2:"70";s:3:"r h";s:2:"71";s:3:"wyd";s:2:"72";s:3:"wyr";s:2:"73";s:3:"ai ";s:2:"74";s:3:"ar ";s:2:"75";s:3:"in ";s:2:"76";s:3:"rth";s:2:"77";s:3:" fy";s:2:"78";s:3:" he";s:2:"79";s:3:" me";s:2:"80";s:3:" yr";s:2:"81";s:3:"'n ";s:2:"82";s:3:"dia";s:2:"83";s:3:"est";s:2:"84";s:3:"h c";s:2:"85";s:3:"hai";s:2:"86";s:3:"i d";s:2:"87";s:3:"id ";s:2:"88";s:3:"r y";s:2:"89";s:3:"y b";s:2:"90";s:3:" dy";s:2:"91";s:3:" ha";s:2:"92";s:3:"ada";s:2:"93";s:3:"i b";s:2:"94";s:3:"n i";s:2:"95";s:3:"ote";s:2:"96";s:3:"rot";s:2:"97";s:3:"tes";s:2:"98";s:3:"y g";s:2:"99";s:3:"yd ";s:3:"100";s:3:" ad";s:3:"101";s:3:" mr";s:3:"102";s:3:" un";s:3:"103";s:3:"cyn";s:3:"104";s:3:"dau";s:3:"105";s:3:"ddy";s:3:"106";s:3:"edo";s:3:"107";s:3:"i c";s:3:"108";s:3:"i w";s:3:"109";s:3:"ith";s:3:"110";s:3:"lae";s:3:"111";s:3:"lla";s:3:"112";s:3:"nd ";s:3:"113";s:3:"oda";s:3:"114";s:3:"ryd";s:3:"115";s:3:"tho";s:3:"116";s:3:" a ";s:3:"117";s:3:" dr";s:3:"118";s:3:"aid";s:3:"119";s:3:"ain";s:3:"120";s:3:"ddo";s:3:"121";s:3:"dyd";s:3:"122";s:3:"fyn";s:3:"123";s:3:"gyn";s:3:"124";s:3:"hol";s:3:"125";s:3:"io ";s:3:"126";s:3:"o a";s:3:"127";s:3:"wch";s:3:"128";s:3:"wyb";s:3:"129";s:3:"ybo";s:3:"130";s:3:"ych";s:3:"131";s:3:" br";s:3:"132";s:3:" by";s:3:"133";s:3:" di";s:3:"134";s:3:" fe";s:3:"135";s:3:" na";s:3:"136";s:3:" o'";s:3:"137";s:3:" pe";s:3:"138";s:3:"art";s:3:"139";s:3:"byd";s:3:"140";s:3:"dro";s:3:"141";s:3:"gal";s:3:"142";s:3:"l e";s:3:"143";s:3:"lai";s:3:"144";s:3:"mr ";s:3:"145";s:3:"n n";s:3:"146";s:3:"r a";s:3:"147";s:3:"rhy";s:3:"148";s:3:"wn ";s:3:"149";s:3:"ynn";s:3:"150";s:3:" on";s:3:"151";s:3:" r ";s:3:"152";s:3:"cae";s:3:"153";s:3:"d g";s:3:"154";s:3:"d o";s:3:"155";s:3:"d w";s:3:"156";s:3:"gan";s:3:"157";s:3:"gwy";s:3:"158";s:3:"n d";s:3:"159";s:3:"n f";s:3:"160";s:3:"n o";s:3:"161";s:3:"ned";s:3:"162";s:3:"ni ";s:3:"163";s:3:"o'r";s:3:"164";s:3:"r d";s:3:"165";s:3:"ud ";s:3:"166";s:3:"wei";s:3:"167";s:3:"wrt";s:3:"168";s:3:" an";s:3:"169";s:3:" cw";s:3:"170";s:3:" da";s:3:"171";s:3:" ni";s:3:"172";s:3:" pa";s:3:"173";s:3:" pr";s:3:"174";s:3:" wy";s:3:"175";s:3:"d e";s:3:"176";s:3:"dai";s:3:"177";s:3:"dim";s:3:"178";s:3:"eud";s:3:"179";s:3:"gwa";s:3:"180";s:3:"idd";s:3:"181";s:3:"im ";s:3:"182";s:3:"iri";s:3:"183";s:3:"lwy";s:3:"184";s:3:"n b";s:3:"185";s:3:"nol";s:3:"186";s:3:"r o";s:3:"187";s:3:"rwy";s:3:"188";s:3:" ch";s:3:"189";s:3:" er";s:3:"190";s:3:" fo";s:3:"191";s:3:" ge";s:3:"192";s:3:" hy";s:3:"193";s:3:" i'";s:3:"194";s:3:" ro";s:3:"195";s:3:" sa";s:3:"196";s:3:" tr";s:3:"197";s:3:"bob";s:3:"198";s:3:"cwy";s:3:"199";s:3:"cyf";s:3:"200";s:3:"dio";s:3:"201";s:3:"dyn";s:3:"202";s:3:"eit";s:3:"203";s:3:"hel";s:3:"204";s:3:"hyn";s:3:"205";s:3:"ich";s:3:"206";s:3:"ll ";s:3:"207";s:3:"mdd";s:3:"208";s:3:"n r";s:3:"209";s:3:"ond";s:3:"210";s:3:"pro";s:3:"211";s:3:"r c";s:3:"212";s:3:"r g";s:3:"213";s:3:"red";s:3:"214";s:3:"rha";s:3:"215";s:3:"u a";s:3:"216";s:3:"u c";s:3:"217";s:3:"u y";s:3:"218";s:3:"y c";s:3:"219";s:3:"ymd";s:3:"220";s:3:"ymr";s:3:"221";s:3:"yw ";s:3:"222";s:3:" ac";s:3:"223";s:3:" be";s:3:"224";s:3:" bl";s:3:"225";s:3:" co";s:3:"226";s:3:" os";s:3:"227";s:3:"adw";s:3:"228";s:3:"ae ";s:3:"229";s:3:"af ";s:3:"230";s:3:"d p";s:3:"231";s:3:"efn";s:3:"232";s:3:"eic";s:3:"233";s:3:"en ";s:3:"234";s:3:"eol";s:3:"235";s:3:"es ";s:3:"236";s:3:"fer";s:3:"237";s:3:"gel";s:3:"238";s:3:"h g";s:3:"239";s:3:"hod";s:3:"240";s:3:"ied";s:3:"241";s:3:"ir ";s:3:"242";s:3:"laf";s:3:"243";s:3:"n h";s:3:"244";s:3:"na ";s:3:"245";s:3:"nyd";s:3:"246";s:3:"odo";s:3:"247";s:3:"ofy";s:3:"248";s:3:"rdd";s:3:"249";s:3:"rie";s:3:"250";s:3:"ros";s:3:"251";s:3:"stw";s:3:"252";s:3:"twy";s:3:"253";s:3:"yda";s:3:"254";s:3:"yng";s:3:"255";s:3:" at";s:3:"256";s:3:" de";s:3:"257";s:3:" go";s:3:"258";s:3:" id";s:3:"259";s:3:" oe";s:3:"260";s:4:" â ";s:3:"261";s:3:"'ch";s:3:"262";s:3:"ac ";s:3:"263";s:3:"ach";s:3:"264";s:3:"ae'";s:3:"265";s:3:"al ";s:3:"266";s:3:"bl ";s:3:"267";s:3:"d c";s:3:"268";s:3:"d l";s:3:"269";s:3:"dan";s:3:"270";s:3:"dde";s:3:"271";s:3:"ddw";s:3:"272";s:3:"dir";s:3:"273";s:3:"dla";s:3:"274";s:3:"ed ";s:3:"275";s:3:"ela";s:3:"276";s:3:"ell";s:3:"277";s:3:"ene";s:3:"278";s:3:"ewn";s:3:"279";s:3:"gyd";s:3:"280";s:3:"hau";s:3:"281";s:3:"hyw";s:3:"282";s:3:"i a";s:3:"283";s:3:"i f";s:3:"284";s:3:"iol";s:3:"285";s:3:"ion";s:3:"286";s:3:"l a";s:3:"287";s:3:"l i";s:3:"288";s:3:"lia";s:3:"289";s:3:"med";s:3:"290";s:3:"mon";s:3:"291";s:3:"n s";s:3:"292";s:3:"no ";s:3:"293";s:3:"obl";s:3:"294";s:3:"ola";s:3:"295";s:3:"ref";s:3:"296";s:3:"rn ";s:3:"297";s:3:"thi";s:3:"298";s:3:"un ";s:3:"299";}}s:18:"trigram-unicodemap";a:13:{s:11:"Basic Latin";a:38:{s:8:"albanian";i:661;s:5:"azeri";i:653;s:7:"bengali";i:1;s:7:"cebuano";i:750;s:8:"croatian";i:733;s:5:"czech";i:652;s:6:"danish";i:734;s:5:"dutch";i:741;s:7:"english";i:723;s:8:"estonian";i:739;s:7:"finnish";i:743;s:6:"french";i:733;s:6:"german";i:750;s:5:"hausa";i:752;s:8:"hawaiian";i:751;s:9:"hungarian";i:693;s:9:"icelandic";i:662;s:10:"indonesian";i:776;s:7:"italian";i:741;s:5:"latin";i:764;s:7:"latvian";i:693;s:10:"lithuanian";i:738;s:9:"mongolian";i:19;s:9:"norwegian";i:742;s:6:"pidgin";i:702;s:6:"polish";i:701;s:10:"portuguese";i:726;s:8:"romanian";i:714;s:6:"slovak";i:677;s:7:"slovene";i:740;s:6:"somali";i:755;s:7:"spanish";i:749;s:7:"swahili";i:770;s:7:"swedish";i:717;s:7:"tagalog";i:767;s:7:"turkish";i:673;s:10:"vietnamese";i:503;s:5:"welsh";i:728;}s:18:"Latin-1 Supplement";a:21:{s:8:"albanian";i:68;s:5:"azeri";i:10;s:5:"czech";i:51;s:6:"danish";i:13;s:8:"estonian";i:19;s:7:"finnish";i:39;s:6:"french";i:21;s:6:"german";i:8;s:9:"hungarian";i:72;s:9:"icelandic";i:80;s:7:"italian";i:3;s:9:"norwegian";i:5;s:6:"polish";i:6;s:10:"portuguese";i:18;s:8:"romanian";i:9;s:6:"slovak";i:37;s:7:"spanish";i:6;s:7:"swedish";i:26;s:7:"turkish";i:25;s:10:"vietnamese";i:56;s:5:"welsh";i:1;}s:14:"[Malformatted]";a:42:{s:8:"albanian";i:68;s:6:"arabic";i:724;s:5:"azeri";i:109;s:7:"bengali";i:1472;s:9:"bulgarian";i:750;s:8:"croatian";i:10;s:5:"czech";i:78;s:6:"danish";i:13;s:8:"estonian";i:19;s:5:"farsi";i:706;s:7:"finnish";i:39;s:6:"french";i:21;s:6:"german";i:8;s:5:"hausa";i:8;s:5:"hindi";i:1386;s:9:"hungarian";i:74;s:9:"icelandic";i:80;s:7:"italian";i:3;s:6:"kazakh";i:767;s:6:"kyrgyz";i:767;s:7:"latvian";i:56;s:10:"lithuanian";i:30;s:10:"macedonian";i:755;s:9:"mongolian";i:743;s:6:"nepali";i:1514;s:9:"norwegian";i:5;s:6:"pashto";i:677;s:6:"polish";i:45;s:10:"portuguese";i:18;s:8:"romanian";i:31;s:7:"russian";i:759;s:7:"serbian";i:757;s:6:"slovak";i:45;s:7:"slovene";i:10;s:7:"spanish";i:6;s:7:"swedish";i:26;s:7:"turkish";i:87;s:9:"ukrainian";i:748;s:4:"urdu";i:682;s:5:"uzbek";i:773;s:10:"vietnamese";i:289;s:5:"welsh";i:1;}s:6:"Arabic";a:4:{s:6:"arabic";i:724;s:5:"farsi";i:706;s:6:"pashto";i:677;s:4:"urdu";i:682;}s:16:"Latin Extended-B";a:3:{s:5:"azeri";i:73;s:5:"hausa";i:8;s:10:"vietnamese";i:19;}s:16:"Latin Extended-A";a:12:{s:5:"azeri";i:25;s:8:"croatian";i:10;s:5:"czech";i:27;s:9:"hungarian";i:2;s:7:"latvian";i:56;s:10:"lithuanian";i:30;s:6:"polish";i:39;s:8:"romanian";i:22;s:6:"slovak";i:8;s:7:"slovene";i:10;s:7:"turkish";i:62;s:10:"vietnamese";i:20;}s:27:"Combining Diacritical Marks";a:1:{s:5:"azeri";i:1;}s:7:"Bengali";a:1:{s:7:"bengali";i:714;}s:8:"Gujarati";a:1:{s:7:"bengali";i:16;}s:8:"Gurmukhi";a:1:{s:7:"bengali";i:6;}s:8:"Cyrillic";a:9:{s:9:"bulgarian";i:750;s:6:"kazakh";i:767;s:6:"kyrgyz";i:767;s:10:"macedonian";i:755;s:9:"mongolian";i:743;s:7:"russian";i:759;s:7:"serbian";i:757;s:9:"ukrainian";i:748;s:5:"uzbek";i:773;}s:10:"Devanagari";a:2:{s:5:"hindi";i:693;s:6:"nepali";i:757;}s:25:"Latin Extended Additional";a:1:{s:10:"vietnamese";i:97;}}} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/language-detect/unicode_blocks.dat b/inc/3rdparty/libraries/language-detect/unicode_blocks.dat
new file mode 100644
index 00000000..3b24cd2c
--- /dev/null
+++ b/inc/3rdparty/libraries/language-detect/unicode_blocks.dat
@@ -0,0 +1 @@
a:145:{i:0;a:3:{i:0;s:6:"0x0000";i:1;s:6:"0x007F";i:2;s:11:"Basic Latin";}i:1;a:3:{i:0;s:6:"0x0080";i:1;s:6:"0x00FF";i:2;s:18:"Latin-1 Supplement";}i:2;a:3:{i:0;s:6:"0x0100";i:1;s:6:"0x017F";i:2;s:16:"Latin Extended-A";}i:3;a:3:{i:0;s:6:"0x0180";i:1;s:6:"0x024F";i:2;s:16:"Latin Extended-B";}i:4;a:3:{i:0;s:6:"0x0250";i:1;s:6:"0x02AF";i:2;s:14:"IPA Extensions";}i:5;a:3:{i:0;s:6:"0x02B0";i:1;s:6:"0x02FF";i:2;s:24:"Spacing Modifier Letters";}i:6;a:3:{i:0;s:6:"0x0300";i:1;s:6:"0x036F";i:2;s:27:"Combining Diacritical Marks";}i:7;a:3:{i:0;s:6:"0x0370";i:1;s:6:"0x03FF";i:2;s:16:"Greek and Coptic";}i:8;a:3:{i:0;s:6:"0x0400";i:1;s:6:"0x04FF";i:2;s:8:"Cyrillic";}i:9;a:3:{i:0;s:6:"0x0500";i:1;s:6:"0x052F";i:2;s:19:"Cyrillic Supplement";}i:10;a:3:{i:0;s:6:"0x0530";i:1;s:6:"0x058F";i:2;s:8:"Armenian";}i:11;a:3:{i:0;s:6:"0x0590";i:1;s:6:"0x05FF";i:2;s:6:"Hebrew";}i:12;a:3:{i:0;s:6:"0x0600";i:1;s:6:"0x06FF";i:2;s:6:"Arabic";}i:13;a:3:{i:0;s:6:"0x0700";i:1;s:6:"0x074F";i:2;s:6:"Syriac";}i:14;a:3:{i:0;s:6:"0x0750";i:1;s:6:"0x077F";i:2;s:17:"Arabic Supplement";}i:15;a:3:{i:0;s:6:"0x0780";i:1;s:6:"0x07BF";i:2;s:6:"Thaana";}i:16;a:3:{i:0;s:6:"0x0900";i:1;s:6:"0x097F";i:2;s:10:"Devanagari";}i:17;a:3:{i:0;s:6:"0x0980";i:1;s:6:"0x09FF";i:2;s:7:"Bengali";}i:18;a:3:{i:0;s:6:"0x0A00";i:1;s:6:"0x0A7F";i:2;s:8:"Gurmukhi";}i:19;a:3:{i:0;s:6:"0x0A80";i:1;s:6:"0x0AFF";i:2;s:8:"Gujarati";}i:20;a:3:{i:0;s:6:"0x0B00";i:1;s:6:"0x0B7F";i:2;s:5:"Oriya";}i:21;a:3:{i:0;s:6:"0x0B80";i:1;s:6:"0x0BFF";i:2;s:5:"Tamil";}i:22;a:3:{i:0;s:6:"0x0C00";i:1;s:6:"0x0C7F";i:2;s:6:"Telugu";}i:23;a:3:{i:0;s:6:"0x0C80";i:1;s:6:"0x0CFF";i:2;s:7:"Kannada";}i:24;a:3:{i:0;s:6:"0x0D00";i:1;s:6:"0x0D7F";i:2;s:9:"Malayalam";}i:25;a:3:{i:0;s:6:"0x0D80";i:1;s:6:"0x0DFF";i:2;s:7:"Sinhala";}i:26;a:3:{i:0;s:6:"0x0E00";i:1;s:6:"0x0E7F";i:2;s:4:"Thai";}i:27;a:3:{i:0;s:6:"0x0E80";i:1;s:6:"0x0EFF";i:2;s:3:"Lao";}i:28;a:3:{i:0;s:6:"0x0F00";i:1;s:6:"0x0FFF";i:2;s:7:"Tibetan";}i:29;a:3:{i:0;s:6:"0x1000";i:1;s:6:"0x109F";i:2;s:7:"Myanmar";}i:30;a:3:{i:0;s:6:"0x10A0";i:1;s:6:"0x10FF";i:2;s:8:"Georgian";}i:31;a:3:{i:0;s:6:"0x1100";i:1;s:6:"0x11FF";i:2;s:11:"Hangul Jamo";}i:32;a:3:{i:0;s:6:"0x1200";i:1;s:6:"0x137F";i:2;s:8:"Ethiopic";}i:33;a:3:{i:0;s:6:"0x1380";i:1;s:6:"0x139F";i:2;s:19:"Ethiopic Supplement";}i:34;a:3:{i:0;s:6:"0x13A0";i:1;s:6:"0x13FF";i:2;s:8:"Cherokee";}i:35;a:3:{i:0;s:6:"0x1400";i:1;s:6:"0x167F";i:2;s:37:"Unified Canadian Aboriginal Syllabics";}i:36;a:3:{i:0;s:6:"0x1680";i:1;s:6:"0x169F";i:2;s:5:"Ogham";}i:37;a:3:{i:0;s:6:"0x16A0";i:1;s:6:"0x16FF";i:2;s:5:"Runic";}i:38;a:3:{i:0;s:6:"0x1700";i:1;s:6:"0x171F";i:2;s:7:"Tagalog";}i:39;a:3:{i:0;s:6:"0x1720";i:1;s:6:"0x173F";i:2;s:7:"Hanunoo";}i:40;a:3:{i:0;s:6:"0x1740";i:1;s:6:"0x175F";i:2;s:5:"Buhid";}i:41;a:3:{i:0;s:6:"0x1760";i:1;s:6:"0x177F";i:2;s:8:"Tagbanwa";}i:42;a:3:{i:0;s:6:"0x1780";i:1;s:6:"0x17FF";i:2;s:5:"Khmer";}i:43;a:3:{i:0;s:6:"0x1800";i:1;s:6:"0x18AF";i:2;s:9:"Mongolian";}i:44;a:3:{i:0;s:6:"0x1900";i:1;s:6:"0x194F";i:2;s:5:"Limbu";}i:45;a:3:{i:0;s:6:"0x1950";i:1;s:6:"0x197F";i:2;s:6:"Tai Le";}i:46;a:3:{i:0;s:6:"0x1980";i:1;s:6:"0x19DF";i:2;s:11:"New Tai Lue";}i:47;a:3:{i:0;s:6:"0x19E0";i:1;s:6:"0x19FF";i:2;s:13:"Khmer Symbols";}i:48;a:3:{i:0;s:6:"0x1A00";i:1;s:6:"0x1A1F";i:2;s:8:"Buginese";}i:49;a:3:{i:0;s:6:"0x1D00";i:1;s:6:"0x1D7F";i:2;s:19:"Phonetic Extensions";}i:50;a:3:{i:0;s:6:"0x1D80";i:1;s:6:"0x1DBF";i:2;s:30:"Phonetic Extensions Supplement";}i:51;a:3:{i:0;s:6:"0x1DC0";i:1;s:6:"0x1DFF";i:2;s:38:"Combining Diacritical Marks Supplement";}i:52;a:3:{i:0;s:6:"0x1E00";i:1;s:6:"0x1EFF";i:2;s:25:"Latin Extended Additional";}i:53;a:3:{i:0;s:6:"0x1F00";i:1;s:6:"0x1FFF";i:2;s:14:"Greek Extended";}i:54;a:3:{i:0;s:6:"0x2000";i:1;s:6:"0x206F";i:2;s:19:"General Punctuation";}i:55;a:3:{i:0;s:6:"0x2070";i:1;s:6:"0x209F";i:2;s:27:"Superscripts and Subscripts";}i:56;a:3:{i:0;s:6:"0x20A0";i:1;s:6:"0x20CF";i:2;s:16:"Currency Symbols";}i:57;a:3:{i:0;s:6:"0x20D0";i:1;s:6:"0x20FF";i:2;s:39:"Combining Diacritical Marks for Symbols";}i:58;a:3:{i:0;s:6:"0x2100";i:1;s:6:"0x214F";i:2;s:18:"Letterlike Symbols";}i:59;a:3:{i:0;s:6:"0x2150";i:1;s:6:"0x218F";i:2;s:12:"Number Forms";}i:60;a:3:{i:0;s:6:"0x2190";i:1;s:6:"0x21FF";i:2;s:6:"Arrows";}i:61;a:3:{i:0;s:6:"0x2200";i:1;s:6:"0x22FF";i:2;s:22:"Mathematical Operators";}i:62;a:3:{i:0;s:6:"0x2300";i:1;s:6:"0x23FF";i:2;s:23:"Miscellaneous Technical";}i:63;a:3:{i:0;s:6:"0x2400";i:1;s:6:"0x243F";i:2;s:16:"Control Pictures";}i:64;a:3:{i:0;s:6:"0x2440";i:1;s:6:"0x245F";i:2;s:29:"Optical Character Recognition";}i:65;a:3:{i:0;s:6:"0x2460";i:1;s:6:"0x24FF";i:2;s:22:"Enclosed Alphanumerics";}i:66;a:3:{i:0;s:6:"0x2500";i:1;s:6:"0x257F";i:2;s:11:"Box Drawing";}i:67;a:3:{i:0;s:6:"0x2580";i:1;s:6:"0x259F";i:2;s:14:"Block Elements";}i:68;a:3:{i:0;s:6:"0x25A0";i:1;s:6:"0x25FF";i:2;s:16:"Geometric Shapes";}i:69;a:3:{i:0;s:6:"0x2600";i:1;s:6:"0x26FF";i:2;s:21:"Miscellaneous Symbols";}i:70;a:3:{i:0;s:6:"0x2700";i:1;s:6:"0x27BF";i:2;s:8:"Dingbats";}i:71;a:3:{i:0;s:6:"0x27C0";i:1;s:6:"0x27EF";i:2;s:36:"Miscellaneous Mathematical Symbols-A";}i:72;a:3:{i:0;s:6:"0x27F0";i:1;s:6:"0x27FF";i:2;s:21:"Supplemental Arrows-A";}i:73;a:3:{i:0;s:6:"0x2800";i:1;s:6:"0x28FF";i:2;s:16:"Braille Patterns";}i:74;a:3:{i:0;s:6:"0x2900";i:1;s:6:"0x297F";i:2;s:21:"Supplemental Arrows-B";}i:75;a:3:{i:0;s:6:"0x2980";i:1;s:6:"0x29FF";i:2;s:36:"Miscellaneous Mathematical Symbols-B";}i:76;a:3:{i:0;s:6:"0x2A00";i:1;s:6:"0x2AFF";i:2;s:35:"Supplemental Mathematical Operators";}i:77;a:3:{i:0;s:6:"0x2B00";i:1;s:6:"0x2BFF";i:2;s:32:"Miscellaneous Symbols and Arrows";}i:78;a:3:{i:0;s:6:"0x2C00";i:1;s:6:"0x2C5F";i:2;s:10:"Glagolitic";}i:79;a:3:{i:0;s:6:"0x2C80";i:1;s:6:"0x2CFF";i:2;s:6:"Coptic";}i:80;a:3:{i:0;s:6:"0x2D00";i:1;s:6:"0x2D2F";i:2;s:19:"Georgian Supplement";}i:81;a:3:{i:0;s:6:"0x2D30";i:1;s:6:"0x2D7F";i:2;s:8:"Tifinagh";}i:82;a:3:{i:0;s:6:"0x2D80";i:1;s:6:"0x2DDF";i:2;s:17:"Ethiopic Extended";}i:83;a:3:{i:0;s:6:"0x2E00";i:1;s:6:"0x2E7F";i:2;s:24:"Supplemental Punctuation";}i:84;a:3:{i:0;s:6:"0x2E80";i:1;s:6:"0x2EFF";i:2;s:23:"CJK Radicals Supplement";}i:85;a:3:{i:0;s:6:"0x2F00";i:1;s:6:"0x2FDF";i:2;s:15:"Kangxi Radicals";}i:86;a:3:{i:0;s:6:"0x2FF0";i:1;s:6:"0x2FFF";i:2;s:34:"Ideographic Description Characters";}i:87;a:3:{i:0;s:6:"0x3000";i:1;s:6:"0x303F";i:2;s:27:"CJK Symbols and Punctuation";}i:88;a:3:{i:0;s:6:"0x3040";i:1;s:6:"0x309F";i:2;s:8:"Hiragana";}i:89;a:3:{i:0;s:6:"0x30A0";i:1;s:6:"0x30FF";i:2;s:8:"Katakana";}i:90;a:3:{i:0;s:6:"0x3100";i:1;s:6:"0x312F";i:2;s:8:"Bopomofo";}i:91;a:3:{i:0;s:6:"0x3130";i:1;s:6:"0x318F";i:2;s:25:"Hangul Compatibility Jamo";}i:92;a:3:{i:0;s:6:"0x3190";i:1;s:6:"0x319F";i:2;s:6:"Kanbun";}i:93;a:3:{i:0;s:6:"0x31A0";i:1;s:6:"0x31BF";i:2;s:17:"Bopomofo Extended";}i:94;a:3:{i:0;s:6:"0x31C0";i:1;s:6:"0x31EF";i:2;s:11:"CJK Strokes";}i:95;a:3:{i:0;s:6:"0x31F0";i:1;s:6:"0x31FF";i:2;s:28:"Katakana Phonetic Extensions";}i:96;a:3:{i:0;s:6:"0x3200";i:1;s:6:"0x32FF";i:2;s:31:"Enclosed CJK Letters and Months";}i:97;a:3:{i:0;s:6:"0x3300";i:1;s:6:"0x33FF";i:2;s:17:"CJK Compatibility";}i:98;a:3:{i:0;s:6:"0x3400";i:1;s:6:"0x4DBF";i:2;s:34:"CJK Unified Ideographs Extension A";}i:99;a:3:{i:0;s:6:"0x4DC0";i:1;s:6:"0x4DFF";i:2;s:23:"Yijing Hexagram Symbols";}i:100;a:3:{i:0;s:6:"0x4E00";i:1;s:6:"0x9FFF";i:2;s:22:"CJK Unified Ideographs";}i:101;a:3:{i:0;s:6:"0xA000";i:1;s:6:"0xA48F";i:2;s:12:"Yi Syllables";}i:102;a:3:{i:0;s:6:"0xA490";i:1;s:6:"0xA4CF";i:2;s:11:"Yi Radicals";}i:103;a:3:{i:0;s:6:"0xA700";i:1;s:6:"0xA71F";i:2;s:21:"Modifier Tone Letters";}i:104;a:3:{i:0;s:6:"0xA800";i:1;s:6:"0xA82F";i:2;s:12:"Syloti Nagri";}i:105;a:3:{i:0;s:6:"0xAC00";i:1;s:6:"0xD7AF";i:2;s:16:"Hangul Syllables";}i:106;a:3:{i:0;s:6:"0xD800";i:1;s:6:"0xDB7F";i:2;s:15:"High Surrogates";}i:107;a:3:{i:0;s:6:"0xDB80";i:1;s:6:"0xDBFF";i:2;s:27:"High Private Use Surrogates";}i:108;a:3:{i:0;s:6:"0xDC00";i:1;s:6:"0xDFFF";i:2;s:14:"Low Surrogates";}i:109;a:3:{i:0;s:6:"0xE000";i:1;s:6:"0xF8FF";i:2;s:16:"Private Use Area";}i:110;a:3:{i:0;s:6:"0xF900";i:1;s:6:"0xFAFF";i:2;s:28:"CJK Compatibility Ideographs";}i:111;a:3:{i:0;s:6:"0xFB00";i:1;s:6:"0xFB4F";i:2;s:29:"Alphabetic Presentation Forms";}i:112;a:3:{i:0;s:6:"0xFB50";i:1;s:6:"0xFDFF";i:2;s:27:"Arabic Presentation Forms-A";}i:113;a:3:{i:0;s:6:"0xFE00";i:1;s:6:"0xFE0F";i:2;s:19:"Variation Selectors";}i:114;a:3:{i:0;s:6:"0xFE10";i:1;s:6:"0xFE1F";i:2;s:14:"Vertical Forms";}i:115;a:3:{i:0;s:6:"0xFE20";i:1;s:6:"0xFE2F";i:2;s:20:"Combining Half Marks";}i:116;a:3:{i:0;s:6:"0xFE30";i:1;s:6:"0xFE4F";i:2;s:23:"CJK Compatibility Forms";}i:117;a:3:{i:0;s:6:"0xFE50";i:1;s:6:"0xFE6F";i:2;s:19:"Small Form Variants";}i:118;a:3:{i:0;s:6:"0xFE70";i:1;s:6:"0xFEFF";i:2;s:27:"Arabic Presentation Forms-B";}i:119;a:3:{i:0;s:6:"0xFF00";i:1;s:6:"0xFFEF";i:2;s:29:"Halfwidth and Fullwidth Forms";}i:120;a:3:{i:0;s:6:"0xFFF0";i:1;s:6:"0xFFFF";i:2;s:8:"Specials";}i:121;a:3:{i:0;s:7:"0x10000";i:1;s:7:"0x1007F";i:2;s:18:"Linear B Syllabary";}i:122;a:3:{i:0;s:7:"0x10080";i:1;s:7:"0x100FF";i:2;s:18:"Linear B Ideograms";}i:123;a:3:{i:0;s:7:"0x10100";i:1;s:7:"0x1013F";i:2;s:14:"Aegean Numbers";}i:124;a:3:{i:0;s:7:"0x10140";i:1;s:7:"0x1018F";i:2;s:21:"Ancient Greek Numbers";}i:125;a:3:{i:0;s:7:"0x10300";i:1;s:7:"0x1032F";i:2;s:10:"Old Italic";}i:126;a:3:{i:0;s:7:"0x10330";i:1;s:7:"0x1034F";i:2;s:6:"Gothic";}i:127;a:3:{i:0;s:7:"0x10380";i:1;s:7:"0x1039F";i:2;s:8:"Ugaritic";}i:128;a:3:{i:0;s:7:"0x103A0";i:1;s:7:"0x103DF";i:2;s:11:"Old Persian";}i:129;a:3:{i:0;s:7:"0x10400";i:1;s:7:"0x1044F";i:2;s:7:"Deseret";}i:130;a:3:{i:0;s:7:"0x10450";i:1;s:7:"0x1047F";i:2;s:7:"Shavian";}i:131;a:3:{i:0;s:7:"0x10480";i:1;s:7:"0x104AF";i:2;s:7:"Osmanya";}i:132;a:3:{i:0;s:7:"0x10800";i:1;s:7:"0x1083F";i:2;s:17:"Cypriot Syllabary";}i:133;a:3:{i:0;s:7:"0x10A00";i:1;s:7:"0x10A5F";i:2;s:10:"Kharoshthi";}i:134;a:3:{i:0;s:7:"0x1D000";i:1;s:7:"0x1D0FF";i:2;s:25:"Byzantine Musical Symbols";}i:135;a:3:{i:0;s:7:"0x1D100";i:1;s:7:"0x1D1FF";i:2;s:15:"Musical Symbols";}i:136;a:3:{i:0;s:7:"0x1D200";i:1;s:7:"0x1D24F";i:2;s:30:"Ancient Greek Musical Notation";}i:137;a:3:{i:0;s:7:"0x1D300";i:1;s:7:"0x1D35F";i:2;s:21:"Tai Xuan Jing Symbols";}i:138;a:3:{i:0;s:7:"0x1D400";i:1;s:7:"0x1D7FF";i:2;s:33:"Mathematical Alphanumeric Symbols";}i:139;a:3:{i:0;s:7:"0x20000";i:1;s:7:"0x2A6DF";i:2;s:34:"CJK Unified Ideographs Extension B";}i:140;a:3:{i:0;s:7:"0x2F800";i:1;s:7:"0x2FA1F";i:2;s:39:"CJK Compatibility Ideographs Supplement";}i:141;a:3:{i:0;s:7:"0xE0000";i:1;s:7:"0xE007F";i:2;s:4:"Tags";}i:142;a:3:{i:0;s:7:"0xE0100";i:1;s:7:"0xE01EF";i:2;s:30:"Variation Selectors Supplement";}i:143;a:3:{i:0;s:7:"0xF0000";i:1;s:7:"0xFFFFF";i:2;s:32:"Supplementary Private Use Area-A";}i:144;a:3:{i:0;s:8:"0x100000";i:1;s:8:"0x10FFFF";i:2;s:32:"Supplementary Private Use Area-B";}} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/readability/JSLikeHTMLElement.php b/inc/3rdparty/libraries/readability/JSLikeHTMLElement.php
new file mode 100644
index 00000000..a8eeccf4
--- /dev/null
+++ b/inc/3rdparty/libraries/readability/JSLikeHTMLElement.php
@@ -0,0 +1,110 @@
1<?php
2/**
3* JavaScript-like HTML DOM Element
4*
5* This class extends PHP's DOMElement to allow
6* users to get and set the innerHTML property of
7* HTML elements in the same way it's done in
8* JavaScript.
9*
10* Example usage:
11* @code
12* require_once 'JSLikeHTMLElement.php';
13* header('Content-Type: text/plain');
14* $doc = new DOMDocument();
15* $doc->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
16* $doc->loadHTML('<div><p>Para 1</p><p>Para 2</p></div>');
17* $elem = $doc->getElementsByTagName('div')->item(0);
18*
19* // print innerHTML
20* echo $elem->innerHTML; // prints '<p>Para 1</p><p>Para 2</p>'
21* echo "\n\n";
22*
23* // set innerHTML
24* $elem->innerHTML = '<a href="http://fivefilters.org">FiveFilters.org</a>';
25* echo $elem->innerHTML; // prints '<a href="http://fivefilters.org">FiveFilters.org</a>'
26* echo "\n\n";
27*
28* // print document (with our changes)
29* echo $doc->saveXML();
30* @endcode
31*
32* @author Keyvan Minoukadeh - http://www.keyvan.net - keyvan@keyvan.net
33* @see http://fivefilters.org (the project this was written for)
34*/
35class JSLikeHTMLElement extends DOMElement
36{
37 /**
38 * Used for setting innerHTML like it's done in JavaScript:
39 * @code
40 * $div->innerHTML = '<h2>Chapter 2</h2><p>The story begins...</p>';
41 * @endcode
42 */
43 public function __set($name, $value) {
44 if ($name == 'innerHTML') {
45 // first, empty the element
46 for ($x=$this->childNodes->length-1; $x>=0; $x--) {
47 $this->removeChild($this->childNodes->item($x));
48 }
49 // $value holds our new inner HTML
50 if ($value != '') {
51 $f = $this->ownerDocument->createDocumentFragment();
52 // appendXML() expects well-formed markup (XHTML)
53 $result = @$f->appendXML($value); // @ to suppress PHP warnings
54 if ($result) {
55 if ($f->hasChildNodes()) $this->appendChild($f);
56 } else {
57 // $value is probably ill-formed
58 $f = new DOMDocument();
59 $value = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
60 // Using <htmlfragment> will generate a warning, but so will bad HTML
61 // (and by this point, bad HTML is what we've got).
62 // We use it (and suppress the warning) because an HTML fragment will
63 // be wrapped around <html><body> tags which we don't really want to keep.
64 // Note: despite the warning, if loadHTML succeeds it will return true.
65 $result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>');
66 if ($result) {
67 $import = $f->getElementsByTagName('htmlfragment')->item(0);
68 foreach ($import->childNodes as $child) {
69 $importedNode = $this->ownerDocument->importNode($child, true);
70 $this->appendChild($importedNode);
71 }
72 } else {
73 // oh well, we tried, we really did. :(
74 // this element is now empty
75 }
76 }
77 }
78 } else {
79 $trace = debug_backtrace();
80 trigger_error('Undefined property via __set(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
81 }
82 }
83
84 /**
85 * Used for getting innerHTML like it's done in JavaScript:
86 * @code
87 * $string = $div->innerHTML;
88 * @endcode
89 */
90 public function __get($name)
91 {
92 if ($name == 'innerHTML') {
93 $inner = '';
94 foreach ($this->childNodes as $child) {
95 $inner .= $this->ownerDocument->saveXML($child);
96 }
97 return $inner;
98 }
99
100 $trace = debug_backtrace();
101 trigger_error('Undefined property via __get(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE);
102 return null;
103 }
104
105 public function __toString()
106 {
107 return '['.$this->tagName.']';
108 }
109}
110?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/readability/Readability.php b/inc/3rdparty/libraries/readability/Readability.php
new file mode 100644
index 00000000..2e8991cc
--- /dev/null
+++ b/inc/3rdparty/libraries/readability/Readability.php
@@ -0,0 +1,1138 @@
1<?php
2/**
3* Arc90's Readability ported to PHP for FiveFilters.org
4* Based on readability.js version 1.7.1 (without multi-page support)
5* Updated to allow HTML5 parsing with html5lib
6* Updated with lightClean mode to preserve more images and youtube/vimeo/viddler embeds
7* ------------------------------------------------------
8* Original URL: http://lab.arc90.com/experiments/readability/js/readability.js
9* Arc90's project URL: http://lab.arc90.com/experiments/readability/
10* JS Source: http://code.google.com/p/arc90labs-readability
11* Ported by: Keyvan Minoukadeh, http://www.keyvan.net
12* More information: http://fivefilters.org/content-only/
13* License: Apache License, Version 2.0
14* Requires: PHP5
15* Date: 2012-09-19
16*
17* Differences between the PHP port and the original
18* ------------------------------------------------------
19* Arc90's Readability is designed to run in the browser. It works on the DOM
20* tree (the parsed HTML) after the page's CSS styles have been applied and
21* Javascript code executed. This PHP port does not run inside a browser.
22* We use PHP's ability to parse HTML to build our DOM tree, but we cannot
23* rely on CSS or Javascript support. As such, the results will not always
24* match Arc90's Readability. (For example, if a web page contains CSS style
25* rules or Javascript code which hide certain HTML elements from display,
26* Arc90's Readability will dismiss those from consideration but our PHP port,
27* unable to understand CSS or Javascript, will not know any better.)
28*
29* Another significant difference is that the aim of Arc90's Readability is
30* to re-present the main content block of a given web page so users can
31* read it more easily in their browsers. Correct identification, clean up,
32* and separation of the content block is only a part of this process.
33* This PHP port is only concerned with this part, it does not include code
34* that relates to presentation in the browser - Arc90 already do
35* that extremely well, and for PDF output there's FiveFilters.org's
36* PDF Newspaper: http://fivefilters.org/pdf-newspaper/.
37*
38* Finally, this class contains methods that might be useful for developers
39* working on HTML document fragments. So without deviating too much from
40* the original code (which I don't want to do because it makes debugging
41* and updating more difficult), I've tried to make it a little more
42* developer friendly. You should be able to use the methods here on
43* existing DOMElement objects without passing an entire HTML document to
44* be parsed.
45*/
46
47// This class allows us to do JavaScript like assignements to innerHTML
48require_once(dirname(__FILE__).'/JSLikeHTMLElement.php');
49
50// Alternative usage (for testing only!)
51// uncomment the lines below and call Readability.php in your browser
52// passing it the URL of the page you'd like content from, e.g.:
53// Readability.php?url=http://medialens.org/alerts/09/090615_the_guardian_climate.php
54
55/*
56if (!isset($_GET['url']) || $_GET['url'] == '') {
57 die('Please pass a URL to the script. E.g. Readability.php?url=bla.com/story.html');
58}
59$url = $_GET['url'];
60if (!preg_match('!^https?://!i', $url)) $url = 'http://'.$url;
61$html = file_get_contents($url);
62$r = new Readability($html, $url);
63$r->init();
64echo $r->articleContent->innerHTML;
65*/
66
67class Readability
68{
69 public $version = '1.7.1-without-multi-page';
70 public $convertLinksToFootnotes = false;
71 public $revertForcedParagraphElements = true;
72 public $articleTitle;
73 public $articleContent;
74 public $dom;
75 public $url = null; // optional - URL where HTML was retrieved
76 public $debug = false;
77 public $lightClean = true; // preserves more content (experimental) added 2012-09-19
78 protected $body = null; //
79 protected $bodyCache = null; // Cache the body HTML in case we need to re-use it later
80 protected $flags = 7; // 1 | 2 | 4; // Start with all flags set.
81 protected $success = false; // indicates whether we were able to extract or not
82
83 /**
84 * All of the regular expressions in use within readability.
85 * Defined up here so we don't instantiate them repeatedly in loops.
86 **/
87 public $regexps = array(
88 'unlikelyCandidates' => '/combx|comment|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|ad-break|agegate|pagination|pager|popup/i',
89 'okMaybeItsACandidate' => '/and|article|body|column|main|shadow/i',
90 'positive' => '/article|body|content|entry|hentry|main|page|attachment|pagination|post|text|blog|story/i',
91 'negative' => '/combx|comment|com-|contact|foot|footer|_nav|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget/i',
92 'divToPElements' => '/<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i',
93 'replaceBrs' => '/(<br[^>]*>[ \n\r\t]*){2,}/i',
94 'replaceFonts' => '/<(\/?)font[^>]*>/i',
95 // 'trimRe' => '/^\s+|\s+$/g', // PHP has trim()
96 'normalize' => '/\s{2,}/',
97 'killBreaks' => '/(<br\s*\/?>(\s|&nbsp;?)*){1,}/',
98 'video' => '!//(player\.|www\.)?(youtube|vimeo|viddler)\.com!i',
99 'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i'
100 );
101
102 /* constants */
103 const FLAG_STRIP_UNLIKELYS = 1;
104 const FLAG_WEIGHT_CLASSES = 2;
105 const FLAG_CLEAN_CONDITIONALLY = 4;
106
107 /**
108 * Create instance of Readability
109 * @param string UTF-8 encoded string
110 * @param string (optional) URL associated with HTML (used for footnotes)
111 * @param string which parser to use for turning raw HTML into a DOMDocument (either 'libxml' or 'html5lib')
112 */
113 function __construct($html, $url=null, $parser='libxml')
114 {
115 $this->url = $url;
116 /* Turn all double br's into p's */
117 $html = preg_replace($this->regexps['replaceBrs'], '</p><p>', $html);
118 $html = preg_replace($this->regexps['replaceFonts'], '<$1span>', $html);
119 $html = mb_convert_encoding($html, 'HTML-ENTITIES', "UTF-8");
120 if (trim($html) == '') $html = '<html></html>';
121 if ($parser=='html5lib' && ($this->dom = HTML5_Parser::parse($html))) {
122 // all good
123 } else {
124 $this->dom = new DOMDocument();
125 $this->dom->preserveWhiteSpace = false;
126 @$this->dom->loadHTML($html);
127 }
128 $this->dom->registerNodeClass('DOMElement', 'JSLikeHTMLElement');
129 }
130
131 /**
132 * Get article title element
133 * @return DOMElement
134 */
135 public function getTitle() {
136 return $this->articleTitle;
137 }
138
139 /**
140 * Get article content element
141 * @return DOMElement
142 */
143 public function getContent() {
144 return $this->articleContent;
145 }
146
147 /**
148 * Runs readability.
149 *
150 * Workflow:
151 * 1. Prep the document by removing script tags, css, etc.
152 * 2. Build readability's DOM tree.
153 * 3. Grab the article content from the current dom tree.
154 * 4. Replace the current DOM tree with the new one.
155 * 5. Read peacefully.
156 *
157 * @return boolean true if we found content, false otherwise
158 **/
159 public function init()
160 {
161 if (!isset($this->dom->documentElement)) return false;
162 $this->removeScripts($this->dom);
163 //die($this->getInnerHTML($this->dom->documentElement));
164
165 // Assume successful outcome
166 $this->success = true;
167
168 $bodyElems = $this->dom->getElementsByTagName('body');
169 if ($bodyElems->length > 0) {
170 if ($this->bodyCache == null) {
171 $this->bodyCache = $bodyElems->item(0)->innerHTML;
172 }
173 if ($this->body == null) {
174 $this->body = $bodyElems->item(0);
175 }
176 }
177
178 $this->prepDocument();
179
180 //die($this->dom->documentElement->parentNode->nodeType);
181 //$this->setInnerHTML($this->dom->documentElement, $this->getInnerHTML($this->dom->documentElement));
182 //die($this->getInnerHTML($this->dom->documentElement));
183
184 /* Build readability's DOM tree */
185 $overlay = $this->dom->createElement('div');
186 $innerDiv = $this->dom->createElement('div');
187 $articleTitle = $this->getArticleTitle();
188 $articleContent = $this->grabArticle();
189
190 if (!$articleContent) {
191 $this->success = false;
192 $articleContent = $this->dom->createElement('div');
193 $articleContent->setAttribute('id', 'readability-content');
194 $articleContent->innerHTML = '<p>Sorry, Readability was unable to parse this page for content.</p>';
195 }
196
197 $overlay->setAttribute('id', 'readOverlay');
198 $innerDiv->setAttribute('id', 'readInner');
199
200 /* Glue the structure of our document together. */
201 $innerDiv->appendChild($articleTitle);
202 $innerDiv->appendChild($articleContent);
203 $overlay->appendChild($innerDiv);
204
205 /* Clear the old HTML, insert the new content. */
206 $this->body->innerHTML = '';
207 $this->body->appendChild($overlay);
208 //document.body.insertBefore(overlay, document.body.firstChild);
209 $this->body->removeAttribute('style');
210
211 $this->postProcessContent($articleContent);
212
213 // Set title and content instance variables
214 $this->articleTitle = $articleTitle;
215 $this->articleContent = $articleContent;
216
217 return $this->success;
218 }
219
220 /**
221 * Debug
222 */
223 protected function dbg($msg) {
224 if ($this->debug) echo '* ',$msg, "\n";
225 }
226
227 /**
228 * Run any post-process modifications to article content as necessary.
229 *
230 * @param DOMElement
231 * @return void
232 */
233 public function postProcessContent($articleContent) {
234 if ($this->convertLinksToFootnotes && !preg_match('/wikipedia\.org/', @$this->url)) {
235 $this->addFootnotes($articleContent);
236 }
237 }
238
239 /**
240 * Get the article title as an H1.
241 *
242 * @return DOMElement
243 */
244 protected function getArticleTitle() {
245 $curTitle = '';
246 $origTitle = '';
247
248 try {
249 $curTitle = $origTitle = $this->getInnerText($this->dom->getElementsByTagName('title')->item(0));
250 } catch(Exception $e) {}
251
252 if (preg_match('/ [\|\-] /', $curTitle))
253 {
254 $curTitle = preg_replace('/(.*)[\|\-] .*/i', '$1', $origTitle);
255
256 if (count(explode(' ', $curTitle)) < 3) {
257 $curTitle = preg_replace('/[^\|\-]*[\|\-](.*)/i', '$1', $origTitle);
258 }
259 }
260 else if (strpos($curTitle, ': ') !== false)
261 {
262 $curTitle = preg_replace('/.*:(.*)/i', '$1', $origTitle);
263
264 if (count(explode(' ', $curTitle)) < 3) {
265 $curTitle = preg_replace('/[^:]*[:](.*)/i','$1', $origTitle);
266 }
267 }
268 else if(strlen($curTitle) > 150 || strlen($curTitle) < 15)
269 {
270 $hOnes = $this->dom->getElementsByTagName('h1');
271 if($hOnes->length == 1)
272 {
273 $curTitle = $this->getInnerText($hOnes->item(0));
274 }
275 }
276
277 $curTitle = trim($curTitle);
278
279 if (count(explode(' ', $curTitle)) <= 4) {
280 $curTitle = $origTitle;
281 }
282
283 $articleTitle = $this->dom->createElement('h1');
284 $articleTitle->innerHTML = $curTitle;
285
286 return $articleTitle;
287 }
288
289 /**
290 * Prepare the HTML document for readability to scrape it.
291 * This includes things like stripping javascript, CSS, and handling terrible markup.
292 *
293 * @return void
294 **/
295 protected function prepDocument() {
296 /**
297 * In some cases a body element can't be found (if the HTML is totally hosed for example)
298 * so we create a new body node and append it to the document.
299 */
300 if ($this->body == null)
301 {
302 $this->body = $this->dom->createElement('body');
303 $this->dom->documentElement->appendChild($this->body);
304 }
305 $this->body->setAttribute('id', 'readabilityBody');
306
307 /* Remove all style tags in head */
308 $styleTags = $this->dom->getElementsByTagName('style');
309 for ($i = $styleTags->length-1; $i >= 0; $i--)
310 {
311 $styleTags->item($i)->parentNode->removeChild($styleTags->item($i));
312 }
313
314 /* Turn all double br's into p's */
315 /* Note, this is pretty costly as far as processing goes. Maybe optimize later. */
316 //document.body.innerHTML = document.body.innerHTML.replace(readability.regexps.replaceBrs, '</p><p>').replace(readability.regexps.replaceFonts, '<$1span>');
317 // We do this in the constructor for PHP as that's when we have raw HTML - before parsing it into a DOM tree.
318 // Manipulating innerHTML as it's done in JS is not possible in PHP.
319 }
320
321 /**
322 * For easier reading, convert this document to have footnotes at the bottom rather than inline links.
323 * @see http://www.roughtype.com/archives/2010/05/experiments_in.php
324 *
325 * @return void
326 **/
327 public function addFootnotes($articleContent) {
328 $footnotesWrapper = $this->dom->createElement('div');
329 $footnotesWrapper->setAttribute('id', 'readability-footnotes');
330 $footnotesWrapper->innerHTML = '<h3>References</h3>';
331
332 $articleFootnotes = $this->dom->createElement('ol');
333 $articleFootnotes->setAttribute('id', 'readability-footnotes-list');
334 $footnotesWrapper->appendChild($articleFootnotes);
335
336 $articleLinks = $articleContent->getElementsByTagName('a');
337
338 $linkCount = 0;
339 for ($i = 0; $i < $articleLinks->length; $i++)
340 {
341 $articleLink = $articleLinks->item($i);
342 $footnoteLink = $articleLink->cloneNode(true);
343 $refLink = $this->dom->createElement('a');
344 $footnote = $this->dom->createElement('li');
345 $linkDomain = @parse_url($footnoteLink->getAttribute('href'), PHP_URL_HOST);
346 if (!$linkDomain && isset($this->url)) $linkDomain = @parse_url($this->url, PHP_URL_HOST);
347 //linkDomain = footnoteLink.host ? footnoteLink.host : document.location.host,
348 $linkText = $this->getInnerText($articleLink);
349
350 if ((strpos($articleLink->getAttribute('class'), 'readability-DoNotFootnote') !== false) || preg_match($this->regexps['skipFootnoteLink'], $linkText)) {
351 continue;
352 }
353
354 $linkCount++;
355
356 /** Add a superscript reference after the article link */
357 $refLink->setAttribute('href', '#readabilityFootnoteLink-' . $linkCount);
358 $refLink->innerHTML = '<small><sup>[' . $linkCount . ']</sup></small>';
359 $refLink->setAttribute('class', 'readability-DoNotFootnote');
360 $refLink->setAttribute('style', 'color: inherit;');
361
362 //TODO: does this work or should we use DOMNode.isSameNode()?
363 if ($articleLink->parentNode->lastChild == $articleLink) {
364 $articleLink->parentNode->appendChild($refLink);
365 } else {
366 $articleLink->parentNode->insertBefore($refLink, $articleLink->nextSibling);
367 }
368
369 $articleLink->setAttribute('style', 'color: inherit; text-decoration: none;');
370 $articleLink->setAttribute('name', 'readabilityLink-' . $linkCount);
371
372 $footnote->innerHTML = '<small><sup><a href="#readabilityLink-' . $linkCount . '" title="Jump to Link in Article">^</a></sup></small> ';
373
374 $footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') != '' ? $footnoteLink->getAttribute('title') : $linkText);
375 $footnoteLink->setAttribute('name', 'readabilityFootnoteLink-' . $linkCount);
376
377 $footnote->appendChild($footnoteLink);
378 if ($linkDomain) $footnote->innerHTML = $footnote->innerHTML . '<small> (' . $linkDomain . ')</small>';
379
380 $articleFootnotes->appendChild($footnote);
381 }
382
383 if ($linkCount > 0) {
384 $articleContent->appendChild($footnotesWrapper);
385 }
386 }
387
388 /**
389 * Reverts P elements with class 'readability-styled'
390 * to text nodes - which is what they were before.
391 *
392 * @param DOMElement
393 * @return void
394 */
395 function revertReadabilityStyledElements($articleContent) {
396 $xpath = new DOMXPath($articleContent->ownerDocument);
397 $elems = $xpath->query('.//p[@class="readability-styled"]', $articleContent);
398 //$elems = $articleContent->getElementsByTagName('p');
399 for ($i = $elems->length-1; $i >= 0; $i--) {
400 $e = $elems->item($i);
401 $e->parentNode->replaceChild($articleContent->ownerDocument->createTextNode($e->textContent), $e);
402 //if ($e->hasAttribute('class') && $e->getAttribute('class') == 'readability-styled') {
403 // $e->parentNode->replaceChild($this->dom->createTextNode($e->textContent), $e);
404 //}
405 }
406 }
407
408 /**
409 * Prepare the article node for display. Clean out any inline styles,
410 * iframes, forms, strip extraneous <p> tags, etc.
411 *
412 * @param DOMElement
413 * @return void
414 */
415 function prepArticle($articleContent) {
416 $this->cleanStyles($articleContent);
417 $this->killBreaks($articleContent);
418 if ($this->revertForcedParagraphElements) {
419 $this->revertReadabilityStyledElements($articleContent);
420 }
421
422 /* Clean out junk from the article content */
423 $this->cleanConditionally($articleContent, 'form');
424 $this->clean($articleContent, 'object');
425 $this->clean($articleContent, 'h1');
426
427 /**
428 * If there is only one h2, they are probably using it
429 * as a header and not a subheader, so remove it since we already have a header.
430 ***/
431 if (!$this->lightClean && ($articleContent->getElementsByTagName('h2')->length == 1)) {
432 $this->clean($articleContent, 'h2');
433 }
434 $this->clean($articleContent, 'iframe');
435
436 $this->cleanHeaders($articleContent);
437
438 /* Do these last as the previous stuff may have removed junk that will affect these */
439 $this->cleanConditionally($articleContent, 'table');
440 $this->cleanConditionally($articleContent, 'ul');
441 $this->cleanConditionally($articleContent, 'div');
442
443 /* Remove extra paragraphs */
444 $articleParagraphs = $articleContent->getElementsByTagName('p');
445 for ($i = $articleParagraphs->length-1; $i >= 0; $i--)
446 {
447 $imgCount = $articleParagraphs->item($i)->getElementsByTagName('img')->length;
448 $embedCount = $articleParagraphs->item($i)->getElementsByTagName('embed')->length;
449 $objectCount = $articleParagraphs->item($i)->getElementsByTagName('object')->length;
450 $iframeCount = $articleParagraphs->item($i)->getElementsByTagName('iframe')->length;
451
452 if ($imgCount === 0 && $embedCount === 0 && $objectCount === 0 && $iframeCount === 0 && $this->getInnerText($articleParagraphs->item($i), false) == '')
453 {
454 $articleParagraphs->item($i)->parentNode->removeChild($articleParagraphs->item($i));
455 }
456 }
457
458 try {
459 $articleContent->innerHTML = preg_replace('/<br[^>]*>\s*<p/i', '<p', $articleContent->innerHTML);
460 //articleContent.innerHTML = articleContent.innerHTML.replace(/<br[^>]*>\s*<p/gi, '<p');
461 }
462 catch (Exception $e) {
463 $this->dbg("Cleaning innerHTML of breaks failed. This is an IE strict-block-elements bug. Ignoring.: " . $e);
464 }
465 }
466
467 /**
468 * Initialize a node with the readability object. Also checks the
469 * className/id for special names to add to its score.
470 *
471 * @param Element
472 * @return void
473 **/
474 protected function initializeNode($node) {
475 $readability = $this->dom->createAttribute('readability');
476 $readability->value = 0; // this is our contentScore
477 $node->setAttributeNode($readability);
478
479 switch (strtoupper($node->tagName)) { // unsure if strtoupper is needed, but using it just in case
480 case 'DIV':
481 $readability->value += 5;
482 break;
483
484 case 'PRE':
485 case 'TD':
486 case 'BLOCKQUOTE':
487 $readability->value += 3;
488 break;
489
490 case 'ADDRESS':
491 case 'OL':
492 case 'UL':
493 case 'DL':
494 case 'DD':
495 case 'DT':
496 case 'LI':
497 case 'FORM':
498 $readability->value -= 3;
499 break;
500
501 case 'H1':
502 case 'H2':
503 case 'H3':
504 case 'H4':
505 case 'H5':
506 case 'H6':
507 case 'TH':
508 $readability->value -= 5;
509 break;
510 }
511 $readability->value += $this->getClassWeight($node);
512 }
513
514 /***
515 * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is
516 * most likely to be the stuff a user wants to read. Then return it wrapped up in a div.
517 *
518 * @return DOMElement
519 **/
520 protected function grabArticle($page=null) {
521 $stripUnlikelyCandidates = $this->flagIsActive(self::FLAG_STRIP_UNLIKELYS);
522 if (!$page) $page = $this->dom;
523 $allElements = $page->getElementsByTagName('*');
524 /**
525 * First, node prepping. Trash nodes that look cruddy (like ones with the class name "comment", etc), and turn divs
526 * into P tags where they have been used inappropriately (as in, where they contain no other block level elements.)
527 *
528 * Note: Assignment from index for performance. See http://www.peachpit.com/articles/article.aspx?p=31567&seqNum=5
529 * TODO: Shouldn't this be a reverse traversal?
530 **/
531 $node = null;
532 $nodesToScore = array();
533 for ($nodeIndex = 0; ($node = $allElements->item($nodeIndex)); $nodeIndex++) {
534 //for ($nodeIndex=$targetList->length-1; $nodeIndex >= 0; $nodeIndex--) {
535 //$node = $targetList->item($nodeIndex);
536 $tagName = strtoupper($node->tagName);
537 /* Remove unlikely candidates */
538 if ($stripUnlikelyCandidates) {
539 $unlikelyMatchString = $node->getAttribute('class') . $node->getAttribute('id');
540 if (
541 preg_match($this->regexps['unlikelyCandidates'], $unlikelyMatchString) &&
542 !preg_match($this->regexps['okMaybeItsACandidate'], $unlikelyMatchString) &&
543 $tagName != 'BODY'
544 )
545 {
546 $this->dbg('Removing unlikely candidate - ' . $unlikelyMatchString);
547 //$nodesToRemove[] = $node;
548 $node->parentNode->removeChild($node);
549 $nodeIndex--;
550 continue;
551 }
552 }
553
554 if ($tagName == 'P' || $tagName == 'TD' || $tagName == 'PRE') {
555 $nodesToScore[] = $node;
556 }
557
558 /* Turn all divs that don't have children block level elements into p's */
559 if ($tagName == 'DIV') {
560 if (!preg_match($this->regexps['divToPElements'], $node->innerHTML)) {
561 //$this->dbg('Altering div to p');
562 $newNode = $this->dom->createElement('p');
563 try {
564 $newNode->innerHTML = $node->innerHTML;
565 //$nodesToReplace[] = array('new'=>$newNode, 'old'=>$node);
566 $node->parentNode->replaceChild($newNode, $node);
567 $nodeIndex--;
568 $nodesToScore[] = $node; // or $newNode?
569 }
570 catch(Exception $e) {
571 $this->dbg('Could not alter div to p, reverting back to div.: ' . $e);
572 }
573 }
574 else
575 {
576 /* EXPERIMENTAL */
577 // TODO: change these p elements back to text nodes after processing
578 for ($i = 0, $il = $node->childNodes->length; $i < $il; $i++) {
579 $childNode = $node->childNodes->item($i);
580 if ($childNode->nodeType == 3) { // XML_TEXT_NODE
581 //$this->dbg('replacing text node with a p tag with the same content.');
582 $p = $this->dom->createElement('p');
583 $p->innerHTML = $childNode->nodeValue;
584 $p->setAttribute('style', 'display: inline;');
585 $p->setAttribute('class', 'readability-styled');
586 $childNode->parentNode->replaceChild($p, $childNode);
587 }
588 }
589 }
590 }
591 }
592
593 /**
594 * Loop through all paragraphs, and assign a score to them based on how content-y they look.
595 * Then add their score to their parent node.
596 *
597 * A score is determined by things like number of commas, class names, etc. Maybe eventually link density.
598 **/
599 $candidates = array();
600 for ($pt=0; $pt < count($nodesToScore); $pt++) {
601 $parentNode = $nodesToScore[$pt]->parentNode;
602 // $grandParentNode = $parentNode ? $parentNode->parentNode : null;
603 $grandParentNode = !$parentNode ? null : (($parentNode->parentNode instanceof DOMElement) ? $parentNode->parentNode : null);
604 $innerText = $this->getInnerText($nodesToScore[$pt]);
605
606 if (!$parentNode || !isset($parentNode->tagName)) {
607 continue;
608 }
609
610 /* If this paragraph is less than 25 characters, don't even count it. */
611 if(strlen($innerText) < 25) {
612 continue;
613 }
614
615 /* Initialize readability data for the parent. */
616 if (!$parentNode->hasAttribute('readability'))
617 {
618 $this->initializeNode($parentNode);
619 $candidates[] = $parentNode;
620 }
621
622 /* Initialize readability data for the grandparent. */
623 if ($grandParentNode && !$grandParentNode->hasAttribute('readability') && isset($grandParentNode->tagName))
624 {
625 $this->initializeNode($grandParentNode);
626 $candidates[] = $grandParentNode;
627 }
628
629 $contentScore = 0;
630
631 /* Add a point for the paragraph itself as a base. */
632 $contentScore++;
633
634 /* Add points for any commas within this paragraph */
635 $contentScore += count(explode(',', $innerText));
636
637 /* For every 100 characters in this paragraph, add another point. Up to 3 points. */
638 $contentScore += min(floor(strlen($innerText) / 100), 3);
639
640 /* Add the score to the parent. The grandparent gets half. */
641 $parentNode->getAttributeNode('readability')->value += $contentScore;
642
643 if ($grandParentNode) {
644 $grandParentNode->getAttributeNode('readability')->value += $contentScore/2;
645 }
646 }
647
648 /**
649 * After we've calculated scores, loop through all of the possible candidate nodes we found
650 * and find the one with the highest score.
651 **/
652 $topCandidate = null;
653 for ($c=0, $cl=count($candidates); $c < $cl; $c++)
654 {
655 /**
656 * Scale the final candidates score based on link density. Good content should have a
657 * relatively small link density (5% or less) and be mostly unaffected by this operation.
658 **/
659 $readability = $candidates[$c]->getAttributeNode('readability');
660 $readability->value = $readability->value * (1-$this->getLinkDensity($candidates[$c]));
661
662 $this->dbg('Candidate: ' . $candidates[$c]->tagName . ' (' . $candidates[$c]->getAttribute('class') . ':' . $candidates[$c]->getAttribute('id') . ') with score ' . $readability->value);
663
664 if (!$topCandidate || $readability->value > (int)$topCandidate->getAttribute('readability')) {
665 $topCandidate = $candidates[$c];
666 }
667 }
668
669 /**
670 * If we still have no top candidate, just use the body as a last resort.
671 * We also have to copy the body node so it is something we can modify.
672 **/
673 if ($topCandidate === null || strtoupper($topCandidate->tagName) == 'BODY')
674 {
675 $topCandidate = $this->dom->createElement('div');
676 if ($page instanceof DOMDocument) {
677 if (!isset($page->documentElement)) {
678 // we don't have a body either? what a mess! :)
679 } else {
680 $topCandidate->innerHTML = $page->documentElement->innerHTML;
681 $page->documentElement->innerHTML = '';
682 $page->documentElement->appendChild($topCandidate);
683 }
684 } else {
685 $topCandidate->innerHTML = $page->innerHTML;
686 $page->innerHTML = '';
687 $page->appendChild($topCandidate);
688 }
689 $this->initializeNode($topCandidate);
690 }
691
692 /**
693 * Now that we have the top candidate, look through its siblings for content that might also be related.
694 * Things like preambles, content split by ads that we removed, etc.
695 **/
696 $articleContent = $this->dom->createElement('div');
697 $articleContent->setAttribute('id', 'readability-content');
698 $siblingScoreThreshold = max(10, ((int)$topCandidate->getAttribute('readability')) * 0.2);
699 $siblingNodes = $topCandidate->parentNode->childNodes;
700 if (!isset($siblingNodes)) {
701 $siblingNodes = new stdClass;
702 $siblingNodes->length = 0;
703 }
704
705 for ($s=0, $sl=$siblingNodes->length; $s < $sl; $s++)
706 {
707 $siblingNode = $siblingNodes->item($s);
708 $append = false;
709
710 $this->dbg('Looking at sibling node: ' . $siblingNode->nodeName . (($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('readability')) ? (' with score ' . $siblingNode->getAttribute('readability')) : ''));
711
712 //dbg('Sibling has score ' . ($siblingNode->readability ? siblingNode.readability.contentScore : 'Unknown'));
713
714 if ($siblingNode === $topCandidate)
715 // or if ($siblingNode->isSameNode($topCandidate))
716 {
717 $append = true;
718 }
719
720 $contentBonus = 0;
721 /* Give a bonus if sibling nodes and top candidates have the example same classname */
722 if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->getAttribute('class') == $topCandidate->getAttribute('class') && $topCandidate->getAttribute('class') != '') {
723 $contentBonus += ((int)$topCandidate->getAttribute('readability')) * 0.2;
724 }
725
726 if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('readability') && (((int)$siblingNode->getAttribute('readability')) + $contentBonus) >= $siblingScoreThreshold)
727 {
728 $append = true;
729 }
730
731 if (strtoupper($siblingNode->nodeName) == 'P') {
732 $linkDensity = $this->getLinkDensity($siblingNode);
733 $nodeContent = $this->getInnerText($siblingNode);
734 $nodeLength = strlen($nodeContent);
735
736 if ($nodeLength > 80 && $linkDensity < 0.25)
737 {
738 $append = true;
739 }
740 else if ($nodeLength < 80 && $linkDensity === 0 && preg_match('/\.( |$)/', $nodeContent))
741 {
742 $append = true;
743 }
744 }
745
746 if ($append)
747 {
748 $this->dbg('Appending node: ' . $siblingNode->nodeName);
749
750 $nodeToAppend = null;
751 $sibNodeName = strtoupper($siblingNode->nodeName);
752 if ($sibNodeName != 'DIV' && $sibNodeName != 'P') {
753 /* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */
754
755 $this->dbg('Altering siblingNode of ' . $sibNodeName . ' to div.');
756 $nodeToAppend = $this->dom->createElement('div');
757 try {
758 $nodeToAppend->setAttribute('id', $siblingNode->getAttribute('id'));
759 $nodeToAppend->innerHTML = $siblingNode->innerHTML;
760 }
761 catch(Exception $e)
762 {
763 $this->dbg('Could not alter siblingNode to div, reverting back to original.');
764 $nodeToAppend = $siblingNode;
765 $s--;
766 $sl--;
767 }
768 } else {
769 $nodeToAppend = $siblingNode;
770 $s--;
771 $sl--;
772 }
773
774 /* To ensure a node does not interfere with readability styles, remove its classnames */
775 $nodeToAppend->removeAttribute('class');
776
777 /* Append sibling and subtract from our list because it removes the node when you append to another node */
778 $articleContent->appendChild($nodeToAppend);
779 }
780 }
781
782 /**
783 * So we have all of the content that we need. Now we clean it up for presentation.
784 **/
785 $this->prepArticle($articleContent);
786
787 /**
788 * Now that we've gone through the full algorithm, check to see if we got any meaningful content.
789 * If we didn't, we may need to re-run grabArticle with different flags set. This gives us a higher
790 * likelihood of finding the content, and the sieve approach gives us a higher likelihood of
791 * finding the -right- content.
792 **/
793 if (strlen($this->getInnerText($articleContent, false)) < 250)
794 {
795 // TODO: find out why element disappears sometimes, e.g. for this URL http://www.businessinsider.com/6-hedge-fund-etfs-for-average-investors-2011-7
796 // in the meantime, we check and create an empty element if it's not there.
797 if (!isset($this->body->childNodes)) $this->body = $this->dom->createElement('body');
798 $this->body->innerHTML = $this->bodyCache;
799
800 if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) {
801 $this->removeFlag(self::FLAG_STRIP_UNLIKELYS);
802 return $this->grabArticle($this->body);
803 }
804 else if ($this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) {
805 $this->removeFlag(self::FLAG_WEIGHT_CLASSES);
806 return $this->grabArticle($this->body);
807 }
808 else if ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
809 $this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY);
810 return $this->grabArticle($this->body);
811 }
812 else {
813 return false;
814 }
815 }
816 return $articleContent;
817 }
818
819 /**
820 * Remove script tags from document
821 *
822 * @param DOMElement
823 * @return void
824 */
825 public function removeScripts($doc) {
826 $scripts = $doc->getElementsByTagName('script');
827 for($i = $scripts->length-1; $i >= 0; $i--)
828 {
829 $scripts->item($i)->parentNode->removeChild($scripts->item($i));
830 }
831 }
832
833 /**
834 * Get the inner text of a node.
835 * This also strips out any excess whitespace to be found.
836 *
837 * @param DOMElement $
838 * @param boolean $normalizeSpaces (default: true)
839 * @return string
840 **/
841 public function getInnerText($e, $normalizeSpaces=true) {
842 $textContent = '';
843
844 if (!isset($e->textContent) || $e->textContent == '') {
845 return '';
846 }
847
848 $textContent = trim($e->textContent);
849
850 if ($normalizeSpaces) {
851 return preg_replace($this->regexps['normalize'], ' ', $textContent);
852 } else {
853 return $textContent;
854 }
855 }
856
857 /**
858 * Get the number of times a string $s appears in the node $e.
859 *
860 * @param DOMElement $e
861 * @param string - what to count. Default is ","
862 * @return number (integer)
863 **/
864 public function getCharCount($e, $s=',') {
865 return substr_count($this->getInnerText($e), $s);
866 }
867
868 /**
869 * Remove the style attribute on every $e and under.
870 *
871 * @param DOMElement $e
872 * @return void
873 */
874 public function cleanStyles($e) {
875 if (!is_object($e)) return;
876 $elems = $e->getElementsByTagName('*');
877 foreach ($elems as $elem) {
878 $elem->removeAttribute('style');
879 }
880 }
881
882 /**
883 * Get the density of links as a percentage of the content
884 * This is the amount of text that is inside a link divided by the total text in the node.
885 *
886 * @param DOMElement $e
887 * @return number (float)
888 */
889 public function getLinkDensity($e) {
890 $links = $e->getElementsByTagName('a');
891 $textLength = strlen($this->getInnerText($e));
892 $linkLength = 0;
893 for ($i=0, $il=$links->length; $i < $il; $i++)
894 {
895 $linkLength += strlen($this->getInnerText($links->item($i)));
896 }
897 if ($textLength > 0) {
898 return $linkLength / $textLength;
899 } else {
900 return 0;
901 }
902 }
903
904 /**
905 * Get an elements class/id weight. Uses regular expressions to tell if this
906 * element looks good or bad.
907 *
908 * @param DOMElement $e
909 * @return number (Integer)
910 */
911 public function getClassWeight($e) {
912 if(!$this->flagIsActive(self::FLAG_WEIGHT_CLASSES)) {
913 return 0;
914 }
915
916 $weight = 0;
917
918 /* Look for a special classname */
919 if ($e->hasAttribute('class') && $e->getAttribute('class') != '')
920 {
921 if (preg_match($this->regexps['negative'], $e->getAttribute('class'))) {
922 $weight -= 25;
923 }
924 if (preg_match($this->regexps['positive'], $e->getAttribute('class'))) {
925 $weight += 25;
926 }
927 }
928
929 /* Look for a special ID */
930 if ($e->hasAttribute('id') && $e->getAttribute('id') != '')
931 {
932 if (preg_match($this->regexps['negative'], $e->getAttribute('id'))) {
933 $weight -= 25;
934 }
935 if (preg_match($this->regexps['positive'], $e->getAttribute('id'))) {
936 $weight += 25;
937 }
938 }
939 return $weight;
940 }
941
942 /**
943 * Remove extraneous break tags from a node.
944 *
945 * @param DOMElement $node
946 * @return void
947 */
948 public function killBreaks($node) {
949 $html = $node->innerHTML;
950 $html = preg_replace($this->regexps['killBreaks'], '<br />', $html);
951 $node->innerHTML = $html;
952 }
953
954 /**
955 * Clean a node of all elements of type "tag".
956 * (Unless it's a youtube/vimeo video. People love movies.)
957 *
958 * Updated 2012-09-18 to preserve youtube/vimeo iframes
959 *
960 * @param DOMElement $e
961 * @param string $tag
962 * @return void
963 */
964 public function clean($e, $tag) {
965 $targetList = $e->getElementsByTagName($tag);
966 $isEmbed = ($tag == 'iframe' || $tag == 'object' || $tag == 'embed');
967
968 for ($y=$targetList->length-1; $y >= 0; $y--) {
969 /* Allow youtube and vimeo videos through as people usually want to see those. */
970 if ($isEmbed) {
971 $attributeValues = '';
972 for ($i=0, $il=$targetList->item($y)->attributes->length; $i < $il; $i++) {
973 $attributeValues .= $targetList->item($y)->attributes->item($i)->value . '|'; // DOMAttr? (TODO: test)
974 }
975
976 /* First, check the elements attributes to see if any of them contain youtube or vimeo */
977 if (preg_match($this->regexps['video'], $attributeValues)) {
978 continue;
979 }
980
981 /* Then check the elements inside this element for the same. */
982 if (preg_match($this->regexps['video'], $targetList->item($y)->innerHTML)) {
983 continue;
984 }
985 }
986 $targetList->item($y)->parentNode->removeChild($targetList->item($y));
987 }
988 }
989
990 /**
991 * Clean an element of all tags of type "tag" if they look fishy.
992 * "Fishy" is an algorithm based on content length, classnames,
993 * link density, number of images & embeds, etc.
994 *
995 * @param DOMElement $e
996 * @param string $tag
997 * @return void
998 */
999 public function cleanConditionally($e, $tag) {
1000 if (!$this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
1001 return;
1002 }
1003
1004 $tagsList = $e->getElementsByTagName($tag);
1005 $curTagsLength = $tagsList->length;
1006
1007 /**
1008 * Gather counts for other typical elements embedded within.
1009 * Traverse backwards so we can remove nodes at the same time without effecting the traversal.
1010 *
1011 * TODO: Consider taking into account original contentScore here.
1012 */
1013 for ($i=$curTagsLength-1; $i >= 0; $i--) {
1014 $weight = $this->getClassWeight($tagsList->item($i));
1015 $contentScore = ($tagsList->item($i)->hasAttribute('readability')) ? (int)$tagsList->item($i)->getAttribute('readability') : 0;
1016
1017 $this->dbg('Cleaning Conditionally ' . $tagsList->item($i)->tagName . ' (' . $tagsList->item($i)->getAttribute('class') . ':' . $tagsList->item($i)->getAttribute('id') . ')' . (($tagsList->item($i)->hasAttribute('readability')) ? (' with score ' . $tagsList->item($i)->getAttribute('readability')) : ''));
1018
1019 if ($weight + $contentScore < 0) {
1020 $tagsList->item($i)->parentNode->removeChild($tagsList->item($i));
1021 }
1022 else if ( $this->getCharCount($tagsList->item($i), ',') < 10) {
1023 /**
1024 * If there are not very many commas, and the number of
1025 * non-paragraph elements is more than paragraphs or other ominous signs, remove the element.
1026 **/
1027 $p = $tagsList->item($i)->getElementsByTagName('p')->length;
1028 $img = $tagsList->item($i)->getElementsByTagName('img')->length;
1029 $li = $tagsList->item($i)->getElementsByTagName('li')->length-100;
1030 $input = $tagsList->item($i)->getElementsByTagName('input')->length;
1031 $a = $tagsList->item($i)->getElementsByTagName('a')->length;
1032
1033 $embedCount = 0;
1034 $embeds = $tagsList->item($i)->getElementsByTagName('embed');
1035 for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) {
1036 if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) {
1037 $embedCount++;
1038 }
1039 }
1040 $embeds = $tagsList->item($i)->getElementsByTagName('iframe');
1041 for ($ei=0, $il=$embeds->length; $ei < $il; $ei++) {
1042 if (preg_match($this->regexps['video'], $embeds->item($ei)->getAttribute('src'))) {
1043 $embedCount++;
1044 }
1045 }
1046
1047 $linkDensity = $this->getLinkDensity($tagsList->item($i));
1048 $contentLength = strlen($this->getInnerText($tagsList->item($i)));
1049 $toRemove = false;
1050
1051 if ($this->lightClean) {
1052 $this->dbg('Light clean...');
1053 if ( ($img > $p) && ($img > 4) ) {
1054 $this->dbg(' more than 4 images and more image elements than paragraph elements');
1055 $toRemove = true;
1056 } else if ($li > $p && $tag != 'ul' && $tag != 'ol') {
1057 $this->dbg(' too many <li> elements, and parent is not <ul> or <ol>');
1058 $toRemove = true;
1059 } else if ( $input > floor($p/3) ) {
1060 $this->dbg(' too many <input> elements');
1061 $toRemove = true;
1062 } else if ($contentLength < 25 && ($embedCount === 0 && ($img === 0 || $img > 2))) {
1063 $this->dbg(' content length less than 25 chars, 0 embeds and either 0 images or more than 2 images');
1064 $toRemove = true;
1065 } else if($weight < 25 && $linkDensity > 0.2) {
1066 $this->dbg(' weight smaller than 25 and link density above 0.2');
1067 $toRemove = true;
1068 } else if($a > 2 && ($weight >= 25 && $linkDensity > 0.5)) {
1069 $this->dbg(' more than 2 links and weight above 25 but link density greater than 0.5');
1070 $toRemove = true;
1071 } else if($embedCount > 3) {
1072 $this->dbg(' more than 3 embeds');
1073 $toRemove = true;
1074 }
1075 } else {
1076 $this->dbg('Standard clean...');
1077 if ( $img > $p ) {
1078 $this->dbg(' more image elements than paragraph elements');
1079 $toRemove = true;
1080 } else if ($li > $p && $tag != 'ul' && $tag != 'ol') {
1081 $this->dbg(' too many <li> elements, and parent is not <ul> or <ol>');
1082 $toRemove = true;
1083 } else if ( $input > floor($p/3) ) {
1084 $this->dbg(' too many <input> elements');
1085 $toRemove = true;
1086 } else if ($contentLength < 25 && ($img === 0 || $img > 2) ) {
1087 $this->dbg(' content length less than 25 chars and 0 images, or more than 2 images');
1088 $toRemove = true;
1089 } else if($weight < 25 && $linkDensity > 0.2) {
1090 $this->dbg(' weight smaller than 25 and link density above 0.2');
1091 $toRemove = true;
1092 } else if($weight >= 25 && $linkDensity > 0.5) {
1093 $this->dbg(' weight above 25 but link density greater than 0.5');
1094 $toRemove = true;
1095 } else if(($embedCount == 1 && $contentLength < 75) || $embedCount > 1) {
1096 $this->dbg(' 1 embed and content length smaller than 75 chars, or more than one embed');
1097 $toRemove = true;
1098 }
1099 }
1100
1101 if ($toRemove) {
1102 //$this->dbg('Removing: '.$tagsList->item($i)->innerHTML);
1103 $tagsList->item($i)->parentNode->removeChild($tagsList->item($i));
1104 }
1105 }
1106 }
1107 }
1108
1109 /**
1110 * Clean out spurious headers from an Element. Checks things like classnames and link density.
1111 *
1112 * @param DOMElement $e
1113 * @return void
1114 */
1115 public function cleanHeaders($e) {
1116 for ($headerIndex = 1; $headerIndex < 3; $headerIndex++) {
1117 $headers = $e->getElementsByTagName('h' . $headerIndex);
1118 for ($i=$headers->length-1; $i >=0; $i--) {
1119 if ($this->getClassWeight($headers->item($i)) < 0 || $this->getLinkDensity($headers->item($i)) > 0.33) {
1120 $headers->item($i)->parentNode->removeChild($headers->item($i));
1121 }
1122 }
1123 }
1124 }
1125
1126 public function flagIsActive($flag) {
1127 return ($this->flags & $flag) > 0;
1128 }
1129
1130 public function addFlag($flag) {
1131 $this->flags = $this->flags | $flag;
1132 }
1133
1134 public function removeFlag($flag) {
1135 $this->flags = $this->flags & ~$flag;
1136 }
1137}
1138?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/simplepie/LICENSE.txt b/inc/3rdparty/libraries/simplepie/LICENSE.txt
new file mode 100644
index 00000000..a822a4bd
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/LICENSE.txt
@@ -0,0 +1,26 @@
1Copyright (c) 2004-2007, Ryan Parman and Geoffrey Sneddon.
2All rights reserved.
3
4Redistribution and use in source and binary forms, with or without modification, are
5permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this list of
8 conditions and the following disclaimer.
9
10 * Redistributions in binary form must reproduce the above copyright notice, this list
11 of conditions and the following disclaimer in the documentation and/or other materials
12 provided with the distribution.
13
14 * Neither the name of the SimplePie Team nor the names of its contributors may be used
15 to endorse or promote products derived from this software without specific prior
16 written permission.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
19OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
21AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/inc/3rdparty/libraries/simplepie/autoloader.php b/inc/3rdparty/libraries/simplepie/autoloader.php
new file mode 100644
index 00000000..c16a8f8b
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/autoloader.php
@@ -0,0 +1,86 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46// autoloader
47spl_autoload_register(array(new SimplePie_Autoloader(), 'autoload'));
48
49if (!class_exists('SimplePie'))
50{
51 trigger_error('Autoloader not registered properly', E_USER_ERROR);
52}
53
54/**
55 * Autoloader class
56 *
57 * @package SimplePie
58 * @subpackage API
59 */
60class SimplePie_Autoloader
61{
62 /**
63 * Constructor
64 */
65 public function __construct()
66 {
67 $this->path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'library';
68 }
69
70 /**
71 * Autoloader
72 *
73 * @param string $class The name of the class to attempt to load.
74 */
75 public function autoload($class)
76 {
77 // Only load the class if it starts with "SimplePie"
78 if (strpos($class, 'SimplePie') !== 0)
79 {
80 return;
81 }
82
83 $filename = $this->path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
84 include $filename;
85 }
86} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie.php b/inc/3rdparty/libraries/simplepie/library/SimplePie.php
new file mode 100644
index 00000000..b33c635f
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie.php
@@ -0,0 +1,3058 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * SimplePie Name
47 */
48define('SIMPLEPIE_NAME', 'SimplePie');
49
50/**
51 * SimplePie Version
52 */
53define('SIMPLEPIE_VERSION', '1.3.1');
54
55/**
56 * SimplePie Build
57 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
58 */
59define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::get_build()));
60
61/**
62 * SimplePie Website URL
63 */
64define('SIMPLEPIE_URL', 'http://simplepie.org');
65
66/**
67 * SimplePie Useragent
68 * @see SimplePie::set_useragent()
69 */
70define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
71
72/**
73 * SimplePie Linkback
74 */
75define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
76
77/**
78 * No Autodiscovery
79 * @see SimplePie::set_autodiscovery_level()
80 */
81define('SIMPLEPIE_LOCATOR_NONE', 0);
82
83/**
84 * Feed Link Element Autodiscovery
85 * @see SimplePie::set_autodiscovery_level()
86 */
87define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
88
89/**
90 * Local Feed Extension Autodiscovery
91 * @see SimplePie::set_autodiscovery_level()
92 */
93define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
94
95/**
96 * Local Feed Body Autodiscovery
97 * @see SimplePie::set_autodiscovery_level()
98 */
99define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
100
101/**
102 * Remote Feed Extension Autodiscovery
103 * @see SimplePie::set_autodiscovery_level()
104 */
105define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
106
107/**
108 * Remote Feed Body Autodiscovery
109 * @see SimplePie::set_autodiscovery_level()
110 */
111define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
112
113/**
114 * All Feed Autodiscovery
115 * @see SimplePie::set_autodiscovery_level()
116 */
117define('SIMPLEPIE_LOCATOR_ALL', 31);
118
119/**
120 * No known feed type
121 */
122define('SIMPLEPIE_TYPE_NONE', 0);
123
124/**
125 * RSS 0.90
126 */
127define('SIMPLEPIE_TYPE_RSS_090', 1);
128
129/**
130 * RSS 0.91 (Netscape)
131 */
132define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
133
134/**
135 * RSS 0.91 (Userland)
136 */
137define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
138
139/**
140 * RSS 0.91 (both Netscape and Userland)
141 */
142define('SIMPLEPIE_TYPE_RSS_091', 6);
143
144/**
145 * RSS 0.92
146 */
147define('SIMPLEPIE_TYPE_RSS_092', 8);
148
149/**
150 * RSS 0.93
151 */
152define('SIMPLEPIE_TYPE_RSS_093', 16);
153
154/**
155 * RSS 0.94
156 */
157define('SIMPLEPIE_TYPE_RSS_094', 32);
158
159/**
160 * RSS 1.0
161 */
162define('SIMPLEPIE_TYPE_RSS_10', 64);
163
164/**
165 * RSS 2.0
166 */
167define('SIMPLEPIE_TYPE_RSS_20', 128);
168
169/**
170 * RDF-based RSS
171 */
172define('SIMPLEPIE_TYPE_RSS_RDF', 65);
173
174/**
175 * Non-RDF-based RSS (truly intended as syndication format)
176 */
177define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
178
179/**
180 * All RSS
181 */
182define('SIMPLEPIE_TYPE_RSS_ALL', 255);
183
184/**
185 * Atom 0.3
186 */
187define('SIMPLEPIE_TYPE_ATOM_03', 256);
188
189/**
190 * Atom 1.0
191 */
192define('SIMPLEPIE_TYPE_ATOM_10', 512);
193
194/**
195 * All Atom
196 */
197define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
198
199/**
200 * All feed types
201 */
202define('SIMPLEPIE_TYPE_ALL', 1023);
203
204/**
205 * No construct
206 */
207define('SIMPLEPIE_CONSTRUCT_NONE', 0);
208
209/**
210 * Text construct
211 */
212define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
213
214/**
215 * HTML construct
216 */
217define('SIMPLEPIE_CONSTRUCT_HTML', 2);
218
219/**
220 * XHTML construct
221 */
222define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
223
224/**
225 * base64-encoded construct
226 */
227define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
228
229/**
230 * IRI construct
231 */
232define('SIMPLEPIE_CONSTRUCT_IRI', 16);
233
234/**
235 * A construct that might be HTML
236 */
237define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
238
239/**
240 * All constructs
241 */
242define('SIMPLEPIE_CONSTRUCT_ALL', 63);
243
244/**
245 * Don't change case
246 */
247define('SIMPLEPIE_SAME_CASE', 1);
248
249/**
250 * Change to lowercase
251 */
252define('SIMPLEPIE_LOWERCASE', 2);
253
254/**
255 * Change to uppercase
256 */
257define('SIMPLEPIE_UPPERCASE', 4);
258
259/**
260 * PCRE for HTML attributes
261 */
262define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
263
264/**
265 * PCRE for XML attributes
266 */
267define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
268
269/**
270 * XML Namespace
271 */
272define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
273
274/**
275 * Atom 1.0 Namespace
276 */
277define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
278
279/**
280 * Atom 0.3 Namespace
281 */
282define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
283
284/**
285 * RDF Namespace
286 */
287define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
288
289/**
290 * RSS 0.90 Namespace
291 */
292define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
293
294/**
295 * RSS 1.0 Namespace
296 */
297define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
298
299/**
300 * RSS 1.0 Content Module Namespace
301 */
302define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
303
304/**
305 * RSS 2.0 Namespace
306 * (Stupid, I know, but I'm certain it will confuse people less with support.)
307 */
308define('SIMPLEPIE_NAMESPACE_RSS_20', '');
309
310/**
311 * DC 1.0 Namespace
312 */
313define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
314
315/**
316 * DC 1.1 Namespace
317 */
318define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
319
320/**
321 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
322 */
323define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
324
325/**
326 * GeoRSS Namespace
327 */
328define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
329
330/**
331 * Media RSS Namespace
332 */
333define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
334
335/**
336 * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
337 */
338define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
339
340/**
341 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
342 */
343define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
344
345/**
346 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
347 */
348define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
349
350/**
351 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
352 */
353define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
354
355/**
356 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
357 */
358define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
359
360/**
361 * iTunes RSS Namespace
362 */
363define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
364
365/**
366 * XHTML Namespace
367 */
368define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
369
370/**
371 * IANA Link Relations Registry
372 */
373define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
374
375/**
376 * No file source
377 */
378define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
379
380/**
381 * Remote file source
382 */
383define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
384
385/**
386 * Local file source
387 */
388define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
389
390/**
391 * fsockopen() file source
392 */
393define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
394
395/**
396 * cURL file source
397 */
398define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
399
400/**
401 * file_get_contents() file source
402 */
403define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
404
405
406
407/**
408 * SimplePie
409 *
410 * @package SimplePie
411 * @subpackage API
412 */
413class SimplePie
414{
415 /**
416 * @var array Raw data
417 * @access private
418 */
419 public $data = array();
420
421 /**
422 * @var mixed Error string
423 * @access private
424 */
425 public $error;
426
427 /**
428 * @var object Instance of SimplePie_Sanitize (or other class)
429 * @see SimplePie::set_sanitize_class()
430 * @access private
431 */
432 public $sanitize;
433
434 /**
435 * @var string SimplePie Useragent
436 * @see SimplePie::set_useragent()
437 * @access private
438 */
439 public $useragent = SIMPLEPIE_USERAGENT;
440
441 /**
442 * @var string Feed URL
443 * @see SimplePie::set_feed_url()
444 * @access private
445 */
446 public $feed_url;
447
448 /**
449 * @var object Instance of SimplePie_File to use as a feed
450 * @see SimplePie::set_file()
451 * @access private
452 */
453 public $file;
454
455 /**
456 * @var string Raw feed data
457 * @see SimplePie::set_raw_data()
458 * @access private
459 */
460 public $raw_data;
461
462 /**
463 * @var int Timeout for fetching remote files
464 * @see SimplePie::set_timeout()
465 * @access private
466 */
467 public $timeout = 10;
468
469 /**
470 * @var bool Forces fsockopen() to be used for remote files instead
471 * of cURL, even if a new enough version is installed
472 * @see SimplePie::force_fsockopen()
473 * @access private
474 */
475 public $force_fsockopen = false;
476
477 /**
478 * @var bool Force the given data/URL to be treated as a feed no matter what
479 * it appears like
480 * @see SimplePie::force_feed()
481 * @access private
482 */
483 public $force_feed = false;
484
485 /**
486 * @var bool Enable/Disable Caching
487 * @see SimplePie::enable_cache()
488 * @access private
489 */
490 public $cache = true;
491
492 /**
493 * @var int Cache duration (in seconds)
494 * @see SimplePie::set_cache_duration()
495 * @access private
496 */
497 public $cache_duration = 3600;
498
499 /**
500 * @var int Auto-discovery cache duration (in seconds)
501 * @see SimplePie::set_autodiscovery_cache_duration()
502 * @access private
503 */
504 public $autodiscovery_cache_duration = 604800; // 7 Days.
505
506 /**
507 * @var string Cache location (relative to executing script)
508 * @see SimplePie::set_cache_location()
509 * @access private
510 */
511 public $cache_location = './cache';
512
513 /**
514 * @var string Function that creates the cache filename
515 * @see SimplePie::set_cache_name_function()
516 * @access private
517 */
518 public $cache_name_function = 'md5';
519
520 /**
521 * @var bool Reorder feed by date descending
522 * @see SimplePie::enable_order_by_date()
523 * @access private
524 */
525 public $order_by_date = true;
526
527 /**
528 * @var mixed Force input encoding to be set to the follow value
529 * (false, or anything type-cast to false, disables this feature)
530 * @see SimplePie::set_input_encoding()
531 * @access private
532 */
533 public $input_encoding = false;
534
535 /**
536 * @var int Feed Autodiscovery Level
537 * @see SimplePie::set_autodiscovery_level()
538 * @access private
539 */
540 public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
541
542 /**
543 * Class registry object
544 *
545 * @var SimplePie_Registry
546 */
547 public $registry;
548
549 /**
550 * @var int Maximum number of feeds to check with autodiscovery
551 * @see SimplePie::set_max_checked_feeds()
552 * @access private
553 */
554 public $max_checked_feeds = 10;
555
556 /**
557 * @var array All the feeds found during the autodiscovery process
558 * @see SimplePie::get_all_discovered_feeds()
559 * @access private
560 */
561 public $all_discovered_feeds = array();
562
563 /**
564 * @var string Web-accessible path to the handler_image.php file.
565 * @see SimplePie::set_image_handler()
566 * @access private
567 */
568 public $image_handler = '';
569
570 /**
571 * @var array Stores the URLs when multiple feeds are being initialized.
572 * @see SimplePie::set_feed_url()
573 * @access private
574 */
575 public $multifeed_url = array();
576
577 /**
578 * @var array Stores SimplePie objects when multiple feeds initialized.
579 * @access private
580 */
581 public $multifeed_objects = array();
582
583 /**
584 * @var array Stores the get_object_vars() array for use with multifeeds.
585 * @see SimplePie::set_feed_url()
586 * @access private
587 */
588 public $config_settings = null;
589
590 /**
591 * @var integer Stores the number of items to return per-feed with multifeeds.
592 * @see SimplePie::set_item_limit()
593 * @access private
594 */
595 public $item_limit = 0;
596
597 /**
598 * @var array Stores the default attributes to be stripped by strip_attributes().
599 * @see SimplePie::strip_attributes()
600 * @access private
601 */
602 public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
603
604 /**
605 * @var array Stores the default tags to be stripped by strip_htmltags().
606 * @see SimplePie::strip_htmltags()
607 * @access private
608 */
609 public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
610
611 /**
612 * The SimplePie class contains feed level data and options
613 *
614 * To use SimplePie, create the SimplePie object with no parameters. You can
615 * then set configuration options using the provided methods. After setting
616 * them, you must initialise the feed using $feed->init(). At that point the
617 * object's methods and properties will be available to you.
618 *
619 * Previously, it was possible to pass in the feed URL along with cache
620 * options directly into the constructor. This has been removed as of 1.3 as
621 * it caused a lot of confusion.
622 *
623 * @since 1.0 Preview Release
624 */
625 public function __construct()
626 {
627 if (version_compare(PHP_VERSION, '5.2', '<'))
628 {
629 trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
630 die();
631 }
632
633 // Other objects, instances created here so we can set options on them
634 $this->sanitize = new SimplePie_Sanitize();
635 $this->registry = new SimplePie_Registry();
636
637 if (func_num_args() > 0)
638 {
639 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
640 trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
641
642 $args = func_get_args();
643 switch (count($args)) {
644 case 3:
645 $this->set_cache_duration($args[2]);
646 case 2:
647 $this->set_cache_location($args[1]);
648 case 1:
649 $this->set_feed_url($args[0]);
650 $this->init();
651 }
652 }
653 }
654
655 /**
656 * Used for converting object to a string
657 */
658 public function __toString()
659 {
660 return md5(serialize($this->data));
661 }
662
663 /**
664 * Remove items that link back to this before destroying this object
665 */
666 public function __destruct()
667 {
668 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
669 {
670 if (!empty($this->data['items']))
671 {
672 foreach ($this->data['items'] as $item)
673 {
674 $item->__destruct();
675 }
676 unset($item, $this->data['items']);
677 }
678 if (!empty($this->data['ordered_items']))
679 {
680 foreach ($this->data['ordered_items'] as $item)
681 {
682 $item->__destruct();
683 }
684 unset($item, $this->data['ordered_items']);
685 }
686 }
687 }
688
689 /**
690 * Force the given data/URL to be treated as a feed
691 *
692 * This tells SimplePie to ignore the content-type provided by the server.
693 * Be careful when using this option, as it will also disable autodiscovery.
694 *
695 * @since 1.1
696 * @param bool $enable Force the given data/URL to be treated as a feed
697 */
698 public function force_feed($enable = false)
699 {
700 $this->force_feed = (bool) $enable;
701 }
702
703 /**
704 * Set the URL of the feed you want to parse
705 *
706 * This allows you to enter the URL of the feed you want to parse, or the
707 * website you want to try to use auto-discovery on. This takes priority
708 * over any set raw data.
709 *
710 * You can set multiple feeds to mash together by passing an array instead
711 * of a string for the $url. Remember that with each additional feed comes
712 * additional processing and resources.
713 *
714 * @since 1.0 Preview Release
715 * @see set_raw_data()
716 * @param string|array $url This is the URL (or array of URLs) that you want to parse.
717 */
718 public function set_feed_url($url)
719 {
720 $this->multifeed_url = array();
721 if (is_array($url))
722 {
723 foreach ($url as $value)
724 {
725 $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
726 }
727 }
728 else
729 {
730 $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
731 }
732 }
733
734 /**
735 * Set an instance of {@see SimplePie_File} to use as a feed
736 *
737 * @param SimplePie_File &$file
738 * @return bool True on success, false on failure
739 */
740 public function set_file(&$file)
741 {
742 if ($file instanceof SimplePie_File)
743 {
744 $this->feed_url = $file->url;
745 $this->file =& $file;
746 return true;
747 }
748 return false;
749 }
750
751 /**
752 * Set the raw XML data to parse
753 *
754 * Allows you to use a string of RSS/Atom data instead of a remote feed.
755 *
756 * If you have a feed available as a string in PHP, you can tell SimplePie
757 * to parse that data string instead of a remote feed. Any set feed URL
758 * takes precedence.
759 *
760 * @since 1.0 Beta 3
761 * @param string $data RSS or Atom data as a string.
762 * @see set_feed_url()
763 */
764 public function set_raw_data($data)
765 {
766 $this->raw_data = $data;
767 }
768
769 /**
770 * Set the the default timeout for fetching remote feeds
771 *
772 * This allows you to change the maximum time the feed's server to respond
773 * and send the feed back.
774 *
775 * @since 1.0 Beta 3
776 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
777 */
778 public function set_timeout($timeout = 10)
779 {
780 $this->timeout = (int) $timeout;
781 }
782
783 /**
784 * Force SimplePie to use fsockopen() instead of cURL
785 *
786 * @since 1.0 Beta 3
787 * @param bool $enable Force fsockopen() to be used
788 */
789 public function force_fsockopen($enable = false)
790 {
791 $this->force_fsockopen = (bool) $enable;
792 }
793
794 /**
795 * Enable/disable caching in SimplePie.
796 *
797 * This option allows you to disable caching all-together in SimplePie.
798 * However, disabling the cache can lead to longer load times.
799 *
800 * @since 1.0 Preview Release
801 * @param bool $enable Enable caching
802 */
803 public function enable_cache($enable = true)
804 {
805 $this->cache = (bool) $enable;
806 }
807
808 /**
809 * Set the length of time (in seconds) that the contents of a feed will be
810 * cached
811 *
812 * @param int $seconds The feed content cache duration
813 */
814 public function set_cache_duration($seconds = 3600)
815 {
816 $this->cache_duration = (int) $seconds;
817 }
818
819 /**
820 * Set the length of time (in seconds) that the autodiscovered feed URL will
821 * be cached
822 *
823 * @param int $seconds The autodiscovered feed URL cache duration.
824 */
825 public function set_autodiscovery_cache_duration($seconds = 604800)
826 {
827 $this->autodiscovery_cache_duration = (int) $seconds;
828 }
829
830 /**
831 * Set the file system location where the cached files should be stored
832 *
833 * @param string $location The file system location.
834 */
835 public function set_cache_location($location = './cache')
836 {
837 $this->cache_location = (string) $location;
838 }
839
840 /**
841 * Set whether feed items should be sorted into reverse chronological order
842 *
843 * @param bool $enable Sort as reverse chronological order.
844 */
845 public function enable_order_by_date($enable = true)
846 {
847 $this->order_by_date = (bool) $enable;
848 }
849
850 /**
851 * Set the character encoding used to parse the feed
852 *
853 * This overrides the encoding reported by the feed, however it will fall
854 * back to the normal encoding detection if the override fails
855 *
856 * @param string $encoding Character encoding
857 */
858 public function set_input_encoding($encoding = false)
859 {
860 if ($encoding)
861 {
862 $this->input_encoding = (string) $encoding;
863 }
864 else
865 {
866 $this->input_encoding = false;
867 }
868 }
869
870 /**
871 * Set how much feed autodiscovery to do
872 *
873 * @see SIMPLEPIE_LOCATOR_NONE
874 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
875 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
876 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
877 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
878 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
879 * @see SIMPLEPIE_LOCATOR_ALL
880 * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
881 */
882 public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
883 {
884 $this->autodiscovery = (int) $level;
885 }
886
887 /**
888 * Get the class registry
889 *
890 * Use this to override SimplePie's default classes
891 * @see SimplePie_Registry
892 * @return SimplePie_Registry
893 */
894 public function &get_registry()
895 {
896 return $this->registry;
897 }
898
899 /**#@+
900 * Useful when you are overloading or extending SimplePie's default classes.
901 *
902 * @deprecated Use {@see get_registry()} instead
903 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
904 * @param string $class Name of custom class
905 * @return boolean True on success, false otherwise
906 */
907 /**
908 * Set which class SimplePie uses for caching
909 */
910 public function set_cache_class($class = 'SimplePie_Cache')
911 {
912 return $this->registry->register('Cache', $class, true);
913 }
914
915 /**
916 * Set which class SimplePie uses for auto-discovery
917 */
918 public function set_locator_class($class = 'SimplePie_Locator')
919 {
920 return $this->registry->register('Locator', $class, true);
921 }
922
923 /**
924 * Set which class SimplePie uses for XML parsing
925 */
926 public function set_parser_class($class = 'SimplePie_Parser')
927 {
928 return $this->registry->register('Parser', $class, true);
929 }
930
931 /**
932 * Set which class SimplePie uses for remote file fetching
933 */
934 public function set_file_class($class = 'SimplePie_File')
935 {
936 return $this->registry->register('File', $class, true);
937 }
938
939 /**
940 * Set which class SimplePie uses for data sanitization
941 */
942 public function set_sanitize_class($class = 'SimplePie_Sanitize')
943 {
944 return $this->registry->register('Sanitize', $class, true);
945 }
946
947 /**
948 * Set which class SimplePie uses for handling feed items
949 */
950 public function set_item_class($class = 'SimplePie_Item')
951 {
952 return $this->registry->register('Item', $class, true);
953 }
954
955 /**
956 * Set which class SimplePie uses for handling author data
957 */
958 public function set_author_class($class = 'SimplePie_Author')
959 {
960 return $this->registry->register('Author', $class, true);
961 }
962
963 /**
964 * Set which class SimplePie uses for handling category data
965 */
966 public function set_category_class($class = 'SimplePie_Category')
967 {
968 return $this->registry->register('Category', $class, true);
969 }
970
971 /**
972 * Set which class SimplePie uses for feed enclosures
973 */
974 public function set_enclosure_class($class = 'SimplePie_Enclosure')
975 {
976 return $this->registry->register('Enclosure', $class, true);
977 }
978
979 /**
980 * Set which class SimplePie uses for `<media:text>` captions
981 */
982 public function set_caption_class($class = 'SimplePie_Caption')
983 {
984 return $this->registry->register('Caption', $class, true);
985 }
986
987 /**
988 * Set which class SimplePie uses for `<media:copyright>`
989 */
990 public function set_copyright_class($class = 'SimplePie_Copyright')
991 {
992 return $this->registry->register('Copyright', $class, true);
993 }
994
995 /**
996 * Set which class SimplePie uses for `<media:credit>`
997 */
998 public function set_credit_class($class = 'SimplePie_Credit')
999 {
1000 return $this->registry->register('Credit', $class, true);
1001 }
1002
1003 /**
1004 * Set which class SimplePie uses for `<media:rating>`
1005 */
1006 public function set_rating_class($class = 'SimplePie_Rating')
1007 {
1008 return $this->registry->register('Rating', $class, true);
1009 }
1010
1011 /**
1012 * Set which class SimplePie uses for `<media:restriction>`
1013 */
1014 public function set_restriction_class($class = 'SimplePie_Restriction')
1015 {
1016 return $this->registry->register('Restriction', $class, true);
1017 }
1018
1019 /**
1020 * Set which class SimplePie uses for content-type sniffing
1021 */
1022 public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1023 {
1024 return $this->registry->register('Content_Type_Sniffer', $class, true);
1025 }
1026
1027 /**
1028 * Set which class SimplePie uses item sources
1029 */
1030 public function set_source_class($class = 'SimplePie_Source')
1031 {
1032 return $this->registry->register('Source', $class, true);
1033 }
1034 /**#@-*/
1035
1036 /**
1037 * Set the user agent string
1038 *
1039 * @param string $ua New user agent string.
1040 */
1041 public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1042 {
1043 $this->useragent = (string) $ua;
1044 }
1045
1046 /**
1047 * Set callback function to create cache filename with
1048 *
1049 * @param mixed $function Callback function
1050 */
1051 public function set_cache_name_function($function = 'md5')
1052 {
1053 if (is_callable($function))
1054 {
1055 $this->cache_name_function = $function;
1056 }
1057 }
1058
1059 /**
1060 * Set options to make SP as fast as possible
1061 *
1062 * Forgoes a substantial amount of data sanitization in favor of speed. This
1063 * turns SimplePie into a dumb parser of feeds.
1064 *
1065 * @param bool $set Whether to set them or not
1066 */
1067 public function set_stupidly_fast($set = false)
1068 {
1069 if ($set)
1070 {
1071 $this->enable_order_by_date(false);
1072 $this->remove_div(false);
1073 $this->strip_comments(false);
1074 $this->strip_htmltags(false);
1075 $this->strip_attributes(false);
1076 $this->set_image_handler(false);
1077 }
1078 }
1079
1080 /**
1081 * Set maximum number of feeds to check with autodiscovery
1082 *
1083 * @param int $max Maximum number of feeds to check
1084 */
1085 public function set_max_checked_feeds($max = 10)
1086 {
1087 $this->max_checked_feeds = (int) $max;
1088 }
1089
1090 public function remove_div($enable = true)
1091 {
1092 $this->sanitize->remove_div($enable);
1093 }
1094
1095 public function strip_htmltags($tags = '', $encode = null)
1096 {
1097 if ($tags === '')
1098 {
1099 $tags = $this->strip_htmltags;
1100 }
1101 $this->sanitize->strip_htmltags($tags);
1102 if ($encode !== null)
1103 {
1104 $this->sanitize->encode_instead_of_strip($tags);
1105 }
1106 }
1107
1108 public function encode_instead_of_strip($enable = true)
1109 {
1110 $this->sanitize->encode_instead_of_strip($enable);
1111 }
1112
1113 public function strip_attributes($attribs = '')
1114 {
1115 if ($attribs === '')
1116 {
1117 $attribs = $this->strip_attributes;
1118 }
1119 $this->sanitize->strip_attributes($attribs);
1120 }
1121
1122 /**
1123 * Set the output encoding
1124 *
1125 * Allows you to override SimplePie's output to match that of your webpage.
1126 * This is useful for times when your webpages are not being served as
1127 * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
1128 * is similar to {@see set_input_encoding()}.
1129 *
1130 * It should be noted, however, that not all character encodings can support
1131 * all characters. If your page is being served as ISO-8859-1 and you try
1132 * to display a Japanese feed, you'll likely see garbled characters.
1133 * Because of this, it is highly recommended to ensure that your webpages
1134 * are served as UTF-8.
1135 *
1136 * The number of supported character encodings depends on whether your web
1137 * host supports {@link http://php.net/mbstring mbstring},
1138 * {@link http://php.net/iconv iconv}, or both. See
1139 * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
1140 * more information.
1141 *
1142 * @param string $encoding
1143 */
1144 public function set_output_encoding($encoding = 'UTF-8')
1145 {
1146 $this->sanitize->set_output_encoding($encoding);
1147 }
1148
1149 public function strip_comments($strip = false)
1150 {
1151 $this->sanitize->strip_comments($strip);
1152 }
1153
1154 /**
1155 * Set element/attribute key/value pairs of HTML attributes
1156 * containing URLs that need to be resolved relative to the feed
1157 *
1158 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1159 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1160 * |q|@cite
1161 *
1162 * @since 1.0
1163 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
1164 */
1165 public function set_url_replacements($element_attribute = null)
1166 {
1167 $this->sanitize->set_url_replacements($element_attribute);
1168 }
1169
1170 /**
1171 * Set the handler to enable the display of cached images.
1172 *
1173 * @param str $page Web-accessible path to the handler_image.php file.
1174 * @param str $qs The query string that the value should be passed to.
1175 */
1176 public function set_image_handler($page = false, $qs = 'i')
1177 {
1178 if ($page !== false)
1179 {
1180 $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1181 }
1182 else
1183 {
1184 $this->image_handler = '';
1185 }
1186 }
1187
1188 /**
1189 * Set the limit for items returned per-feed with multifeeds
1190 *
1191 * @param integer $limit The maximum number of items to return.
1192 */
1193 public function set_item_limit($limit = 0)
1194 {
1195 $this->item_limit = (int) $limit;
1196 }
1197
1198 /**
1199 * Initialize the feed object
1200 *
1201 * This is what makes everything happen. Period. This is where all of the
1202 * configuration options get processed, feeds are fetched, cached, and
1203 * parsed, and all of that other good stuff.
1204 *
1205 * @return boolean True if successful, false otherwise
1206 */
1207 public function init()
1208 {
1209 // Check absolute bare minimum requirements.
1210 if (!extension_loaded('xml') || !extension_loaded('pcre'))
1211 {
1212 return false;
1213 }
1214 // Then check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader.
1215 elseif (!extension_loaded('xmlreader'))
1216 {
1217 static $xml_is_sane = null;
1218 if ($xml_is_sane === null)
1219 {
1220 $parser_check = xml_parser_create();
1221 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1222 xml_parser_free($parser_check);
1223 $xml_is_sane = isset($values[0]['value']);
1224 }
1225 if (!$xml_is_sane)
1226 {
1227 return false;
1228 }
1229 }
1230
1231 if (method_exists($this->sanitize, 'set_registry'))
1232 {
1233 $this->sanitize->set_registry($this->registry);
1234 }
1235
1236 // Pass whatever was set with config options over to the sanitizer.
1237 // Pass the classes in for legacy support; new classes should use the registry instead
1238 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
1239 $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
1240
1241 if (!empty($this->multifeed_url))
1242 {
1243 $i = 0;
1244 $success = 0;
1245 $this->multifeed_objects = array();
1246 $this->error = array();
1247 foreach ($this->multifeed_url as $url)
1248 {
1249 $this->multifeed_objects[$i] = clone $this;
1250 $this->multifeed_objects[$i]->set_feed_url($url);
1251 $single_success = $this->multifeed_objects[$i]->init();
1252 $success |= $single_success;
1253 if (!$single_success)
1254 {
1255 $this->error[$i] = $this->multifeed_objects[$i]->error();
1256 }
1257 $i++;
1258 }
1259 return (bool) $success;
1260 }
1261 elseif ($this->feed_url === null && $this->raw_data === null)
1262 {
1263 return false;
1264 }
1265
1266 $this->error = null;
1267 $this->data = array();
1268 $this->multifeed_objects = array();
1269 $cache = false;
1270
1271 if ($this->feed_url !== null)
1272 {
1273 $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
1274
1275 // Decide whether to enable caching
1276 if ($this->cache && $parsed_feed_url['scheme'] !== '')
1277 {
1278 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
1279 }
1280
1281 // Fetch the data via SimplePie_File into $this->raw_data
1282 if (($fetched = $this->fetch_data($cache)) === true)
1283 {
1284 return true;
1285 }
1286 elseif ($fetched === false) {
1287 return false;
1288 }
1289
1290 list($headers, $sniffed) = $fetched;
1291 }
1292
1293 // Set up array of possible encodings
1294 $encodings = array();
1295
1296 // First check to see if input has been overridden.
1297 if ($this->input_encoding !== false)
1298 {
1299 $encodings[] = $this->input_encoding;
1300 }
1301
1302 $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1303 $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1304
1305 // RFC 3023 (only applies to sniffed content)
1306 if (isset($sniffed))
1307 {
1308 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1309 {
1310 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1311 {
1312 $encodings[] = strtoupper($charset[1]);
1313 }
1314 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1315 $encodings[] = 'UTF-8';
1316 }
1317 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1318 {
1319 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1320 {
1321 $encodings[] = $charset[1];
1322 }
1323 $encodings[] = 'US-ASCII';
1324 }
1325 // Text MIME-type default
1326 elseif (substr($sniffed, 0, 5) === 'text/')
1327 {
1328 $encodings[] = 'US-ASCII';
1329 }
1330 }
1331
1332 // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1333 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1334 $encodings[] = 'UTF-8';
1335 $encodings[] = 'ISO-8859-1';
1336
1337 // There's no point in trying an encoding twice
1338 $encodings = array_unique($encodings);
1339
1340 // Loop through each possible encoding, till we return something, or run out of possibilities
1341 foreach ($encodings as $encoding)
1342 {
1343 // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1344 if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
1345 {
1346 // Create new parser
1347 $parser = $this->registry->create('Parser');
1348
1349 // If it's parsed fine
1350 if ($parser->parse($utf8_data, 'UTF-8'))
1351 {
1352 $this->data = $parser->get_data();
1353 if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
1354 {
1355 $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1356 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1357 return false;
1358 }
1359
1360 if (isset($headers))
1361 {
1362 $this->data['headers'] = $headers;
1363 }
1364 $this->data['build'] = SIMPLEPIE_BUILD;
1365
1366 // Cache the file if caching is enabled
1367 if ($cache && !$cache->save($this))
1368 {
1369 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1370 }
1371 return true;
1372 }
1373 }
1374 }
1375
1376 if (isset($parser))
1377 {
1378 // We have an error, just set SimplePie_Misc::error to it and quit
1379 $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
1380 }
1381 else
1382 {
1383 $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.';
1384 }
1385
1386 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1387
1388 return false;
1389 }
1390
1391 /**
1392 * Fetch the data via SimplePie_File
1393 *
1394 * If the data is already cached, attempt to fetch it from there instead
1395 * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
1396 * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
1397 */
1398 protected function fetch_data(&$cache)
1399 {
1400 // If it's enabled, use the cache
1401 if ($cache)
1402 {
1403 // Load the Cache
1404 $this->data = $cache->load();
1405 if (!empty($this->data))
1406 {
1407 // If the cache is for an outdated build of SimplePie
1408 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1409 {
1410 $cache->unlink();
1411 $this->data = array();
1412 }
1413 // If we've hit a collision just rerun it with caching disabled
1414 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1415 {
1416 $cache = false;
1417 $this->data = array();
1418 }
1419 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1420 elseif (isset($this->data['feed_url']))
1421 {
1422 // If the autodiscovery cache is still valid use it.
1423 if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1424 {
1425 // Do not need to do feed autodiscovery yet.
1426 if ($this->data['feed_url'] !== $this->data['url'])
1427 {
1428 $this->set_feed_url($this->data['feed_url']);
1429 return $this->init();
1430 }
1431
1432 $cache->unlink();
1433 $this->data = array();
1434 }
1435 }
1436 // Check if the cache has been updated
1437 elseif ($cache->mtime() + $this->cache_duration < time())
1438 {
1439 // If we have last-modified and/or etag set
1440 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1441 {
1442 $headers = array(
1443 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1444 );
1445 if (isset($this->data['headers']['last-modified']))
1446 {
1447 $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1448 }
1449 if (isset($this->data['headers']['etag']))
1450 {
1451 $headers['if-none-match'] = $this->data['headers']['etag'];
1452 }
1453
1454 $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
1455
1456 if ($file->success)
1457 {
1458 if ($file->status_code === 304)
1459 {
1460 $cache->touch();
1461 return true;
1462 }
1463 }
1464 else
1465 {
1466 unset($file);
1467 }
1468 }
1469 }
1470 // If the cache is still valid, just return true
1471 else
1472 {
1473 $this->raw_data = false;
1474 return true;
1475 }
1476 }
1477 // If the cache is empty, delete it
1478 else
1479 {
1480 $cache->unlink();
1481 $this->data = array();
1482 }
1483 }
1484 // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
1485 if (!isset($file))
1486 {
1487 if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
1488 {
1489 $file =& $this->file;
1490 }
1491 else
1492 {
1493 $headers = array(
1494 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1495 );
1496 $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
1497 }
1498 }
1499 // If the file connection has an error, set SimplePie::error to that and quit
1500 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1501 {
1502 $this->error = $file->error;
1503 return !empty($this->data);
1504 }
1505
1506 if (!$this->force_feed)
1507 {
1508 // Check if the supplied URL is a feed, if it isn't, look for it.
1509 $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
1510
1511 if (!$locate->is_feed($file))
1512 {
1513 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1514 unset($file);
1515 try
1516 {
1517 if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
1518 {
1519 $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed.";
1520 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1521 return false;
1522 }
1523 }
1524 catch (SimplePie_Exception $e)
1525 {
1526 // This is usually because DOMDocument doesn't exist
1527 $this->error = $e->getMessage();
1528 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
1529 return false;
1530 }
1531 if ($cache)
1532 {
1533 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1534 if (!$cache->save($this))
1535 {
1536 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1537 }
1538 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
1539 }
1540 $this->feed_url = $file->url;
1541 }
1542 $locate = null;
1543 }
1544
1545 $this->raw_data = $file->body;
1546
1547 $headers = $file->headers;
1548 $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1549 $sniffed = $sniffer->get_type();
1550
1551 return array($headers, $sniffed);
1552 }
1553
1554 /**
1555 * Get the error message for the occured error
1556 *
1557 * @return string|array Error message, or array of messages for multifeeds
1558 */
1559 public function error()
1560 {
1561 return $this->error;
1562 }
1563
1564 /**
1565 * Get the raw XML
1566 *
1567 * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1568 * the data instead of printing it.
1569 *
1570 * @return string|boolean Raw XML data, false if the cache is used
1571 */
1572 public function get_raw_data()
1573 {
1574 return $this->raw_data;
1575 }
1576
1577 /**
1578 * Get the character encoding used for output
1579 *
1580 * @since Preview Release
1581 * @return string
1582 */
1583 public function get_encoding()
1584 {
1585 return $this->sanitize->output_encoding;
1586 }
1587
1588 /**
1589 * Send the content-type header with correct encoding
1590 *
1591 * This method ensures that the SimplePie-enabled page is being served with
1592 * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
1593 * and character encoding HTTP headers (character encoding determined by the
1594 * {@see set_output_encoding} config option).
1595 *
1596 * This won't work properly if any content or whitespace has already been
1597 * sent to the browser, because it relies on PHP's
1598 * {@link http://php.net/header header()} function, and these are the
1599 * circumstances under which the function works.
1600 *
1601 * Because it's setting these settings for the entire page (as is the nature
1602 * of HTTP headers), this should only be used once per page (again, at the
1603 * top).
1604 *
1605 * @param string $mime MIME type to serve the page as
1606 */
1607 public function handle_content_type($mime = 'text/html')
1608 {
1609 if (!headers_sent())
1610 {
1611 $header = "Content-type: $mime;";
1612 if ($this->get_encoding())
1613 {
1614 $header .= ' charset=' . $this->get_encoding();
1615 }
1616 else
1617 {
1618 $header .= ' charset=UTF-8';
1619 }
1620 header($header);
1621 }
1622 }
1623
1624 /**
1625 * Get the type of the feed
1626 *
1627 * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1628 * using {@link http://php.net/language.operators.bitwise bitwise operators}
1629 *
1630 * @since 0.8 (usage changed to using constants in 1.0)
1631 * @see SIMPLEPIE_TYPE_NONE Unknown.
1632 * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
1633 * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
1634 * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
1635 * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
1636 * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
1637 * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
1638 * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
1639 * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
1640 * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
1641 * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
1642 * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
1643 * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
1644 * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
1645 * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
1646 * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
1647 * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
1648 * @return int SIMPLEPIE_TYPE_* constant
1649 */
1650 public function get_type()
1651 {
1652 if (!isset($this->data['type']))
1653 {
1654 $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1655 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1656 {
1657 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1658 }
1659 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1660 {
1661 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1662 }
1663 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1664 {
1665 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1666 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1667 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1668 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1669 {
1670 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1671 }
1672 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1673 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1674 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1675 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1676 {
1677 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1678 }
1679 }
1680 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1681 {
1682 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1683 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1684 {
1685 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1686 {
1687 case '0.91':
1688 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1689 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1690 {
1691 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1692 {
1693 case '0':
1694 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1695 break;
1696
1697 case '24':
1698 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1699 break;
1700 }
1701 }
1702 break;
1703
1704 case '0.92':
1705 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1706 break;
1707
1708 case '0.93':
1709 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1710 break;
1711
1712 case '0.94':
1713 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1714 break;
1715
1716 case '2.0':
1717 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1718 break;
1719 }
1720 }
1721 }
1722 else
1723 {
1724 $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1725 }
1726 }
1727 return $this->data['type'];
1728 }
1729
1730 /**
1731 * Get the URL for the feed
1732 *
1733 * May or may not be different from the URL passed to {@see set_feed_url()},
1734 * depending on whether auto-discovery was used.
1735 *
1736 * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
1737 * @todo If we have a perm redirect we should return the new URL
1738 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
1739 * @todo Also, |atom:link|@rel=self
1740 * @return string|null
1741 */
1742 public function subscribe_url()
1743 {
1744 if ($this->feed_url !== null)
1745 {
1746 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1747 }
1748 else
1749 {
1750 return null;
1751 }
1752 }
1753
1754 /**
1755 * Get data for an feed-level element
1756 *
1757 * This method allows you to get access to ANY element/attribute that is a
1758 * sub-element of the opening feed tag.
1759 *
1760 * The return value is an indexed array of elements matching the given
1761 * namespace and tag name. Each element has `attribs`, `data` and `child`
1762 * subkeys. For `attribs` and `child`, these contain namespace subkeys.
1763 * `attribs` then has one level of associative name => value data (where
1764 * `value` is a string) after the namespace. `child` has tag-indexed keys
1765 * after the namespace, each member of which is an indexed array matching
1766 * this same format.
1767 *
1768 * For example:
1769 * <pre>
1770 * // This is probably a bad example because we already support
1771 * // <media:content> natively, but it shows you how to parse through
1772 * // the nodes.
1773 * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
1774 * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
1775 * $file = $content[0]['attribs']['']['url'];
1776 * echo $file;
1777 * </pre>
1778 *
1779 * @since 1.0
1780 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1781 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1782 * @param string $tag Tag name
1783 * @return array
1784 */
1785 public function get_feed_tags($namespace, $tag)
1786 {
1787 $type = $this->get_type();
1788 if ($type & SIMPLEPIE_TYPE_ATOM_10)
1789 {
1790 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1791 {
1792 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1793 }
1794 }
1795 if ($type & SIMPLEPIE_TYPE_ATOM_03)
1796 {
1797 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1798 {
1799 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1800 }
1801 }
1802 if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1803 {
1804 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1805 {
1806 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1807 }
1808 }
1809 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1810 {
1811 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
1812 {
1813 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
1814 }
1815 }
1816 return null;
1817 }
1818
1819 /**
1820 * Get data for an channel-level element
1821 *
1822 * This method allows you to get access to ANY element/attribute in the
1823 * channel/header section of the feed.
1824 *
1825 * See {@see SimplePie::get_feed_tags()} for a description of the return value
1826 *
1827 * @since 1.0
1828 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1829 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1830 * @param string $tag Tag name
1831 * @return array
1832 */
1833 public function get_channel_tags($namespace, $tag)
1834 {
1835 $type = $this->get_type();
1836 if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1837 {
1838 if ($return = $this->get_feed_tags($namespace, $tag))
1839 {
1840 return $return;
1841 }
1842 }
1843 if ($type & SIMPLEPIE_TYPE_RSS_10)
1844 {
1845 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1846 {
1847 if (isset($channel[0]['child'][$namespace][$tag]))
1848 {
1849 return $channel[0]['child'][$namespace][$tag];
1850 }
1851 }
1852 }
1853 if ($type & SIMPLEPIE_TYPE_RSS_090)
1854 {
1855 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1856 {
1857 if (isset($channel[0]['child'][$namespace][$tag]))
1858 {
1859 return $channel[0]['child'][$namespace][$tag];
1860 }
1861 }
1862 }
1863 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1864 {
1865 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
1866 {
1867 if (isset($channel[0]['child'][$namespace][$tag]))
1868 {
1869 return $channel[0]['child'][$namespace][$tag];
1870 }
1871 }
1872 }
1873 return null;
1874 }
1875
1876 /**
1877 * Get data for an channel-level element
1878 *
1879 * This method allows you to get access to ANY element/attribute in the
1880 * image/logo section of the feed.
1881 *
1882 * See {@see SimplePie::get_feed_tags()} for a description of the return value
1883 *
1884 * @since 1.0
1885 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1886 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1887 * @param string $tag Tag name
1888 * @return array
1889 */
1890 public function get_image_tags($namespace, $tag)
1891 {
1892 $type = $this->get_type();
1893 if ($type & SIMPLEPIE_TYPE_RSS_10)
1894 {
1895 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1896 {
1897 if (isset($image[0]['child'][$namespace][$tag]))
1898 {
1899 return $image[0]['child'][$namespace][$tag];
1900 }
1901 }
1902 }
1903 if ($type & SIMPLEPIE_TYPE_RSS_090)
1904 {
1905 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1906 {
1907 if (isset($image[0]['child'][$namespace][$tag]))
1908 {
1909 return $image[0]['child'][$namespace][$tag];
1910 }
1911 }
1912 }
1913 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1914 {
1915 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
1916 {
1917 if (isset($image[0]['child'][$namespace][$tag]))
1918 {
1919 return $image[0]['child'][$namespace][$tag];
1920 }
1921 }
1922 }
1923 return null;
1924 }
1925
1926 /**
1927 * Get the base URL value from the feed
1928 *
1929 * Uses `<xml:base>` if available, otherwise uses the first link in the
1930 * feed, or failing that, the URL of the feed itself.
1931 *
1932 * @see get_link
1933 * @see subscribe_url
1934 *
1935 * @param array $element
1936 * @return string
1937 */
1938 public function get_base($element = array())
1939 {
1940 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1941 {
1942 return $element['xml_base'];
1943 }
1944 elseif ($this->get_link() !== null)
1945 {
1946 return $this->get_link();
1947 }
1948 else
1949 {
1950 return $this->subscribe_url();
1951 }
1952 }
1953
1954 /**
1955 * Sanitize feed data
1956 *
1957 * @access private
1958 * @see SimplePie_Sanitize::sanitize()
1959 * @param string $data Data to sanitize
1960 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
1961 * @param string $base Base URL to resolve URLs against
1962 * @return string Sanitized data
1963 */
1964 public function sanitize($data, $type, $base = '')
1965 {
1966 return $this->sanitize->sanitize($data, $type, $base);
1967 }
1968
1969 /**
1970 * Get the title of the feed
1971 *
1972 * Uses `<atom:title>`, `<title>` or `<dc:title>`
1973 *
1974 * @since 1.0 (previously called `get_feed_title` since 0.8)
1975 * @return string|null
1976 */
1977 public function get_title()
1978 {
1979 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1980 {
1981 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1982 }
1983 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1984 {
1985 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1986 }
1987 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1988 {
1989 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1990 }
1991 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1992 {
1993 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1994 }
1995 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1996 {
1997 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1998 }
1999 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2000 {
2001 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2002 }
2003 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2004 {
2005 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2006 }
2007 else
2008 {
2009 return null;
2010 }
2011 }
2012
2013 /**
2014 * Get a category for the feed
2015 *
2016 * @since Unknown
2017 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
2018 * @return SimplePie_Category|null
2019 */
2020 public function get_category($key = 0)
2021 {
2022 $categories = $this->get_categories();
2023 if (isset($categories[$key]))
2024 {
2025 return $categories[$key];
2026 }
2027 else
2028 {
2029 return null;
2030 }
2031 }
2032
2033 /**
2034 * Get all categories for the feed
2035 *
2036 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2037 *
2038 * @since Unknown
2039 * @return array|null List of {@see SimplePie_Category} objects
2040 */
2041 public function get_categories()
2042 {
2043 $categories = array();
2044
2045 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2046 {
2047 $term = null;
2048 $scheme = null;
2049 $label = null;
2050 if (isset($category['attribs']['']['term']))
2051 {
2052 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2053 }
2054 if (isset($category['attribs']['']['scheme']))
2055 {
2056 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2057 }
2058 if (isset($category['attribs']['']['label']))
2059 {
2060 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2061 }
2062 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2063 }
2064 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2065 {
2066 // This is really the label, but keep this as the term also for BC.
2067 // Label will also work on retrieving because that falls back to term.
2068 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2069 if (isset($category['attribs']['']['domain']))
2070 {
2071 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2072 }
2073 else
2074 {
2075 $scheme = null;
2076 }
2077 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
2078 }
2079 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2080 {
2081 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2082 }
2083 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2084 {
2085 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2086 }
2087
2088 if (!empty($categories))
2089 {
2090 return array_unique($categories);
2091 }
2092 else
2093 {
2094 return null;
2095 }
2096 }
2097
2098 /**
2099 * Get an author for the feed
2100 *
2101 * @since 1.1
2102 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
2103 * @return SimplePie_Author|null
2104 */
2105 public function get_author($key = 0)
2106 {
2107 $authors = $this->get_authors();
2108 if (isset($authors[$key]))
2109 {
2110 return $authors[$key];
2111 }
2112 else
2113 {
2114 return null;
2115 }
2116 }
2117
2118 /**
2119 * Get all authors for the feed
2120 *
2121 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2122 *
2123 * @since 1.1
2124 * @return array|null List of {@see SimplePie_Author} objects
2125 */
2126 public function get_authors()
2127 {
2128 $authors = array();
2129 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2130 {
2131 $name = null;
2132 $uri = null;
2133 $email = null;
2134 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2135 {
2136 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2137 }
2138 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2139 {
2140 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
2141 }
2142 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2143 {
2144 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2145 }
2146 if ($name !== null || $email !== null || $uri !== null)
2147 {
2148 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
2149 }
2150 }
2151 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2152 {
2153 $name = null;
2154 $url = null;
2155 $email = null;
2156 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2157 {
2158 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2159 }
2160 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2161 {
2162 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
2163 }
2164 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2165 {
2166 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2167 }
2168 if ($name !== null || $email !== null || $url !== null)
2169 {
2170 $authors[] = $this->registry->create('Author', array($name, $url, $email));
2171 }
2172 }
2173 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2174 {
2175 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2176 }
2177 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2178 {
2179 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2180 }
2181 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2182 {
2183 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2184 }
2185
2186 if (!empty($authors))
2187 {
2188 return array_unique($authors);
2189 }
2190 else
2191 {
2192 return null;
2193 }
2194 }
2195
2196 /**
2197 * Get a contributor for the feed
2198 *
2199 * @since 1.1
2200 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
2201 * @return SimplePie_Author|null
2202 */
2203 public function get_contributor($key = 0)
2204 {
2205 $contributors = $this->get_contributors();
2206 if (isset($contributors[$key]))
2207 {
2208 return $contributors[$key];
2209 }
2210 else
2211 {
2212 return null;
2213 }
2214 }
2215
2216 /**
2217 * Get all contributors for the feed
2218 *
2219 * Uses `<atom:contributor>`
2220 *
2221 * @since 1.1
2222 * @return array|null List of {@see SimplePie_Author} objects
2223 */
2224 public function get_contributors()
2225 {
2226 $contributors = array();
2227 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2228 {
2229 $name = null;
2230 $uri = null;
2231 $email = null;
2232 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2233 {
2234 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2235 }
2236 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2237 {
2238 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
2239 }
2240 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2241 {
2242 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2243 }
2244 if ($name !== null || $email !== null || $uri !== null)
2245 {
2246 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
2247 }
2248 }
2249 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2250 {
2251 $name = null;
2252 $url = null;
2253 $email = null;
2254 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2255 {
2256 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2257 }
2258 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2259 {
2260 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
2261 }
2262 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2263 {
2264 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2265 }
2266 if ($name !== null || $email !== null || $url !== null)
2267 {
2268 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
2269 }
2270 }
2271
2272 if (!empty($contributors))
2273 {
2274 return array_unique($contributors);
2275 }
2276 else
2277 {
2278 return null;
2279 }
2280 }
2281
2282 /**
2283 * Get a single link for the feed
2284 *
2285 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2286 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
2287 * @param string $rel The relationship of the link to return
2288 * @return string|null Link URL
2289 */
2290 public function get_link($key = 0, $rel = 'alternate')
2291 {
2292 $links = $this->get_links($rel);
2293 if (isset($links[$key]))
2294 {
2295 return $links[$key];
2296 }
2297 else
2298 {
2299 return null;
2300 }
2301 }
2302
2303 /**
2304 * Get the permalink for the item
2305 *
2306 * Returns the first link available with a relationship of "alternate".
2307 * Identical to {@see get_link()} with key 0
2308 *
2309 * @see get_link
2310 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2311 * @internal Added for parity between the parent-level and the item/entry-level.
2312 * @return string|null Link URL
2313 */
2314 public function get_permalink()
2315 {
2316 return $this->get_link(0);
2317 }
2318
2319 /**
2320 * Get all links for the feed
2321 *
2322 * Uses `<atom:link>` or `<link>`
2323 *
2324 * @since Beta 2
2325 * @param string $rel The relationship of links to return
2326 * @return array|null Links found for the feed (strings)
2327 */
2328 public function get_links($rel = 'alternate')
2329 {
2330 if (!isset($this->data['links']))
2331 {
2332 $this->data['links'] = array();
2333 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2334 {
2335 foreach ($links as $link)
2336 {
2337 if (isset($link['attribs']['']['href']))
2338 {
2339 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2340 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2341 }
2342 }
2343 }
2344 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2345 {
2346 foreach ($links as $link)
2347 {
2348 if (isset($link['attribs']['']['href']))
2349 {
2350 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2351 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2352
2353 }
2354 }
2355 }
2356 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2357 {
2358 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2359 }
2360 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2361 {
2362 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2363 }
2364 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2365 {
2366 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2367 }
2368
2369 $keys = array_keys($this->data['links']);
2370 foreach ($keys as $key)
2371 {
2372 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
2373 {
2374 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2375 {
2376 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2377 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2378 }
2379 else
2380 {
2381 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2382 }
2383 }
2384 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2385 {
2386 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2387 }
2388 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2389 }
2390 }
2391
2392 if (isset($this->data['links'][$rel]))
2393 {
2394 return $this->data['links'][$rel];
2395 }
2396 else
2397 {
2398 return null;
2399 }
2400 }
2401
2402 public function get_all_discovered_feeds()
2403 {
2404 return $this->all_discovered_feeds;
2405 }
2406
2407 /**
2408 * Get the content for the item
2409 *
2410 * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2411 * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2412 *
2413 * @since 1.0 (previously called `get_feed_description()` since 0.8)
2414 * @return string|null
2415 */
2416 public function get_description()
2417 {
2418 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2419 {
2420 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2421 }
2422 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2423 {
2424 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2425 }
2426 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2427 {
2428 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2429 }
2430 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2431 {
2432 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2433 }
2434 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2435 {
2436 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2437 }
2438 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2439 {
2440 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2441 }
2442 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2443 {
2444 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2445 }
2446 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2447 {
2448 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2449 }
2450 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2451 {
2452 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2453 }
2454 else
2455 {
2456 return null;
2457 }
2458 }
2459
2460 /**
2461 * Get the copyright info for the feed
2462 *
2463 * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2464 *
2465 * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2466 * @return string|null
2467 */
2468 public function get_copyright()
2469 {
2470 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2471 {
2472 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2473 }
2474 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2475 {
2476 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2477 }
2478 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2479 {
2480 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2481 }
2482 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2483 {
2484 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2485 }
2486 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2487 {
2488 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2489 }
2490 else
2491 {
2492 return null;
2493 }
2494 }
2495
2496 /**
2497 * Get the language for the feed
2498 *
2499 * Uses `<language>`, `<dc:language>`, or @xml_lang
2500 *
2501 * @since 1.0 (previously called `get_feed_language()` since 0.8)
2502 * @return string|null
2503 */
2504 public function get_language()
2505 {
2506 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2507 {
2508 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2509 }
2510 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2511 {
2512 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2513 }
2514 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2515 {
2516 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2517 }
2518 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2519 {
2520 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2521 }
2522 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2523 {
2524 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2525 }
2526 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2527 {
2528 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2529 }
2530 elseif (isset($this->data['headers']['content-language']))
2531 {
2532 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2533 }
2534 else
2535 {
2536 return null;
2537 }
2538 }
2539
2540 /**
2541 * Get the latitude coordinates for the item
2542 *
2543 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2544 *
2545 * Uses `<geo:lat>` or `<georss:point>`
2546 *
2547 * @since 1.0
2548 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2549 * @link http://www.georss.org/ GeoRSS
2550 * @return string|null
2551 */
2552 public function get_latitude()
2553 {
2554
2555 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2556 {
2557 return (float) $return[0]['data'];
2558 }
2559 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2560 {
2561 return (float) $match[1];
2562 }
2563 else
2564 {
2565 return null;
2566 }
2567 }
2568
2569 /**
2570 * Get the longitude coordinates for the feed
2571 *
2572 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2573 *
2574 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2575 *
2576 * @since 1.0
2577 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2578 * @link http://www.georss.org/ GeoRSS
2579 * @return string|null
2580 */
2581 public function get_longitude()
2582 {
2583 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2584 {
2585 return (float) $return[0]['data'];
2586 }
2587 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2588 {
2589 return (float) $return[0]['data'];
2590 }
2591 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2592 {
2593 return (float) $match[2];
2594 }
2595 else
2596 {
2597 return null;
2598 }
2599 }
2600
2601 /**
2602 * Get the feed logo's title
2603 *
2604 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2605 *
2606 * Uses `<image><title>` or `<image><dc:title>`
2607 *
2608 * @return string|null
2609 */
2610 public function get_image_title()
2611 {
2612 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2613 {
2614 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2615 }
2616 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2617 {
2618 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2619 }
2620 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2621 {
2622 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2623 }
2624 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2625 {
2626 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2627 }
2628 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2629 {
2630 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2631 }
2632 else
2633 {
2634 return null;
2635 }
2636 }
2637
2638 /**
2639 * Get the feed logo's URL
2640 *
2641 * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
2642 * have a "feed logo" URL. This points directly to the image itself.
2643 *
2644 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2645 * `<image><title>` or `<image><dc:title>`
2646 *
2647 * @return string|null
2648 */
2649 public function get_image_url()
2650 {
2651 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2652 {
2653 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2654 }
2655 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2656 {
2657 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2658 }
2659 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2660 {
2661 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2662 }
2663 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2664 {
2665 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2666 }
2667 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2668 {
2669 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2670 }
2671 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2672 {
2673 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2674 }
2675 else
2676 {
2677 return null;
2678 }
2679 }
2680
2681
2682 /**
2683 * Get the feed logo's link
2684 *
2685 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
2686 * points to a human-readable page that the image should link to.
2687 *
2688 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2689 * `<image><title>` or `<image><dc:title>`
2690 *
2691 * @return string|null
2692 */
2693 public function get_image_link()
2694 {
2695 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2696 {
2697 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2698 }
2699 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2700 {
2701 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2702 }
2703 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2704 {
2705 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2706 }
2707 else
2708 {
2709 return null;
2710 }
2711 }
2712
2713 /**
2714 * Get the feed logo's link
2715 *
2716 * RSS 2.0 feeds are allowed to have a "feed logo" width.
2717 *
2718 * Uses `<image><width>` or defaults to 88.0 if no width is specified and
2719 * the feed is an RSS 2.0 feed.
2720 *
2721 * @return int|float|null
2722 */
2723 public function get_image_width()
2724 {
2725 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2726 {
2727 return round($return[0]['data']);
2728 }
2729 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2730 {
2731 return 88.0;
2732 }
2733 else
2734 {
2735 return null;
2736 }
2737 }
2738
2739 /**
2740 * Get the feed logo's height
2741 *
2742 * RSS 2.0 feeds are allowed to have a "feed logo" height.
2743 *
2744 * Uses `<image><height>` or defaults to 31.0 if no height is specified and
2745 * the feed is an RSS 2.0 feed.
2746 *
2747 * @return int|float|null
2748 */
2749 public function get_image_height()
2750 {
2751 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2752 {
2753 return round($return[0]['data']);
2754 }
2755 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2756 {
2757 return 31.0;
2758 }
2759 else
2760 {
2761 return null;
2762 }
2763 }
2764
2765 /**
2766 * Get the number of items in the feed
2767 *
2768 * This is well-suited for {@link http://php.net/for for()} loops with
2769 * {@see get_item()}
2770 *
2771 * @param int $max Maximum value to return. 0 for no limit
2772 * @return int Number of items in the feed
2773 */
2774 public function get_item_quantity($max = 0)
2775 {
2776 $max = (int) $max;
2777 $qty = count($this->get_items());
2778 if ($max === 0)
2779 {
2780 return $qty;
2781 }
2782 else
2783 {
2784 return ($qty > $max) ? $max : $qty;
2785 }
2786 }
2787
2788 /**
2789 * Get a single item from the feed
2790 *
2791 * This is better suited for {@link http://php.net/for for()} loops, whereas
2792 * {@see get_items()} is better suited for
2793 * {@link http://php.net/foreach foreach()} loops.
2794 *
2795 * @see get_item_quantity()
2796 * @since Beta 2
2797 * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
2798 * @return SimplePie_Item|null
2799 */
2800 public function get_item($key = 0)
2801 {
2802 $items = $this->get_items();
2803 if (isset($items[$key]))
2804 {
2805 return $items[$key];
2806 }
2807 else
2808 {
2809 return null;
2810 }
2811 }
2812
2813 /**
2814 * Get all items from the feed
2815 *
2816 * This is better suited for {@link http://php.net/for for()} loops, whereas
2817 * {@see get_items()} is better suited for
2818 * {@link http://php.net/foreach foreach()} loops.
2819 *
2820 * @see get_item_quantity
2821 * @since Beta 2
2822 * @param int $start Index to start at
2823 * @param int $end Number of items to return. 0 for all items after `$start`
2824 * @return array|null List of {@see SimplePie_Item} objects
2825 */
2826 public function get_items($start = 0, $end = 0)
2827 {
2828 if (!isset($this->data['items']))
2829 {
2830 if (!empty($this->multifeed_objects))
2831 {
2832 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
2833 }
2834 else
2835 {
2836 $this->data['items'] = array();
2837 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
2838 {
2839 $keys = array_keys($items);
2840 foreach ($keys as $key)
2841 {
2842 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2843 }
2844 }
2845 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
2846 {
2847 $keys = array_keys($items);
2848 foreach ($keys as $key)
2849 {
2850 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2851 }
2852 }
2853 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
2854 {
2855 $keys = array_keys($items);
2856 foreach ($keys as $key)
2857 {
2858 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2859 }
2860 }
2861 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
2862 {
2863 $keys = array_keys($items);
2864 foreach ($keys as $key)
2865 {
2866 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2867 }
2868 }
2869 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
2870 {
2871 $keys = array_keys($items);
2872 foreach ($keys as $key)
2873 {
2874 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
2875 }
2876 }
2877 }
2878 }
2879
2880 if (!empty($this->data['items']))
2881 {
2882 // If we want to order it by date, check if all items have a date, and then sort it
2883 if ($this->order_by_date && empty($this->multifeed_objects))
2884 {
2885 if (!isset($this->data['ordered_items']))
2886 {
2887 $do_sort = true;
2888 foreach ($this->data['items'] as $item)
2889 {
2890 if (!$item->get_date('U'))
2891 {
2892 $do_sort = false;
2893 break;
2894 }
2895 }
2896 $item = null;
2897 $this->data['ordered_items'] = $this->data['items'];
2898 if ($do_sort)
2899 {
2900 usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
2901 }
2902 }
2903 $items = $this->data['ordered_items'];
2904 }
2905 else
2906 {
2907 $items = $this->data['items'];
2908 }
2909
2910 // Slice the data as desired
2911 if ($end === 0)
2912 {
2913 return array_slice($items, $start);
2914 }
2915 else
2916 {
2917 return array_slice($items, $start, $end);
2918 }
2919 }
2920 else
2921 {
2922 return array();
2923 }
2924 }
2925
2926 /**
2927 * Set the favicon handler
2928 *
2929 * @deprecated Use your own favicon handling instead
2930 */
2931 public function set_favicon_handler($page = false, $qs = 'i')
2932 {
2933 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2934 trigger_error('Favicon handling has been removed, please use your own handling', $level);
2935 return false;
2936 }
2937
2938 /**
2939 * Get the favicon for the current feed
2940 *
2941 * @deprecated Use your own favicon handling instead
2942 */
2943 public function get_favicon()
2944 {
2945 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2946 trigger_error('Favicon handling has been removed, please use your own handling', $level);
2947
2948 if (($url = $this->get_link()) !== null)
2949 {
2950 return 'http://g.etfv.co/' . urlencode($url);
2951 }
2952
2953 return false;
2954 }
2955
2956 /**
2957 * Magic method handler
2958 *
2959 * @param string $method Method name
2960 * @param array $args Arguments to the method
2961 * @return mixed
2962 */
2963 public function __call($method, $args)
2964 {
2965 if (strpos($method, 'subscribe_') === 0)
2966 {
2967 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2968 trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
2969 return '';
2970 }
2971 if ($method === 'enable_xml_dump')
2972 {
2973 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
2974 trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
2975 return false;
2976 }
2977
2978 $class = get_class($this);
2979 $trace = debug_backtrace();
2980 $file = $trace[0]['file'];
2981 $line = $trace[0]['line'];
2982 trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
2983 }
2984
2985 /**
2986 * Sorting callback for items
2987 *
2988 * @access private
2989 * @param SimplePie $a
2990 * @param SimplePie $b
2991 * @return boolean
2992 */
2993 public static function sort_items($a, $b)
2994 {
2995 return $a->get_date('U') <= $b->get_date('U');
2996 }
2997
2998 /**
2999 * Merge items from several feeds into one
3000 *
3001 * If you're merging multiple feeds together, they need to all have dates
3002 * for the items or else SimplePie will refuse to sort them.
3003 *
3004 * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
3005 * @param array $urls List of SimplePie feed objects to merge
3006 * @param int $start Starting item
3007 * @param int $end Number of items to return
3008 * @param int $limit Maximum number of items per feed
3009 * @return array
3010 */
3011 public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3012 {
3013 if (is_array($urls) && sizeof($urls) > 0)
3014 {
3015 $items = array();
3016 foreach ($urls as $arg)
3017 {
3018 if ($arg instanceof SimplePie)
3019 {
3020 $items = array_merge($items, $arg->get_items(0, $limit));
3021 }
3022 else
3023 {
3024 trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3025 }
3026 }
3027
3028 $do_sort = true;
3029 foreach ($items as $item)
3030 {
3031 if (!$item->get_date('U'))
3032 {
3033 $do_sort = false;
3034 break;
3035 }
3036 }
3037 $item = null;
3038 if ($do_sort)
3039 {
3040 usort($items, array(get_class($urls[0]), 'sort_items'));
3041 }
3042
3043 if ($end === 0)
3044 {
3045 return array_slice($items, $start);
3046 }
3047 else
3048 {
3049 return array_slice($items, $start, $end);
3050 }
3051 }
3052 else
3053 {
3054 trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3055 return array();
3056 }
3057 }
3058}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Author.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Author.php
new file mode 100644
index 00000000..bbf3812f
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Author.php
@@ -0,0 +1,157 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Manages all author-related data
47 *
48 * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_author_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Author
56{
57 /**
58 * Author's name
59 *
60 * @var string
61 * @see get_name()
62 */
63 var $name;
64
65 /**
66 * Author's link
67 *
68 * @var string
69 * @see get_link()
70 */
71 var $link;
72
73 /**
74 * Author's email address
75 *
76 * @var string
77 * @see get_email()
78 */
79 var $email;
80
81 /**
82 * Constructor, used to input the data
83 *
84 * @param string $name
85 * @param string $link
86 * @param string $email
87 */
88 public function __construct($name = null, $link = null, $email = null)
89 {
90 $this->name = $name;
91 $this->link = $link;
92 $this->email = $email;
93 }
94
95 /**
96 * String-ified version
97 *
98 * @return string
99 */
100 public function __toString()
101 {
102 // There is no $this->data here
103 return md5(serialize($this));
104 }
105
106 /**
107 * Author's name
108 *
109 * @return string|null
110 */
111 public function get_name()
112 {
113 if ($this->name !== null)
114 {
115 return $this->name;
116 }
117 else
118 {
119 return null;
120 }
121 }
122
123 /**
124 * Author's link
125 *
126 * @return string|null
127 */
128 public function get_link()
129 {
130 if ($this->link !== null)
131 {
132 return $this->link;
133 }
134 else
135 {
136 return null;
137 }
138 }
139
140 /**
141 * Author's email address
142 *
143 * @return string|null
144 */
145 public function get_email()
146 {
147 if ($this->email !== null)
148 {
149 return $this->email;
150 }
151 else
152 {
153 return null;
154 }
155 }
156}
157
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache.php
new file mode 100644
index 00000000..75586d74
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache.php
@@ -0,0 +1,133 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Used to create cache objects
47 *
48 * This class can be overloaded with {@see SimplePie::set_cache_class()},
49 * although the preferred way is to create your own handler
50 * via {@see register()}
51 *
52 * @package SimplePie
53 * @subpackage Caching
54 */
55class SimplePie_Cache
56{
57 /**
58 * Cache handler classes
59 *
60 * These receive 3 parameters to their constructor, as documented in
61 * {@see register()}
62 * @var array
63 */
64 protected static $handlers = array(
65 'mysql' => 'SimplePie_Cache_MySQL',
66 'memcache' => 'SimplePie_Cache_Memcache',
67 );
68
69 /**
70 * Don't call the constructor. Please.
71 */
72 private function __construct() { }
73
74 /**
75 * Create a new SimplePie_Cache object
76 *
77 * @param string $location URL location (scheme is used to determine handler)
78 * @param string $filename Unique identifier for cache object
79 * @param string $extension 'spi' or 'spc'
80 * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
81 */
82 public static function get_handler($location, $filename, $extension)
83 {
84 $type = explode(':', $location, 2);
85 $type = $type[0];
86 if (!empty(self::$handlers[$type]))
87 {
88 $class = self::$handlers[$type];
89 return new $class($location, $filename, $extension);
90 }
91
92 return new SimplePie_Cache_File($location, $filename, $extension);
93 }
94
95 /**
96 * Create a new SimplePie_Cache object
97 *
98 * @deprecated Use {@see get_handler} instead
99 */
100 public function create($location, $filename, $extension)
101 {
102 trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
103 return self::get_handler($location, $filename, $extension);
104 }
105
106 /**
107 * Register a handler
108 *
109 * @param string $type DSN type to register for
110 * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
111 */
112 public static function register($type, $class)
113 {
114 self::$handlers[$type] = $class;
115 }
116
117 /**
118 * Parse a URL into an array
119 *
120 * @param string $url
121 * @return array
122 */
123 public static function parse_URL($url)
124 {
125 $params = parse_url($url);
126 $params['extras'] = array();
127 if (isset($params['query']))
128 {
129 parse_str($params['query'], $params['extras']);
130 }
131 return $params;
132 }
133}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Base.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Base.php
new file mode 100644
index 00000000..937e3463
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Base.php
@@ -0,0 +1,114 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Base for cache objects
47 *
48 * Classes to be used with {@see SimplePie_Cache::register()} are expected
49 * to implement this interface.
50 *
51 * @package SimplePie
52 * @subpackage Caching
53 */
54interface SimplePie_Cache_Base
55{
56 /**
57 * Feed cache type
58 *
59 * @var string
60 */
61 const TYPE_FEED = 'spc';
62
63 /**
64 * Image cache type
65 *
66 * @var string
67 */
68 const TYPE_IMAGE = 'spi';
69
70 /**
71 * Create a new cache object
72 *
73 * @param string $location Location string (from SimplePie::$cache_location)
74 * @param string $name Unique ID for the cache
75 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
76 */
77 public function __construct($location, $name, $type);
78
79 /**
80 * Save data to the cache
81 *
82 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
83 * @return bool Successfulness
84 */
85 public function save($data);
86
87 /**
88 * Retrieve the data saved to the cache
89 *
90 * @return array Data for SimplePie::$data
91 */
92 public function load();
93
94 /**
95 * Retrieve the last modified time for the cache
96 *
97 * @return int Timestamp
98 */
99 public function mtime();
100
101 /**
102 * Set the last modified time to the current time
103 *
104 * @return bool Success status
105 */
106 public function touch();
107
108 /**
109 * Remove the cache
110 *
111 * @return bool Success status
112 */
113 public function unlink();
114}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/DB.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/DB.php
new file mode 100644
index 00000000..ac509ae0
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/DB.php
@@ -0,0 +1,137 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Base class for database-based caches
47 *
48 * @package SimplePie
49 * @subpackage Caching
50 */
51abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
52{
53 /**
54 * Helper for database conversion
55 *
56 * Converts a given {@see SimplePie} object into data to be stored
57 *
58 * @param SimplePie $data
59 * @return array First item is the serialized data for storage, second item is the unique ID for this item
60 */
61 protected static function prepare_simplepie_object_for_cache($data)
62 {
63 $items = $data->get_items();
64 $items_by_id = array();
65
66 if (!empty($items))
67 {
68 foreach ($items as $item)
69 {
70 $items_by_id[$item->get_id()] = $item;
71 }
72
73 if (count($items_by_id) !== count($items))
74 {
75 $items_by_id = array();
76 foreach ($items as $item)
77 {
78 $items_by_id[$item->get_id(true)] = $item;
79 }
80 }
81
82 if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
83 {
84 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
85 }
86 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
87 {
88 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
89 }
90 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
91 {
92 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
93 }
94 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
95 {
96 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
97 }
98 else
99 {
100 $channel = null;
101 }
102
103 if ($channel !== null)
104 {
105 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
106 {
107 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
108 }
109 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
110 {
111 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
112 }
113 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
114 {
115 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
116 }
117 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
118 {
119 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
120 }
121 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
122 {
123 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
124 }
125 }
126 if (isset($data->data['items']))
127 {
128 unset($data->data['items']);
129 }
130 if (isset($data->data['ordered_items']))
131 {
132 unset($data->data['ordered_items']);
133 }
134 }
135 return array(serialize($data->data), $items_by_id);
136 }
137}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/File.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/File.php
new file mode 100644
index 00000000..5797b3ae
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/File.php
@@ -0,0 +1,173 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Caches data to the filesystem
47 *
48 * @package SimplePie
49 * @subpackage Caching
50 */
51class SimplePie_Cache_File implements SimplePie_Cache_Base
52{
53 /**
54 * Location string
55 *
56 * @see SimplePie::$cache_location
57 * @var string
58 */
59 protected $location;
60
61 /**
62 * Filename
63 *
64 * @var string
65 */
66 protected $filename;
67
68 /**
69 * File extension
70 *
71 * @var string
72 */
73 protected $extension;
74
75 /**
76 * File path
77 *
78 * @var string
79 */
80 protected $name;
81
82 /**
83 * Create a new cache object
84 *
85 * @param string $location Location string (from SimplePie::$cache_location)
86 * @param string $name Unique ID for the cache
87 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
88 */
89 public function __construct($location, $name, $type)
90 {
91 $this->location = $location;
92 $this->filename = $name;
93 $this->extension = $type;
94 $this->name = "$this->location/$this->filename.$this->extension";
95 }
96
97 /**
98 * Save data to the cache
99 *
100 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
101 * @return bool Successfulness
102 */
103 public function save($data)
104 {
105 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
106 {
107 if ($data instanceof SimplePie)
108 {
109 $data = $data->data;
110 }
111
112 $data = serialize($data);
113 return (bool) file_put_contents($this->name, $data);
114 }
115 return false;
116 }
117
118 /**
119 * Retrieve the data saved to the cache
120 *
121 * @return array Data for SimplePie::$data
122 */
123 public function load()
124 {
125 if (file_exists($this->name) && is_readable($this->name))
126 {
127 return unserialize(file_get_contents($this->name));
128 }
129 return false;
130 }
131
132 /**
133 * Retrieve the last modified time for the cache
134 *
135 * @return int Timestamp
136 */
137 public function mtime()
138 {
139 if (file_exists($this->name))
140 {
141 return filemtime($this->name);
142 }
143 return false;
144 }
145
146 /**
147 * Set the last modified time to the current time
148 *
149 * @return bool Success status
150 */
151 public function touch()
152 {
153 if (file_exists($this->name))
154 {
155 return touch($this->name);
156 }
157 return false;
158 }
159
160 /**
161 * Remove the cache
162 *
163 * @return bool Success status
164 */
165 public function unlink()
166 {
167 if (file_exists($this->name))
168 {
169 return unlink($this->name);
170 }
171 return false;
172 }
173}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Memcache.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Memcache.php
new file mode 100644
index 00000000..fd447806
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/Memcache.php
@@ -0,0 +1,183 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Caches data to memcache
47 *
48 * Registered for URLs with the "memcache" protocol
49 *
50 * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
51 * connect to memcache on `localhost` on port 11211. All tables will be
52 * prefixed with `sp_` and data will expire after 3600 seconds
53 *
54 * @package SimplePie
55 * @subpackage Caching
56 * @uses Memcache
57 */
58class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
59{
60 /**
61 * Memcache instance
62 *
63 * @var Memcache
64 */
65 protected $cache;
66
67 /**
68 * Options
69 *
70 * @var array
71 */
72 protected $options;
73
74 /**
75 * Cache name
76 *
77 * @var string
78 */
79 protected $name;
80
81 /**
82 * Create a new cache object
83 *
84 * @param string $location Location string (from SimplePie::$cache_location)
85 * @param string $name Unique ID for the cache
86 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
87 */
88 public function __construct($location, $name, $type)
89 {
90 $this->options = array(
91 'host' => '127.0.0.1',
92 'port' => 11211,
93 'extras' => array(
94 'timeout' => 3600, // one hour
95 'prefix' => 'simplepie_',
96 ),
97 );
98 $parsed = SimplePie_Cache::parse_URL($location);
99 $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
100 $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
101 $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
102 $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
103
104 $this->cache = new Memcache();
105 $this->cache->addServer($this->options['host'], (int) $this->options['port']);
106 }
107
108 /**
109 * Save data to the cache
110 *
111 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
112 * @return bool Successfulness
113 */
114 public function save($data)
115 {
116 if ($data instanceof SimplePie)
117 {
118 $data = $data->data;
119 }
120 return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
121 }
122
123 /**
124 * Retrieve the data saved to the cache
125 *
126 * @return array Data for SimplePie::$data
127 */
128 public function load()
129 {
130 $data = $this->cache->get($this->name);
131
132 if ($data !== false)
133 {
134 return unserialize($data);
135 }
136 return false;
137 }
138
139 /**
140 * Retrieve the last modified time for the cache
141 *
142 * @return int Timestamp
143 */
144 public function mtime()
145 {
146 $data = $this->cache->get($this->name);
147
148 if ($data !== false)
149 {
150 // essentially ignore the mtime because Memcache expires on it's own
151 return time();
152 }
153
154 return false;
155 }
156
157 /**
158 * Set the last modified time to the current time
159 *
160 * @return bool Success status
161 */
162 public function touch()
163 {
164 $data = $this->cache->get($this->name);
165
166 if ($data !== false)
167 {
168 return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
169 }
170
171 return false;
172 }
173
174 /**
175 * Remove the cache
176 *
177 * @return bool Success status
178 */
179 public function unlink()
180 {
181 return $this->cache->delete($this->name, 0);
182 }
183}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/MySQL.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/MySQL.php
new file mode 100644
index 00000000..d53ebc11
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Cache/MySQL.php
@@ -0,0 +1,438 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Caches data to a MySQL database
47 *
48 * Registered for URLs with the "mysql" protocol
49 *
50 * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
51 * connect to the `mydb` database on `localhost` on port 3306, with the user
52 * `root` and the password `password`. All tables will be prefixed with `sp_`
53 *
54 * @package SimplePie
55 * @subpackage Caching
56 */
57class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
58{
59 /**
60 * PDO instance
61 *
62 * @var PDO
63 */
64 protected $mysql;
65
66 /**
67 * Options
68 *
69 * @var array
70 */
71 protected $options;
72
73 /**
74 * Cache ID
75 *
76 * @var string
77 */
78 protected $id;
79
80 /**
81 * Create a new cache object
82 *
83 * @param string $location Location string (from SimplePie::$cache_location)
84 * @param string $name Unique ID for the cache
85 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
86 */
87 public function __construct($location, $name, $type)
88 {
89 $this->options = array(
90 'user' => null,
91 'pass' => null,
92 'host' => '127.0.0.1',
93 'port' => '3306',
94 'path' => '',
95 'extras' => array(
96 'prefix' => '',
97 ),
98 );
99 $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
100
101 // Path is prefixed with a "/"
102 $this->options['dbname'] = substr($this->options['path'], 1);
103
104 try
105 {
106 $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
107 }
108 catch (PDOException $e)
109 {
110 $this->mysql = null;
111 return;
112 }
113
114 $this->id = $name . $type;
115
116 if (!$query = $this->mysql->query('SHOW TABLES'))
117 {
118 $this->mysql = null;
119 return;
120 }
121
122 $db = array();
123 while ($row = $query->fetchColumn())
124 {
125 $db[] = $row;
126 }
127
128 if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
129 {
130 $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
131 if ($query === false)
132 {
133 $this->mysql = null;
134 }
135 }
136
137 if (!in_array($this->options['extras']['prefix'] . 'items', $db))
138 {
139 $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
140 if ($query === false)
141 {
142 $this->mysql = null;
143 }
144 }
145 }
146
147 /**
148 * Save data to the cache
149 *
150 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
151 * @return bool Successfulness
152 */
153 public function save($data)
154 {
155 if ($this->mysql === null)
156 {
157 return false;
158 }
159
160 if ($data instanceof SimplePie)
161 {
162 $data = clone $data;
163
164 $prepared = self::prepare_simplepie_object_for_cache($data);
165
166 $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
167 $query->bindValue(':feed', $this->id);
168 if ($query->execute())
169 {
170 if ($query->fetchColumn() > 0)
171 {
172 $items = count($prepared[1]);
173 if ($items)
174 {
175 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
176 $query = $this->mysql->prepare($sql);
177 $query->bindValue(':items', $items);
178 }
179 else
180 {
181 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
182 $query = $this->mysql->prepare($sql);
183 }
184
185 $query->bindValue(':data', $prepared[0]);
186 $query->bindValue(':time', time());
187 $query->bindValue(':feed', $this->id);
188 if (!$query->execute())
189 {
190 return false;
191 }
192 }
193 else
194 {
195 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
196 $query->bindValue(':feed', $this->id);
197 $query->bindValue(':count', count($prepared[1]));
198 $query->bindValue(':data', $prepared[0]);
199 $query->bindValue(':time', time());
200 if (!$query->execute())
201 {
202 return false;
203 }
204 }
205
206 $ids = array_keys($prepared[1]);
207 if (!empty($ids))
208 {
209 foreach ($ids as $id)
210 {
211 $database_ids[] = $this->mysql->quote($id);
212 }
213
214 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
215 $query->bindValue(':feed', $this->id);
216
217 if ($query->execute())
218 {
219 $existing_ids = array();
220 while ($row = $query->fetchColumn())
221 {
222 $existing_ids[] = $row;
223 }
224
225 $new_ids = array_diff($ids, $existing_ids);
226
227 foreach ($new_ids as $new_id)
228 {
229 if (!($date = $prepared[1][$new_id]->get_date('U')))
230 {
231 $date = time();
232 }
233
234 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
235 $query->bindValue(':feed', $this->id);
236 $query->bindValue(':id', $new_id);
237 $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
238 $query->bindValue(':date', $date);
239 if (!$query->execute())
240 {
241 return false;
242 }
243 }
244 return true;
245 }
246 }
247 else
248 {
249 return true;
250 }
251 }
252 }
253 else
254 {
255 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
256 $query->bindValue(':feed', $this->id);
257 if ($query->execute())
258 {
259 if ($query->rowCount() > 0)
260 {
261 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
262 $query->bindValue(':data', serialize($data));
263 $query->bindValue(':time', time());
264 $query->bindValue(':feed', $this->id);
265 if ($this->execute())
266 {
267 return true;
268 }
269 }
270 else
271 {
272 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
273 $query->bindValue(':id', $this->id);
274 $query->bindValue(':data', serialize($data));
275 $query->bindValue(':time', time());
276 if ($query->execute())
277 {
278 return true;
279 }
280 }
281 }
282 }
283 return false;
284 }
285
286 /**
287 * Retrieve the data saved to the cache
288 *
289 * @return array Data for SimplePie::$data
290 */
291 public function load()
292 {
293 if ($this->mysql === null)
294 {
295 return false;
296 }
297
298 $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
299 $query->bindValue(':id', $this->id);
300 if ($query->execute() && ($row = $query->fetch()))
301 {
302 $data = unserialize($row[1]);
303
304 if (isset($this->options['items'][0]))
305 {
306 $items = (int) $this->options['items'][0];
307 }
308 else
309 {
310 $items = (int) $row[0];
311 }
312
313 if ($items !== 0)
314 {
315 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
316 {
317 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
318 }
319 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
320 {
321 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
322 }
323 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
324 {
325 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
326 }
327 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
328 {
329 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
330 }
331 else
332 {
333 $feed = null;
334 }
335
336 if ($feed !== null)
337 {
338 $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
339 if ($items > 0)
340 {
341 $sql .= ' LIMIT ' . $items;
342 }
343
344 $query = $this->mysql->prepare($sql);
345 $query->bindValue(':feed', $this->id);
346 if ($query->execute())
347 {
348 while ($row = $query->fetchColumn())
349 {
350 $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
351 }
352 }
353 else
354 {
355 return false;
356 }
357 }
358 }
359 return $data;
360 }
361 return false;
362 }
363
364 /**
365 * Retrieve the last modified time for the cache
366 *
367 * @return int Timestamp
368 */
369 public function mtime()
370 {
371 if ($this->mysql === null)
372 {
373 return false;
374 }
375
376 $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
377 $query->bindValue(':id', $this->id);
378 if ($query->execute() && ($time = $query->fetchColumn()))
379 {
380 return $time;
381 }
382 else
383 {
384 return false;
385 }
386 }
387
388 /**
389 * Set the last modified time to the current time
390 *
391 * @return bool Success status
392 */
393 public function touch()
394 {
395 if ($this->mysql === null)
396 {
397 return false;
398 }
399
400 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
401 $query->bindValue(':time', time());
402 $query->bindValue(':id', $this->id);
403 if ($query->execute() && $query->rowCount() > 0)
404 {
405 return true;
406 }
407 else
408 {
409 return false;
410 }
411 }
412
413 /**
414 * Remove the cache
415 *
416 * @return bool Success status
417 */
418 public function unlink()
419 {
420 if ($this->mysql === null)
421 {
422 return false;
423 }
424
425 $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
426 $query->bindValue(':id', $this->id);
427 $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
428 $query2->bindValue(':id', $this->id);
429 if ($query->execute() && $query2->execute())
430 {
431 return true;
432 }
433 else
434 {
435 return false;
436 }
437 }
438}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Caption.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Caption.php
new file mode 100644
index 00000000..52922c5d
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Caption.php
@@ -0,0 +1,210 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Handles `<media:text>` captions as defined in Media RSS.
48 *
49 * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
50 *
51 * This class can be overloaded with {@see SimplePie::set_caption_class()}
52 *
53 * @package SimplePie
54 * @subpackage API
55 */
56class SimplePie_Caption
57{
58 /**
59 * Content type
60 *
61 * @var string
62 * @see get_type()
63 */
64 var $type;
65
66 /**
67 * Language
68 *
69 * @var string
70 * @see get_language()
71 */
72 var $lang;
73
74 /**
75 * Start time
76 *
77 * @var string
78 * @see get_starttime()
79 */
80 var $startTime;
81
82 /**
83 * End time
84 *
85 * @var string
86 * @see get_endtime()
87 */
88 var $endTime;
89
90 /**
91 * Caption text
92 *
93 * @var string
94 * @see get_text()
95 */
96 var $text;
97
98 /**
99 * Constructor, used to input the data
100 *
101 * For documentation on all the parameters, see the corresponding
102 * properties and their accessors
103 */
104 public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
105 {
106 $this->type = $type;
107 $this->lang = $lang;
108 $this->startTime = $startTime;
109 $this->endTime = $endTime;
110 $this->text = $text;
111 }
112
113 /**
114 * String-ified version
115 *
116 * @return string
117 */
118 public function __toString()
119 {
120 // There is no $this->data here
121 return md5(serialize($this));
122 }
123
124 /**
125 * Get the end time
126 *
127 * @return string|null Time in the format 'hh:mm:ss.SSS'
128 */
129 public function get_endtime()
130 {
131 if ($this->endTime !== null)
132 {
133 return $this->endTime;
134 }
135 else
136 {
137 return null;
138 }
139 }
140
141 /**
142 * Get the language
143 *
144 * @link http://tools.ietf.org/html/rfc3066
145 * @return string|null Language code as per RFC 3066
146 */
147 public function get_language()
148 {
149 if ($this->lang !== null)
150 {
151 return $this->lang;
152 }
153 else
154 {
155 return null;
156 }
157 }
158
159 /**
160 * Get the start time
161 *
162 * @return string|null Time in the format 'hh:mm:ss.SSS'
163 */
164 public function get_starttime()
165 {
166 if ($this->startTime !== null)
167 {
168 return $this->startTime;
169 }
170 else
171 {
172 return null;
173 }
174 }
175
176 /**
177 * Get the text of the caption
178 *
179 * @return string|null
180 */
181 public function get_text()
182 {
183 if ($this->text !== null)
184 {
185 return $this->text;
186 }
187 else
188 {
189 return null;
190 }
191 }
192
193 /**
194 * Get the content type (not MIME type)
195 *
196 * @return string|null Either 'text' or 'html'
197 */
198 public function get_type()
199 {
200 if ($this->type !== null)
201 {
202 return $this->type;
203 }
204 else
205 {
206 return null;
207 }
208 }
209}
210
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Category.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Category.php
new file mode 100644
index 00000000..ad0407b4
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Category.php
@@ -0,0 +1,157 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Manages all category-related data
47 *
48 * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_category_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Category
56{
57 /**
58 * Category identifier
59 *
60 * @var string
61 * @see get_term
62 */
63 var $term;
64
65 /**
66 * Categorization scheme identifier
67 *
68 * @var string
69 * @see get_scheme()
70 */
71 var $scheme;
72
73 /**
74 * Human readable label
75 *
76 * @var string
77 * @see get_label()
78 */
79 var $label;
80
81 /**
82 * Constructor, used to input the data
83 *
84 * @param string $term
85 * @param string $scheme
86 * @param string $label
87 */
88 public function __construct($term = null, $scheme = null, $label = null)
89 {
90 $this->term = $term;
91 $this->scheme = $scheme;
92 $this->label = $label;
93 }
94
95 /**
96 * String-ified version
97 *
98 * @return string
99 */
100 public function __toString()
101 {
102 // There is no $this->data here
103 return md5(serialize($this));
104 }
105
106 /**
107 * Get the category identifier
108 *
109 * @return string|null
110 */
111 public function get_term()
112 {
113 if ($this->term !== null)
114 {
115 return $this->term;
116 }
117 else
118 {
119 return null;
120 }
121 }
122
123 /**
124 * Get the categorization scheme identifier
125 *
126 * @return string|null
127 */
128 public function get_scheme()
129 {
130 if ($this->scheme !== null)
131 {
132 return $this->scheme;
133 }
134 else
135 {
136 return null;
137 }
138 }
139
140 /**
141 * Get the human readable label
142 *
143 * @return string|null
144 */
145 public function get_label()
146 {
147 if ($this->label !== null)
148 {
149 return $this->label;
150 }
151 else
152 {
153 return $this->get_term();
154 }
155 }
156}
157
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Content/Type/Sniffer.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Content/Type/Sniffer.php
new file mode 100644
index 00000000..20d053dc
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Content/Type/Sniffer.php
@@ -0,0 +1,332 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Content-type sniffing
48 *
49 * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
50 *
51 * This is used since we can't always trust Content-Type headers, and is based
52 * upon the HTML5 parsing rules.
53 *
54 *
55 * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
56 *
57 * @package SimplePie
58 * @subpackage HTTP
59 */
60class SimplePie_Content_Type_Sniffer
61{
62 /**
63 * File object
64 *
65 * @var SimplePie_File
66 */
67 var $file;
68
69 /**
70 * Create an instance of the class with the input file
71 *
72 * @param SimplePie_Content_Type_Sniffer $file Input file
73 */
74 public function __construct($file)
75 {
76 $this->file = $file;
77 }
78
79 /**
80 * Get the Content-Type of the specified file
81 *
82 * @return string Actual Content-Type
83 */
84 public function get_type()
85 {
86 if (isset($this->file->headers['content-type']))
87 {
88 if (!isset($this->file->headers['content-encoding'])
89 && ($this->file->headers['content-type'] === 'text/plain'
90 || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
91 || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
92 || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
93 {
94 return $this->text_or_binary();
95 }
96
97 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
98 {
99 $official = substr($this->file->headers['content-type'], 0, $pos);
100 }
101 else
102 {
103 $official = $this->file->headers['content-type'];
104 }
105 $official = trim(strtolower($official));
106
107 if ($official === 'unknown/unknown'
108 || $official === 'application/unknown')
109 {
110 return $this->unknown();
111 }
112 elseif (substr($official, -4) === '+xml'
113 || $official === 'text/xml'
114 || $official === 'application/xml')
115 {
116 return $official;
117 }
118 elseif (substr($official, 0, 6) === 'image/')
119 {
120 if ($return = $this->image())
121 {
122 return $return;
123 }
124 else
125 {
126 return $official;
127 }
128 }
129 elseif ($official === 'text/html')
130 {
131 return $this->feed_or_html();
132 }
133 else
134 {
135 return $official;
136 }
137 }
138 else
139 {
140 return $this->unknown();
141 }
142 }
143
144 /**
145 * Sniff text or binary
146 *
147 * @return string Actual Content-Type
148 */
149 public function text_or_binary()
150 {
151 if (substr($this->file->body, 0, 2) === "\xFE\xFF"
152 || substr($this->file->body, 0, 2) === "\xFF\xFE"
153 || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
154 || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
155 {
156 return 'text/plain';
157 }
158 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
159 {
160 return 'application/octect-stream';
161 }
162 else
163 {
164 return 'text/plain';
165 }
166 }
167
168 /**
169 * Sniff unknown
170 *
171 * @return string Actual Content-Type
172 */
173 public function unknown()
174 {
175 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
176 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
177 || strtolower(substr($this->file->body, $ws, 5)) === '<html'
178 || strtolower(substr($this->file->body, $ws, 7)) === '<script')
179 {
180 return 'text/html';
181 }
182 elseif (substr($this->file->body, 0, 5) === '%PDF-')
183 {
184 return 'application/pdf';
185 }
186 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
187 {
188 return 'application/postscript';
189 }
190 elseif (substr($this->file->body, 0, 6) === 'GIF87a'
191 || substr($this->file->body, 0, 6) === 'GIF89a')
192 {
193 return 'image/gif';
194 }
195 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
196 {
197 return 'image/png';
198 }
199 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
200 {
201 return 'image/jpeg';
202 }
203 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
204 {
205 return 'image/bmp';
206 }
207 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
208 {
209 return 'image/vnd.microsoft.icon';
210 }
211 else
212 {
213 return $this->text_or_binary();
214 }
215 }
216
217 /**
218 * Sniff images
219 *
220 * @return string Actual Content-Type
221 */
222 public function image()
223 {
224 if (substr($this->file->body, 0, 6) === 'GIF87a'
225 || substr($this->file->body, 0, 6) === 'GIF89a')
226 {
227 return 'image/gif';
228 }
229 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
230 {
231 return 'image/png';
232 }
233 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
234 {
235 return 'image/jpeg';
236 }
237 elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
238 {
239 return 'image/bmp';
240 }
241 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
242 {
243 return 'image/vnd.microsoft.icon';
244 }
245 else
246 {
247 return false;
248 }
249 }
250
251 /**
252 * Sniff HTML
253 *
254 * @return string Actual Content-Type
255 */
256 public function feed_or_html()
257 {
258 $len = strlen($this->file->body);
259 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
260
261 while ($pos < $len)
262 {
263 switch ($this->file->body[$pos])
264 {
265 case "\x09":
266 case "\x0A":
267 case "\x0D":
268 case "\x20":
269 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
270 continue 2;
271
272 case '<':
273 $pos++;
274 break;
275
276 default:
277 return 'text/html';
278 }
279
280 if (substr($this->file->body, $pos, 3) === '!--')
281 {
282 $pos += 3;
283 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
284 {
285 $pos += 3;
286 }
287 else
288 {
289 return 'text/html';
290 }
291 }
292 elseif (substr($this->file->body, $pos, 1) === '!')
293 {
294 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
295 {
296 $pos++;
297 }
298 else
299 {
300 return 'text/html';
301 }
302 }
303 elseif (substr($this->file->body, $pos, 1) === '?')
304 {
305 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
306 {
307 $pos += 2;
308 }
309 else
310 {
311 return 'text/html';
312 }
313 }
314 elseif (substr($this->file->body, $pos, 3) === 'rss'
315 || substr($this->file->body, $pos, 7) === 'rdf:RDF')
316 {
317 return 'application/rss+xml';
318 }
319 elseif (substr($this->file->body, $pos, 4) === 'feed')
320 {
321 return 'application/atom+xml';
322 }
323 else
324 {
325 return 'text/html';
326 }
327 }
328
329 return 'text/html';
330 }
331}
332
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Copyright.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Copyright.php
new file mode 100644
index 00000000..57c535a6
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Copyright.php
@@ -0,0 +1,130 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Manages `<media:copyright>` copyright tags as defined in Media RSS
47 *
48 * Used by {@see SimplePie_Enclosure::get_copyright()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_copyright_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Copyright
56{
57 /**
58 * Copyright URL
59 *
60 * @var string
61 * @see get_url()
62 */
63 var $url;
64
65 /**
66 * Attribution
67 *
68 * @var string
69 * @see get_attribution()
70 */
71 var $label;
72
73 /**
74 * Constructor, used to input the data
75 *
76 * For documentation on all the parameters, see the corresponding
77 * properties and their accessors
78 */
79 public function __construct($url = null, $label = null)
80 {
81 $this->url = $url;
82 $this->label = $label;
83 }
84
85 /**
86 * String-ified version
87 *
88 * @return string
89 */
90 public function __toString()
91 {
92 // There is no $this->data here
93 return md5(serialize($this));
94 }
95
96 /**
97 * Get the copyright URL
98 *
99 * @return string|null URL to copyright information
100 */
101 public function get_url()
102 {
103 if ($this->url !== null)
104 {
105 return $this->url;
106 }
107 else
108 {
109 return null;
110 }
111 }
112
113 /**
114 * Get the attribution text
115 *
116 * @return string|null
117 */
118 public function get_attribution()
119 {
120 if ($this->label !== null)
121 {
122 return $this->label;
123 }
124 else
125 {
126 return null;
127 }
128 }
129}
130
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Core.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Core.php
new file mode 100644
index 00000000..46d99662
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Core.php
@@ -0,0 +1,57 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * SimplePie class.
47 *
48 * Class for backward compatibility.
49 *
50 * @deprecated Use {@see SimplePie} directly
51 * @package SimplePie
52 * @subpackage API
53 */
54class SimplePie_Core extends SimplePie
55{
56
57} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Credit.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Credit.php
new file mode 100644
index 00000000..d3a3442a
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Credit.php
@@ -0,0 +1,156 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Handles `<media:credit>` as defined in Media RSS
47 *
48 * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_credit_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Credit
56{
57 /**
58 * Credited role
59 *
60 * @var string
61 * @see get_role()
62 */
63 var $role;
64
65 /**
66 * Organizational scheme
67 *
68 * @var string
69 * @see get_scheme()
70 */
71 var $scheme;
72
73 /**
74 * Credited name
75 *
76 * @var string
77 * @see get_name()
78 */
79 var $name;
80
81 /**
82 * Constructor, used to input the data
83 *
84 * For documentation on all the parameters, see the corresponding
85 * properties and their accessors
86 */
87 public function __construct($role = null, $scheme = null, $name = null)
88 {
89 $this->role = $role;
90 $this->scheme = $scheme;
91 $this->name = $name;
92 }
93
94 /**
95 * String-ified version
96 *
97 * @return string
98 */
99 public function __toString()
100 {
101 // There is no $this->data here
102 return md5(serialize($this));
103 }
104
105 /**
106 * Get the role of the person receiving credit
107 *
108 * @return string|null
109 */
110 public function get_role()
111 {
112 if ($this->role !== null)
113 {
114 return $this->role;
115 }
116 else
117 {
118 return null;
119 }
120 }
121
122 /**
123 * Get the organizational scheme
124 *
125 * @return string|null
126 */
127 public function get_scheme()
128 {
129 if ($this->scheme !== null)
130 {
131 return $this->scheme;
132 }
133 else
134 {
135 return null;
136 }
137 }
138
139 /**
140 * Get the credited person/entity's name
141 *
142 * @return string|null
143 */
144 public function get_name()
145 {
146 if ($this->name !== null)
147 {
148 return $this->name;
149 }
150 else
151 {
152 return null;
153 }
154 }
155}
156
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Decode/HTML/Entities.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Decode/HTML/Entities.php
new file mode 100644
index 00000000..069e8d8e
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Decode/HTML/Entities.php
@@ -0,0 +1,617 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Decode HTML Entities
48 *
49 * This implements HTML5 as of revision 967 (2007-06-28)
50 *
51 * @deprecated Use DOMDocument instead!
52 * @package SimplePie
53 */
54class SimplePie_Decode_HTML_Entities
55{
56 /**
57 * Data to be parsed
58 *
59 * @access private
60 * @var string
61 */
62 var $data = '';
63
64 /**
65 * Currently consumed bytes
66 *
67 * @access private
68 * @var string
69 */
70 var $consumed = '';
71
72 /**
73 * Position of the current byte being parsed
74 *
75 * @access private
76 * @var int
77 */
78 var $position = 0;
79
80 /**
81 * Create an instance of the class with the input data
82 *
83 * @access public
84 * @param string $data Input data
85 */
86 public function __construct($data)
87 {
88 $this->data = $data;
89 }
90
91 /**
92 * Parse the input data
93 *
94 * @access public
95 * @return string Output data
96 */
97 public function parse()
98 {
99 while (($this->position = strpos($this->data, '&', $this->position)) !== false)
100 {
101 $this->consume();
102 $this->entity();
103 $this->consumed = '';
104 }
105 return $this->data;
106 }
107
108 /**
109 * Consume the next byte
110 *
111 * @access private
112 * @return mixed The next byte, or false, if there is no more data
113 */
114 public function consume()
115 {
116 if (isset($this->data[$this->position]))
117 {
118 $this->consumed .= $this->data[$this->position];
119 return $this->data[$this->position++];
120 }
121 else
122 {
123 return false;
124 }
125 }
126
127 /**
128 * Consume a range of characters
129 *
130 * @access private
131 * @param string $chars Characters to consume
132 * @return mixed A series of characters that match the range, or false
133 */
134 public function consume_range($chars)
135 {
136 if ($len = strspn($this->data, $chars, $this->position))
137 {
138 $data = substr($this->data, $this->position, $len);
139 $this->consumed .= $data;
140 $this->position += $len;
141 return $data;
142 }
143 else
144 {
145 return false;
146 }
147 }
148
149 /**
150 * Unconsume one byte
151 *
152 * @access private
153 */
154 public function unconsume()
155 {
156 $this->consumed = substr($this->consumed, 0, -1);
157 $this->position--;
158 }
159
160 /**
161 * Decode an entity
162 *
163 * @access private
164 */
165 public function entity()
166 {
167 switch ($this->consume())
168 {
169 case "\x09":
170 case "\x0A":
171 case "\x0B":
172 case "\x0B":
173 case "\x0C":
174 case "\x20":
175 case "\x3C":
176 case "\x26":
177 case false:
178 break;
179
180 case "\x23":
181 switch ($this->consume())
182 {
183 case "\x78":
184 case "\x58":
185 $range = '0123456789ABCDEFabcdef';
186 $hex = true;
187 break;
188
189 default:
190 $range = '0123456789';
191 $hex = false;
192 $this->unconsume();
193 break;
194 }
195
196 if ($codepoint = $this->consume_range($range))
197 {
198 static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
199
200 if ($hex)
201 {
202 $codepoint = hexdec($codepoint);
203 }
204 else
205 {
206 $codepoint = intval($codepoint);
207 }
208
209 if (isset($windows_1252_specials[$codepoint]))
210 {
211 $replacement = $windows_1252_specials[$codepoint];
212 }
213 else
214 {
215 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
216 }
217
218 if (!in_array($this->consume(), array(';', false), true))
219 {
220 $this->unconsume();
221 }
222
223 $consumed_length = strlen($this->consumed);
224 $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
225 $this->position += strlen($replacement) - $consumed_length;
226 }
227 break;
228
229 default:
230 static $entities = array(
231 'Aacute' => "\xC3\x81",
232 'aacute' => "\xC3\xA1",
233 'Aacute;' => "\xC3\x81",
234 'aacute;' => "\xC3\xA1",
235 'Acirc' => "\xC3\x82",
236 'acirc' => "\xC3\xA2",
237 'Acirc;' => "\xC3\x82",
238 'acirc;' => "\xC3\xA2",
239 'acute' => "\xC2\xB4",
240 'acute;' => "\xC2\xB4",
241 'AElig' => "\xC3\x86",
242 'aelig' => "\xC3\xA6",
243 'AElig;' => "\xC3\x86",
244 'aelig;' => "\xC3\xA6",
245 'Agrave' => "\xC3\x80",
246 'agrave' => "\xC3\xA0",
247 'Agrave;' => "\xC3\x80",
248 'agrave;' => "\xC3\xA0",
249 'alefsym;' => "\xE2\x84\xB5",
250 'Alpha;' => "\xCE\x91",
251 'alpha;' => "\xCE\xB1",
252 'AMP' => "\x26",
253 'amp' => "\x26",
254 'AMP;' => "\x26",
255 'amp;' => "\x26",
256 'and;' => "\xE2\x88\xA7",
257 'ang;' => "\xE2\x88\xA0",
258 'apos;' => "\x27",
259 'Aring' => "\xC3\x85",
260 'aring' => "\xC3\xA5",
261 'Aring;' => "\xC3\x85",
262 'aring;' => "\xC3\xA5",
263 'asymp;' => "\xE2\x89\x88",
264 'Atilde' => "\xC3\x83",
265 'atilde' => "\xC3\xA3",
266 'Atilde;' => "\xC3\x83",
267 'atilde;' => "\xC3\xA3",
268 'Auml' => "\xC3\x84",
269 'auml' => "\xC3\xA4",
270 'Auml;' => "\xC3\x84",
271 'auml;' => "\xC3\xA4",
272 'bdquo;' => "\xE2\x80\x9E",
273 'Beta;' => "\xCE\x92",
274 'beta;' => "\xCE\xB2",
275 'brvbar' => "\xC2\xA6",
276 'brvbar;' => "\xC2\xA6",
277 'bull;' => "\xE2\x80\xA2",
278 'cap;' => "\xE2\x88\xA9",
279 'Ccedil' => "\xC3\x87",
280 'ccedil' => "\xC3\xA7",
281 'Ccedil;' => "\xC3\x87",
282 'ccedil;' => "\xC3\xA7",
283 'cedil' => "\xC2\xB8",
284 'cedil;' => "\xC2\xB8",
285 'cent' => "\xC2\xA2",
286 'cent;' => "\xC2\xA2",
287 'Chi;' => "\xCE\xA7",
288 'chi;' => "\xCF\x87",
289 'circ;' => "\xCB\x86",
290 'clubs;' => "\xE2\x99\xA3",
291 'cong;' => "\xE2\x89\x85",
292 'COPY' => "\xC2\xA9",
293 'copy' => "\xC2\xA9",
294 'COPY;' => "\xC2\xA9",
295 'copy;' => "\xC2\xA9",
296 'crarr;' => "\xE2\x86\xB5",
297 'cup;' => "\xE2\x88\xAA",
298 'curren' => "\xC2\xA4",
299 'curren;' => "\xC2\xA4",
300 'Dagger;' => "\xE2\x80\xA1",
301 'dagger;' => "\xE2\x80\xA0",
302 'dArr;' => "\xE2\x87\x93",
303 'darr;' => "\xE2\x86\x93",
304 'deg' => "\xC2\xB0",
305 'deg;' => "\xC2\xB0",
306 'Delta;' => "\xCE\x94",
307 'delta;' => "\xCE\xB4",
308 'diams;' => "\xE2\x99\xA6",
309 'divide' => "\xC3\xB7",
310 'divide;' => "\xC3\xB7",
311 'Eacute' => "\xC3\x89",
312 'eacute' => "\xC3\xA9",
313 'Eacute;' => "\xC3\x89",
314 'eacute;' => "\xC3\xA9",
315 'Ecirc' => "\xC3\x8A",
316 'ecirc' => "\xC3\xAA",
317 'Ecirc;' => "\xC3\x8A",
318 'ecirc;' => "\xC3\xAA",
319 'Egrave' => "\xC3\x88",
320 'egrave' => "\xC3\xA8",
321 'Egrave;' => "\xC3\x88",
322 'egrave;' => "\xC3\xA8",
323 'empty;' => "\xE2\x88\x85",
324 'emsp;' => "\xE2\x80\x83",
325 'ensp;' => "\xE2\x80\x82",
326 'Epsilon;' => "\xCE\x95",
327 'epsilon;' => "\xCE\xB5",
328 'equiv;' => "\xE2\x89\xA1",
329 'Eta;' => "\xCE\x97",
330 'eta;' => "\xCE\xB7",
331 'ETH' => "\xC3\x90",
332 'eth' => "\xC3\xB0",
333 'ETH;' => "\xC3\x90",
334 'eth;' => "\xC3\xB0",
335 'Euml' => "\xC3\x8B",
336 'euml' => "\xC3\xAB",
337 'Euml;' => "\xC3\x8B",
338 'euml;' => "\xC3\xAB",
339 'euro;' => "\xE2\x82\xAC",
340 'exist;' => "\xE2\x88\x83",
341 'fnof;' => "\xC6\x92",
342 'forall;' => "\xE2\x88\x80",
343 'frac12' => "\xC2\xBD",
344 'frac12;' => "\xC2\xBD",
345 'frac14' => "\xC2\xBC",
346 'frac14;' => "\xC2\xBC",
347 'frac34' => "\xC2\xBE",
348 'frac34;' => "\xC2\xBE",
349 'frasl;' => "\xE2\x81\x84",
350 'Gamma;' => "\xCE\x93",
351 'gamma;' => "\xCE\xB3",
352 'ge;' => "\xE2\x89\xA5",
353 'GT' => "\x3E",
354 'gt' => "\x3E",
355 'GT;' => "\x3E",
356 'gt;' => "\x3E",
357 'hArr;' => "\xE2\x87\x94",
358 'harr;' => "\xE2\x86\x94",
359 'hearts;' => "\xE2\x99\xA5",
360 'hellip;' => "\xE2\x80\xA6",
361 'Iacute' => "\xC3\x8D",
362 'iacute' => "\xC3\xAD",
363 'Iacute;' => "\xC3\x8D",
364 'iacute;' => "\xC3\xAD",
365 'Icirc' => "\xC3\x8E",
366 'icirc' => "\xC3\xAE",
367 'Icirc;' => "\xC3\x8E",
368 'icirc;' => "\xC3\xAE",
369 'iexcl' => "\xC2\xA1",
370 'iexcl;' => "\xC2\xA1",
371 'Igrave' => "\xC3\x8C",
372 'igrave' => "\xC3\xAC",
373 'Igrave;' => "\xC3\x8C",
374 'igrave;' => "\xC3\xAC",
375 'image;' => "\xE2\x84\x91",
376 'infin;' => "\xE2\x88\x9E",
377 'int;' => "\xE2\x88\xAB",
378 'Iota;' => "\xCE\x99",
379 'iota;' => "\xCE\xB9",
380 'iquest' => "\xC2\xBF",
381 'iquest;' => "\xC2\xBF",
382 'isin;' => "\xE2\x88\x88",
383 'Iuml' => "\xC3\x8F",
384 'iuml' => "\xC3\xAF",
385 'Iuml;' => "\xC3\x8F",
386 'iuml;' => "\xC3\xAF",
387 'Kappa;' => "\xCE\x9A",
388 'kappa;' => "\xCE\xBA",
389 'Lambda;' => "\xCE\x9B",
390 'lambda;' => "\xCE\xBB",
391 'lang;' => "\xE3\x80\x88",
392 'laquo' => "\xC2\xAB",
393 'laquo;' => "\xC2\xAB",
394 'lArr;' => "\xE2\x87\x90",
395 'larr;' => "\xE2\x86\x90",
396 'lceil;' => "\xE2\x8C\x88",
397 'ldquo;' => "\xE2\x80\x9C",
398 'le;' => "\xE2\x89\xA4",
399 'lfloor;' => "\xE2\x8C\x8A",
400 'lowast;' => "\xE2\x88\x97",
401 'loz;' => "\xE2\x97\x8A",
402 'lrm;' => "\xE2\x80\x8E",
403 'lsaquo;' => "\xE2\x80\xB9",
404 'lsquo;' => "\xE2\x80\x98",
405 'LT' => "\x3C",
406 'lt' => "\x3C",
407 'LT;' => "\x3C",
408 'lt;' => "\x3C",
409 'macr' => "\xC2\xAF",
410 'macr;' => "\xC2\xAF",
411 'mdash;' => "\xE2\x80\x94",
412 'micro' => "\xC2\xB5",
413 'micro;' => "\xC2\xB5",
414 'middot' => "\xC2\xB7",
415 'middot;' => "\xC2\xB7",
416 'minus;' => "\xE2\x88\x92",
417 'Mu;' => "\xCE\x9C",
418 'mu;' => "\xCE\xBC",
419 'nabla;' => "\xE2\x88\x87",
420 'nbsp' => "\xC2\xA0",
421 'nbsp;' => "\xC2\xA0",
422 'ndash;' => "\xE2\x80\x93",
423 'ne;' => "\xE2\x89\xA0",
424 'ni;' => "\xE2\x88\x8B",
425 'not' => "\xC2\xAC",
426 'not;' => "\xC2\xAC",
427 'notin;' => "\xE2\x88\x89",
428 'nsub;' => "\xE2\x8A\x84",
429 'Ntilde' => "\xC3\x91",
430 'ntilde' => "\xC3\xB1",
431 'Ntilde;' => "\xC3\x91",
432 'ntilde;' => "\xC3\xB1",
433 'Nu;' => "\xCE\x9D",
434 'nu;' => "\xCE\xBD",
435 'Oacute' => "\xC3\x93",
436 'oacute' => "\xC3\xB3",
437 'Oacute;' => "\xC3\x93",
438 'oacute;' => "\xC3\xB3",
439 'Ocirc' => "\xC3\x94",
440 'ocirc' => "\xC3\xB4",
441 'Ocirc;' => "\xC3\x94",
442 'ocirc;' => "\xC3\xB4",
443 'OElig;' => "\xC5\x92",
444 'oelig;' => "\xC5\x93",
445 'Ograve' => "\xC3\x92",
446 'ograve' => "\xC3\xB2",
447 'Ograve;' => "\xC3\x92",
448 'ograve;' => "\xC3\xB2",
449 'oline;' => "\xE2\x80\xBE",
450 'Omega;' => "\xCE\xA9",
451 'omega;' => "\xCF\x89",
452 'Omicron;' => "\xCE\x9F",
453 'omicron;' => "\xCE\xBF",
454 'oplus;' => "\xE2\x8A\x95",
455 'or;' => "\xE2\x88\xA8",
456 'ordf' => "\xC2\xAA",
457 'ordf;' => "\xC2\xAA",
458 'ordm' => "\xC2\xBA",
459 'ordm;' => "\xC2\xBA",
460 'Oslash' => "\xC3\x98",
461 'oslash' => "\xC3\xB8",
462 'Oslash;' => "\xC3\x98",
463 'oslash;' => "\xC3\xB8",
464 'Otilde' => "\xC3\x95",
465 'otilde' => "\xC3\xB5",
466 'Otilde;' => "\xC3\x95",
467 'otilde;' => "\xC3\xB5",
468 'otimes;' => "\xE2\x8A\x97",
469 'Ouml' => "\xC3\x96",
470 'ouml' => "\xC3\xB6",
471 'Ouml;' => "\xC3\x96",
472 'ouml;' => "\xC3\xB6",
473 'para' => "\xC2\xB6",
474 'para;' => "\xC2\xB6",
475 'part;' => "\xE2\x88\x82",
476 'permil;' => "\xE2\x80\xB0",
477 'perp;' => "\xE2\x8A\xA5",
478 'Phi;' => "\xCE\xA6",
479 'phi;' => "\xCF\x86",
480 'Pi;' => "\xCE\xA0",
481 'pi;' => "\xCF\x80",
482 'piv;' => "\xCF\x96",
483 'plusmn' => "\xC2\xB1",
484 'plusmn;' => "\xC2\xB1",
485 'pound' => "\xC2\xA3",
486 'pound;' => "\xC2\xA3",
487 'Prime;' => "\xE2\x80\xB3",
488 'prime;' => "\xE2\x80\xB2",
489 'prod;' => "\xE2\x88\x8F",
490 'prop;' => "\xE2\x88\x9D",
491 'Psi;' => "\xCE\xA8",
492 'psi;' => "\xCF\x88",
493 'QUOT' => "\x22",
494 'quot' => "\x22",
495 'QUOT;' => "\x22",
496 'quot;' => "\x22",
497 'radic;' => "\xE2\x88\x9A",
498 'rang;' => "\xE3\x80\x89",
499 'raquo' => "\xC2\xBB",
500 'raquo;' => "\xC2\xBB",
501 'rArr;' => "\xE2\x87\x92",
502 'rarr;' => "\xE2\x86\x92",
503 'rceil;' => "\xE2\x8C\x89",
504 'rdquo;' => "\xE2\x80\x9D",
505 'real;' => "\xE2\x84\x9C",
506 'REG' => "\xC2\xAE",
507 'reg' => "\xC2\xAE",
508 'REG;' => "\xC2\xAE",
509 'reg;' => "\xC2\xAE",
510 'rfloor;' => "\xE2\x8C\x8B",
511 'Rho;' => "\xCE\xA1",
512 'rho;' => "\xCF\x81",
513 'rlm;' => "\xE2\x80\x8F",
514 'rsaquo;' => "\xE2\x80\xBA",
515 'rsquo;' => "\xE2\x80\x99",
516 'sbquo;' => "\xE2\x80\x9A",
517 'Scaron;' => "\xC5\xA0",
518 'scaron;' => "\xC5\xA1",
519 'sdot;' => "\xE2\x8B\x85",
520 'sect' => "\xC2\xA7",
521 'sect;' => "\xC2\xA7",
522 'shy' => "\xC2\xAD",
523 'shy;' => "\xC2\xAD",
524 'Sigma;' => "\xCE\xA3",
525 'sigma;' => "\xCF\x83",
526 'sigmaf;' => "\xCF\x82",
527 'sim;' => "\xE2\x88\xBC",
528 'spades;' => "\xE2\x99\xA0",
529 'sub;' => "\xE2\x8A\x82",
530 'sube;' => "\xE2\x8A\x86",
531 'sum;' => "\xE2\x88\x91",
532 'sup;' => "\xE2\x8A\x83",
533 'sup1' => "\xC2\xB9",
534 'sup1;' => "\xC2\xB9",
535 'sup2' => "\xC2\xB2",
536 'sup2;' => "\xC2\xB2",
537 'sup3' => "\xC2\xB3",
538 'sup3;' => "\xC2\xB3",
539 'supe;' => "\xE2\x8A\x87",
540 'szlig' => "\xC3\x9F",
541 'szlig;' => "\xC3\x9F",
542 'Tau;' => "\xCE\xA4",
543 'tau;' => "\xCF\x84",
544 'there4;' => "\xE2\x88\xB4",
545 'Theta;' => "\xCE\x98",
546 'theta;' => "\xCE\xB8",
547 'thetasym;' => "\xCF\x91",
548 'thinsp;' => "\xE2\x80\x89",
549 'THORN' => "\xC3\x9E",
550 'thorn' => "\xC3\xBE",
551 'THORN;' => "\xC3\x9E",
552 'thorn;' => "\xC3\xBE",
553 'tilde;' => "\xCB\x9C",
554 'times' => "\xC3\x97",
555 'times;' => "\xC3\x97",
556 'TRADE;' => "\xE2\x84\xA2",
557 'trade;' => "\xE2\x84\xA2",
558 'Uacute' => "\xC3\x9A",
559 'uacute' => "\xC3\xBA",
560 'Uacute;' => "\xC3\x9A",
561 'uacute;' => "\xC3\xBA",
562 'uArr;' => "\xE2\x87\x91",
563 'uarr;' => "\xE2\x86\x91",
564 'Ucirc' => "\xC3\x9B",
565 'ucirc' => "\xC3\xBB",
566 'Ucirc;' => "\xC3\x9B",
567 'ucirc;' => "\xC3\xBB",
568 'Ugrave' => "\xC3\x99",
569 'ugrave' => "\xC3\xB9",
570 'Ugrave;' => "\xC3\x99",
571 'ugrave;' => "\xC3\xB9",
572 'uml' => "\xC2\xA8",
573 'uml;' => "\xC2\xA8",
574 'upsih;' => "\xCF\x92",
575 'Upsilon;' => "\xCE\xA5",
576 'upsilon;' => "\xCF\x85",
577 'Uuml' => "\xC3\x9C",
578 'uuml' => "\xC3\xBC",
579 'Uuml;' => "\xC3\x9C",
580 'uuml;' => "\xC3\xBC",
581 'weierp;' => "\xE2\x84\x98",
582 'Xi;' => "\xCE\x9E",
583 'xi;' => "\xCE\xBE",
584 'Yacute' => "\xC3\x9D",
585 'yacute' => "\xC3\xBD",
586 'Yacute;' => "\xC3\x9D",
587 'yacute;' => "\xC3\xBD",
588 'yen' => "\xC2\xA5",
589 'yen;' => "\xC2\xA5",
590 'yuml' => "\xC3\xBF",
591 'Yuml;' => "\xC5\xB8",
592 'yuml;' => "\xC3\xBF",
593 'Zeta;' => "\xCE\x96",
594 'zeta;' => "\xCE\xB6",
595 'zwj;' => "\xE2\x80\x8D",
596 'zwnj;' => "\xE2\x80\x8C"
597 );
598
599 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
600 {
601 $consumed = substr($this->consumed, 1);
602 if (isset($entities[$consumed]))
603 {
604 $match = $consumed;
605 }
606 }
607
608 if ($match !== null)
609 {
610 $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
611 $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
612 }
613 break;
614 }
615 }
616}
617
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Enclosure.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Enclosure.php
new file mode 100644
index 00000000..55674379
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Enclosure.php
@@ -0,0 +1,1380 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Handles everything related to enclosures (including Media RSS and iTunes RSS)
47 *
48 * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Enclosure
56{
57 /**
58 * @var string
59 * @see get_bitrate()
60 */
61 var $bitrate;
62
63 /**
64 * @var array
65 * @see get_captions()
66 */
67 var $captions;
68
69 /**
70 * @var array
71 * @see get_categories()
72 */
73 var $categories;
74
75 /**
76 * @var int
77 * @see get_channels()
78 */
79 var $channels;
80
81 /**
82 * @var SimplePie_Copyright
83 * @see get_copyright()
84 */
85 var $copyright;
86
87 /**
88 * @var array
89 * @see get_credits()
90 */
91 var $credits;
92
93 /**
94 * @var string
95 * @see get_description()
96 */
97 var $description;
98
99 /**
100 * @var int
101 * @see get_duration()
102 */
103 var $duration;
104
105 /**
106 * @var string
107 * @see get_expression()
108 */
109 var $expression;
110
111 /**
112 * @var string
113 * @see get_framerate()
114 */
115 var $framerate;
116
117 /**
118 * @var string
119 * @see get_handler()
120 */
121 var $handler;
122
123 /**
124 * @var array
125 * @see get_hashes()
126 */
127 var $hashes;
128
129 /**
130 * @var string
131 * @see get_height()
132 */
133 var $height;
134
135 /**
136 * @deprecated
137 * @var null
138 */
139 var $javascript;
140
141 /**
142 * @var array
143 * @see get_keywords()
144 */
145 var $keywords;
146
147 /**
148 * @var string
149 * @see get_language()
150 */
151 var $lang;
152
153 /**
154 * @var string
155 * @see get_length()
156 */
157 var $length;
158
159 /**
160 * @var string
161 * @see get_link()
162 */
163 var $link;
164
165 /**
166 * @var string
167 * @see get_medium()
168 */
169 var $medium;
170
171 /**
172 * @var string
173 * @see get_player()
174 */
175 var $player;
176
177 /**
178 * @var array
179 * @see get_ratings()
180 */
181 var $ratings;
182
183 /**
184 * @var array
185 * @see get_restrictions()
186 */
187 var $restrictions;
188
189 /**
190 * @var string
191 * @see get_sampling_rate()
192 */
193 var $samplingrate;
194
195 /**
196 * @var array
197 * @see get_thumbnails()
198 */
199 var $thumbnails;
200
201 /**
202 * @var string
203 * @see get_title()
204 */
205 var $title;
206
207 /**
208 * @var string
209 * @see get_type()
210 */
211 var $type;
212
213 /**
214 * @var string
215 * @see get_width()
216 */
217 var $width;
218
219 /**
220 * Constructor, used to input the data
221 *
222 * For documentation on all the parameters, see the corresponding
223 * properties and their accessors
224 *
225 * @uses idna_convert If available, this will convert an IDN
226 */
227 public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
228 {
229 $this->bitrate = $bitrate;
230 $this->captions = $captions;
231 $this->categories = $categories;
232 $this->channels = $channels;
233 $this->copyright = $copyright;
234 $this->credits = $credits;
235 $this->description = $description;
236 $this->duration = $duration;
237 $this->expression = $expression;
238 $this->framerate = $framerate;
239 $this->hashes = $hashes;
240 $this->height = $height;
241 $this->keywords = $keywords;
242 $this->lang = $lang;
243 $this->length = $length;
244 $this->link = $link;
245 $this->medium = $medium;
246 $this->player = $player;
247 $this->ratings = $ratings;
248 $this->restrictions = $restrictions;
249 $this->samplingrate = $samplingrate;
250 $this->thumbnails = $thumbnails;
251 $this->title = $title;
252 $this->type = $type;
253 $this->width = $width;
254
255 if (class_exists('idna_convert'))
256 {
257 $idn = new idna_convert();
258 $parsed = SimplePie_Misc::parse_url($link);
259 $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
260 }
261 $this->handler = $this->get_handler(); // Needs to load last
262 }
263
264 /**
265 * String-ified version
266 *
267 * @return string
268 */
269 public function __toString()
270 {
271 // There is no $this->data here
272 return md5(serialize($this));
273 }
274
275 /**
276 * Get the bitrate
277 *
278 * @return string|null
279 */
280 public function get_bitrate()
281 {
282 if ($this->bitrate !== null)
283 {
284 return $this->bitrate;
285 }
286 else
287 {
288 return null;
289 }
290 }
291
292 /**
293 * Get a single caption
294 *
295 * @param int $key
296 * @return SimplePie_Caption|null
297 */
298 public function get_caption($key = 0)
299 {
300 $captions = $this->get_captions();
301 if (isset($captions[$key]))
302 {
303 return $captions[$key];
304 }
305 else
306 {
307 return null;
308 }
309 }
310
311 /**
312 * Get all captions
313 *
314 * @return array|null Array of {@see SimplePie_Caption} objects
315 */
316 public function get_captions()
317 {
318 if ($this->captions !== null)
319 {
320 return $this->captions;
321 }
322 else
323 {
324 return null;
325 }
326 }
327
328 /**
329 * Get a single category
330 *
331 * @param int $key
332 * @return SimplePie_Category|null
333 */
334 public function get_category($key = 0)
335 {
336 $categories = $this->get_categories();
337 if (isset($categories[$key]))
338 {
339 return $categories[$key];
340 }
341 else
342 {
343 return null;
344 }
345 }
346
347 /**
348 * Get all categories
349 *
350 * @return array|null Array of {@see SimplePie_Category} objects
351 */
352 public function get_categories()
353 {
354 if ($this->categories !== null)
355 {
356 return $this->categories;
357 }
358 else
359 {
360 return null;
361 }
362 }
363
364 /**
365 * Get the number of audio channels
366 *
367 * @return int|null
368 */
369 public function get_channels()
370 {
371 if ($this->channels !== null)
372 {
373 return $this->channels;
374 }
375 else
376 {
377 return null;
378 }
379 }
380
381 /**
382 * Get the copyright information
383 *
384 * @return SimplePie_Copyright|null
385 */
386 public function get_copyright()
387 {
388 if ($this->copyright !== null)
389 {
390 return $this->copyright;
391 }
392 else
393 {
394 return null;
395 }
396 }
397
398 /**
399 * Get a single credit
400 *
401 * @param int $key
402 * @return SimplePie_Credit|null
403 */
404 public function get_credit($key = 0)
405 {
406 $credits = $this->get_credits();
407 if (isset($credits[$key]))
408 {
409 return $credits[$key];
410 }
411 else
412 {
413 return null;
414 }
415 }
416
417 /**
418 * Get all credits
419 *
420 * @return array|null Array of {@see SimplePie_Credit} objects
421 */
422 public function get_credits()
423 {
424 if ($this->credits !== null)
425 {
426 return $this->credits;
427 }
428 else
429 {
430 return null;
431 }
432 }
433
434 /**
435 * Get the description of the enclosure
436 *
437 * @return string|null
438 */
439 public function get_description()
440 {
441 if ($this->description !== null)
442 {
443 return $this->description;
444 }
445 else
446 {
447 return null;
448 }
449 }
450
451 /**
452 * Get the duration of the enclosure
453 *
454 * @param string $convert Convert seconds into hh:mm:ss
455 * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
456 */
457 public function get_duration($convert = false)
458 {
459 if ($this->duration !== null)
460 {
461 if ($convert)
462 {
463 $time = SimplePie_Misc::time_hms($this->duration);
464 return $time;
465 }
466 else
467 {
468 return $this->duration;
469 }
470 }
471 else
472 {
473 return null;
474 }
475 }
476
477 /**
478 * Get the expression
479 *
480 * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
481 */
482 public function get_expression()
483 {
484 if ($this->expression !== null)
485 {
486 return $this->expression;
487 }
488 else
489 {
490 return 'full';
491 }
492 }
493
494 /**
495 * Get the file extension
496 *
497 * @return string|null
498 */
499 public function get_extension()
500 {
501 if ($this->link !== null)
502 {
503 $url = SimplePie_Misc::parse_url($this->link);
504 if ($url['path'] !== '')
505 {
506 return pathinfo($url['path'], PATHINFO_EXTENSION);
507 }
508 }
509 return null;
510 }
511
512 /**
513 * Get the framerate (in frames-per-second)
514 *
515 * @return string|null
516 */
517 public function get_framerate()
518 {
519 if ($this->framerate !== null)
520 {
521 return $this->framerate;
522 }
523 else
524 {
525 return null;
526 }
527 }
528
529 /**
530 * Get the preferred handler
531 *
532 * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
533 */
534 public function get_handler()
535 {
536 return $this->get_real_type(true);
537 }
538
539 /**
540 * Get a single hash
541 *
542 * @link http://www.rssboard.org/media-rss#media-hash
543 * @param int $key
544 * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
545 */
546 public function get_hash($key = 0)
547 {
548 $hashes = $this->get_hashes();
549 if (isset($hashes[$key]))
550 {
551 return $hashes[$key];
552 }
553 else
554 {
555 return null;
556 }
557 }
558
559 /**
560 * Get all credits
561 *
562 * @return array|null Array of strings, see {@see get_hash()}
563 */
564 public function get_hashes()
565 {
566 if ($this->hashes !== null)
567 {
568 return $this->hashes;
569 }
570 else
571 {
572 return null;
573 }
574 }
575
576 /**
577 * Get the height
578 *
579 * @return string|null
580 */
581 public function get_height()
582 {
583 if ($this->height !== null)
584 {
585 return $this->height;
586 }
587 else
588 {
589 return null;
590 }
591 }
592
593 /**
594 * Get the language
595 *
596 * @link http://tools.ietf.org/html/rfc3066
597 * @return string|null Language code as per RFC 3066
598 */
599 public function get_language()
600 {
601 if ($this->lang !== null)
602 {
603 return $this->lang;
604 }
605 else
606 {
607 return null;
608 }
609 }
610
611 /**
612 * Get a single keyword
613 *
614 * @param int $key
615 * @return string|null
616 */
617 public function get_keyword($key = 0)
618 {
619 $keywords = $this->get_keywords();
620 if (isset($keywords[$key]))
621 {
622 return $keywords[$key];
623 }
624 else
625 {
626 return null;
627 }
628 }
629
630 /**
631 * Get all keywords
632 *
633 * @return array|null Array of strings
634 */
635 public function get_keywords()
636 {
637 if ($this->keywords !== null)
638 {
639 return $this->keywords;
640 }
641 else
642 {
643 return null;
644 }
645 }
646
647 /**
648 * Get length
649 *
650 * @return float Length in bytes
651 */
652 public function get_length()
653 {
654 if ($this->length !== null)
655 {
656 return $this->length;
657 }
658 else
659 {
660 return null;
661 }
662 }
663
664 /**
665 * Get the URL
666 *
667 * @return string|null
668 */
669 public function get_link()
670 {
671 if ($this->link !== null)
672 {
673 return urldecode($this->link);
674 }
675 else
676 {
677 return null;
678 }
679 }
680
681 /**
682 * Get the medium
683 *
684 * @link http://www.rssboard.org/media-rss#media-content
685 * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
686 */
687 public function get_medium()
688 {
689 if ($this->medium !== null)
690 {
691 return $this->medium;
692 }
693 else
694 {
695 return null;
696 }
697 }
698
699 /**
700 * Get the player URL
701 *
702 * Typically the same as {@see get_permalink()}
703 * @return string|null Player URL
704 */
705 public function get_player()
706 {
707 if ($this->player !== null)
708 {
709 return $this->player;
710 }
711 else
712 {
713 return null;
714 }
715 }
716
717 /**
718 * Get a single rating
719 *
720 * @param int $key
721 * @return SimplePie_Rating|null
722 */
723 public function get_rating($key = 0)
724 {
725 $ratings = $this->get_ratings();
726 if (isset($ratings[$key]))
727 {
728 return $ratings[$key];
729 }
730 else
731 {
732 return null;
733 }
734 }
735
736 /**
737 * Get all ratings
738 *
739 * @return array|null Array of {@see SimplePie_Rating} objects
740 */
741 public function get_ratings()
742 {
743 if ($this->ratings !== null)
744 {
745 return $this->ratings;
746 }
747 else
748 {
749 return null;
750 }
751 }
752
753 /**
754 * Get a single restriction
755 *
756 * @param int $key
757 * @return SimplePie_Restriction|null
758 */
759 public function get_restriction($key = 0)
760 {
761 $restrictions = $this->get_restrictions();
762 if (isset($restrictions[$key]))
763 {
764 return $restrictions[$key];
765 }
766 else
767 {
768 return null;
769 }
770 }
771
772 /**
773 * Get all restrictions
774 *
775 * @return array|null Array of {@see SimplePie_Restriction} objects
776 */
777 public function get_restrictions()
778 {
779 if ($this->restrictions !== null)
780 {
781 return $this->restrictions;
782 }
783 else
784 {
785 return null;
786 }
787 }
788
789 /**
790 * Get the sampling rate (in kHz)
791 *
792 * @return string|null
793 */
794 public function get_sampling_rate()
795 {
796 if ($this->samplingrate !== null)
797 {
798 return $this->samplingrate;
799 }
800 else
801 {
802 return null;
803 }
804 }
805
806 /**
807 * Get the file size (in MiB)
808 *
809 * @return float|null File size in mebibytes (1048 bytes)
810 */
811 public function get_size()
812 {
813 $length = $this->get_length();
814 if ($length !== null)
815 {
816 return round($length/1048576, 2);
817 }
818 else
819 {
820 return null;
821 }
822 }
823
824 /**
825 * Get a single thumbnail
826 *
827 * @param int $key
828 * @return string|null Thumbnail URL
829 */
830 public function get_thumbnail($key = 0)
831 {
832 $thumbnails = $this->get_thumbnails();
833 if (isset($thumbnails[$key]))
834 {
835 return $thumbnails[$key];
836 }
837 else
838 {
839 return null;
840 }
841 }
842
843 /**
844 * Get all thumbnails
845 *
846 * @return array|null Array of thumbnail URLs
847 */
848 public function get_thumbnails()
849 {
850 if ($this->thumbnails !== null)
851 {
852 return $this->thumbnails;
853 }
854 else
855 {
856 return null;
857 }
858 }
859
860 /**
861 * Get the title
862 *
863 * @return string|null
864 */
865 public function get_title()
866 {
867 if ($this->title !== null)
868 {
869 return $this->title;
870 }
871 else
872 {
873 return null;
874 }
875 }
876
877 /**
878 * Get mimetype of the enclosure
879 *
880 * @see get_real_type()
881 * @return string|null MIME type
882 */
883 public function get_type()
884 {
885 if ($this->type !== null)
886 {
887 return $this->type;
888 }
889 else
890 {
891 return null;
892 }
893 }
894
895 /**
896 * Get the width
897 *
898 * @return string|null
899 */
900 public function get_width()
901 {
902 if ($this->width !== null)
903 {
904 return $this->width;
905 }
906 else
907 {
908 return null;
909 }
910 }
911
912 /**
913 * Embed the enclosure using `<embed>`
914 *
915 * @deprecated Use the second parameter to {@see embed} instead
916 *
917 * @param array|string $options See first paramter to {@see embed}
918 * @return string HTML string to output
919 */
920 public function native_embed($options='')
921 {
922 return $this->embed($options, true);
923 }
924
925 /**
926 * Embed the enclosure using Javascript
927 *
928 * `$options` is an array or comma-separated key:value string, with the
929 * following properties:
930 *
931 * - `alt` (string): Alternate content for when an end-user does not have
932 * the appropriate handler installed or when a file type is
933 * unsupported. Can be any text or HTML. Defaults to blank.
934 * - `altclass` (string): If a file type is unsupported, the end-user will
935 * see the alt text (above) linked directly to the content. That link
936 * will have this value as its class name. Defaults to blank.
937 * - `audio` (string): This is an image that should be used as a
938 * placeholder for audio files before they're loaded (QuickTime-only).
939 * Can be any relative or absolute URL. Defaults to blank.
940 * - `bgcolor` (string): The background color for the media, if not
941 * already transparent. Defaults to `#ffffff`.
942 * - `height` (integer): The height of the embedded media. Accepts any
943 * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
944 * and it is recommended that you use this default.
945 * - `loop` (boolean): Do you want the media to loop when its done?
946 * Defaults to `false`.
947 * - `mediaplayer` (string): The location of the included
948 * `mediaplayer.swf` file. This allows for the playback of Flash Video
949 * (`.flv`) files, and is the default handler for non-Odeo MP3's.
950 * Defaults to blank.
951 * - `video` (string): This is an image that should be used as a
952 * placeholder for video files before they're loaded (QuickTime-only).
953 * Can be any relative or absolute URL. Defaults to blank.
954 * - `width` (integer): The width of the embedded media. Accepts any
955 * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
956 * and it is recommended that you use this default.
957 * - `widescreen` (boolean): Is the enclosure widescreen or standard?
958 * This applies only to video enclosures, and will automatically resize
959 * the content appropriately. Defaults to `false`, implying 4:3 mode.
960 *
961 * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
962 * will default to 480x360 video resolution. Widescreen (16:9) mode with
963 * `width` and `height` set to `auto` will default to 480x270 video resolution.
964 *
965 * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
966 * @param array|string $options Comma-separated key:value list, or array
967 * @param bool $native Use `<embed>`
968 * @return string HTML string to output
969 */
970 public function embed($options = '', $native = false)
971 {
972 // Set up defaults
973 $audio = '';
974 $video = '';
975 $alt = '';
976 $altclass = '';
977 $loop = 'false';
978 $width = 'auto';
979 $height = 'auto';
980 $bgcolor = '#ffffff';
981 $mediaplayer = '';
982 $widescreen = false;
983 $handler = $this->get_handler();
984 $type = $this->get_real_type();
985
986 // Process options and reassign values as necessary
987 if (is_array($options))
988 {
989 extract($options);
990 }
991 else
992 {
993 $options = explode(',', $options);
994 foreach($options as $option)
995 {
996 $opt = explode(':', $option, 2);
997 if (isset($opt[0], $opt[1]))
998 {
999 $opt[0] = trim($opt[0]);
1000 $opt[1] = trim($opt[1]);
1001 switch ($opt[0])
1002 {
1003 case 'audio':
1004 $audio = $opt[1];
1005 break;
1006
1007 case 'video':
1008 $video = $opt[1];
1009 break;
1010
1011 case 'alt':
1012 $alt = $opt[1];
1013 break;
1014
1015 case 'altclass':
1016 $altclass = $opt[1];
1017 break;
1018
1019 case 'loop':
1020 $loop = $opt[1];
1021 break;
1022
1023 case 'width':
1024 $width = $opt[1];
1025 break;
1026
1027 case 'height':
1028 $height = $opt[1];
1029 break;
1030
1031 case 'bgcolor':
1032 $bgcolor = $opt[1];
1033 break;
1034
1035 case 'mediaplayer':
1036 $mediaplayer = $opt[1];
1037 break;
1038
1039 case 'widescreen':
1040 $widescreen = $opt[1];
1041 break;
1042 }
1043 }
1044 }
1045 }
1046
1047 $mime = explode('/', $type, 2);
1048 $mime = $mime[0];
1049
1050 // Process values for 'auto'
1051 if ($width === 'auto')
1052 {
1053 if ($mime === 'video')
1054 {
1055 if ($height === 'auto')
1056 {
1057 $width = 480;
1058 }
1059 elseif ($widescreen)
1060 {
1061 $width = round((intval($height)/9)*16);
1062 }
1063 else
1064 {
1065 $width = round((intval($height)/3)*4);
1066 }
1067 }
1068 else
1069 {
1070 $width = '100%';
1071 }
1072 }
1073
1074 if ($height === 'auto')
1075 {
1076 if ($mime === 'audio')
1077 {
1078 $height = 0;
1079 }
1080 elseif ($mime === 'video')
1081 {
1082 if ($width === 'auto')
1083 {
1084 if ($widescreen)
1085 {
1086 $height = 270;
1087 }
1088 else
1089 {
1090 $height = 360;
1091 }
1092 }
1093 elseif ($widescreen)
1094 {
1095 $height = round((intval($width)/16)*9);
1096 }
1097 else
1098 {
1099 $height = round((intval($width)/4)*3);
1100 }
1101 }
1102 else
1103 {
1104 $height = 376;
1105 }
1106 }
1107 elseif ($mime === 'audio')
1108 {
1109 $height = 0;
1110 }
1111
1112 // Set proper placeholder value
1113 if ($mime === 'audio')
1114 {
1115 $placeholder = $audio;
1116 }
1117 elseif ($mime === 'video')
1118 {
1119 $placeholder = $video;
1120 }
1121
1122 $embed = '';
1123
1124 // Flash
1125 if ($handler === 'flash')
1126 {
1127 if ($native)
1128 {
1129 $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
1130 }
1131 else
1132 {
1133 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
1134 }
1135 }
1136
1137 // Flash Media Player file types.
1138 // Preferred handler for MP3 file types.
1139 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
1140 {
1141 $height += 20;
1142 if ($native)
1143 {
1144 $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
1145 }
1146 else
1147 {
1148 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
1149 }
1150 }
1151
1152 // QuickTime 7 file types. Need to test with QuickTime 6.
1153 // Only handle MP3's if the Flash Media Player is not present.
1154 elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
1155 {
1156 $height += 16;
1157 if ($native)
1158 {
1159 if ($placeholder !== '')
1160 {
1161 $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
1162 }
1163 else
1164 {
1165 $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
1166 }
1167 }
1168 else
1169 {
1170 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
1171 }
1172 }
1173
1174 // Windows Media
1175 elseif ($handler === 'wmedia')
1176 {
1177 $height += 45;
1178 if ($native)
1179 {
1180 $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
1181 }
1182 else
1183 {
1184 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
1185 }
1186 }
1187
1188 // Everything else
1189 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
1190
1191 return $embed;
1192 }
1193
1194 /**
1195 * Get the real media type
1196 *
1197 * Often, feeds lie to us, necessitating a bit of deeper inspection. This
1198 * converts types to their canonical representations based on the file
1199 * extension
1200 *
1201 * @see get_type()
1202 * @param bool $find_handler Internal use only, use {@see get_handler()} instead
1203 * @return string MIME type
1204 */
1205 public function get_real_type($find_handler = false)
1206 {
1207 // Mime-types by handler.
1208 $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
1209 $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
1210 $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
1211 $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
1212 $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
1213
1214 if ($this->get_type() !== null)
1215 {
1216 $type = strtolower($this->type);
1217 }
1218 else
1219 {
1220 $type = null;
1221 }
1222
1223 // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
1224 if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
1225 {
1226 switch (strtolower($this->get_extension()))
1227 {
1228 // Audio mime-types
1229 case 'aac':
1230 case 'adts':
1231 $type = 'audio/acc';
1232 break;
1233
1234 case 'aif':
1235 case 'aifc':
1236 case 'aiff':
1237 case 'cdda':
1238 $type = 'audio/aiff';
1239 break;
1240
1241 case 'bwf':
1242 $type = 'audio/wav';
1243 break;
1244
1245 case 'kar':
1246 case 'mid':
1247 case 'midi':
1248 case 'smf':
1249 $type = 'audio/midi';
1250 break;
1251
1252 case 'm4a':
1253 $type = 'audio/x-m4a';
1254 break;
1255
1256 case 'mp3':
1257 case 'swa':
1258 $type = 'audio/mp3';
1259 break;
1260
1261 case 'wav':
1262 $type = 'audio/wav';
1263 break;
1264
1265 case 'wax':
1266 $type = 'audio/x-ms-wax';
1267 break;
1268
1269 case 'wma':
1270 $type = 'audio/x-ms-wma';
1271 break;
1272
1273 // Video mime-types
1274 case '3gp':
1275 case '3gpp':
1276 $type = 'video/3gpp';
1277 break;
1278
1279 case '3g2':
1280 case '3gp2':
1281 $type = 'video/3gpp2';
1282 break;
1283
1284 case 'asf':
1285 $type = 'video/x-ms-asf';
1286 break;
1287
1288 case 'flv':
1289 $type = 'video/x-flv';
1290 break;
1291
1292 case 'm1a':
1293 case 'm1s':
1294 case 'm1v':
1295 case 'm15':
1296 case 'm75':
1297 case 'mp2':
1298 case 'mpa':
1299 case 'mpeg':
1300 case 'mpg':
1301 case 'mpm':
1302 case 'mpv':
1303 $type = 'video/mpeg';
1304 break;
1305
1306 case 'm4v':
1307 $type = 'video/x-m4v';
1308 break;
1309
1310 case 'mov':
1311 case 'qt':
1312 $type = 'video/quicktime';
1313 break;
1314
1315 case 'mp4':
1316 case 'mpg4':
1317 $type = 'video/mp4';
1318 break;
1319
1320 case 'sdv':
1321 $type = 'video/sd-video';
1322 break;
1323
1324 case 'wm':
1325 $type = 'video/x-ms-wm';
1326 break;
1327
1328 case 'wmv':
1329 $type = 'video/x-ms-wmv';
1330 break;
1331
1332 case 'wvx':
1333 $type = 'video/x-ms-wvx';
1334 break;
1335
1336 // Flash mime-types
1337 case 'spl':
1338 $type = 'application/futuresplash';
1339 break;
1340
1341 case 'swf':
1342 $type = 'application/x-shockwave-flash';
1343 break;
1344 }
1345 }
1346
1347 if ($find_handler)
1348 {
1349 if (in_array($type, $types_flash))
1350 {
1351 return 'flash';
1352 }
1353 elseif (in_array($type, $types_fmedia))
1354 {
1355 return 'fmedia';
1356 }
1357 elseif (in_array($type, $types_quicktime))
1358 {
1359 return 'quicktime';
1360 }
1361 elseif (in_array($type, $types_wmedia))
1362 {
1363 return 'wmedia';
1364 }
1365 elseif (in_array($type, $types_mp3))
1366 {
1367 return 'mp3';
1368 }
1369 else
1370 {
1371 return null;
1372 }
1373 }
1374 else
1375 {
1376 return $type;
1377 }
1378 }
1379}
1380
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Exception.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Exception.php
new file mode 100644
index 00000000..73e104d6
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Exception.php
@@ -0,0 +1,52 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.4-dev
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * General SimplePie exception class
47 *
48 * @package SimplePie
49 */
50class SimplePie_Exception extends Exception
51{
52} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/File.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/File.php
new file mode 100644
index 00000000..b7d1a2ac
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/File.php
@@ -0,0 +1,292 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Used for fetching remote files and reading local files
47 *
48 * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
49 *
50 * This class can be overloaded with {@see SimplePie::set_file_class()}
51 *
52 * @package SimplePie
53 * @subpackage HTTP
54 * @todo Move to properly supporting RFC2616 (HTTP/1.1)
55 */
56class SimplePie_File
57{
58 var $url;
59 var $useragent;
60 var $success = true;
61 var $headers = array();
62 var $body;
63 var $status_code;
64 var $redirects = 0;
65 var $error;
66 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
67
68 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
69 {
70 if (class_exists('idna_convert'))
71 {
72 $idn = new idna_convert();
73 $parsed = SimplePie_Misc::parse_url($url);
74 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
75 }
76 $this->url = $url;
77 $this->useragent = $useragent;
78 if (preg_match('/^http(s)?:\/\//i', $url))
79 {
80 if ($useragent === null)
81 {
82 $useragent = ini_get('user_agent');
83 $this->useragent = $useragent;
84 }
85 if (!is_array($headers))
86 {
87 $headers = array();
88 }
89 if (!$force_fsockopen && function_exists('curl_exec'))
90 {
91 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
92 $fp = curl_init();
93 $headers2 = array();
94 foreach ($headers as $key => $value)
95 {
96 $headers2[] = "$key: $value";
97 }
98 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
99 {
100 curl_setopt($fp, CURLOPT_ENCODING, '');
101 }
102 curl_setopt($fp, CURLOPT_URL, $url);
103 curl_setopt($fp, CURLOPT_HEADER, 1);
104 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
105 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
106 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
107 curl_setopt($fp, CURLOPT_REFERER, $url);
108 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
109 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
110 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
111 {
112 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
113 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
114 }
115
116 $this->headers = curl_exec($fp);
117 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
118 {
119 curl_setopt($fp, CURLOPT_ENCODING, 'none');
120 $this->headers = curl_exec($fp);
121 }
122 if (curl_errno($fp))
123 {
124 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
125 $this->success = false;
126 }
127 else
128 {
129 $info = curl_getinfo($fp);
130 curl_close($fp);
131 $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
132 $this->headers = array_pop($this->headers);
133 $parser = new SimplePie_HTTP_Parser($this->headers);
134 if ($parser->parse())
135 {
136 $this->headers = $parser->headers;
137 $this->body = $parser->body;
138 $this->status_code = $parser->status_code;
139 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
140 {
141 $this->redirects++;
142 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
143 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
144 }
145 }
146 }
147 }
148 else
149 {
150 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
151 $url_parts = parse_url($url);
152 $socket_host = $url_parts['host'];
153 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
154 {
155 $socket_host = "ssl://$url_parts[host]";
156 $url_parts['port'] = 443;
157 }
158 if (!isset($url_parts['port']))
159 {
160 $url_parts['port'] = 80;
161 }
162 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
163 if (!$fp)
164 {
165 $this->error = 'fsockopen error: ' . $errstr;
166 $this->success = false;
167 }
168 else
169 {
170 stream_set_timeout($fp, $timeout);
171 if (isset($url_parts['path']))
172 {
173 if (isset($url_parts['query']))
174 {
175 $get = "$url_parts[path]?$url_parts[query]";
176 }
177 else
178 {
179 $get = $url_parts['path'];
180 }
181 }
182 else
183 {
184 $get = '/';
185 }
186 $out = "GET $get HTTP/1.1\r\n";
187 $out .= "Host: $url_parts[host]\r\n";
188 $out .= "User-Agent: $useragent\r\n";
189 if (extension_loaded('zlib'))
190 {
191 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
192 }
193
194 if (isset($url_parts['user']) && isset($url_parts['pass']))
195 {
196 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
197 }
198 foreach ($headers as $key => $value)
199 {
200 $out .= "$key: $value\r\n";
201 }
202 $out .= "Connection: Close\r\n\r\n";
203 fwrite($fp, $out);
204
205 $info = stream_get_meta_data($fp);
206
207 $this->headers = '';
208 while (!$info['eof'] && !$info['timed_out'])
209 {
210 $this->headers .= fread($fp, 1160);
211 $info = stream_get_meta_data($fp);
212 }
213 if (!$info['timed_out'])
214 {
215 $parser = new SimplePie_HTTP_Parser($this->headers);
216 if ($parser->parse())
217 {
218 $this->headers = $parser->headers;
219 $this->body = $parser->body;
220 $this->status_code = $parser->status_code;
221 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
222 {
223 $this->redirects++;
224 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
225 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
226 }
227 if (isset($this->headers['content-encoding']))
228 {
229 // Hey, we act dumb elsewhere, so let's do that here too
230 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
231 {
232 case 'gzip':
233 case 'x-gzip':
234 $decoder = new SimplePie_gzdecode($this->body);
235 if (!$decoder->parse())
236 {
237 $this->error = 'Unable to decode HTTP "gzip" stream';
238 $this->success = false;
239 }
240 else
241 {
242 $this->body = $decoder->data;
243 }
244 break;
245
246 case 'deflate':
247 if (($decompressed = gzinflate($this->body)) !== false)
248 {
249 $this->body = $decompressed;
250 }
251 else if (($decompressed = gzuncompress($this->body)) !== false)
252 {
253 $this->body = $decompressed;
254 }
255 else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
256 {
257 $this->body = $decompressed;
258 }
259 else
260 {
261 $this->error = 'Unable to decode HTTP "deflate" stream';
262 $this->success = false;
263 }
264 break;
265
266 default:
267 $this->error = 'Unknown content coding';
268 $this->success = false;
269 }
270 }
271 }
272 }
273 else
274 {
275 $this->error = 'fsocket timed out';
276 $this->success = false;
277 }
278 fclose($fp);
279 }
280 }
281 }
282 else
283 {
284 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
285 if (!$this->body = file_get_contents($url))
286 {
287 $this->error = 'file_get_contents could not read the file';
288 $this->success = false;
289 }
290 }
291 }
292}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/HTTP/Parser.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/HTTP/Parser.php
new file mode 100644
index 00000000..bff2222b
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/HTTP/Parser.php
@@ -0,0 +1,500 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * HTTP Response Parser
48 *
49 * @package SimplePie
50 * @subpackage HTTP
51 */
52class SimplePie_HTTP_Parser
53{
54 /**
55 * HTTP Version
56 *
57 * @var float
58 */
59 public $http_version = 0.0;
60
61 /**
62 * Status code
63 *
64 * @var int
65 */
66 public $status_code = 0;
67
68 /**
69 * Reason phrase
70 *
71 * @var string
72 */
73 public $reason = '';
74
75 /**
76 * Key/value pairs of the headers
77 *
78 * @var array
79 */
80 public $headers = array();
81
82 /**
83 * Body of the response
84 *
85 * @var string
86 */
87 public $body = '';
88
89 /**
90 * Current state of the state machine
91 *
92 * @var string
93 */
94 protected $state = 'http_version';
95
96 /**
97 * Input data
98 *
99 * @var string
100 */
101 protected $data = '';
102
103 /**
104 * Input data length (to avoid calling strlen() everytime this is needed)
105 *
106 * @var int
107 */
108 protected $data_length = 0;
109
110 /**
111 * Current position of the pointer
112 *
113 * @var int
114 */
115 protected $position = 0;
116
117 /**
118 * Name of the hedaer currently being parsed
119 *
120 * @var string
121 */
122 protected $name = '';
123
124 /**
125 * Value of the hedaer currently being parsed
126 *
127 * @var string
128 */
129 protected $value = '';
130
131 /**
132 * Create an instance of the class with the input data
133 *
134 * @param string $data Input data
135 */
136 public function __construct($data)
137 {
138 $this->data = $data;
139 $this->data_length = strlen($this->data);
140 }
141
142 /**
143 * Parse the input data
144 *
145 * @return bool true on success, false on failure
146 */
147 public function parse()
148 {
149 while ($this->state && $this->state !== 'emit' && $this->has_data())
150 {
151 $state = $this->state;
152 $this->$state();
153 }
154 $this->data = '';
155 if ($this->state === 'emit' || $this->state === 'body')
156 {
157 return true;
158 }
159 else
160 {
161 $this->http_version = '';
162 $this->status_code = '';
163 $this->reason = '';
164 $this->headers = array();
165 $this->body = '';
166 return false;
167 }
168 }
169
170 /**
171 * Check whether there is data beyond the pointer
172 *
173 * @return bool true if there is further data, false if not
174 */
175 protected function has_data()
176 {
177 return (bool) ($this->position < $this->data_length);
178 }
179
180 /**
181 * See if the next character is LWS
182 *
183 * @return bool true if the next character is LWS, false if not
184 */
185 protected function is_linear_whitespace()
186 {
187 return (bool) ($this->data[$this->position] === "\x09"
188 || $this->data[$this->position] === "\x20"
189 || ($this->data[$this->position] === "\x0A"
190 && isset($this->data[$this->position + 1])
191 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
192 }
193
194 /**
195 * Parse the HTTP version
196 */
197 protected function http_version()
198 {
199 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
200 {
201 $len = strspn($this->data, '0123456789.', 5);
202 $this->http_version = substr($this->data, 5, $len);
203 $this->position += 5 + $len;
204 if (substr_count($this->http_version, '.') <= 1)
205 {
206 $this->http_version = (float) $this->http_version;
207 $this->position += strspn($this->data, "\x09\x20", $this->position);
208 $this->state = 'status';
209 }
210 else
211 {
212 $this->state = false;
213 }
214 }
215 else
216 {
217 $this->state = false;
218 }
219 }
220
221 /**
222 * Parse the status code
223 */
224 protected function status()
225 {
226 if ($len = strspn($this->data, '0123456789', $this->position))
227 {
228 $this->status_code = (int) substr($this->data, $this->position, $len);
229 $this->position += $len;
230 $this->state = 'reason';
231 }
232 else
233 {
234 $this->state = false;
235 }
236 }
237
238 /**
239 * Parse the reason phrase
240 */
241 protected function reason()
242 {
243 $len = strcspn($this->data, "\x0A", $this->position);
244 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
245 $this->position += $len + 1;
246 $this->state = 'new_line';
247 }
248
249 /**
250 * Deal with a new line, shifting data around as needed
251 */
252 protected function new_line()
253 {
254 $this->value = trim($this->value, "\x0D\x20");
255 if ($this->name !== '' && $this->value !== '')
256 {
257 $this->name = strtolower($this->name);
258 // We should only use the last Content-Type header. c.f. issue #1
259 if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
260 {
261 $this->headers[$this->name] .= ', ' . $this->value;
262 }
263 else
264 {
265 $this->headers[$this->name] = $this->value;
266 }
267 }
268 $this->name = '';
269 $this->value = '';
270 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
271 {
272 $this->position += 2;
273 $this->state = 'body';
274 }
275 elseif ($this->data[$this->position] === "\x0A")
276 {
277 $this->position++;
278 $this->state = 'body';
279 }
280 else
281 {
282 $this->state = 'name';
283 }
284 }
285
286 /**
287 * Parse a header name
288 */
289 protected function name()
290 {
291 $len = strcspn($this->data, "\x0A:", $this->position);
292 if (isset($this->data[$this->position + $len]))
293 {
294 if ($this->data[$this->position + $len] === "\x0A")
295 {
296 $this->position += $len;
297 $this->state = 'new_line';
298 }
299 else
300 {
301 $this->name = substr($this->data, $this->position, $len);
302 $this->position += $len + 1;
303 $this->state = 'value';
304 }
305 }
306 else
307 {
308 $this->state = false;
309 }
310 }
311
312 /**
313 * Parse LWS, replacing consecutive LWS characters with a single space
314 */
315 protected function linear_whitespace()
316 {
317 do
318 {
319 if (substr($this->data, $this->position, 2) === "\x0D\x0A")
320 {
321 $this->position += 2;
322 }
323 elseif ($this->data[$this->position] === "\x0A")
324 {
325 $this->position++;
326 }
327 $this->position += strspn($this->data, "\x09\x20", $this->position);
328 } while ($this->has_data() && $this->is_linear_whitespace());
329 $this->value .= "\x20";
330 }
331
332 /**
333 * See what state to move to while within non-quoted header values
334 */
335 protected function value()
336 {
337 if ($this->is_linear_whitespace())
338 {
339 $this->linear_whitespace();
340 }
341 else
342 {
343 switch ($this->data[$this->position])
344 {
345 case '"':
346 // Workaround for ETags: we have to include the quotes as
347 // part of the tag.
348 if (strtolower($this->name) === 'etag')
349 {
350 $this->value .= '"';
351 $this->position++;
352 $this->state = 'value_char';
353 break;
354 }
355 $this->position++;
356 $this->state = 'quote';
357 break;
358
359 case "\x0A":
360 $this->position++;
361 $this->state = 'new_line';
362 break;
363
364 default:
365 $this->state = 'value_char';
366 break;
367 }
368 }
369 }
370
371 /**
372 * Parse a header value while outside quotes
373 */
374 protected function value_char()
375 {
376 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
377 $this->value .= substr($this->data, $this->position, $len);
378 $this->position += $len;
379 $this->state = 'value';
380 }
381
382 /**
383 * See what state to move to while within quoted header values
384 */
385 protected function quote()
386 {
387 if ($this->is_linear_whitespace())
388 {
389 $this->linear_whitespace();
390 }
391 else
392 {
393 switch ($this->data[$this->position])
394 {
395 case '"':
396 $this->position++;
397 $this->state = 'value';
398 break;
399
400 case "\x0A":
401 $this->position++;
402 $this->state = 'new_line';
403 break;
404
405 case '\\':
406 $this->position++;
407 $this->state = 'quote_escaped';
408 break;
409
410 default:
411 $this->state = 'quote_char';
412 break;
413 }
414 }
415 }
416
417 /**
418 * Parse a header value while within quotes
419 */
420 protected function quote_char()
421 {
422 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
423 $this->value .= substr($this->data, $this->position, $len);
424 $this->position += $len;
425 $this->state = 'value';
426 }
427
428 /**
429 * Parse an escaped character within quotes
430 */
431 protected function quote_escaped()
432 {
433 $this->value .= $this->data[$this->position];
434 $this->position++;
435 $this->state = 'quote';
436 }
437
438 /**
439 * Parse the body
440 */
441 protected function body()
442 {
443 $this->body = substr($this->data, $this->position);
444 if (!empty($this->headers['transfer-encoding']))
445 {
446 unset($this->headers['transfer-encoding']);
447 $this->state = 'chunked';
448 }
449 else
450 {
451 $this->state = 'emit';
452 }
453 }
454
455 /**
456 * Parsed a "Transfer-Encoding: chunked" body
457 */
458 protected function chunked()
459 {
460 if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
461 {
462 $this->state = 'emit';
463 return;
464 }
465
466 $decoded = '';
467 $encoded = $this->body;
468
469 while (true)
470 {
471 $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
472 if (!$is_chunked)
473 {
474 // Looks like it's not chunked after all
475 $this->state = 'emit';
476 return;
477 }
478
479 $length = hexdec(trim($matches[1]));
480 if ($length === 0)
481 {
482 // Ignore trailer headers
483 $this->state = 'emit';
484 $this->body = $decoded;
485 return;
486 }
487
488 $chunk_length = strlen($matches[0]);
489 $decoded .= $part = substr($encoded, $chunk_length, $length);
490 $encoded = substr($encoded, $chunk_length + $length + 2);
491
492 if (trim($encoded) === '0' || empty($encoded))
493 {
494 $this->state = 'emit';
495 $this->body = $decoded;
496 return;
497 }
498 }
499 }
500}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/IRI.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/IRI.php
new file mode 100644
index 00000000..d3198c04
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/IRI.php
@@ -0,0 +1,1238 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * IRI parser/serialiser/normaliser
47 *
48 * @package SimplePie
49 * @subpackage HTTP
50 * @author Geoffrey Sneddon
51 * @author Steve Minutillo
52 * @author Ryan McCue
53 * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
54 * @license http://www.opensource.org/licenses/bsd-license.php
55 */
56class SimplePie_IRI
57{
58 /**
59 * Scheme
60 *
61 * @var string
62 */
63 protected $scheme = null;
64
65 /**
66 * User Information
67 *
68 * @var string
69 */
70 protected $iuserinfo = null;
71
72 /**
73 * ihost
74 *
75 * @var string
76 */
77 protected $ihost = null;
78
79 /**
80 * Port
81 *
82 * @var string
83 */
84 protected $port = null;
85
86 /**
87 * ipath
88 *
89 * @var string
90 */
91 protected $ipath = '';
92
93 /**
94 * iquery
95 *
96 * @var string
97 */
98 protected $iquery = null;
99
100 /**
101 * ifragment
102 *
103 * @var string
104 */
105 protected $ifragment = null;
106
107 /**
108 * Normalization database
109 *
110 * Each key is the scheme, each value is an array with each key as the IRI
111 * part and value as the default value for that part.
112 */
113 protected $normalization = array(
114 'acap' => array(
115 'port' => 674
116 ),
117 'dict' => array(
118 'port' => 2628
119 ),
120 'file' => array(
121 'ihost' => 'localhost'
122 ),
123 'http' => array(
124 'port' => 80,
125 'ipath' => '/'
126 ),
127 'https' => array(
128 'port' => 443,
129 'ipath' => '/'
130 ),
131 );
132
133 /**
134 * Return the entire IRI when you try and read the object as a string
135 *
136 * @return string
137 */
138 public function __toString()
139 {
140 return $this->get_iri();
141 }
142
143 /**
144 * Overload __set() to provide access via properties
145 *
146 * @param string $name Property name
147 * @param mixed $value Property value
148 */
149 public function __set($name, $value)
150 {
151 if (method_exists($this, 'set_' . $name))
152 {
153 call_user_func(array($this, 'set_' . $name), $value);
154 }
155 elseif (
156 $name === 'iauthority'
157 || $name === 'iuserinfo'
158 || $name === 'ihost'
159 || $name === 'ipath'
160 || $name === 'iquery'
161 || $name === 'ifragment'
162 )
163 {
164 call_user_func(array($this, 'set_' . substr($name, 1)), $value);
165 }
166 }
167
168 /**
169 * Overload __get() to provide access via properties
170 *
171 * @param string $name Property name
172 * @return mixed
173 */
174 public function __get($name)
175 {
176 // isset() returns false for null, we don't want to do that
177 // Also why we use array_key_exists below instead of isset()
178 $props = get_object_vars($this);
179
180 if (
181 $name === 'iri' ||
182 $name === 'uri' ||
183 $name === 'iauthority' ||
184 $name === 'authority'
185 )
186 {
187 $return = $this->{"get_$name"}();
188 }
189 elseif (array_key_exists($name, $props))
190 {
191 $return = $this->$name;
192 }
193 // host -> ihost
194 elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
195 {
196 $name = $prop;
197 $return = $this->$prop;
198 }
199 // ischeme -> scheme
200 elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
201 {
202 $name = $prop;
203 $return = $this->$prop;
204 }
205 else
206 {
207 trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
208 $return = null;
209 }
210
211 if ($return === null && isset($this->normalization[$this->scheme][$name]))
212 {
213 return $this->normalization[$this->scheme][$name];
214 }
215 else
216 {
217 return $return;
218 }
219 }
220
221 /**
222 * Overload __isset() to provide access via properties
223 *
224 * @param string $name Property name
225 * @return bool
226 */
227 public function __isset($name)
228 {
229 if (method_exists($this, 'get_' . $name) || isset($this->$name))
230 {
231 return true;
232 }
233 else
234 {
235 return false;
236 }
237 }
238
239 /**
240 * Overload __unset() to provide access via properties
241 *
242 * @param string $name Property name
243 */
244 public function __unset($name)
245 {
246 if (method_exists($this, 'set_' . $name))
247 {
248 call_user_func(array($this, 'set_' . $name), '');
249 }
250 }
251
252 /**
253 * Create a new IRI object, from a specified string
254 *
255 * @param string $iri
256 */
257 public function __construct($iri = null)
258 {
259 $this->set_iri($iri);
260 }
261
262 /**
263 * Create a new IRI object by resolving a relative IRI
264 *
265 * Returns false if $base is not absolute, otherwise an IRI.
266 *
267 * @param IRI|string $base (Absolute) Base IRI
268 * @param IRI|string $relative Relative IRI
269 * @return IRI|false
270 */
271 public static function absolutize($base, $relative)
272 {
273 if (!($relative instanceof SimplePie_IRI))
274 {
275 $relative = new SimplePie_IRI($relative);
276 }
277 if (!$relative->is_valid())
278 {
279 return false;
280 }
281 elseif ($relative->scheme !== null)
282 {
283 return clone $relative;
284 }
285 else
286 {
287 if (!($base instanceof SimplePie_IRI))
288 {
289 $base = new SimplePie_IRI($base);
290 }
291 if ($base->scheme !== null && $base->is_valid())
292 {
293 if ($relative->get_iri() !== '')
294 {
295 if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
296 {
297 $target = clone $relative;
298 $target->scheme = $base->scheme;
299 }
300 else
301 {
302 $target = new SimplePie_IRI;
303 $target->scheme = $base->scheme;
304 $target->iuserinfo = $base->iuserinfo;
305 $target->ihost = $base->ihost;
306 $target->port = $base->port;
307 if ($relative->ipath !== '')
308 {
309 if ($relative->ipath[0] === '/')
310 {
311 $target->ipath = $relative->ipath;
312 }
313 elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
314 {
315 $target->ipath = '/' . $relative->ipath;
316 }
317 elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
318 {
319 $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
320 }
321 else
322 {
323 $target->ipath = $relative->ipath;
324 }
325 $target->ipath = $target->remove_dot_segments($target->ipath);
326 $target->iquery = $relative->iquery;
327 }
328 else
329 {
330 $target->ipath = $base->ipath;
331 if ($relative->iquery !== null)
332 {
333 $target->iquery = $relative->iquery;
334 }
335 elseif ($base->iquery !== null)
336 {
337 $target->iquery = $base->iquery;
338 }
339 }
340 $target->ifragment = $relative->ifragment;
341 }
342 }
343 else
344 {
345 $target = clone $base;
346 $target->ifragment = null;
347 }
348 $target->scheme_normalization();
349 return $target;
350 }
351 else
352 {
353 return false;
354 }
355 }
356 }
357
358 /**
359 * Parse an IRI into scheme/authority/path/query/fragment segments
360 *
361 * @param string $iri
362 * @return array
363 */
364 protected function parse_iri($iri)
365 {
366 $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
367 if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
368 {
369 if ($match[1] === '')
370 {
371 $match['scheme'] = null;
372 }
373 if (!isset($match[3]) || $match[3] === '')
374 {
375 $match['authority'] = null;
376 }
377 if (!isset($match[5]))
378 {
379 $match['path'] = '';
380 }
381 if (!isset($match[6]) || $match[6] === '')
382 {
383 $match['query'] = null;
384 }
385 if (!isset($match[8]) || $match[8] === '')
386 {
387 $match['fragment'] = null;
388 }
389 return $match;
390 }
391 else
392 {
393 // This can occur when a paragraph is accidentally parsed as a URI
394 return false;
395 }
396 }
397
398 /**
399 * Remove dot segments from a path
400 *
401 * @param string $input
402 * @return string
403 */
404 protected function remove_dot_segments($input)
405 {
406 $output = '';
407 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
408 {
409 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
410 if (strpos($input, '../') === 0)
411 {
412 $input = substr($input, 3);
413 }
414 elseif (strpos($input, './') === 0)
415 {
416 $input = substr($input, 2);
417 }
418 // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
419 elseif (strpos($input, '/./') === 0)
420 {
421 $input = substr($input, 2);
422 }
423 elseif ($input === '/.')
424 {
425 $input = '/';
426 }
427 // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
428 elseif (strpos($input, '/../') === 0)
429 {
430 $input = substr($input, 3);
431 $output = substr_replace($output, '', strrpos($output, '/'));
432 }
433 elseif ($input === '/..')
434 {
435 $input = '/';
436 $output = substr_replace($output, '', strrpos($output, '/'));
437 }
438 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
439 elseif ($input === '.' || $input === '..')
440 {
441 $input = '';
442 }
443 // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
444 elseif (($pos = strpos($input, '/', 1)) !== false)
445 {
446 $output .= substr($input, 0, $pos);
447 $input = substr_replace($input, '', 0, $pos);
448 }
449 else
450 {
451 $output .= $input;
452 $input = '';
453 }
454 }
455 return $output . $input;
456 }
457
458 /**
459 * Replace invalid character with percent encoding
460 *
461 * @param string $string Input string
462 * @param string $extra_chars Valid characters not in iunreserved or
463 * iprivate (this is ASCII-only)
464 * @param bool $iprivate Allow iprivate
465 * @return string
466 */
467 protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
468 {
469 // Normalize as many pct-encoded sections as possible
470 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
471
472 // Replace invalid percent characters
473 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
474
475 // Add unreserved and % to $extra_chars (the latter is safe because all
476 // pct-encoded sections are now valid).
477 $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
478
479 // Now replace any bytes that aren't allowed with their pct-encoded versions
480 $position = 0;
481 $strlen = strlen($string);
482 while (($position += strspn($string, $extra_chars, $position)) < $strlen)
483 {
484 $value = ord($string[$position]);
485
486 // Start position
487 $start = $position;
488
489 // By default we are valid
490 $valid = true;
491
492 // No one byte sequences are valid due to the while.
493 // Two byte sequence:
494 if (($value & 0xE0) === 0xC0)
495 {
496 $character = ($value & 0x1F) << 6;
497 $length = 2;
498 $remaining = 1;
499 }
500 // Three byte sequence:
501 elseif (($value & 0xF0) === 0xE0)
502 {
503 $character = ($value & 0x0F) << 12;
504 $length = 3;
505 $remaining = 2;
506 }
507 // Four byte sequence:
508 elseif (($value & 0xF8) === 0xF0)
509 {
510 $character = ($value & 0x07) << 18;
511 $length = 4;
512 $remaining = 3;
513 }
514 // Invalid byte:
515 else
516 {
517 $valid = false;
518 $length = 1;
519 $remaining = 0;
520 }
521
522 if ($remaining)
523 {
524 if ($position + $length <= $strlen)
525 {
526 for ($position++; $remaining; $position++)
527 {
528 $value = ord($string[$position]);
529
530 // Check that the byte is valid, then add it to the character:
531 if (($value & 0xC0) === 0x80)
532 {
533 $character |= ($value & 0x3F) << (--$remaining * 6);
534 }
535 // If it is invalid, count the sequence as invalid and reprocess the current byte:
536 else
537 {
538 $valid = false;
539 $position--;
540 break;
541 }
542 }
543 }
544 else
545 {
546 $position = $strlen - 1;
547 $valid = false;
548 }
549 }
550
551 // Percent encode anything invalid or not in ucschar
552 if (
553 // Invalid sequences
554 !$valid
555 // Non-shortest form sequences are invalid
556 || $length > 1 && $character <= 0x7F
557 || $length > 2 && $character <= 0x7FF
558 || $length > 3 && $character <= 0xFFFF
559 // Outside of range of ucschar codepoints
560 // Noncharacters
561 || ($character & 0xFFFE) === 0xFFFE
562 || $character >= 0xFDD0 && $character <= 0xFDEF
563 || (
564 // Everything else not in ucschar
565 $character > 0xD7FF && $character < 0xF900
566 || $character < 0xA0
567 || $character > 0xEFFFD
568 )
569 && (
570 // Everything not in iprivate, if it applies
571 !$iprivate
572 || $character < 0xE000
573 || $character > 0x10FFFD
574 )
575 )
576 {
577 // If we were a character, pretend we weren't, but rather an error.
578 if ($valid)
579 $position--;
580
581 for ($j = $start; $j <= $position; $j++)
582 {
583 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
584 $j += 2;
585 $position += 2;
586 $strlen += 2;
587 }
588 }
589 }
590
591 return $string;
592 }
593
594 /**
595 * Callback function for preg_replace_callback.
596 *
597 * Removes sequences of percent encoded bytes that represent UTF-8
598 * encoded characters in iunreserved
599 *
600 * @param array $match PCRE match
601 * @return string Replacement
602 */
603 protected function remove_iunreserved_percent_encoded($match)
604 {
605 // As we just have valid percent encoded sequences we can just explode
606 // and ignore the first member of the returned array (an empty string).
607 $bytes = explode('%', $match[0]);
608
609 // Initialize the new string (this is what will be returned) and that
610 // there are no bytes remaining in the current sequence (unsurprising
611 // at the first byte!).
612 $string = '';
613 $remaining = 0;
614
615 // Loop over each and every byte, and set $value to its value
616 for ($i = 1, $len = count($bytes); $i < $len; $i++)
617 {
618 $value = hexdec($bytes[$i]);
619
620 // If we're the first byte of sequence:
621 if (!$remaining)
622 {
623 // Start position
624 $start = $i;
625
626 // By default we are valid
627 $valid = true;
628
629 // One byte sequence:
630 if ($value <= 0x7F)
631 {
632 $character = $value;
633 $length = 1;
634 }
635 // Two byte sequence:
636 elseif (($value & 0xE0) === 0xC0)
637 {
638 $character = ($value & 0x1F) << 6;
639 $length = 2;
640 $remaining = 1;
641 }
642 // Three byte sequence:
643 elseif (($value & 0xF0) === 0xE0)
644 {
645 $character = ($value & 0x0F) << 12;
646 $length = 3;
647 $remaining = 2;
648 }
649 // Four byte sequence:
650 elseif (($value & 0xF8) === 0xF0)
651 {
652 $character = ($value & 0x07) << 18;
653 $length = 4;
654 $remaining = 3;
655 }
656 // Invalid byte:
657 else
658 {
659 $valid = false;
660 $remaining = 0;
661 }
662 }
663 // Continuation byte:
664 else
665 {
666 // Check that the byte is valid, then add it to the character:
667 if (($value & 0xC0) === 0x80)
668 {
669 $remaining--;
670 $character |= ($value & 0x3F) << ($remaining * 6);
671 }
672 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
673 else
674 {
675 $valid = false;
676 $remaining = 0;
677 $i--;
678 }
679 }
680
681 // If we've reached the end of the current byte sequence, append it to Unicode::$data
682 if (!$remaining)
683 {
684 // Percent encode anything invalid or not in iunreserved
685 if (
686 // Invalid sequences
687 !$valid
688 // Non-shortest form sequences are invalid
689 || $length > 1 && $character <= 0x7F
690 || $length > 2 && $character <= 0x7FF
691 || $length > 3 && $character <= 0xFFFF
692 // Outside of range of iunreserved codepoints
693 || $character < 0x2D
694 || $character > 0xEFFFD
695 // Noncharacters
696 || ($character & 0xFFFE) === 0xFFFE
697 || $character >= 0xFDD0 && $character <= 0xFDEF
698 // Everything else not in iunreserved (this is all BMP)
699 || $character === 0x2F
700 || $character > 0x39 && $character < 0x41
701 || $character > 0x5A && $character < 0x61
702 || $character > 0x7A && $character < 0x7E
703 || $character > 0x7E && $character < 0xA0
704 || $character > 0xD7FF && $character < 0xF900
705 )
706 {
707 for ($j = $start; $j <= $i; $j++)
708 {
709 $string .= '%' . strtoupper($bytes[$j]);
710 }
711 }
712 else
713 {
714 for ($j = $start; $j <= $i; $j++)
715 {
716 $string .= chr(hexdec($bytes[$j]));
717 }
718 }
719 }
720 }
721
722 // If we have any bytes left over they are invalid (i.e., we are
723 // mid-way through a multi-byte sequence)
724 if ($remaining)
725 {
726 for ($j = $start; $j < $len; $j++)
727 {
728 $string .= '%' . strtoupper($bytes[$j]);
729 }
730 }
731
732 return $string;
733 }
734
735 protected function scheme_normalization()
736 {
737 if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
738 {
739 $this->iuserinfo = null;
740 }
741 if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
742 {
743 $this->ihost = null;
744 }
745 if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
746 {
747 $this->port = null;
748 }
749 if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
750 {
751 $this->ipath = '';
752 }
753 if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
754 {
755 $this->iquery = null;
756 }
757 if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
758 {
759 $this->ifragment = null;
760 }
761 }
762
763 /**
764 * Check if the object represents a valid IRI. This needs to be done on each
765 * call as some things change depending on another part of the IRI.
766 *
767 * @return bool
768 */
769 public function is_valid()
770 {
771 $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
772 if ($this->ipath !== '' &&
773 (
774 $isauthority && (
775 $this->ipath[0] !== '/' ||
776 substr($this->ipath, 0, 2) === '//'
777 ) ||
778 (
779 $this->scheme === null &&
780 !$isauthority &&
781 strpos($this->ipath, ':') !== false &&
782 (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
783 )
784 )
785 )
786 {
787 return false;
788 }
789
790 return true;
791 }
792
793 /**
794 * Set the entire IRI. Returns true on success, false on failure (if there
795 * are any invalid characters).
796 *
797 * @param string $iri
798 * @return bool
799 */
800 public function set_iri($iri)
801 {
802 static $cache;
803 if (!$cache)
804 {
805 $cache = array();
806 }
807
808 if ($iri === null)
809 {
810 return true;
811 }
812 elseif (isset($cache[$iri]))
813 {
814 list($this->scheme,
815 $this->iuserinfo,
816 $this->ihost,
817 $this->port,
818 $this->ipath,
819 $this->iquery,
820 $this->ifragment,
821 $return) = $cache[$iri];
822 return $return;
823 }
824 else
825 {
826 $parsed = $this->parse_iri((string) $iri);
827 if (!$parsed)
828 {
829 return false;
830 }
831
832 $return = $this->set_scheme($parsed['scheme'])
833 && $this->set_authority($parsed['authority'])
834 && $this->set_path($parsed['path'])
835 && $this->set_query($parsed['query'])
836 && $this->set_fragment($parsed['fragment']);
837
838 $cache[$iri] = array($this->scheme,
839 $this->iuserinfo,
840 $this->ihost,
841 $this->port,
842 $this->ipath,
843 $this->iquery,
844 $this->ifragment,
845 $return);
846 return $return;
847 }
848 }
849
850 /**
851 * Set the scheme. Returns true on success, false on failure (if there are
852 * any invalid characters).
853 *
854 * @param string $scheme
855 * @return bool
856 */
857 public function set_scheme($scheme)
858 {
859 if ($scheme === null)
860 {
861 $this->scheme = null;
862 }
863 elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
864 {
865 $this->scheme = null;
866 return false;
867 }
868 else
869 {
870 $this->scheme = strtolower($scheme);
871 }
872 return true;
873 }
874
875 /**
876 * Set the authority. Returns true on success, false on failure (if there are
877 * any invalid characters).
878 *
879 * @param string $authority
880 * @return bool
881 */
882 public function set_authority($authority)
883 {
884 static $cache;
885 if (!$cache)
886 $cache = array();
887
888 if ($authority === null)
889 {
890 $this->iuserinfo = null;
891 $this->ihost = null;
892 $this->port = null;
893 return true;
894 }
895 elseif (isset($cache[$authority]))
896 {
897 list($this->iuserinfo,
898 $this->ihost,
899 $this->port,
900 $return) = $cache[$authority];
901
902 return $return;
903 }
904 else
905 {
906 $remaining = $authority;
907 if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
908 {
909 $iuserinfo = substr($remaining, 0, $iuserinfo_end);
910 $remaining = substr($remaining, $iuserinfo_end + 1);
911 }
912 else
913 {
914 $iuserinfo = null;
915 }
916 if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
917 {
918 if (($port = substr($remaining, $port_start + 1)) === false)
919 {
920 $port = null;
921 }
922 $remaining = substr($remaining, 0, $port_start);
923 }
924 else
925 {
926 $port = null;
927 }
928
929 $return = $this->set_userinfo($iuserinfo) &&
930 $this->set_host($remaining) &&
931 $this->set_port($port);
932
933 $cache[$authority] = array($this->iuserinfo,
934 $this->ihost,
935 $this->port,
936 $return);
937
938 return $return;
939 }
940 }
941
942 /**
943 * Set the iuserinfo.
944 *
945 * @param string $iuserinfo
946 * @return bool
947 */
948 public function set_userinfo($iuserinfo)
949 {
950 if ($iuserinfo === null)
951 {
952 $this->iuserinfo = null;
953 }
954 else
955 {
956 $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
957 $this->scheme_normalization();
958 }
959
960 return true;
961 }
962
963 /**
964 * Set the ihost. Returns true on success, false on failure (if there are
965 * any invalid characters).
966 *
967 * @param string $ihost
968 * @return bool
969 */
970 public function set_host($ihost)
971 {
972 if ($ihost === null)
973 {
974 $this->ihost = null;
975 return true;
976 }
977 elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
978 {
979 if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
980 {
981 $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
982 }
983 else
984 {
985 $this->ihost = null;
986 return false;
987 }
988 }
989 else
990 {
991 $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
992
993 // Lowercase, but ignore pct-encoded sections (as they should
994 // remain uppercase). This must be done after the previous step
995 // as that can add unescaped characters.
996 $position = 0;
997 $strlen = strlen($ihost);
998 while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
999 {
1000 if ($ihost[$position] === '%')
1001 {
1002 $position += 3;
1003 }
1004 else
1005 {
1006 $ihost[$position] = strtolower($ihost[$position]);
1007 $position++;
1008 }
1009 }
1010
1011 $this->ihost = $ihost;
1012 }
1013
1014 $this->scheme_normalization();
1015
1016 return true;
1017 }
1018
1019 /**
1020 * Set the port. Returns true on success, false on failure (if there are
1021 * any invalid characters).
1022 *
1023 * @param string $port
1024 * @return bool
1025 */
1026 public function set_port($port)
1027 {
1028 if ($port === null)
1029 {
1030 $this->port = null;
1031 return true;
1032 }
1033 elseif (strspn($port, '0123456789') === strlen($port))
1034 {
1035 $this->port = (int) $port;
1036 $this->scheme_normalization();
1037 return true;
1038 }
1039 else
1040 {
1041 $this->port = null;
1042 return false;
1043 }
1044 }
1045
1046 /**
1047 * Set the ipath.
1048 *
1049 * @param string $ipath
1050 * @return bool
1051 */
1052 public function set_path($ipath)
1053 {
1054 static $cache;
1055 if (!$cache)
1056 {
1057 $cache = array();
1058 }
1059
1060 $ipath = (string) $ipath;
1061
1062 if (isset($cache[$ipath]))
1063 {
1064 $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
1065 }
1066 else
1067 {
1068 $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
1069 $removed = $this->remove_dot_segments($valid);
1070
1071 $cache[$ipath] = array($valid, $removed);
1072 $this->ipath = ($this->scheme !== null) ? $removed : $valid;
1073 }
1074
1075 $this->scheme_normalization();
1076 return true;
1077 }
1078
1079 /**
1080 * Set the iquery.
1081 *
1082 * @param string $iquery
1083 * @return bool
1084 */
1085 public function set_query($iquery)
1086 {
1087 if ($iquery === null)
1088 {
1089 $this->iquery = null;
1090 }
1091 else
1092 {
1093 $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
1094 $this->scheme_normalization();
1095 }
1096 return true;
1097 }
1098
1099 /**
1100 * Set the ifragment.
1101 *
1102 * @param string $ifragment
1103 * @return bool
1104 */
1105 public function set_fragment($ifragment)
1106 {
1107 if ($ifragment === null)
1108 {
1109 $this->ifragment = null;
1110 }
1111 else
1112 {
1113 $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
1114 $this->scheme_normalization();
1115 }
1116 return true;
1117 }
1118
1119 /**
1120 * Convert an IRI to a URI (or parts thereof)
1121 *
1122 * @return string
1123 */
1124 public function to_uri($string)
1125 {
1126 static $non_ascii;
1127 if (!$non_ascii)
1128 {
1129 $non_ascii = implode('', range("\x80", "\xFF"));
1130 }
1131
1132 $position = 0;
1133 $strlen = strlen($string);
1134 while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
1135 {
1136 $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
1137 $position += 3;
1138 $strlen += 2;
1139 }
1140
1141 return $string;
1142 }
1143
1144 /**
1145 * Get the complete IRI
1146 *
1147 * @return string
1148 */
1149 public function get_iri()
1150 {
1151 if (!$this->is_valid())
1152 {
1153 return false;
1154 }
1155
1156 $iri = '';
1157 if ($this->scheme !== null)
1158 {
1159 $iri .= $this->scheme . ':';
1160 }
1161 if (($iauthority = $this->get_iauthority()) !== null)
1162 {
1163 $iri .= '//' . $iauthority;
1164 }
1165 if ($this->ipath !== '')
1166 {
1167 $iri .= $this->ipath;
1168 }
1169 elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
1170 {
1171 $iri .= $this->normalization[$this->scheme]['ipath'];
1172 }
1173 if ($this->iquery !== null)
1174 {
1175 $iri .= '?' . $this->iquery;
1176 }
1177 if ($this->ifragment !== null)
1178 {
1179 $iri .= '#' . $this->ifragment;
1180 }
1181
1182 return $iri;
1183 }
1184
1185 /**
1186 * Get the complete URI
1187 *
1188 * @return string
1189 */
1190 public function get_uri()
1191 {
1192 return $this->to_uri($this->get_iri());
1193 }
1194
1195 /**
1196 * Get the complete iauthority
1197 *
1198 * @return string
1199 */
1200 protected function get_iauthority()
1201 {
1202 if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
1203 {
1204 $iauthority = '';
1205 if ($this->iuserinfo !== null)
1206 {
1207 $iauthority .= $this->iuserinfo . '@';
1208 }
1209 if ($this->ihost !== null)
1210 {
1211 $iauthority .= $this->ihost;
1212 }
1213 if ($this->port !== null)
1214 {
1215 $iauthority .= ':' . $this->port;
1216 }
1217 return $iauthority;
1218 }
1219 else
1220 {
1221 return null;
1222 }
1223 }
1224
1225 /**
1226 * Get the complete authority
1227 *
1228 * @return string
1229 */
1230 protected function get_authority()
1231 {
1232 $iauthority = $this->get_iauthority();
1233 if (is_string($iauthority))
1234 return $this->to_uri($iauthority);
1235 else
1236 return $iauthority;
1237 }
1238}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Item.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Item.php
new file mode 100644
index 00000000..a77574b3
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Item.php
@@ -0,0 +1,2964 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Manages all item-related data
48 *
49 * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
50 *
51 * This class can be overloaded with {@see SimplePie::set_item_class()}
52 *
53 * @package SimplePie
54 * @subpackage API
55 */
56class SimplePie_Item
57{
58 /**
59 * Parent feed
60 *
61 * @access private
62 * @var SimplePie
63 */
64 var $feed;
65
66 /**
67 * Raw data
68 *
69 * @access private
70 * @var array
71 */
72 var $data = array();
73
74 /**
75 * Registry object
76 *
77 * @see set_registry
78 * @var SimplePie_Registry
79 */
80 protected $registry;
81
82 /**
83 * Create a new item object
84 *
85 * This is usually used by {@see SimplePie::get_items} and
86 * {@see SimplePie::get_item}. Avoid creating this manually.
87 *
88 * @param SimplePie $feed Parent feed
89 * @param array $data Raw data
90 */
91 public function __construct($feed, $data)
92 {
93 $this->feed = $feed;
94 $this->data = $data;
95 }
96
97 /**
98 * Set the registry handler
99 *
100 * This is usually used by {@see SimplePie_Registry::create}
101 *
102 * @since 1.3
103 * @param SimplePie_Registry $registry
104 */
105 public function set_registry(SimplePie_Registry $registry)
106 {
107 $this->registry = $registry;
108 }
109
110 /**
111 * Get a string representation of the item
112 *
113 * @return string
114 */
115 public function __toString()
116 {
117 return md5(serialize($this->data));
118 }
119
120 /**
121 * Remove items that link back to this before destroying this object
122 */
123 public function __destruct()
124 {
125 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
126 {
127 unset($this->feed);
128 }
129 }
130
131 /**
132 * Get data for an item-level element
133 *
134 * This method allows you to get access to ANY element/attribute that is a
135 * sub-element of the item/entry tag.
136 *
137 * See {@see SimplePie::get_feed_tags()} for a description of the return value
138 *
139 * @since 1.0
140 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
141 * @param string $namespace The URL of the XML namespace of the elements you're trying to access
142 * @param string $tag Tag name
143 * @return array
144 */
145 public function get_item_tags($namespace, $tag)
146 {
147 if (isset($this->data['child'][$namespace][$tag]))
148 {
149 return $this->data['child'][$namespace][$tag];
150 }
151 else
152 {
153 return null;
154 }
155 }
156
157 /**
158 * Get the base URL value from the parent feed
159 *
160 * Uses `<xml:base>`
161 *
162 * @param array $element
163 * @return string
164 */
165 public function get_base($element = array())
166 {
167 return $this->feed->get_base($element);
168 }
169
170 /**
171 * Sanitize feed data
172 *
173 * @access private
174 * @see SimplePie::sanitize()
175 * @param string $data Data to sanitize
176 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
177 * @param string $base Base URL to resolve URLs against
178 * @return string Sanitized data
179 */
180 public function sanitize($data, $type, $base = '')
181 {
182 return $this->feed->sanitize($data, $type, $base);
183 }
184
185 /**
186 * Get the parent feed
187 *
188 * Note: this may not work as you think for multifeeds!
189 *
190 * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
191 * @since 1.0
192 * @return SimplePie
193 */
194 public function get_feed()
195 {
196 return $this->feed;
197 }
198
199 /**
200 * Get the unique identifier for the item
201 *
202 * This is usually used when writing code to check for new items in a feed.
203 *
204 * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
205 * for RDF. If none of these are supplied (or `$hash` is true), creates an
206 * MD5 hash based on the permalink and title. If either of those are not
207 * supplied, creates a hash based on the full feed data.
208 *
209 * @since Beta 2
210 * @param boolean $hash Should we force using a hash instead of the supplied ID?
211 * @return string
212 */
213 public function get_id($hash = false)
214 {
215 if (!$hash)
216 {
217 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
218 {
219 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
220 }
221 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
222 {
223 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
224 }
225 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
226 {
227 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
228 }
229 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
230 {
231 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
232 }
233 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
234 {
235 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
236 }
237 elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
238 {
239 return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
240 }
241 elseif (($return = $this->get_permalink()) !== null)
242 {
243 return $return;
244 }
245 elseif (($return = $this->get_title()) !== null)
246 {
247 return $return;
248 }
249 }
250 if ($this->get_permalink() !== null || $this->get_title() !== null)
251 {
252 return md5($this->get_permalink() . $this->get_title());
253 }
254 else
255 {
256 return md5(serialize($this->data));
257 }
258 }
259
260 /**
261 * Get the title of the item
262 *
263 * Uses `<atom:title>`, `<title>` or `<dc:title>`
264 *
265 * @since Beta 2 (previously called `get_item_title` since 0.8)
266 * @return string|null
267 */
268 public function get_title()
269 {
270 if (!isset($this->data['title']))
271 {
272 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
273 {
274 $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
275 }
276 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
277 {
278 $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
279 }
280 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
281 {
282 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
283 }
284 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
285 {
286 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
287 }
288 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
289 {
290 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
291 }
292 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
293 {
294 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
295 }
296 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
297 {
298 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
299 }
300 else
301 {
302 $this->data['title'] = null;
303 }
304 }
305 return $this->data['title'];
306 }
307
308 /**
309 * Get the content for the item
310 *
311 * Prefers summaries over full content , but will return full content if a
312 * summary does not exist.
313 *
314 * To prefer full content instead, use {@see get_content}
315 *
316 * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
317 * `<itunes:subtitle>`
318 *
319 * @since 0.8
320 * @param boolean $description_only Should we avoid falling back to the content?
321 * @return string|null
322 */
323 public function get_description($description_only = false)
324 {
325 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
326 {
327 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
328 }
329 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
330 {
331 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
332 }
333 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
334 {
335 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
336 }
337 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
338 {
339 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
340 }
341 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
342 {
343 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
344 }
345 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
346 {
347 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
348 }
349 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
350 {
351 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
352 }
353 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
354 {
355 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
356 }
357 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
358 {
359 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
360 }
361
362 elseif (!$description_only)
363 {
364 return $this->get_content(true);
365 }
366 else
367 {
368 return null;
369 }
370 }
371
372 /**
373 * Get the content for the item
374 *
375 * Prefers full content over summaries, but will return a summary if full
376 * content does not exist.
377 *
378 * To prefer summaries instead, use {@see get_description}
379 *
380 * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
381 *
382 * @since 1.0
383 * @param boolean $content_only Should we avoid falling back to the description?
384 * @return string|null
385 */
386 public function get_content($content_only = false)
387 {
388 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
389 {
390 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
391 }
392 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
393 {
394 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
395 }
396 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
397 {
398 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
399 }
400 elseif (!$content_only)
401 {
402 return $this->get_description(true);
403 }
404 else
405 {
406 return null;
407 }
408 }
409
410 /**
411 * Get a category for the item
412 *
413 * @since Beta 3 (previously called `get_categories()` since Beta 2)
414 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
415 * @return SimplePie_Category|null
416 */
417 public function get_category($key = 0)
418 {
419 $categories = $this->get_categories();
420 if (isset($categories[$key]))
421 {
422 return $categories[$key];
423 }
424 else
425 {
426 return null;
427 }
428 }
429
430 /**
431 * Get all categories for the item
432 *
433 * Uses `<atom:category>`, `<category>` or `<dc:subject>`
434 *
435 * @since Beta 3
436 * @return array|null List of {@see SimplePie_Category} objects
437 */
438 public function get_categories()
439 {
440 $categories = array();
441
442 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
443 {
444 $term = null;
445 $scheme = null;
446 $label = null;
447 if (isset($category['attribs']['']['term']))
448 {
449 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
450 }
451 if (isset($category['attribs']['']['scheme']))
452 {
453 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
454 }
455 if (isset($category['attribs']['']['label']))
456 {
457 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
458 }
459 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
460 }
461 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
462 {
463 // This is really the label, but keep this as the term also for BC.
464 // Label will also work on retrieving because that falls back to term.
465 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
466 if (isset($category['attribs']['']['domain']))
467 {
468 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
469 }
470 else
471 {
472 $scheme = null;
473 }
474 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
475 }
476 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
477 {
478 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
479 }
480 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
481 {
482 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
483 }
484
485 if (!empty($categories))
486 {
487 return array_unique($categories);
488 }
489 else
490 {
491 return null;
492 }
493 }
494
495 /**
496 * Get an author for the item
497 *
498 * @since Beta 2
499 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
500 * @return SimplePie_Author|null
501 */
502 public function get_author($key = 0)
503 {
504 $authors = $this->get_authors();
505 if (isset($authors[$key]))
506 {
507 return $authors[$key];
508 }
509 else
510 {
511 return null;
512 }
513 }
514
515 /**
516 * Get a contributor for the item
517 *
518 * @since 1.1
519 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
520 * @return SimplePie_Author|null
521 */
522 public function get_contributor($key = 0)
523 {
524 $contributors = $this->get_contributors();
525 if (isset($contributors[$key]))
526 {
527 return $contributors[$key];
528 }
529 else
530 {
531 return null;
532 }
533 }
534
535 /**
536 * Get all contributors for the item
537 *
538 * Uses `<atom:contributor>`
539 *
540 * @since 1.1
541 * @return array|null List of {@see SimplePie_Author} objects
542 */
543 public function get_contributors()
544 {
545 $contributors = array();
546 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
547 {
548 $name = null;
549 $uri = null;
550 $email = null;
551 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
552 {
553 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
554 }
555 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
556 {
557 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
558 }
559 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
560 {
561 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
562 }
563 if ($name !== null || $email !== null || $uri !== null)
564 {
565 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
566 }
567 }
568 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
569 {
570 $name = null;
571 $url = null;
572 $email = null;
573 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
574 {
575 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
576 }
577 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
578 {
579 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
580 }
581 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
582 {
583 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
584 }
585 if ($name !== null || $email !== null || $url !== null)
586 {
587 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
588 }
589 }
590
591 if (!empty($contributors))
592 {
593 return array_unique($contributors);
594 }
595 else
596 {
597 return null;
598 }
599 }
600
601 /**
602 * Get all authors for the item
603 *
604 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
605 *
606 * @since Beta 2
607 * @return array|null List of {@see SimplePie_Author} objects
608 */
609 public function get_authors()
610 {
611 $authors = array();
612 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
613 {
614 $name = null;
615 $uri = null;
616 $email = null;
617 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
618 {
619 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
620 }
621 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
622 {
623 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
624 }
625 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
626 {
627 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
628 }
629 if ($name !== null || $email !== null || $uri !== null)
630 {
631 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
632 }
633 }
634 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
635 {
636 $name = null;
637 $url = null;
638 $email = null;
639 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
640 {
641 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
642 }
643 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
644 {
645 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
646 }
647 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
648 {
649 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
650 }
651 if ($name !== null || $email !== null || $url !== null)
652 {
653 $authors[] = $this->registry->create('Author', array($name, $url, $email));
654 }
655 }
656 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
657 {
658 $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
659 }
660 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
661 {
662 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
663 }
664 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
665 {
666 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
667 }
668 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
669 {
670 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
671 }
672
673 if (!empty($authors))
674 {
675 return array_unique($authors);
676 }
677 elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
678 {
679 return $authors;
680 }
681 elseif ($authors = $this->feed->get_authors())
682 {
683 return $authors;
684 }
685 else
686 {
687 return null;
688 }
689 }
690
691 /**
692 * Get the copyright info for the item
693 *
694 * Uses `<atom:rights>` or `<dc:rights>`
695 *
696 * @since 1.1
697 * @return string
698 */
699 public function get_copyright()
700 {
701 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
702 {
703 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
704 }
705 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
706 {
707 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
708 }
709 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
710 {
711 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
712 }
713 else
714 {
715 return null;
716 }
717 }
718
719 /**
720 * Get the posting date/time for the item
721 *
722 * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
723 * `<atom:modified>`, `<pubDate>` or `<dc:date>`
724 *
725 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
726 * {@see get_gmdate}
727 *
728 * @since Beta 2 (previously called `get_item_date` since 0.8)
729 *
730 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
731 * @return int|string|null
732 */
733 public function get_date($date_format = 'j F Y, g:i a')
734 {
735 if (!isset($this->data['date']))
736 {
737 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
738 {
739 $this->data['date']['raw'] = $return[0]['data'];
740 }
741 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
742 {
743 $this->data['date']['raw'] = $return[0]['data'];
744 }
745 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
746 {
747 $this->data['date']['raw'] = $return[0]['data'];
748 }
749 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
750 {
751 $this->data['date']['raw'] = $return[0]['data'];
752 }
753 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
754 {
755 $this->data['date']['raw'] = $return[0]['data'];
756 }
757 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
758 {
759 $this->data['date']['raw'] = $return[0]['data'];
760 }
761 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
762 {
763 $this->data['date']['raw'] = $return[0]['data'];
764 }
765 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
766 {
767 $this->data['date']['raw'] = $return[0]['data'];
768 }
769
770 if (!empty($this->data['date']['raw']))
771 {
772 $parser = $this->registry->call('Parse_Date', 'get');
773 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
774 }
775 else
776 {
777 $this->data['date'] = null;
778 }
779 }
780 if ($this->data['date'])
781 {
782 $date_format = (string) $date_format;
783 switch ($date_format)
784 {
785 case '':
786 return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
787
788 case 'U':
789 return $this->data['date']['parsed'];
790
791 default:
792 return date($date_format, $this->data['date']['parsed']);
793 }
794 }
795 else
796 {
797 return null;
798 }
799 }
800
801 /**
802 * Get the update date/time for the item
803 *
804 * Uses `<atom:updated>`
805 *
806 * Note: obeys PHP's timezone setting. To get a UTC date/time, use
807 * {@see get_gmdate}
808 *
809 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
810 * @return int|string|null
811 */
812 public function get_updated_date($date_format = 'j F Y, g:i a')
813 {
814 if (!isset($this->data['updated']))
815 {
816 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
817 {
818 $this->data['updated']['raw'] = $return[0]['data'];
819 }
820
821 if (!empty($this->data['updated']['raw']))
822 {
823 $parser = $this->registry->call('Parse_Date', 'get');
824 $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
825 }
826 else
827 {
828 $this->data['updated'] = null;
829 }
830 }
831 if ($this->data['updated'])
832 {
833 $date_format = (string) $date_format;
834 switch ($date_format)
835 {
836 case '':
837 return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
838
839 case 'U':
840 return $this->data['updated']['parsed'];
841
842 default:
843 return date($date_format, $this->data['updated']['parsed']);
844 }
845 }
846 else
847 {
848 return null;
849 }
850 }
851
852 /**
853 * Get the localized posting date/time for the item
854 *
855 * Returns the date formatted in the localized language. To display in
856 * languages other than the server's default, you need to change the locale
857 * with {@link http://php.net/setlocale setlocale()}. The available
858 * localizations depend on which ones are installed on your web server.
859 *
860 * @since 1.0
861 *
862 * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
863 * @return int|string|null
864 */
865 public function get_local_date($date_format = '%c')
866 {
867 if (!$date_format)
868 {
869 return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
870 }
871 elseif (($date = $this->get_date('U')) !== null && $date !== false)
872 {
873 return strftime($date_format, $date);
874 }
875 else
876 {
877 return null;
878 }
879 }
880
881 /**
882 * Get the posting date/time for the item (UTC time)
883 *
884 * @see get_date
885 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
886 * @return int|string|null
887 */
888 public function get_gmdate($date_format = 'j F Y, g:i a')
889 {
890 $date = $this->get_date('U');
891 if ($date === null)
892 {
893 return null;
894 }
895
896 return gmdate($date_format, $date);
897 }
898
899 /**
900 * Get the update date/time for the item (UTC time)
901 *
902 * @see get_updated_date
903 * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
904 * @return int|string|null
905 */
906 public function get_updated_gmdate($date_format = 'j F Y, g:i a')
907 {
908 $date = $this->get_updated_date('U');
909 if ($date === null)
910 {
911 return null;
912 }
913
914 return gmdate($date_format, $date);
915 }
916
917 /**
918 * Get the permalink for the item
919 *
920 * Returns the first link available with a relationship of "alternate".
921 * Identical to {@see get_link()} with key 0
922 *
923 * @see get_link
924 * @since 0.8
925 * @return string|null Permalink URL
926 */
927 public function get_permalink()
928 {
929 $link = $this->get_link();
930 $enclosure = $this->get_enclosure(0);
931 if ($link !== null)
932 {
933 return $link;
934 }
935 elseif ($enclosure !== null)
936 {
937 return $enclosure->get_link();
938 }
939 else
940 {
941 return null;
942 }
943 }
944
945 /**
946 * Get a single link for the item
947 *
948 * @since Beta 3
949 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
950 * @param string $rel The relationship of the link to return
951 * @return string|null Link URL
952 */
953 public function get_link($key = 0, $rel = 'alternate')
954 {
955 $links = $this->get_links($rel);
956 if ($links[$key] !== null)
957 {
958 return $links[$key];
959 }
960 else
961 {
962 return null;
963 }
964 }
965
966 /**
967 * Get all links for the item
968 *
969 * Uses `<atom:link>`, `<link>` or `<guid>`
970 *
971 * @since Beta 2
972 * @param string $rel The relationship of links to return
973 * @return array|null Links found for the item (strings)
974 */
975 public function get_links($rel = 'alternate')
976 {
977 if (!isset($this->data['links']))
978 {
979 $this->data['links'] = array();
980 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
981 {
982 if (isset($link['attribs']['']['href']))
983 {
984 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
985 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
986
987 }
988 }
989 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
990 {
991 if (isset($link['attribs']['']['href']))
992 {
993 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
994 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
995 }
996 }
997 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
998 {
999 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1000 }
1001 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
1002 {
1003 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1004 }
1005 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
1006 {
1007 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1008 }
1009 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
1010 {
1011 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
1012 {
1013 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
1014 }
1015 }
1016
1017 $keys = array_keys($this->data['links']);
1018 foreach ($keys as $key)
1019 {
1020 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
1021 {
1022 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
1023 {
1024 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
1025 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
1026 }
1027 else
1028 {
1029 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
1030 }
1031 }
1032 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
1033 {
1034 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
1035 }
1036 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
1037 }
1038 }
1039 if (isset($this->data['links'][$rel]))
1040 {
1041 return $this->data['links'][$rel];
1042 }
1043 else
1044 {
1045 return null;
1046 }
1047 }
1048
1049 /**
1050 * Get an enclosure from the item
1051 *
1052 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
1053 *
1054 * @since Beta 2
1055 * @todo Add ability to prefer one type of content over another (in a media group).
1056 * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
1057 * @return SimplePie_Enclosure|null
1058 */
1059 public function get_enclosure($key = 0, $prefer = null)
1060 {
1061 $enclosures = $this->get_enclosures();
1062 if (isset($enclosures[$key]))
1063 {
1064 return $enclosures[$key];
1065 }
1066 else
1067 {
1068 return null;
1069 }
1070 }
1071
1072 /**
1073 * Get all available enclosures (podcasts, etc.)
1074 *
1075 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
1076 *
1077 * At this point, we're pretty much assuming that all enclosures for an item
1078 * are the same content. Anything else is too complicated to
1079 * properly support.
1080 *
1081 * @since Beta 2
1082 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
1083 * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
1084 * @return array|null List of SimplePie_Enclosure items
1085 */
1086 public function get_enclosures()
1087 {
1088 if (!isset($this->data['enclosures']))
1089 {
1090 $this->data['enclosures'] = array();
1091
1092 // Elements
1093 $captions_parent = null;
1094 $categories_parent = null;
1095 $copyrights_parent = null;
1096 $credits_parent = null;
1097 $description_parent = null;
1098 $duration_parent = null;
1099 $hashes_parent = null;
1100 $keywords_parent = null;
1101 $player_parent = null;
1102 $ratings_parent = null;
1103 $restrictions_parent = null;
1104 $thumbnails_parent = null;
1105 $title_parent = null;
1106
1107 // Let's do the channel and item-level ones first, and just re-use them if we need to.
1108 $parent = $this->get_feed();
1109
1110 // CAPTIONS
1111 if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
1112 {
1113 foreach ($captions as $caption)
1114 {
1115 $caption_type = null;
1116 $caption_lang = null;
1117 $caption_startTime = null;
1118 $caption_endTime = null;
1119 $caption_text = null;
1120 if (isset($caption['attribs']['']['type']))
1121 {
1122 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1123 }
1124 if (isset($caption['attribs']['']['lang']))
1125 {
1126 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1127 }
1128 if (isset($caption['attribs']['']['start']))
1129 {
1130 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
1131 }
1132 if (isset($caption['attribs']['']['end']))
1133 {
1134 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
1135 }
1136 if (isset($caption['data']))
1137 {
1138 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1139 }
1140 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
1141 }
1142 }
1143 elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
1144 {
1145 foreach ($captions as $caption)
1146 {
1147 $caption_type = null;
1148 $caption_lang = null;
1149 $caption_startTime = null;
1150 $caption_endTime = null;
1151 $caption_text = null;
1152 if (isset($caption['attribs']['']['type']))
1153 {
1154 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1155 }
1156 if (isset($caption['attribs']['']['lang']))
1157 {
1158 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1159 }
1160 if (isset($caption['attribs']['']['start']))
1161 {
1162 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
1163 }
1164 if (isset($caption['attribs']['']['end']))
1165 {
1166 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
1167 }
1168 if (isset($caption['data']))
1169 {
1170 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1171 }
1172 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
1173 }
1174 }
1175 if (is_array($captions_parent))
1176 {
1177 $captions_parent = array_values(array_unique($captions_parent));
1178 }
1179
1180 // CATEGORIES
1181 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
1182 {
1183 $term = null;
1184 $scheme = null;
1185 $label = null;
1186 if (isset($category['data']))
1187 {
1188 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1189 }
1190 if (isset($category['attribs']['']['scheme']))
1191 {
1192 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1193 }
1194 else
1195 {
1196 $scheme = 'http://search.yahoo.com/mrss/category_schema';
1197 }
1198 if (isset($category['attribs']['']['label']))
1199 {
1200 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
1201 }
1202 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
1203 }
1204 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
1205 {
1206 $term = null;
1207 $scheme = null;
1208 $label = null;
1209 if (isset($category['data']))
1210 {
1211 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1212 }
1213 if (isset($category['attribs']['']['scheme']))
1214 {
1215 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1216 }
1217 else
1218 {
1219 $scheme = 'http://search.yahoo.com/mrss/category_schema';
1220 }
1221 if (isset($category['attribs']['']['label']))
1222 {
1223 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
1224 }
1225 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
1226 }
1227 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
1228 {
1229 $term = null;
1230 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
1231 $label = null;
1232 if (isset($category['attribs']['']['text']))
1233 {
1234 $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
1235 }
1236 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
1237
1238 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
1239 {
1240 foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
1241 {
1242 if (isset($subcategory['attribs']['']['text']))
1243 {
1244 $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
1245 }
1246 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
1247 }
1248 }
1249 }
1250 if (is_array($categories_parent))
1251 {
1252 $categories_parent = array_values(array_unique($categories_parent));
1253 }
1254
1255 // COPYRIGHT
1256 if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
1257 {
1258 $copyright_url = null;
1259 $copyright_label = null;
1260 if (isset($copyright[0]['attribs']['']['url']))
1261 {
1262 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
1263 }
1264 if (isset($copyright[0]['data']))
1265 {
1266 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1267 }
1268 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
1269 }
1270 elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
1271 {
1272 $copyright_url = null;
1273 $copyright_label = null;
1274 if (isset($copyright[0]['attribs']['']['url']))
1275 {
1276 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
1277 }
1278 if (isset($copyright[0]['data']))
1279 {
1280 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1281 }
1282 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
1283 }
1284
1285 // CREDITS
1286 if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
1287 {
1288 foreach ($credits as $credit)
1289 {
1290 $credit_role = null;
1291 $credit_scheme = null;
1292 $credit_name = null;
1293 if (isset($credit['attribs']['']['role']))
1294 {
1295 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
1296 }
1297 if (isset($credit['attribs']['']['scheme']))
1298 {
1299 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1300 }
1301 else
1302 {
1303 $credit_scheme = 'urn:ebu';
1304 }
1305 if (isset($credit['data']))
1306 {
1307 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1308 }
1309 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
1310 }
1311 }
1312 elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
1313 {
1314 foreach ($credits as $credit)
1315 {
1316 $credit_role = null;
1317 $credit_scheme = null;
1318 $credit_name = null;
1319 if (isset($credit['attribs']['']['role']))
1320 {
1321 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
1322 }
1323 if (isset($credit['attribs']['']['scheme']))
1324 {
1325 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1326 }
1327 else
1328 {
1329 $credit_scheme = 'urn:ebu';
1330 }
1331 if (isset($credit['data']))
1332 {
1333 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1334 }
1335 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
1336 }
1337 }
1338 if (is_array($credits_parent))
1339 {
1340 $credits_parent = array_values(array_unique($credits_parent));
1341 }
1342
1343 // DESCRIPTION
1344 if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
1345 {
1346 if (isset($description_parent[0]['data']))
1347 {
1348 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1349 }
1350 }
1351 elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
1352 {
1353 if (isset($description_parent[0]['data']))
1354 {
1355 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1356 }
1357 }
1358
1359 // DURATION
1360 if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
1361 {
1362 $seconds = null;
1363 $minutes = null;
1364 $hours = null;
1365 if (isset($duration_parent[0]['data']))
1366 {
1367 $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
1368 if (sizeof($temp) > 0)
1369 {
1370 $seconds = (int) array_pop($temp);
1371 }
1372 if (sizeof($temp) > 0)
1373 {
1374 $minutes = (int) array_pop($temp);
1375 $seconds += $minutes * 60;
1376 }
1377 if (sizeof($temp) > 0)
1378 {
1379 $hours = (int) array_pop($temp);
1380 $seconds += $hours * 3600;
1381 }
1382 unset($temp);
1383 $duration_parent = $seconds;
1384 }
1385 }
1386
1387 // HASHES
1388 if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
1389 {
1390 foreach ($hashes_iterator as $hash)
1391 {
1392 $value = null;
1393 $algo = null;
1394 if (isset($hash['data']))
1395 {
1396 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1397 }
1398 if (isset($hash['attribs']['']['algo']))
1399 {
1400 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
1401 }
1402 else
1403 {
1404 $algo = 'md5';
1405 }
1406 $hashes_parent[] = $algo.':'.$value;
1407 }
1408 }
1409 elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
1410 {
1411 foreach ($hashes_iterator as $hash)
1412 {
1413 $value = null;
1414 $algo = null;
1415 if (isset($hash['data']))
1416 {
1417 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1418 }
1419 if (isset($hash['attribs']['']['algo']))
1420 {
1421 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
1422 }
1423 else
1424 {
1425 $algo = 'md5';
1426 }
1427 $hashes_parent[] = $algo.':'.$value;
1428 }
1429 }
1430 if (is_array($hashes_parent))
1431 {
1432 $hashes_parent = array_values(array_unique($hashes_parent));
1433 }
1434
1435 // KEYWORDS
1436 if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
1437 {
1438 if (isset($keywords[0]['data']))
1439 {
1440 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
1441 foreach ($temp as $word)
1442 {
1443 $keywords_parent[] = trim($word);
1444 }
1445 }
1446 unset($temp);
1447 }
1448 elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
1449 {
1450 if (isset($keywords[0]['data']))
1451 {
1452 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
1453 foreach ($temp as $word)
1454 {
1455 $keywords_parent[] = trim($word);
1456 }
1457 }
1458 unset($temp);
1459 }
1460 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
1461 {
1462 if (isset($keywords[0]['data']))
1463 {
1464 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
1465 foreach ($temp as $word)
1466 {
1467 $keywords_parent[] = trim($word);
1468 }
1469 }
1470 unset($temp);
1471 }
1472 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
1473 {
1474 if (isset($keywords[0]['data']))
1475 {
1476 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
1477 foreach ($temp as $word)
1478 {
1479 $keywords_parent[] = trim($word);
1480 }
1481 }
1482 unset($temp);
1483 }
1484 if (is_array($keywords_parent))
1485 {
1486 $keywords_parent = array_values(array_unique($keywords_parent));
1487 }
1488
1489 // PLAYER
1490 if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
1491 {
1492 if (isset($player_parent[0]['attribs']['']['url']))
1493 {
1494 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
1495 }
1496 }
1497 elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
1498 {
1499 if (isset($player_parent[0]['attribs']['']['url']))
1500 {
1501 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
1502 }
1503 }
1504
1505 // RATINGS
1506 if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
1507 {
1508 foreach ($ratings as $rating)
1509 {
1510 $rating_scheme = null;
1511 $rating_value = null;
1512 if (isset($rating['attribs']['']['scheme']))
1513 {
1514 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1515 }
1516 else
1517 {
1518 $rating_scheme = 'urn:simple';
1519 }
1520 if (isset($rating['data']))
1521 {
1522 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1523 }
1524 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
1525 }
1526 }
1527 elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
1528 {
1529 foreach ($ratings as $rating)
1530 {
1531 $rating_scheme = 'urn:itunes';
1532 $rating_value = null;
1533 if (isset($rating['data']))
1534 {
1535 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1536 }
1537 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
1538 }
1539 }
1540 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
1541 {
1542 foreach ($ratings as $rating)
1543 {
1544 $rating_scheme = null;
1545 $rating_value = null;
1546 if (isset($rating['attribs']['']['scheme']))
1547 {
1548 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1549 }
1550 else
1551 {
1552 $rating_scheme = 'urn:simple';
1553 }
1554 if (isset($rating['data']))
1555 {
1556 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1557 }
1558 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
1559 }
1560 }
1561 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
1562 {
1563 foreach ($ratings as $rating)
1564 {
1565 $rating_scheme = 'urn:itunes';
1566 $rating_value = null;
1567 if (isset($rating['data']))
1568 {
1569 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1570 }
1571 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
1572 }
1573 }
1574 if (is_array($ratings_parent))
1575 {
1576 $ratings_parent = array_values(array_unique($ratings_parent));
1577 }
1578
1579 // RESTRICTIONS
1580 if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
1581 {
1582 foreach ($restrictions as $restriction)
1583 {
1584 $restriction_relationship = null;
1585 $restriction_type = null;
1586 $restriction_value = null;
1587 if (isset($restriction['attribs']['']['relationship']))
1588 {
1589 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
1590 }
1591 if (isset($restriction['attribs']['']['type']))
1592 {
1593 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1594 }
1595 if (isset($restriction['data']))
1596 {
1597 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1598 }
1599 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
1600 }
1601 }
1602 elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
1603 {
1604 foreach ($restrictions as $restriction)
1605 {
1606 $restriction_relationship = 'allow';
1607 $restriction_type = null;
1608 $restriction_value = 'itunes';
1609 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
1610 {
1611 $restriction_relationship = 'deny';
1612 }
1613 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
1614 }
1615 }
1616 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
1617 {
1618 foreach ($restrictions as $restriction)
1619 {
1620 $restriction_relationship = null;
1621 $restriction_type = null;
1622 $restriction_value = null;
1623 if (isset($restriction['attribs']['']['relationship']))
1624 {
1625 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
1626 }
1627 if (isset($restriction['attribs']['']['type']))
1628 {
1629 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1630 }
1631 if (isset($restriction['data']))
1632 {
1633 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1634 }
1635 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
1636 }
1637 }
1638 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
1639 {
1640 foreach ($restrictions as $restriction)
1641 {
1642 $restriction_relationship = 'allow';
1643 $restriction_type = null;
1644 $restriction_value = 'itunes';
1645 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
1646 {
1647 $restriction_relationship = 'deny';
1648 }
1649 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
1650 }
1651 }
1652 if (is_array($restrictions_parent))
1653 {
1654 $restrictions_parent = array_values(array_unique($restrictions_parent));
1655 }
1656 else
1657 {
1658 $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
1659 }
1660
1661 // THUMBNAILS
1662 if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
1663 {
1664 foreach ($thumbnails as $thumbnail)
1665 {
1666 if (isset($thumbnail['attribs']['']['url']))
1667 {
1668 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
1669 }
1670 }
1671 }
1672 elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
1673 {
1674 foreach ($thumbnails as $thumbnail)
1675 {
1676 if (isset($thumbnail['attribs']['']['url']))
1677 {
1678 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
1679 }
1680 }
1681 }
1682
1683 // TITLES
1684 if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
1685 {
1686 if (isset($title_parent[0]['data']))
1687 {
1688 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1689 }
1690 }
1691 elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
1692 {
1693 if (isset($title_parent[0]['data']))
1694 {
1695 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1696 }
1697 }
1698
1699 // Clear the memory
1700 unset($parent);
1701
1702 // Attributes
1703 $bitrate = null;
1704 $channels = null;
1705 $duration = null;
1706 $expression = null;
1707 $framerate = null;
1708 $height = null;
1709 $javascript = null;
1710 $lang = null;
1711 $length = null;
1712 $medium = null;
1713 $samplingrate = null;
1714 $type = null;
1715 $url = null;
1716 $width = null;
1717
1718 // Elements
1719 $captions = null;
1720 $categories = null;
1721 $copyrights = null;
1722 $credits = null;
1723 $description = null;
1724 $hashes = null;
1725 $keywords = null;
1726 $player = null;
1727 $ratings = null;
1728 $restrictions = null;
1729 $thumbnails = null;
1730 $title = null;
1731
1732 // If we have media:group tags, loop through them.
1733 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
1734 {
1735 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
1736 {
1737 // If we have media:content tags, loop through them.
1738 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
1739 {
1740 if (isset($content['attribs']['']['url']))
1741 {
1742 // Attributes
1743 $bitrate = null;
1744 $channels = null;
1745 $duration = null;
1746 $expression = null;
1747 $framerate = null;
1748 $height = null;
1749 $javascript = null;
1750 $lang = null;
1751 $length = null;
1752 $medium = null;
1753 $samplingrate = null;
1754 $type = null;
1755 $url = null;
1756 $width = null;
1757
1758 // Elements
1759 $captions = null;
1760 $categories = null;
1761 $copyrights = null;
1762 $credits = null;
1763 $description = null;
1764 $hashes = null;
1765 $keywords = null;
1766 $player = null;
1767 $ratings = null;
1768 $restrictions = null;
1769 $thumbnails = null;
1770 $title = null;
1771
1772 // Start checking the attributes of media:content
1773 if (isset($content['attribs']['']['bitrate']))
1774 {
1775 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
1776 }
1777 if (isset($content['attribs']['']['channels']))
1778 {
1779 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
1780 }
1781 if (isset($content['attribs']['']['duration']))
1782 {
1783 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
1784 }
1785 else
1786 {
1787 $duration = $duration_parent;
1788 }
1789 if (isset($content['attribs']['']['expression']))
1790 {
1791 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
1792 }
1793 if (isset($content['attribs']['']['framerate']))
1794 {
1795 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
1796 }
1797 if (isset($content['attribs']['']['height']))
1798 {
1799 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
1800 }
1801 if (isset($content['attribs']['']['lang']))
1802 {
1803 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1804 }
1805 if (isset($content['attribs']['']['fileSize']))
1806 {
1807 $length = ceil($content['attribs']['']['fileSize']);
1808 }
1809 if (isset($content['attribs']['']['medium']))
1810 {
1811 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
1812 }
1813 if (isset($content['attribs']['']['samplingrate']))
1814 {
1815 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
1816 }
1817 if (isset($content['attribs']['']['type']))
1818 {
1819 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1820 }
1821 if (isset($content['attribs']['']['width']))
1822 {
1823 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
1824 }
1825 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
1826
1827 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
1828
1829 // CAPTIONS
1830 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
1831 {
1832 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
1833 {
1834 $caption_type = null;
1835 $caption_lang = null;
1836 $caption_startTime = null;
1837 $caption_endTime = null;
1838 $caption_text = null;
1839 if (isset($caption['attribs']['']['type']))
1840 {
1841 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1842 }
1843 if (isset($caption['attribs']['']['lang']))
1844 {
1845 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1846 }
1847 if (isset($caption['attribs']['']['start']))
1848 {
1849 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
1850 }
1851 if (isset($caption['attribs']['']['end']))
1852 {
1853 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
1854 }
1855 if (isset($caption['data']))
1856 {
1857 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1858 }
1859 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
1860 }
1861 if (is_array($captions))
1862 {
1863 $captions = array_values(array_unique($captions));
1864 }
1865 }
1866 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
1867 {
1868 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
1869 {
1870 $caption_type = null;
1871 $caption_lang = null;
1872 $caption_startTime = null;
1873 $caption_endTime = null;
1874 $caption_text = null;
1875 if (isset($caption['attribs']['']['type']))
1876 {
1877 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
1878 }
1879 if (isset($caption['attribs']['']['lang']))
1880 {
1881 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
1882 }
1883 if (isset($caption['attribs']['']['start']))
1884 {
1885 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
1886 }
1887 if (isset($caption['attribs']['']['end']))
1888 {
1889 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
1890 }
1891 if (isset($caption['data']))
1892 {
1893 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1894 }
1895 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
1896 }
1897 if (is_array($captions))
1898 {
1899 $captions = array_values(array_unique($captions));
1900 }
1901 }
1902 else
1903 {
1904 $captions = $captions_parent;
1905 }
1906
1907 // CATEGORIES
1908 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
1909 {
1910 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
1911 {
1912 $term = null;
1913 $scheme = null;
1914 $label = null;
1915 if (isset($category['data']))
1916 {
1917 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1918 }
1919 if (isset($category['attribs']['']['scheme']))
1920 {
1921 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1922 }
1923 else
1924 {
1925 $scheme = 'http://search.yahoo.com/mrss/category_schema';
1926 }
1927 if (isset($category['attribs']['']['label']))
1928 {
1929 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
1930 }
1931 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
1932 }
1933 }
1934 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
1935 {
1936 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
1937 {
1938 $term = null;
1939 $scheme = null;
1940 $label = null;
1941 if (isset($category['data']))
1942 {
1943 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1944 }
1945 if (isset($category['attribs']['']['scheme']))
1946 {
1947 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
1948 }
1949 else
1950 {
1951 $scheme = 'http://search.yahoo.com/mrss/category_schema';
1952 }
1953 if (isset($category['attribs']['']['label']))
1954 {
1955 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
1956 }
1957 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
1958 }
1959 }
1960 if (is_array($categories) && is_array($categories_parent))
1961 {
1962 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
1963 }
1964 elseif (is_array($categories))
1965 {
1966 $categories = array_values(array_unique($categories));
1967 }
1968 elseif (is_array($categories_parent))
1969 {
1970 $categories = array_values(array_unique($categories_parent));
1971 }
1972
1973 // COPYRIGHTS
1974 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
1975 {
1976 $copyright_url = null;
1977 $copyright_label = null;
1978 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
1979 {
1980 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
1981 }
1982 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
1983 {
1984 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1985 }
1986 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
1987 }
1988 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
1989 {
1990 $copyright_url = null;
1991 $copyright_label = null;
1992 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
1993 {
1994 $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
1995 }
1996 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
1997 {
1998 $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
1999 }
2000 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
2001 }
2002 else
2003 {
2004 $copyrights = $copyrights_parent;
2005 }
2006
2007 // CREDITS
2008 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
2009 {
2010 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
2011 {
2012 $credit_role = null;
2013 $credit_scheme = null;
2014 $credit_name = null;
2015 if (isset($credit['attribs']['']['role']))
2016 {
2017 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
2018 }
2019 if (isset($credit['attribs']['']['scheme']))
2020 {
2021 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2022 }
2023 else
2024 {
2025 $credit_scheme = 'urn:ebu';
2026 }
2027 if (isset($credit['data']))
2028 {
2029 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2030 }
2031 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
2032 }
2033 if (is_array($credits))
2034 {
2035 $credits = array_values(array_unique($credits));
2036 }
2037 }
2038 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
2039 {
2040 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
2041 {
2042 $credit_role = null;
2043 $credit_scheme = null;
2044 $credit_name = null;
2045 if (isset($credit['attribs']['']['role']))
2046 {
2047 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
2048 }
2049 if (isset($credit['attribs']['']['scheme']))
2050 {
2051 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2052 }
2053 else
2054 {
2055 $credit_scheme = 'urn:ebu';
2056 }
2057 if (isset($credit['data']))
2058 {
2059 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2060 }
2061 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
2062 }
2063 if (is_array($credits))
2064 {
2065 $credits = array_values(array_unique($credits));
2066 }
2067 }
2068 else
2069 {
2070 $credits = $credits_parent;
2071 }
2072
2073 // DESCRIPTION
2074 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
2075 {
2076 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2077 }
2078 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
2079 {
2080 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2081 }
2082 else
2083 {
2084 $description = $description_parent;
2085 }
2086
2087 // HASHES
2088 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
2089 {
2090 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
2091 {
2092 $value = null;
2093 $algo = null;
2094 if (isset($hash['data']))
2095 {
2096 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2097 }
2098 if (isset($hash['attribs']['']['algo']))
2099 {
2100 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
2101 }
2102 else
2103 {
2104 $algo = 'md5';
2105 }
2106 $hashes[] = $algo.':'.$value;
2107 }
2108 if (is_array($hashes))
2109 {
2110 $hashes = array_values(array_unique($hashes));
2111 }
2112 }
2113 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
2114 {
2115 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
2116 {
2117 $value = null;
2118 $algo = null;
2119 if (isset($hash['data']))
2120 {
2121 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2122 }
2123 if (isset($hash['attribs']['']['algo']))
2124 {
2125 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
2126 }
2127 else
2128 {
2129 $algo = 'md5';
2130 }
2131 $hashes[] = $algo.':'.$value;
2132 }
2133 if (is_array($hashes))
2134 {
2135 $hashes = array_values(array_unique($hashes));
2136 }
2137 }
2138 else
2139 {
2140 $hashes = $hashes_parent;
2141 }
2142
2143 // KEYWORDS
2144 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
2145 {
2146 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
2147 {
2148 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
2149 foreach ($temp as $word)
2150 {
2151 $keywords[] = trim($word);
2152 }
2153 unset($temp);
2154 }
2155 if (is_array($keywords))
2156 {
2157 $keywords = array_values(array_unique($keywords));
2158 }
2159 }
2160 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
2161 {
2162 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
2163 {
2164 $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
2165 foreach ($temp as $word)
2166 {
2167 $keywords[] = trim($word);
2168 }
2169 unset($temp);
2170 }
2171 if (is_array($keywords))
2172 {
2173 $keywords = array_values(array_unique($keywords));
2174 }
2175 }
2176 else
2177 {
2178 $keywords = $keywords_parent;
2179 }
2180
2181 // PLAYER
2182 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
2183 {
2184 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2185 }
2186 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
2187 {
2188 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2189 }
2190 else
2191 {
2192 $player = $player_parent;
2193 }
2194
2195 // RATINGS
2196 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
2197 {
2198 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
2199 {
2200 $rating_scheme = null;
2201 $rating_value = null;
2202 if (isset($rating['attribs']['']['scheme']))
2203 {
2204 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2205 }
2206 else
2207 {
2208 $rating_scheme = 'urn:simple';
2209 }
2210 if (isset($rating['data']))
2211 {
2212 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2213 }
2214 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
2215 }
2216 if (is_array($ratings))
2217 {
2218 $ratings = array_values(array_unique($ratings));
2219 }
2220 }
2221 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
2222 {
2223 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
2224 {
2225 $rating_scheme = null;
2226 $rating_value = null;
2227 if (isset($rating['attribs']['']['scheme']))
2228 {
2229 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2230 }
2231 else
2232 {
2233 $rating_scheme = 'urn:simple';
2234 }
2235 if (isset($rating['data']))
2236 {
2237 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2238 }
2239 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
2240 }
2241 if (is_array($ratings))
2242 {
2243 $ratings = array_values(array_unique($ratings));
2244 }
2245 }
2246 else
2247 {
2248 $ratings = $ratings_parent;
2249 }
2250
2251 // RESTRICTIONS
2252 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
2253 {
2254 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
2255 {
2256 $restriction_relationship = null;
2257 $restriction_type = null;
2258 $restriction_value = null;
2259 if (isset($restriction['attribs']['']['relationship']))
2260 {
2261 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
2262 }
2263 if (isset($restriction['attribs']['']['type']))
2264 {
2265 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2266 }
2267 if (isset($restriction['data']))
2268 {
2269 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2270 }
2271 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
2272 }
2273 if (is_array($restrictions))
2274 {
2275 $restrictions = array_values(array_unique($restrictions));
2276 }
2277 }
2278 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
2279 {
2280 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
2281 {
2282 $restriction_relationship = null;
2283 $restriction_type = null;
2284 $restriction_value = null;
2285 if (isset($restriction['attribs']['']['relationship']))
2286 {
2287 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
2288 }
2289 if (isset($restriction['attribs']['']['type']))
2290 {
2291 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2292 }
2293 if (isset($restriction['data']))
2294 {
2295 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2296 }
2297 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
2298 }
2299 if (is_array($restrictions))
2300 {
2301 $restrictions = array_values(array_unique($restrictions));
2302 }
2303 }
2304 else
2305 {
2306 $restrictions = $restrictions_parent;
2307 }
2308
2309 // THUMBNAILS
2310 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
2311 {
2312 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
2313 {
2314 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2315 }
2316 if (is_array($thumbnails))
2317 {
2318 $thumbnails = array_values(array_unique($thumbnails));
2319 }
2320 }
2321 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
2322 {
2323 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
2324 {
2325 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2326 }
2327 if (is_array($thumbnails))
2328 {
2329 $thumbnails = array_values(array_unique($thumbnails));
2330 }
2331 }
2332 else
2333 {
2334 $thumbnails = $thumbnails_parent;
2335 }
2336
2337 // TITLES
2338 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
2339 {
2340 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2341 }
2342 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
2343 {
2344 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2345 }
2346 else
2347 {
2348 $title = $title_parent;
2349 }
2350
2351 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
2352 }
2353 }
2354 }
2355 }
2356
2357 // If we have standalone media:content tags, loop through them.
2358 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
2359 {
2360 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
2361 {
2362 if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
2363 {
2364 // Attributes
2365 $bitrate = null;
2366 $channels = null;
2367 $duration = null;
2368 $expression = null;
2369 $framerate = null;
2370 $height = null;
2371 $javascript = null;
2372 $lang = null;
2373 $length = null;
2374 $medium = null;
2375 $samplingrate = null;
2376 $type = null;
2377 $url = null;
2378 $width = null;
2379
2380 // Elements
2381 $captions = null;
2382 $categories = null;
2383 $copyrights = null;
2384 $credits = null;
2385 $description = null;
2386 $hashes = null;
2387 $keywords = null;
2388 $player = null;
2389 $ratings = null;
2390 $restrictions = null;
2391 $thumbnails = null;
2392 $title = null;
2393
2394 // Start checking the attributes of media:content
2395 if (isset($content['attribs']['']['bitrate']))
2396 {
2397 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
2398 }
2399 if (isset($content['attribs']['']['channels']))
2400 {
2401 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
2402 }
2403 if (isset($content['attribs']['']['duration']))
2404 {
2405 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
2406 }
2407 else
2408 {
2409 $duration = $duration_parent;
2410 }
2411 if (isset($content['attribs']['']['expression']))
2412 {
2413 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
2414 }
2415 if (isset($content['attribs']['']['framerate']))
2416 {
2417 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
2418 }
2419 if (isset($content['attribs']['']['height']))
2420 {
2421 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
2422 }
2423 if (isset($content['attribs']['']['lang']))
2424 {
2425 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2426 }
2427 if (isset($content['attribs']['']['fileSize']))
2428 {
2429 $length = ceil($content['attribs']['']['fileSize']);
2430 }
2431 if (isset($content['attribs']['']['medium']))
2432 {
2433 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
2434 }
2435 if (isset($content['attribs']['']['samplingrate']))
2436 {
2437 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
2438 }
2439 if (isset($content['attribs']['']['type']))
2440 {
2441 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2442 }
2443 if (isset($content['attribs']['']['width']))
2444 {
2445 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
2446 }
2447 if (isset($content['attribs']['']['url']))
2448 {
2449 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2450 }
2451 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
2452
2453 // CAPTIONS
2454 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
2455 {
2456 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
2457 {
2458 $caption_type = null;
2459 $caption_lang = null;
2460 $caption_startTime = null;
2461 $caption_endTime = null;
2462 $caption_text = null;
2463 if (isset($caption['attribs']['']['type']))
2464 {
2465 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2466 }
2467 if (isset($caption['attribs']['']['lang']))
2468 {
2469 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2470 }
2471 if (isset($caption['attribs']['']['start']))
2472 {
2473 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
2474 }
2475 if (isset($caption['attribs']['']['end']))
2476 {
2477 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
2478 }
2479 if (isset($caption['data']))
2480 {
2481 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2482 }
2483 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
2484 }
2485 if (is_array($captions))
2486 {
2487 $captions = array_values(array_unique($captions));
2488 }
2489 }
2490 else
2491 {
2492 $captions = $captions_parent;
2493 }
2494
2495 // CATEGORIES
2496 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
2497 {
2498 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
2499 {
2500 $term = null;
2501 $scheme = null;
2502 $label = null;
2503 if (isset($category['data']))
2504 {
2505 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2506 }
2507 if (isset($category['attribs']['']['scheme']))
2508 {
2509 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2510 }
2511 else
2512 {
2513 $scheme = 'http://search.yahoo.com/mrss/category_schema';
2514 }
2515 if (isset($category['attribs']['']['label']))
2516 {
2517 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2518 }
2519 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2520 }
2521 }
2522 if (is_array($categories) && is_array($categories_parent))
2523 {
2524 $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
2525 }
2526 elseif (is_array($categories))
2527 {
2528 $categories = array_values(array_unique($categories));
2529 }
2530 elseif (is_array($categories_parent))
2531 {
2532 $categories = array_values(array_unique($categories_parent));
2533 }
2534 else
2535 {
2536 $categories = null;
2537 }
2538
2539 // COPYRIGHTS
2540 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
2541 {
2542 $copyright_url = null;
2543 $copyright_label = null;
2544 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
2545 {
2546 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
2547 }
2548 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
2549 {
2550 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2551 }
2552 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
2553 }
2554 else
2555 {
2556 $copyrights = $copyrights_parent;
2557 }
2558
2559 // CREDITS
2560 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
2561 {
2562 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
2563 {
2564 $credit_role = null;
2565 $credit_scheme = null;
2566 $credit_name = null;
2567 if (isset($credit['attribs']['']['role']))
2568 {
2569 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
2570 }
2571 if (isset($credit['attribs']['']['scheme']))
2572 {
2573 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2574 }
2575 else
2576 {
2577 $credit_scheme = 'urn:ebu';
2578 }
2579 if (isset($credit['data']))
2580 {
2581 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2582 }
2583 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
2584 }
2585 if (is_array($credits))
2586 {
2587 $credits = array_values(array_unique($credits));
2588 }
2589 }
2590 else
2591 {
2592 $credits = $credits_parent;
2593 }
2594
2595 // DESCRIPTION
2596 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
2597 {
2598 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2599 }
2600 else
2601 {
2602 $description = $description_parent;
2603 }
2604
2605 // HASHES
2606 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
2607 {
2608 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
2609 {
2610 $value = null;
2611 $algo = null;
2612 if (isset($hash['data']))
2613 {
2614 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2615 }
2616 if (isset($hash['attribs']['']['algo']))
2617 {
2618 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
2619 }
2620 else
2621 {
2622 $algo = 'md5';
2623 }
2624 $hashes[] = $algo.':'.$value;
2625 }
2626 if (is_array($hashes))
2627 {
2628 $hashes = array_values(array_unique($hashes));
2629 }
2630 }
2631 else
2632 {
2633 $hashes = $hashes_parent;
2634 }
2635
2636 // KEYWORDS
2637 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
2638 {
2639 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
2640 {
2641 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
2642 foreach ($temp as $word)
2643 {
2644 $keywords[] = trim($word);
2645 }
2646 unset($temp);
2647 }
2648 if (is_array($keywords))
2649 {
2650 $keywords = array_values(array_unique($keywords));
2651 }
2652 }
2653 else
2654 {
2655 $keywords = $keywords_parent;
2656 }
2657
2658 // PLAYER
2659 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
2660 {
2661 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2662 }
2663 else
2664 {
2665 $player = $player_parent;
2666 }
2667
2668 // RATINGS
2669 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
2670 {
2671 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
2672 {
2673 $rating_scheme = null;
2674 $rating_value = null;
2675 if (isset($rating['attribs']['']['scheme']))
2676 {
2677 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2678 }
2679 else
2680 {
2681 $rating_scheme = 'urn:simple';
2682 }
2683 if (isset($rating['data']))
2684 {
2685 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2686 }
2687 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
2688 }
2689 if (is_array($ratings))
2690 {
2691 $ratings = array_values(array_unique($ratings));
2692 }
2693 }
2694 else
2695 {
2696 $ratings = $ratings_parent;
2697 }
2698
2699 // RESTRICTIONS
2700 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
2701 {
2702 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
2703 {
2704 $restriction_relationship = null;
2705 $restriction_type = null;
2706 $restriction_value = null;
2707 if (isset($restriction['attribs']['']['relationship']))
2708 {
2709 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
2710 }
2711 if (isset($restriction['attribs']['']['type']))
2712 {
2713 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2714 }
2715 if (isset($restriction['data']))
2716 {
2717 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2718 }
2719 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
2720 }
2721 if (is_array($restrictions))
2722 {
2723 $restrictions = array_values(array_unique($restrictions));
2724 }
2725 }
2726 else
2727 {
2728 $restrictions = $restrictions_parent;
2729 }
2730
2731 // THUMBNAILS
2732 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
2733 {
2734 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
2735 {
2736 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
2737 }
2738 if (is_array($thumbnails))
2739 {
2740 $thumbnails = array_values(array_unique($thumbnails));
2741 }
2742 }
2743 else
2744 {
2745 $thumbnails = $thumbnails_parent;
2746 }
2747
2748 // TITLES
2749 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
2750 {
2751 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2752 }
2753 else
2754 {
2755 $title = $title_parent;
2756 }
2757
2758 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
2759 }
2760 }
2761 }
2762
2763 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
2764 {
2765 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
2766 {
2767 // Attributes
2768 $bitrate = null;
2769 $channels = null;
2770 $duration = null;
2771 $expression = null;
2772 $framerate = null;
2773 $height = null;
2774 $javascript = null;
2775 $lang = null;
2776 $length = null;
2777 $medium = null;
2778 $samplingrate = null;
2779 $type = null;
2780 $url = null;
2781 $width = null;
2782
2783 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2784 if (isset($link['attribs']['']['type']))
2785 {
2786 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2787 }
2788 if (isset($link['attribs']['']['length']))
2789 {
2790 $length = ceil($link['attribs']['']['length']);
2791 }
2792
2793 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
2794 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
2795 }
2796 }
2797
2798 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
2799 {
2800 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
2801 {
2802 // Attributes
2803 $bitrate = null;
2804 $channels = null;
2805 $duration = null;
2806 $expression = null;
2807 $framerate = null;
2808 $height = null;
2809 $javascript = null;
2810 $lang = null;
2811 $length = null;
2812 $medium = null;
2813 $samplingrate = null;
2814 $type = null;
2815 $url = null;
2816 $width = null;
2817
2818 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2819 if (isset($link['attribs']['']['type']))
2820 {
2821 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2822 }
2823 if (isset($link['attribs']['']['length']))
2824 {
2825 $length = ceil($link['attribs']['']['length']);
2826 }
2827
2828 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
2829 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
2830 }
2831 }
2832
2833 if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
2834 {
2835 if (isset($enclosure[0]['attribs']['']['url']))
2836 {
2837 // Attributes
2838 $bitrate = null;
2839 $channels = null;
2840 $duration = null;
2841 $expression = null;
2842 $framerate = null;
2843 $height = null;
2844 $javascript = null;
2845 $lang = null;
2846 $length = null;
2847 $medium = null;
2848 $samplingrate = null;
2849 $type = null;
2850 $url = null;
2851 $width = null;
2852
2853 $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
2854 if (isset($enclosure[0]['attribs']['']['type']))
2855 {
2856 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
2857 }
2858 if (isset($enclosure[0]['attribs']['']['length']))
2859 {
2860 $length = ceil($enclosure[0]['attribs']['']['length']);
2861 }
2862
2863 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
2864 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
2865 }
2866 }
2867
2868 if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
2869 {
2870 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
2871 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
2872 }
2873
2874 $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
2875 }
2876 if (!empty($this->data['enclosures']))
2877 {
2878 return $this->data['enclosures'];
2879 }
2880 else
2881 {
2882 return null;
2883 }
2884 }
2885
2886 /**
2887 * Get the latitude coordinates for the item
2888 *
2889 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2890 *
2891 * Uses `<geo:lat>` or `<georss:point>`
2892 *
2893 * @since 1.0
2894 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2895 * @link http://www.georss.org/ GeoRSS
2896 * @return string|null
2897 */
2898 public function get_latitude()
2899 {
2900 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2901 {
2902 return (float) $return[0]['data'];
2903 }
2904 elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2905 {
2906 return (float) $match[1];
2907 }
2908 else
2909 {
2910 return null;
2911 }
2912 }
2913
2914 /**
2915 * Get the longitude coordinates for the item
2916 *
2917 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2918 *
2919 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2920 *
2921 * @since 1.0
2922 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2923 * @link http://www.georss.org/ GeoRSS
2924 * @return string|null
2925 */
2926 public function get_longitude()
2927 {
2928 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2929 {
2930 return (float) $return[0]['data'];
2931 }
2932 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2933 {
2934 return (float) $return[0]['data'];
2935 }
2936 elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2937 {
2938 return (float) $match[2];
2939 }
2940 else
2941 {
2942 return null;
2943 }
2944 }
2945
2946 /**
2947 * Get the `<atom:source>` for the item
2948 *
2949 * @since 1.1
2950 * @return SimplePie_Source|null
2951 */
2952 public function get_source()
2953 {
2954 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
2955 {
2956 return $this->registry->create('Source', array($this, $return[0]));
2957 }
2958 else
2959 {
2960 return null;
2961 }
2962 }
2963}
2964
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Locator.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Locator.php
new file mode 100644
index 00000000..57e910c2
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Locator.php
@@ -0,0 +1,372 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Used for feed auto-discovery
47 *
48 *
49 * This class can be overloaded with {@see SimplePie::set_locator_class()}
50 *
51 * @package SimplePie
52 */
53class SimplePie_Locator
54{
55 var $useragent;
56 var $timeout;
57 var $file;
58 var $local = array();
59 var $elsewhere = array();
60 var $cached_entities = array();
61 var $http_base;
62 var $base;
63 var $base_location = 0;
64 var $checked_feeds = 0;
65 var $max_checked_feeds = 10;
66 protected $registry;
67
68 public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
69 {
70 $this->file = $file;
71 $this->useragent = $useragent;
72 $this->timeout = $timeout;
73 $this->max_checked_feeds = $max_checked_feeds;
74
75 if (class_exists('DOMDocument'))
76 {
77 $this->dom = new DOMDocument();
78
79 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
80 $this->dom->loadHTML($this->file->body);
81 restore_error_handler();
82 }
83 else
84 {
85 $this->dom = null;
86 }
87 }
88
89 public function set_registry(SimplePie_Registry $registry)
90 {
91 $this->registry = $registry;
92 }
93
94 public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
95 {
96 if ($this->is_feed($this->file))
97 {
98 return $this->file;
99 }
100
101 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
102 {
103 $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
104 if ($sniffer->get_type() !== 'text/html')
105 {
106 return null;
107 }
108 }
109
110 if ($type & ~SIMPLEPIE_LOCATOR_NONE)
111 {
112 $this->get_base();
113 }
114
115 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
116 {
117 return $working[0];
118 }
119
120 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
121 {
122 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
123 {
124 return $working;
125 }
126
127 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
128 {
129 return $working;
130 }
131
132 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
133 {
134 return $working;
135 }
136
137 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
138 {
139 return $working;
140 }
141 }
142 return null;
143 }
144
145 public function is_feed($file)
146 {
147 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
148 {
149 $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
150 $sniffed = $sniffer->get_type();
151 if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
152 {
153 return true;
154 }
155 else
156 {
157 return false;
158 }
159 }
160 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
161 {
162 return true;
163 }
164 else
165 {
166 return false;
167 }
168 }
169
170 public function get_base()
171 {
172 if ($this->dom === null)
173 {
174 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
175 }
176 $this->http_base = $this->file->url;
177 $this->base = $this->http_base;
178 $elements = $this->dom->getElementsByTagName('base');
179 foreach ($elements as $element)
180 {
181 if ($element->hasAttribute('href'))
182 {
183 $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
184 if ($base === false)
185 {
186 continue;
187 }
188 $this->base = $base;
189 $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
190 break;
191 }
192 }
193 }
194
195 public function autodiscovery()
196 {
197 $done = array();
198 $feeds = array();
199 $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
200 $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
201 $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
202
203 if (!empty($feeds))
204 {
205 return array_values($feeds);
206 }
207 else
208 {
209 return null;
210 }
211 }
212
213 protected function search_elements_by_tag($name, &$done, $feeds)
214 {
215 if ($this->dom === null)
216 {
217 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
218 }
219
220 $links = $this->dom->getElementsByTagName($name);
221 foreach ($links as $link)
222 {
223 if ($this->checked_feeds === $this->max_checked_feeds)
224 {
225 break;
226 }
227 if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
228 {
229 $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
230 $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
231
232 if ($this->base_location < $line)
233 {
234 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
235 }
236 else
237 {
238 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
239 }
240 if ($href === false)
241 {
242 continue;
243 }
244
245 if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
246 {
247 $this->checked_feeds++;
248 $headers = array(
249 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
250 );
251 $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
252 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
253 {
254 $feeds[$href] = $feed;
255 }
256 }
257 $done[] = $href;
258 }
259 }
260
261 return $feeds;
262 }
263
264 public function get_links()
265 {
266 if ($this->dom === null)
267 {
268 throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
269 }
270
271 $links = $this->dom->getElementsByTagName('a');
272 foreach ($links as $link)
273 {
274 if ($link->hasAttribute('href'))
275 {
276 $href = trim($link->getAttribute('href'));
277 $parsed = $this->registry->call('Misc', 'parse_url', array($href));
278 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
279 {
280 if ($this->base_location < $link->getLineNo())
281 {
282 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
283 }
284 else
285 {
286 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
287 }
288 if ($href === false)
289 {
290 continue;
291 }
292
293 $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
294
295 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
296 {
297 $this->local[] = $href;
298 }
299 else
300 {
301 $this->elsewhere[] = $href;
302 }
303 }
304 }
305 }
306 $this->local = array_unique($this->local);
307 $this->elsewhere = array_unique($this->elsewhere);
308 if (!empty($this->local) || !empty($this->elsewhere))
309 {
310 return true;
311 }
312 return null;
313 }
314
315 public function extension(&$array)
316 {
317 foreach ($array as $key => $value)
318 {
319 if ($this->checked_feeds === $this->max_checked_feeds)
320 {
321 break;
322 }
323 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
324 {
325 $this->checked_feeds++;
326
327 $headers = array(
328 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
329 );
330 $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
331 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
332 {
333 return $feed;
334 }
335 else
336 {
337 unset($array[$key]);
338 }
339 }
340 }
341 return null;
342 }
343
344 public function body(&$array)
345 {
346 foreach ($array as $key => $value)
347 {
348 if ($this->checked_feeds === $this->max_checked_feeds)
349 {
350 break;
351 }
352 if (preg_match('/(rss|rdf|atom|xml)/i', $value))
353 {
354 $this->checked_feeds++;
355 $headers = array(
356 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
357 );
358 $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
359 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
360 {
361 return $feed;
362 }
363 else
364 {
365 unset($array[$key]);
366 }
367 }
368 }
369 return null;
370 }
371}
372
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Misc.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Misc.php
new file mode 100644
index 00000000..5d7367f6
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Misc.php
@@ -0,0 +1,2247 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Miscellanous utilities
47 *
48 * @package SimplePie
49 */
50class SimplePie_Misc
51{
52 public static function time_hms($seconds)
53 {
54 $time = '';
55
56 $hours = floor($seconds / 3600);
57 $remainder = $seconds % 3600;
58 if ($hours > 0)
59 {
60 $time .= $hours.':';
61 }
62
63 $minutes = floor($remainder / 60);
64 $seconds = $remainder % 60;
65 if ($minutes < 10 && $hours > 0)
66 {
67 $minutes = '0' . $minutes;
68 }
69 if ($seconds < 10)
70 {
71 $seconds = '0' . $seconds;
72 }
73
74 $time .= $minutes.':';
75 $time .= $seconds;
76
77 return $time;
78 }
79
80 public static function absolutize_url($relative, $base)
81 {
82 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
83 if ($iri === false)
84 {
85 return false;
86 }
87 return $iri->get_uri();
88 }
89
90 /**
91 * Get a HTML/XML element from a HTML string
92 *
93 * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
94 * @param string $realname Element name (including namespace prefix if applicable)
95 * @param string $string HTML document
96 * @return array
97 */
98 public static function get_element($realname, $string)
99 {
100 $return = array();
101 $name = preg_quote($realname, '/');
102 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
103 {
104 for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
105 {
106 $return[$i]['tag'] = $realname;
107 $return[$i]['full'] = $matches[$i][0][0];
108 $return[$i]['offset'] = $matches[$i][0][1];
109 if (strlen($matches[$i][3][0]) <= 2)
110 {
111 $return[$i]['self_closing'] = true;
112 }
113 else
114 {
115 $return[$i]['self_closing'] = false;
116 $return[$i]['content'] = $matches[$i][4][0];
117 }
118 $return[$i]['attribs'] = array();
119 if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
120 {
121 for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
122 {
123 if (count($attribs[$j]) === 2)
124 {
125 $attribs[$j][2] = $attribs[$j][1];
126 }
127 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
128 }
129 }
130 }
131 }
132 return $return;
133 }
134
135 public static function element_implode($element)
136 {
137 $full = "<$element[tag]";
138 foreach ($element['attribs'] as $key => $value)
139 {
140 $key = strtolower($key);
141 $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
142 }
143 if ($element['self_closing'])
144 {
145 $full .= ' />';
146 }
147 else
148 {
149 $full .= ">$element[content]</$element[tag]>";
150 }
151 return $full;
152 }
153
154 public static function error($message, $level, $file, $line)
155 {
156 if ((ini_get('error_reporting') & $level) > 0)
157 {
158 switch ($level)
159 {
160 case E_USER_ERROR:
161 $note = 'PHP Error';
162 break;
163 case E_USER_WARNING:
164 $note = 'PHP Warning';
165 break;
166 case E_USER_NOTICE:
167 $note = 'PHP Notice';
168 break;
169 default:
170 $note = 'Unknown Error';
171 break;
172 }
173
174 $log_error = true;
175 if (!function_exists('error_log'))
176 {
177 $log_error = false;
178 }
179
180 $log_file = @ini_get('error_log');
181 if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
182 {
183 $log_error = false;
184 }
185
186 if ($log_error)
187 {
188 @error_log("$note: $message in $file on line $line", 0);
189 }
190 }
191
192 return $message;
193 }
194
195 public static function fix_protocol($url, $http = 1)
196 {
197 $url = SimplePie_Misc::normalize_url($url);
198 $parsed = SimplePie_Misc::parse_url($url);
199 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
200 {
201 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
202 }
203
204 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
205 {
206 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
207 }
208
209 if ($http === 2 && $parsed['scheme'] !== '')
210 {
211 return "feed:$url";
212 }
213 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
214 {
215 return substr_replace($url, 'podcast', 0, 4);
216 }
217 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
218 {
219 return substr_replace($url, 'itpc', 0, 4);
220 }
221 else
222 {
223 return $url;
224 }
225 }
226
227 public static function parse_url($url)
228 {
229 $iri = new SimplePie_IRI($url);
230 return array(
231 'scheme' => (string) $iri->scheme,
232 'authority' => (string) $iri->authority,
233 'path' => (string) $iri->path,
234 'query' => (string) $iri->query,
235 'fragment' => (string) $iri->fragment
236 );
237 }
238
239 public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
240 {
241 $iri = new SimplePie_IRI('');
242 $iri->scheme = $scheme;
243 $iri->authority = $authority;
244 $iri->path = $path;
245 $iri->query = $query;
246 $iri->fragment = $fragment;
247 return $iri->get_uri();
248 }
249
250 public static function normalize_url($url)
251 {
252 $iri = new SimplePie_IRI($url);
253 return $iri->get_uri();
254 }
255
256 public static function percent_encoding_normalization($match)
257 {
258 $integer = hexdec($match[1]);
259 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
260 {
261 return chr($integer);
262 }
263 else
264 {
265 return strtoupper($match[0]);
266 }
267 }
268
269 /**
270 * Converts a Windows-1252 encoded string to a UTF-8 encoded string
271 *
272 * @static
273 * @param string $string Windows-1252 encoded string
274 * @return string UTF-8 encoded string
275 */
276 public static function windows_1252_to_utf8($string)
277 {
278 static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
279
280 return strtr($string, $convert_table);
281 }
282
283 /**
284 * Change a string from one encoding to another
285 *
286 * @param string $data Raw data in $input encoding
287 * @param string $input Encoding of $data
288 * @param string $output Encoding you want
289 * @return string|boolean False if we can't convert it
290 */
291 public static function change_encoding($data, $input, $output)
292 {
293 $input = SimplePie_Misc::encoding($input);
294 $output = SimplePie_Misc::encoding($output);
295
296 // We fail to fail on non US-ASCII bytes
297 if ($input === 'US-ASCII')
298 {
299 static $non_ascii_octects = '';
300 if (!$non_ascii_octects)
301 {
302 for ($i = 0x80; $i <= 0xFF; $i++)
303 {
304 $non_ascii_octects .= chr($i);
305 }
306 }
307 $data = substr($data, 0, strcspn($data, $non_ascii_octects));
308 }
309
310 // This is first, as behaviour of this is completely predictable
311 if ($input === 'windows-1252' && $output === 'UTF-8')
312 {
313 return SimplePie_Misc::windows_1252_to_utf8($data);
314 }
315 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
316 elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
317 {
318 return $return;
319 }
320 // This is last, as behaviour of this varies with OS userland and PHP version
321 elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
322 {
323 return $return;
324 }
325 // If we can't do anything, just fail
326 else
327 {
328 return false;
329 }
330 }
331
332 protected static function change_encoding_mbstring($data, $input, $output)
333 {
334 if ($input === 'windows-949')
335 {
336 $input = 'EUC-KR';
337 }
338 if ($output === 'windows-949')
339 {
340 $output = 'EUC-KR';
341 }
342 if ($input === 'Windows-31J')
343 {
344 $input = 'SJIS';
345 }
346 if ($output === 'Windows-31J')
347 {
348 $output = 'SJIS';
349 }
350
351 // Check that the encoding is supported
352 if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
353 {
354 return false;
355 }
356 if (!in_array($input, mb_list_encodings()))
357 {
358 return false;
359 }
360
361 // Let's do some conversion
362 if ($return = @mb_convert_encoding($data, $output, $input))
363 {
364 return $return;
365 }
366
367 return false;
368 }
369
370 protected static function change_encoding_iconv($data, $input, $output)
371 {
372 return @iconv($input, $output, $data);
373 }
374
375 /**
376 * Normalize an encoding name
377 *
378 * This is automatically generated by create.php
379 *
380 * To generate it, run `php create.php` on the command line, and copy the
381 * output to replace this function.
382 *
383 * @param string $charset Character set to standardise
384 * @return string Standardised name
385 */
386 public static function encoding($charset)
387 {
388 // Normalization from UTS #22
389 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
390 {
391 case 'adobestandardencoding':
392 case 'csadobestandardencoding':
393 return 'Adobe-Standard-Encoding';
394
395 case 'adobesymbolencoding':
396 case 'cshppsmath':
397 return 'Adobe-Symbol-Encoding';
398
399 case 'ami1251':
400 case 'amiga1251':
401 return 'Amiga-1251';
402
403 case 'ansix31101983':
404 case 'csat5001983':
405 case 'csiso99naplps':
406 case 'isoir99':
407 case 'naplps':
408 return 'ANSI_X3.110-1983';
409
410 case 'arabic7':
411 case 'asmo449':
412 case 'csiso89asmo449':
413 case 'iso9036':
414 case 'isoir89':
415 return 'ASMO_449';
416
417 case 'big5':
418 case 'csbig5':
419 return 'Big5';
420
421 case 'big5hkscs':
422 return 'Big5-HKSCS';
423
424 case 'bocu1':
425 case 'csbocu1':
426 return 'BOCU-1';
427
428 case 'brf':
429 case 'csbrf':
430 return 'BRF';
431
432 case 'bs4730':
433 case 'csiso4unitedkingdom':
434 case 'gb':
435 case 'iso646gb':
436 case 'isoir4':
437 case 'uk':
438 return 'BS_4730';
439
440 case 'bsviewdata':
441 case 'csiso47bsviewdata':
442 case 'isoir47':
443 return 'BS_viewdata';
444
445 case 'cesu8':
446 case 'cscesu8':
447 return 'CESU-8';
448
449 case 'ca':
450 case 'csa71':
451 case 'csaz243419851':
452 case 'csiso121canadian1':
453 case 'iso646ca':
454 case 'isoir121':
455 return 'CSA_Z243.4-1985-1';
456
457 case 'csa72':
458 case 'csaz243419852':
459 case 'csiso122canadian2':
460 case 'iso646ca2':
461 case 'isoir122':
462 return 'CSA_Z243.4-1985-2';
463
464 case 'csaz24341985gr':
465 case 'csiso123csaz24341985gr':
466 case 'isoir123':
467 return 'CSA_Z243.4-1985-gr';
468
469 case 'csiso139csn369103':
470 case 'csn369103':
471 case 'isoir139':
472 return 'CSN_369103';
473
474 case 'csdecmcs':
475 case 'dec':
476 case 'decmcs':
477 return 'DEC-MCS';
478
479 case 'csiso21german':
480 case 'de':
481 case 'din66003':
482 case 'iso646de':
483 case 'isoir21':
484 return 'DIN_66003';
485
486 case 'csdkus':
487 case 'dkus':
488 return 'dk-us';
489
490 case 'csiso646danish':
491 case 'dk':
492 case 'ds2089':
493 case 'iso646dk':
494 return 'DS_2089';
495
496 case 'csibmebcdicatde':
497 case 'ebcdicatde':
498 return 'EBCDIC-AT-DE';
499
500 case 'csebcdicatdea':
501 case 'ebcdicatdea':
502 return 'EBCDIC-AT-DE-A';
503
504 case 'csebcdiccafr':
505 case 'ebcdiccafr':
506 return 'EBCDIC-CA-FR';
507
508 case 'csebcdicdkno':
509 case 'ebcdicdkno':
510 return 'EBCDIC-DK-NO';
511
512 case 'csebcdicdknoa':
513 case 'ebcdicdknoa':
514 return 'EBCDIC-DK-NO-A';
515
516 case 'csebcdices':
517 case 'ebcdices':
518 return 'EBCDIC-ES';
519
520 case 'csebcdicesa':
521 case 'ebcdicesa':
522 return 'EBCDIC-ES-A';
523
524 case 'csebcdicess':
525 case 'ebcdicess':
526 return 'EBCDIC-ES-S';
527
528 case 'csebcdicfise':
529 case 'ebcdicfise':
530 return 'EBCDIC-FI-SE';
531
532 case 'csebcdicfisea':
533 case 'ebcdicfisea':
534 return 'EBCDIC-FI-SE-A';
535
536 case 'csebcdicfr':
537 case 'ebcdicfr':
538 return 'EBCDIC-FR';
539
540 case 'csebcdicit':
541 case 'ebcdicit':
542 return 'EBCDIC-IT';
543
544 case 'csebcdicpt':
545 case 'ebcdicpt':
546 return 'EBCDIC-PT';
547
548 case 'csebcdicuk':
549 case 'ebcdicuk':
550 return 'EBCDIC-UK';
551
552 case 'csebcdicus':
553 case 'ebcdicus':
554 return 'EBCDIC-US';
555
556 case 'csiso111ecmacyrillic':
557 case 'ecmacyrillic':
558 case 'isoir111':
559 case 'koi8e':
560 return 'ECMA-cyrillic';
561
562 case 'csiso17spanish':
563 case 'es':
564 case 'iso646es':
565 case 'isoir17':
566 return 'ES';
567
568 case 'csiso85spanish2':
569 case 'es2':
570 case 'iso646es2':
571 case 'isoir85':
572 return 'ES2';
573
574 case 'cseucpkdfmtjapanese':
575 case 'eucjp':
576 case 'extendedunixcodepackedformatforjapanese':
577 return 'EUC-JP';
578
579 case 'cseucfixwidjapanese':
580 case 'extendedunixcodefixedwidthforjapanese':
581 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
582
583 case 'gb18030':
584 return 'GB18030';
585
586 case 'chinese':
587 case 'cp936':
588 case 'csgb2312':
589 case 'csiso58gb231280':
590 case 'gb2312':
591 case 'gb231280':
592 case 'gbk':
593 case 'isoir58':
594 case 'ms936':
595 case 'windows936':
596 return 'GBK';
597
598 case 'cn':
599 case 'csiso57gb1988':
600 case 'gb198880':
601 case 'iso646cn':
602 case 'isoir57':
603 return 'GB_1988-80';
604
605 case 'csiso153gost1976874':
606 case 'gost1976874':
607 case 'isoir153':
608 case 'stsev35888':
609 return 'GOST_19768-74';
610
611 case 'csiso150':
612 case 'csiso150greekccitt':
613 case 'greekccitt':
614 case 'isoir150':
615 return 'greek-ccitt';
616
617 case 'csiso88greek7':
618 case 'greek7':
619 case 'isoir88':
620 return 'greek7';
621
622 case 'csiso18greek7old':
623 case 'greek7old':
624 case 'isoir18':
625 return 'greek7-old';
626
627 case 'cshpdesktop':
628 case 'hpdesktop':
629 return 'HP-DeskTop';
630
631 case 'cshplegal':
632 case 'hplegal':
633 return 'HP-Legal';
634
635 case 'cshpmath8':
636 case 'hpmath8':
637 return 'HP-Math8';
638
639 case 'cshppifont':
640 case 'hppifont':
641 return 'HP-Pi-font';
642
643 case 'cshproman8':
644 case 'hproman8':
645 case 'r8':
646 case 'roman8':
647 return 'hp-roman8';
648
649 case 'hzgb2312':
650 return 'HZ-GB-2312';
651
652 case 'csibmsymbols':
653 case 'ibmsymbols':
654 return 'IBM-Symbols';
655
656 case 'csibmthai':
657 case 'ibmthai':
658 return 'IBM-Thai';
659
660 case 'cp37':
661 case 'csibm37':
662 case 'ebcdiccpca':
663 case 'ebcdiccpnl':
664 case 'ebcdiccpus':
665 case 'ebcdiccpwt':
666 case 'ibm37':
667 return 'IBM037';
668
669 case 'cp38':
670 case 'csibm38':
671 case 'ebcdicint':
672 case 'ibm38':
673 return 'IBM038';
674
675 case 'cp273':
676 case 'csibm273':
677 case 'ibm273':
678 return 'IBM273';
679
680 case 'cp274':
681 case 'csibm274':
682 case 'ebcdicbe':
683 case 'ibm274':
684 return 'IBM274';
685
686 case 'cp275':
687 case 'csibm275':
688 case 'ebcdicbr':
689 case 'ibm275':
690 return 'IBM275';
691
692 case 'csibm277':
693 case 'ebcdiccpdk':
694 case 'ebcdiccpno':
695 case 'ibm277':
696 return 'IBM277';
697
698 case 'cp278':
699 case 'csibm278':
700 case 'ebcdiccpfi':
701 case 'ebcdiccpse':
702 case 'ibm278':
703 return 'IBM278';
704
705 case 'cp280':
706 case 'csibm280':
707 case 'ebcdiccpit':
708 case 'ibm280':
709 return 'IBM280';
710
711 case 'cp281':
712 case 'csibm281':
713 case 'ebcdicjpe':
714 case 'ibm281':
715 return 'IBM281';
716
717 case 'cp284':
718 case 'csibm284':
719 case 'ebcdiccpes':
720 case 'ibm284':
721 return 'IBM284';
722
723 case 'cp285':
724 case 'csibm285':
725 case 'ebcdiccpgb':
726 case 'ibm285':
727 return 'IBM285';
728
729 case 'cp290':
730 case 'csibm290':
731 case 'ebcdicjpkana':
732 case 'ibm290':
733 return 'IBM290';
734
735 case 'cp297':
736 case 'csibm297':
737 case 'ebcdiccpfr':
738 case 'ibm297':
739 return 'IBM297';
740
741 case 'cp420':
742 case 'csibm420':
743 case 'ebcdiccpar1':
744 case 'ibm420':
745 return 'IBM420';
746
747 case 'cp423':
748 case 'csibm423':
749 case 'ebcdiccpgr':
750 case 'ibm423':
751 return 'IBM423';
752
753 case 'cp424':
754 case 'csibm424':
755 case 'ebcdiccphe':
756 case 'ibm424':
757 return 'IBM424';
758
759 case '437':
760 case 'cp437':
761 case 'cspc8codepage437':
762 case 'ibm437':
763 return 'IBM437';
764
765 case 'cp500':
766 case 'csibm500':
767 case 'ebcdiccpbe':
768 case 'ebcdiccpch':
769 case 'ibm500':
770 return 'IBM500';
771
772 case 'cp775':
773 case 'cspc775baltic':
774 case 'ibm775':
775 return 'IBM775';
776
777 case '850':
778 case 'cp850':
779 case 'cspc850multilingual':
780 case 'ibm850':
781 return 'IBM850';
782
783 case '851':
784 case 'cp851':
785 case 'csibm851':
786 case 'ibm851':
787 return 'IBM851';
788
789 case '852':
790 case 'cp852':
791 case 'cspcp852':
792 case 'ibm852':
793 return 'IBM852';
794
795 case '855':
796 case 'cp855':
797 case 'csibm855':
798 case 'ibm855':
799 return 'IBM855';
800
801 case '857':
802 case 'cp857':
803 case 'csibm857':
804 case 'ibm857':
805 return 'IBM857';
806
807 case 'ccsid858':
808 case 'cp858':
809 case 'ibm858':
810 case 'pcmultilingual850euro':
811 return 'IBM00858';
812
813 case '860':
814 case 'cp860':
815 case 'csibm860':
816 case 'ibm860':
817 return 'IBM860';
818
819 case '861':
820 case 'cp861':
821 case 'cpis':
822 case 'csibm861':
823 case 'ibm861':
824 return 'IBM861';
825
826 case '862':
827 case 'cp862':
828 case 'cspc862latinhebrew':
829 case 'ibm862':
830 return 'IBM862';
831
832 case '863':
833 case 'cp863':
834 case 'csibm863':
835 case 'ibm863':
836 return 'IBM863';
837
838 case 'cp864':
839 case 'csibm864':
840 case 'ibm864':
841 return 'IBM864';
842
843 case '865':
844 case 'cp865':
845 case 'csibm865':
846 case 'ibm865':
847 return 'IBM865';
848
849 case '866':
850 case 'cp866':
851 case 'csibm866':
852 case 'ibm866':
853 return 'IBM866';
854
855 case 'cp868':
856 case 'cpar':
857 case 'csibm868':
858 case 'ibm868':
859 return 'IBM868';
860
861 case '869':
862 case 'cp869':
863 case 'cpgr':
864 case 'csibm869':
865 case 'ibm869':
866 return 'IBM869';
867
868 case 'cp870':
869 case 'csibm870':
870 case 'ebcdiccproece':
871 case 'ebcdiccpyu':
872 case 'ibm870':
873 return 'IBM870';
874
875 case 'cp871':
876 case 'csibm871':
877 case 'ebcdiccpis':
878 case 'ibm871':
879 return 'IBM871';
880
881 case 'cp880':
882 case 'csibm880':
883 case 'ebcdiccyrillic':
884 case 'ibm880':
885 return 'IBM880';
886
887 case 'cp891':
888 case 'csibm891':
889 case 'ibm891':
890 return 'IBM891';
891
892 case 'cp903':
893 case 'csibm903':
894 case 'ibm903':
895 return 'IBM903';
896
897 case '904':
898 case 'cp904':
899 case 'csibbm904':
900 case 'ibm904':
901 return 'IBM904';
902
903 case 'cp905':
904 case 'csibm905':
905 case 'ebcdiccptr':
906 case 'ibm905':
907 return 'IBM905';
908
909 case 'cp918':
910 case 'csibm918':
911 case 'ebcdiccpar2':
912 case 'ibm918':
913 return 'IBM918';
914
915 case 'ccsid924':
916 case 'cp924':
917 case 'ebcdiclatin9euro':
918 case 'ibm924':
919 return 'IBM00924';
920
921 case 'cp1026':
922 case 'csibm1026':
923 case 'ibm1026':
924 return 'IBM1026';
925
926 case 'ibm1047':
927 return 'IBM1047';
928
929 case 'ccsid1140':
930 case 'cp1140':
931 case 'ebcdicus37euro':
932 case 'ibm1140':
933 return 'IBM01140';
934
935 case 'ccsid1141':
936 case 'cp1141':
937 case 'ebcdicde273euro':
938 case 'ibm1141':
939 return 'IBM01141';
940
941 case 'ccsid1142':
942 case 'cp1142':
943 case 'ebcdicdk277euro':
944 case 'ebcdicno277euro':
945 case 'ibm1142':
946 return 'IBM01142';
947
948 case 'ccsid1143':
949 case 'cp1143':
950 case 'ebcdicfi278euro':
951 case 'ebcdicse278euro':
952 case 'ibm1143':
953 return 'IBM01143';
954
955 case 'ccsid1144':
956 case 'cp1144':
957 case 'ebcdicit280euro':
958 case 'ibm1144':
959 return 'IBM01144';
960
961 case 'ccsid1145':
962 case 'cp1145':
963 case 'ebcdices284euro':
964 case 'ibm1145':
965 return 'IBM01145';
966
967 case 'ccsid1146':
968 case 'cp1146':
969 case 'ebcdicgb285euro':
970 case 'ibm1146':
971 return 'IBM01146';
972
973 case 'ccsid1147':
974 case 'cp1147':
975 case 'ebcdicfr297euro':
976 case 'ibm1147':
977 return 'IBM01147';
978
979 case 'ccsid1148':
980 case 'cp1148':
981 case 'ebcdicinternational500euro':
982 case 'ibm1148':
983 return 'IBM01148';
984
985 case 'ccsid1149':
986 case 'cp1149':
987 case 'ebcdicis871euro':
988 case 'ibm1149':
989 return 'IBM01149';
990
991 case 'csiso143iecp271':
992 case 'iecp271':
993 case 'isoir143':
994 return 'IEC_P27-1';
995
996 case 'csiso49inis':
997 case 'inis':
998 case 'isoir49':
999 return 'INIS';
1000
1001 case 'csiso50inis8':
1002 case 'inis8':
1003 case 'isoir50':
1004 return 'INIS-8';
1005
1006 case 'csiso51iniscyrillic':
1007 case 'iniscyrillic':
1008 case 'isoir51':
1009 return 'INIS-cyrillic';
1010
1011 case 'csinvariant':
1012 case 'invariant':
1013 return 'INVARIANT';
1014
1015 case 'iso2022cn':
1016 return 'ISO-2022-CN';
1017
1018 case 'iso2022cnext':
1019 return 'ISO-2022-CN-EXT';
1020
1021 case 'csiso2022jp':
1022 case 'iso2022jp':
1023 return 'ISO-2022-JP';
1024
1025 case 'csiso2022jp2':
1026 case 'iso2022jp2':
1027 return 'ISO-2022-JP-2';
1028
1029 case 'csiso2022kr':
1030 case 'iso2022kr':
1031 return 'ISO-2022-KR';
1032
1033 case 'cswindows30latin1':
1034 case 'iso88591windows30latin1':
1035 return 'ISO-8859-1-Windows-3.0-Latin-1';
1036
1037 case 'cswindows31latin1':
1038 case 'iso88591windows31latin1':
1039 return 'ISO-8859-1-Windows-3.1-Latin-1';
1040
1041 case 'csisolatin2':
1042 case 'iso88592':
1043 case 'iso885921987':
1044 case 'isoir101':
1045 case 'l2':
1046 case 'latin2':
1047 return 'ISO-8859-2';
1048
1049 case 'cswindows31latin2':
1050 case 'iso88592windowslatin2':
1051 return 'ISO-8859-2-Windows-Latin-2';
1052
1053 case 'csisolatin3':
1054 case 'iso88593':
1055 case 'iso885931988':
1056 case 'isoir109':
1057 case 'l3':
1058 case 'latin3':
1059 return 'ISO-8859-3';
1060
1061 case 'csisolatin4':
1062 case 'iso88594':
1063 case 'iso885941988':
1064 case 'isoir110':
1065 case 'l4':
1066 case 'latin4':
1067 return 'ISO-8859-4';
1068
1069 case 'csisolatincyrillic':
1070 case 'cyrillic':
1071 case 'iso88595':
1072 case 'iso885951988':
1073 case 'isoir144':
1074 return 'ISO-8859-5';
1075
1076 case 'arabic':
1077 case 'asmo708':
1078 case 'csisolatinarabic':
1079 case 'ecma114':
1080 case 'iso88596':
1081 case 'iso885961987':
1082 case 'isoir127':
1083 return 'ISO-8859-6';
1084
1085 case 'csiso88596e':
1086 case 'iso88596e':
1087 return 'ISO-8859-6-E';
1088
1089 case 'csiso88596i':
1090 case 'iso88596i':
1091 return 'ISO-8859-6-I';
1092
1093 case 'csisolatingreek':
1094 case 'ecma118':
1095 case 'elot928':
1096 case 'greek':
1097 case 'greek8':
1098 case 'iso88597':
1099 case 'iso885971987':
1100 case 'isoir126':
1101 return 'ISO-8859-7';
1102
1103 case 'csisolatinhebrew':
1104 case 'hebrew':
1105 case 'iso88598':
1106 case 'iso885981988':
1107 case 'isoir138':
1108 return 'ISO-8859-8';
1109
1110 case 'csiso88598e':
1111 case 'iso88598e':
1112 return 'ISO-8859-8-E';
1113
1114 case 'csiso88598i':
1115 case 'iso88598i':
1116 return 'ISO-8859-8-I';
1117
1118 case 'cswindows31latin5':
1119 case 'iso88599windowslatin5':
1120 return 'ISO-8859-9-Windows-Latin-5';
1121
1122 case 'csisolatin6':
1123 case 'iso885910':
1124 case 'iso8859101992':
1125 case 'isoir157':
1126 case 'l6':
1127 case 'latin6':
1128 return 'ISO-8859-10';
1129
1130 case 'iso885913':
1131 return 'ISO-8859-13';
1132
1133 case 'iso885914':
1134 case 'iso8859141998':
1135 case 'isoceltic':
1136 case 'isoir199':
1137 case 'l8':
1138 case 'latin8':
1139 return 'ISO-8859-14';
1140
1141 case 'iso885915':
1142 case 'latin9':
1143 return 'ISO-8859-15';
1144
1145 case 'iso885916':
1146 case 'iso8859162001':
1147 case 'isoir226':
1148 case 'l10':
1149 case 'latin10':
1150 return 'ISO-8859-16';
1151
1152 case 'iso10646j1':
1153 return 'ISO-10646-J-1';
1154
1155 case 'csunicode':
1156 case 'iso10646ucs2':
1157 return 'ISO-10646-UCS-2';
1158
1159 case 'csucs4':
1160 case 'iso10646ucs4':
1161 return 'ISO-10646-UCS-4';
1162
1163 case 'csunicodeascii':
1164 case 'iso10646ucsbasic':
1165 return 'ISO-10646-UCS-Basic';
1166
1167 case 'csunicodelatin1':
1168 case 'iso10646':
1169 case 'iso10646unicodelatin1':
1170 return 'ISO-10646-Unicode-Latin1';
1171
1172 case 'csiso10646utf1':
1173 case 'iso10646utf1':
1174 return 'ISO-10646-UTF-1';
1175
1176 case 'csiso115481':
1177 case 'iso115481':
1178 case 'isotr115481':
1179 return 'ISO-11548-1';
1180
1181 case 'csiso90':
1182 case 'isoir90':
1183 return 'iso-ir-90';
1184
1185 case 'csunicodeibm1261':
1186 case 'isounicodeibm1261':
1187 return 'ISO-Unicode-IBM-1261';
1188
1189 case 'csunicodeibm1264':
1190 case 'isounicodeibm1264':
1191 return 'ISO-Unicode-IBM-1264';
1192
1193 case 'csunicodeibm1265':
1194 case 'isounicodeibm1265':
1195 return 'ISO-Unicode-IBM-1265';
1196
1197 case 'csunicodeibm1268':
1198 case 'isounicodeibm1268':
1199 return 'ISO-Unicode-IBM-1268';
1200
1201 case 'csunicodeibm1276':
1202 case 'isounicodeibm1276':
1203 return 'ISO-Unicode-IBM-1276';
1204
1205 case 'csiso646basic1983':
1206 case 'iso646basic1983':
1207 case 'ref':
1208 return 'ISO_646.basic:1983';
1209
1210 case 'csiso2intlrefversion':
1211 case 'irv':
1212 case 'iso646irv1983':
1213 case 'isoir2':
1214 return 'ISO_646.irv:1983';
1215
1216 case 'csiso2033':
1217 case 'e13b':
1218 case 'iso20331983':
1219 case 'isoir98':
1220 return 'ISO_2033-1983';
1221
1222 case 'csiso5427cyrillic':
1223 case 'iso5427':
1224 case 'isoir37':
1225 return 'ISO_5427';
1226
1227 case 'iso5427cyrillic1981':
1228 case 'iso54271981':
1229 case 'isoir54':
1230 return 'ISO_5427:1981';
1231
1232 case 'csiso5428greek':
1233 case 'iso54281980':
1234 case 'isoir55':
1235 return 'ISO_5428:1980';
1236
1237 case 'csiso6937add':
1238 case 'iso6937225':
1239 case 'isoir152':
1240 return 'ISO_6937-2-25';
1241
1242 case 'csisotextcomm':
1243 case 'iso69372add':
1244 case 'isoir142':
1245 return 'ISO_6937-2-add';
1246
1247 case 'csiso8859supp':
1248 case 'iso8859supp':
1249 case 'isoir154':
1250 case 'latin125':
1251 return 'ISO_8859-supp';
1252
1253 case 'csiso10367box':
1254 case 'iso10367box':
1255 case 'isoir155':
1256 return 'ISO_10367-box';
1257
1258 case 'csiso15italian':
1259 case 'iso646it':
1260 case 'isoir15':
1261 case 'it':
1262 return 'IT';
1263
1264 case 'csiso13jisc6220jp':
1265 case 'isoir13':
1266 case 'jisc62201969':
1267 case 'jisc62201969jp':
1268 case 'katakana':
1269 case 'x2017':
1270 return 'JIS_C6220-1969-jp';
1271
1272 case 'csiso14jisc6220ro':
1273 case 'iso646jp':
1274 case 'isoir14':
1275 case 'jisc62201969ro':
1276 case 'jp':
1277 return 'JIS_C6220-1969-ro';
1278
1279 case 'csiso42jisc62261978':
1280 case 'isoir42':
1281 case 'jisc62261978':
1282 return 'JIS_C6226-1978';
1283
1284 case 'csiso87jisx208':
1285 case 'isoir87':
1286 case 'jisc62261983':
1287 case 'jisx2081983':
1288 case 'x208':
1289 return 'JIS_C6226-1983';
1290
1291 case 'csiso91jisc62291984a':
1292 case 'isoir91':
1293 case 'jisc62291984a':
1294 case 'jpocra':
1295 return 'JIS_C6229-1984-a';
1296
1297 case 'csiso92jisc62991984b':
1298 case 'iso646jpocrb':
1299 case 'isoir92':
1300 case 'jisc62291984b':
1301 case 'jpocrb':
1302 return 'JIS_C6229-1984-b';
1303
1304 case 'csiso93jis62291984badd':
1305 case 'isoir93':
1306 case 'jisc62291984badd':
1307 case 'jpocrbadd':
1308 return 'JIS_C6229-1984-b-add';
1309
1310 case 'csiso94jis62291984hand':
1311 case 'isoir94':
1312 case 'jisc62291984hand':
1313 case 'jpocrhand':
1314 return 'JIS_C6229-1984-hand';
1315
1316 case 'csiso95jis62291984handadd':
1317 case 'isoir95':
1318 case 'jisc62291984handadd':
1319 case 'jpocrhandadd':
1320 return 'JIS_C6229-1984-hand-add';
1321
1322 case 'csiso96jisc62291984kana':
1323 case 'isoir96':
1324 case 'jisc62291984kana':
1325 return 'JIS_C6229-1984-kana';
1326
1327 case 'csjisencoding':
1328 case 'jisencoding':
1329 return 'JIS_Encoding';
1330
1331 case 'cshalfwidthkatakana':
1332 case 'jisx201':
1333 case 'x201':
1334 return 'JIS_X0201';
1335
1336 case 'csiso159jisx2121990':
1337 case 'isoir159':
1338 case 'jisx2121990':
1339 case 'x212':
1340 return 'JIS_X0212-1990';
1341
1342 case 'csiso141jusib1002':
1343 case 'iso646yu':
1344 case 'isoir141':
1345 case 'js':
1346 case 'jusib1002':
1347 case 'yu':
1348 return 'JUS_I.B1.002';
1349
1350 case 'csiso147macedonian':
1351 case 'isoir147':
1352 case 'jusib1003mac':
1353 case 'macedonian':
1354 return 'JUS_I.B1.003-mac';
1355
1356 case 'csiso146serbian':
1357 case 'isoir146':
1358 case 'jusib1003serb':
1359 case 'serbian':
1360 return 'JUS_I.B1.003-serb';
1361
1362 case 'koi7switched':
1363 return 'KOI7-switched';
1364
1365 case 'cskoi8r':
1366 case 'koi8r':
1367 return 'KOI8-R';
1368
1369 case 'koi8u':
1370 return 'KOI8-U';
1371
1372 case 'csksc5636':
1373 case 'iso646kr':
1374 case 'ksc5636':
1375 return 'KSC5636';
1376
1377 case 'cskz1048':
1378 case 'kz1048':
1379 case 'rk1048':
1380 case 'strk10482002':
1381 return 'KZ-1048';
1382
1383 case 'csiso19latingreek':
1384 case 'isoir19':
1385 case 'latingreek':
1386 return 'latin-greek';
1387
1388 case 'csiso27latingreek1':
1389 case 'isoir27':
1390 case 'latingreek1':
1391 return 'Latin-greek-1';
1392
1393 case 'csiso158lap':
1394 case 'isoir158':
1395 case 'lap':
1396 case 'latinlap':
1397 return 'latin-lap';
1398
1399 case 'csmacintosh':
1400 case 'mac':
1401 case 'macintosh':
1402 return 'macintosh';
1403
1404 case 'csmicrosoftpublishing':
1405 case 'microsoftpublishing':
1406 return 'Microsoft-Publishing';
1407
1408 case 'csmnem':
1409 case 'mnem':
1410 return 'MNEM';
1411
1412 case 'csmnemonic':
1413 case 'mnemonic':
1414 return 'MNEMONIC';
1415
1416 case 'csiso86hungarian':
1417 case 'hu':
1418 case 'iso646hu':
1419 case 'isoir86':
1420 case 'msz77953':
1421 return 'MSZ_7795.3';
1422
1423 case 'csnatsdano':
1424 case 'isoir91':
1425 case 'natsdano':
1426 return 'NATS-DANO';
1427
1428 case 'csnatsdanoadd':
1429 case 'isoir92':
1430 case 'natsdanoadd':
1431 return 'NATS-DANO-ADD';
1432
1433 case 'csnatssefi':
1434 case 'isoir81':
1435 case 'natssefi':
1436 return 'NATS-SEFI';
1437
1438 case 'csnatssefiadd':
1439 case 'isoir82':
1440 case 'natssefiadd':
1441 return 'NATS-SEFI-ADD';
1442
1443 case 'csiso151cuba':
1444 case 'cuba':
1445 case 'iso646cu':
1446 case 'isoir151':
1447 case 'ncnc1081':
1448 return 'NC_NC00-10:81';
1449
1450 case 'csiso69french':
1451 case 'fr':
1452 case 'iso646fr':
1453 case 'isoir69':
1454 case 'nfz62010':
1455 return 'NF_Z_62-010';
1456
1457 case 'csiso25french':
1458 case 'iso646fr1':
1459 case 'isoir25':
1460 case 'nfz620101973':
1461 return 'NF_Z_62-010_(1973)';
1462
1463 case 'csiso60danishnorwegian':
1464 case 'csiso60norwegian1':
1465 case 'iso646no':
1466 case 'isoir60':
1467 case 'no':
1468 case 'ns45511':
1469 return 'NS_4551-1';
1470
1471 case 'csiso61norwegian2':
1472 case 'iso646no2':
1473 case 'isoir61':
1474 case 'no2':
1475 case 'ns45512':
1476 return 'NS_4551-2';
1477
1478 case 'osdebcdicdf3irv':
1479 return 'OSD_EBCDIC_DF03_IRV';
1480
1481 case 'osdebcdicdf41':
1482 return 'OSD_EBCDIC_DF04_1';
1483
1484 case 'osdebcdicdf415':
1485 return 'OSD_EBCDIC_DF04_15';
1486
1487 case 'cspc8danishnorwegian':
1488 case 'pc8danishnorwegian':
1489 return 'PC8-Danish-Norwegian';
1490
1491 case 'cspc8turkish':
1492 case 'pc8turkish':
1493 return 'PC8-Turkish';
1494
1495 case 'csiso16portuguese':
1496 case 'iso646pt':
1497 case 'isoir16':
1498 case 'pt':
1499 return 'PT';
1500
1501 case 'csiso84portuguese2':
1502 case 'iso646pt2':
1503 case 'isoir84':
1504 case 'pt2':
1505 return 'PT2';
1506
1507 case 'cp154':
1508 case 'csptcp154':
1509 case 'cyrillicasian':
1510 case 'pt154':
1511 case 'ptcp154':
1512 return 'PTCP154';
1513
1514 case 'scsu':
1515 return 'SCSU';
1516
1517 case 'csiso10swedish':
1518 case 'fi':
1519 case 'iso646fi':
1520 case 'iso646se':
1521 case 'isoir10':
1522 case 'se':
1523 case 'sen850200b':
1524 return 'SEN_850200_B';
1525
1526 case 'csiso11swedishfornames':
1527 case 'iso646se2':
1528 case 'isoir11':
1529 case 'se2':
1530 case 'sen850200c':
1531 return 'SEN_850200_C';
1532
1533 case 'csiso102t617bit':
1534 case 'isoir102':
1535 case 't617bit':
1536 return 'T.61-7bit';
1537
1538 case 'csiso103t618bit':
1539 case 'isoir103':
1540 case 't61':
1541 case 't618bit':
1542 return 'T.61-8bit';
1543
1544 case 'csiso128t101g2':
1545 case 'isoir128':
1546 case 't101g2':
1547 return 'T.101-G2';
1548
1549 case 'cstscii':
1550 case 'tscii':
1551 return 'TSCII';
1552
1553 case 'csunicode11':
1554 case 'unicode11':
1555 return 'UNICODE-1-1';
1556
1557 case 'csunicode11utf7':
1558 case 'unicode11utf7':
1559 return 'UNICODE-1-1-UTF-7';
1560
1561 case 'csunknown8bit':
1562 case 'unknown8bit':
1563 return 'UNKNOWN-8BIT';
1564
1565 case 'ansix341968':
1566 case 'ansix341986':
1567 case 'ascii':
1568 case 'cp367':
1569 case 'csascii':
1570 case 'ibm367':
1571 case 'iso646irv1991':
1572 case 'iso646us':
1573 case 'isoir6':
1574 case 'us':
1575 case 'usascii':
1576 return 'US-ASCII';
1577
1578 case 'csusdk':
1579 case 'usdk':
1580 return 'us-dk';
1581
1582 case 'utf7':
1583 return 'UTF-7';
1584
1585 case 'utf8':
1586 return 'UTF-8';
1587
1588 case 'utf16':
1589 return 'UTF-16';
1590
1591 case 'utf16be':
1592 return 'UTF-16BE';
1593
1594 case 'utf16le':
1595 return 'UTF-16LE';
1596
1597 case 'utf32':
1598 return 'UTF-32';
1599
1600 case 'utf32be':
1601 return 'UTF-32BE';
1602
1603 case 'utf32le':
1604 return 'UTF-32LE';
1605
1606 case 'csventurainternational':
1607 case 'venturainternational':
1608 return 'Ventura-International';
1609
1610 case 'csventuramath':
1611 case 'venturamath':
1612 return 'Ventura-Math';
1613
1614 case 'csventuraus':
1615 case 'venturaus':
1616 return 'Ventura-US';
1617
1618 case 'csiso70videotexsupp1':
1619 case 'isoir70':
1620 case 'videotexsuppl':
1621 return 'videotex-suppl';
1622
1623 case 'csviqr':
1624 case 'viqr':
1625 return 'VIQR';
1626
1627 case 'csviscii':
1628 case 'viscii':
1629 return 'VISCII';
1630
1631 case 'csshiftjis':
1632 case 'cswindows31j':
1633 case 'mskanji':
1634 case 'shiftjis':
1635 case 'windows31j':
1636 return 'Windows-31J';
1637
1638 case 'iso885911':
1639 case 'tis620':
1640 return 'windows-874';
1641
1642 case 'cseuckr':
1643 case 'csksc56011987':
1644 case 'euckr':
1645 case 'isoir149':
1646 case 'korean':
1647 case 'ksc5601':
1648 case 'ksc56011987':
1649 case 'ksc56011989':
1650 case 'windows949':
1651 return 'windows-949';
1652
1653 case 'windows1250':
1654 return 'windows-1250';
1655
1656 case 'windows1251':
1657 return 'windows-1251';
1658
1659 case 'cp819':
1660 case 'csisolatin1':
1661 case 'ibm819':
1662 case 'iso88591':
1663 case 'iso885911987':
1664 case 'isoir100':
1665 case 'l1':
1666 case 'latin1':
1667 case 'windows1252':
1668 return 'windows-1252';
1669
1670 case 'windows1253':
1671 return 'windows-1253';
1672
1673 case 'csisolatin5':
1674 case 'iso88599':
1675 case 'iso885991989':
1676 case 'isoir148':
1677 case 'l5':
1678 case 'latin5':
1679 case 'windows1254':
1680 return 'windows-1254';
1681
1682 case 'windows1255':
1683 return 'windows-1255';
1684
1685 case 'windows1256':
1686 return 'windows-1256';
1687
1688 case 'windows1257':
1689 return 'windows-1257';
1690
1691 case 'windows1258':
1692 return 'windows-1258';
1693
1694 default:
1695 return $charset;
1696 }
1697 }
1698
1699 public static function get_curl_version()
1700 {
1701 if (is_array($curl = curl_version()))
1702 {
1703 $curl = $curl['version'];
1704 }
1705 elseif (substr($curl, 0, 5) === 'curl/')
1706 {
1707 $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
1708 }
1709 elseif (substr($curl, 0, 8) === 'libcurl/')
1710 {
1711 $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
1712 }
1713 else
1714 {
1715 $curl = 0;
1716 }
1717 return $curl;
1718 }
1719
1720 /**
1721 * Strip HTML comments
1722 *
1723 * @param string $data Data to strip comments from
1724 * @return string Comment stripped string
1725 */
1726 public static function strip_comments($data)
1727 {
1728 $output = '';
1729 while (($start = strpos($data, '<!--')) !== false)
1730 {
1731 $output .= substr($data, 0, $start);
1732 if (($end = strpos($data, '-->', $start)) !== false)
1733 {
1734 $data = substr_replace($data, '', 0, $end + 3);
1735 }
1736 else
1737 {
1738 $data = '';
1739 }
1740 }
1741 return $output . $data;
1742 }
1743
1744 public static function parse_date($dt)
1745 {
1746 $parser = SimplePie_Parse_Date::get();
1747 return $parser->parse($dt);
1748 }
1749
1750 /**
1751 * Decode HTML entities
1752 *
1753 * @deprecated Use DOMDocument instead
1754 * @param string $data Input data
1755 * @return string Output data
1756 */
1757 public static function entities_decode($data)
1758 {
1759 $decoder = new SimplePie_Decode_HTML_Entities($data);
1760 return $decoder->parse();
1761 }
1762
1763 /**
1764 * Remove RFC822 comments
1765 *
1766 * @param string $data Data to strip comments from
1767 * @return string Comment stripped string
1768 */
1769 public static function uncomment_rfc822($string)
1770 {
1771 $string = (string) $string;
1772 $position = 0;
1773 $length = strlen($string);
1774 $depth = 0;
1775
1776 $output = '';
1777
1778 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
1779 {
1780 $output .= substr($string, $position, $pos - $position);
1781 $position = $pos + 1;
1782 if ($string[$pos - 1] !== '\\')
1783 {
1784 $depth++;
1785 while ($depth && $position < $length)
1786 {
1787 $position += strcspn($string, '()', $position);
1788 if ($string[$position - 1] === '\\')
1789 {
1790 $position++;
1791 continue;
1792 }
1793 elseif (isset($string[$position]))
1794 {
1795 switch ($string[$position])
1796 {
1797 case '(':
1798 $depth++;
1799 break;
1800
1801 case ')':
1802 $depth--;
1803 break;
1804 }
1805 $position++;
1806 }
1807 else
1808 {
1809 break;
1810 }
1811 }
1812 }
1813 else
1814 {
1815 $output .= '(';
1816 }
1817 }
1818 $output .= substr($string, $position);
1819
1820 return $output;
1821 }
1822
1823 public static function parse_mime($mime)
1824 {
1825 if (($pos = strpos($mime, ';')) === false)
1826 {
1827 return trim($mime);
1828 }
1829 else
1830 {
1831 return trim(substr($mime, 0, $pos));
1832 }
1833 }
1834
1835 public static function atom_03_construct_type($attribs)
1836 {
1837 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
1838 {
1839 $mode = SIMPLEPIE_CONSTRUCT_BASE64;
1840 }
1841 else
1842 {
1843 $mode = SIMPLEPIE_CONSTRUCT_NONE;
1844 }
1845 if (isset($attribs['']['type']))
1846 {
1847 switch (strtolower(trim($attribs['']['type'])))
1848 {
1849 case 'text':
1850 case 'text/plain':
1851 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
1852
1853 case 'html':
1854 case 'text/html':
1855 return SIMPLEPIE_CONSTRUCT_HTML | $mode;
1856
1857 case 'xhtml':
1858 case 'application/xhtml+xml':
1859 return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
1860
1861 default:
1862 return SIMPLEPIE_CONSTRUCT_NONE | $mode;
1863 }
1864 }
1865 else
1866 {
1867 return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
1868 }
1869 }
1870
1871 public static function atom_10_construct_type($attribs)
1872 {
1873 if (isset($attribs['']['type']))
1874 {
1875 switch (strtolower(trim($attribs['']['type'])))
1876 {
1877 case 'text':
1878 return SIMPLEPIE_CONSTRUCT_TEXT;
1879
1880 case 'html':
1881 return SIMPLEPIE_CONSTRUCT_HTML;
1882
1883 case 'xhtml':
1884 return SIMPLEPIE_CONSTRUCT_XHTML;
1885
1886 default:
1887 return SIMPLEPIE_CONSTRUCT_NONE;
1888 }
1889 }
1890 return SIMPLEPIE_CONSTRUCT_TEXT;
1891 }
1892
1893 public static function atom_10_content_construct_type($attribs)
1894 {
1895 if (isset($attribs['']['type']))
1896 {
1897 $type = strtolower(trim($attribs['']['type']));
1898 switch ($type)
1899 {
1900 case 'text':
1901 return SIMPLEPIE_CONSTRUCT_TEXT;
1902
1903 case 'html':
1904 return SIMPLEPIE_CONSTRUCT_HTML;
1905
1906 case 'xhtml':
1907 return SIMPLEPIE_CONSTRUCT_XHTML;
1908 }
1909 if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
1910 {
1911 return SIMPLEPIE_CONSTRUCT_NONE;
1912 }
1913 else
1914 {
1915 return SIMPLEPIE_CONSTRUCT_BASE64;
1916 }
1917 }
1918 else
1919 {
1920 return SIMPLEPIE_CONSTRUCT_TEXT;
1921 }
1922 }
1923
1924 public static function is_isegment_nz_nc($string)
1925 {
1926 return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
1927 }
1928
1929 public static function space_seperated_tokens($string)
1930 {
1931 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
1932 $string_length = strlen($string);
1933
1934 $position = strspn($string, $space_characters);
1935 $tokens = array();
1936
1937 while ($position < $string_length)
1938 {
1939 $len = strcspn($string, $space_characters, $position);
1940 $tokens[] = substr($string, $position, $len);
1941 $position += $len;
1942 $position += strspn($string, $space_characters, $position);
1943 }
1944
1945 return $tokens;
1946 }
1947
1948 /**
1949 * Converts a unicode codepoint to a UTF-8 character
1950 *
1951 * @static
1952 * @param int $codepoint Unicode codepoint
1953 * @return string UTF-8 character
1954 */
1955 public static function codepoint_to_utf8($codepoint)
1956 {
1957 $codepoint = (int) $codepoint;
1958 if ($codepoint < 0)
1959 {
1960 return false;
1961 }
1962 else if ($codepoint <= 0x7f)
1963 {
1964 return chr($codepoint);
1965 }
1966 else if ($codepoint <= 0x7ff)
1967 {
1968 return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
1969 }
1970 else if ($codepoint <= 0xffff)
1971 {
1972 return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
1973 }
1974 else if ($codepoint <= 0x10ffff)
1975 {
1976 return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
1977 }
1978 else
1979 {
1980 // U+FFFD REPLACEMENT CHARACTER
1981 return "\xEF\xBF\xBD";
1982 }
1983 }
1984
1985 /**
1986 * Similar to parse_str()
1987 *
1988 * Returns an associative array of name/value pairs, where the value is an
1989 * array of values that have used the same name
1990 *
1991 * @static
1992 * @param string $str The input string.
1993 * @return array
1994 */
1995 public static function parse_str($str)
1996 {
1997 $return = array();
1998 $str = explode('&', $str);
1999
2000 foreach ($str as $section)
2001 {
2002 if (strpos($section, '=') !== false)
2003 {
2004 list($name, $value) = explode('=', $section, 2);
2005 $return[urldecode($name)][] = urldecode($value);
2006 }
2007 else
2008 {
2009 $return[urldecode($section)][] = null;
2010 }
2011 }
2012
2013 return $return;
2014 }
2015
2016 /**
2017 * Detect XML encoding, as per XML 1.0 Appendix F.1
2018 *
2019 * @todo Add support for EBCDIC
2020 * @param string $data XML data
2021 * @param SimplePie_Registry $registry Class registry
2022 * @return array Possible encodings
2023 */
2024 public static function xml_encoding($data, $registry)
2025 {
2026 // UTF-32 Big Endian BOM
2027 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
2028 {
2029 $encoding[] = 'UTF-32BE';
2030 }
2031 // UTF-32 Little Endian BOM
2032 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
2033 {
2034 $encoding[] = 'UTF-32LE';
2035 }
2036 // UTF-16 Big Endian BOM
2037 elseif (substr($data, 0, 2) === "\xFE\xFF")
2038 {
2039 $encoding[] = 'UTF-16BE';
2040 }
2041 // UTF-16 Little Endian BOM
2042 elseif (substr($data, 0, 2) === "\xFF\xFE")
2043 {
2044 $encoding[] = 'UTF-16LE';
2045 }
2046 // UTF-8 BOM
2047 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
2048 {
2049 $encoding[] = 'UTF-8';
2050 }
2051 // UTF-32 Big Endian Without BOM
2052 elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
2053 {
2054 if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
2055 {
2056 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
2057 if ($parser->parse())
2058 {
2059 $encoding[] = $parser->encoding;
2060 }
2061 }
2062 $encoding[] = 'UTF-32BE';
2063 }
2064 // UTF-32 Little Endian Without BOM
2065 elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
2066 {
2067 if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
2068 {
2069 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
2070 if ($parser->parse())
2071 {
2072 $encoding[] = $parser->encoding;
2073 }
2074 }
2075 $encoding[] = 'UTF-32LE';
2076 }
2077 // UTF-16 Big Endian Without BOM
2078 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
2079 {
2080 if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
2081 {
2082 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
2083 if ($parser->parse())
2084 {
2085 $encoding[] = $parser->encoding;
2086 }
2087 }
2088 $encoding[] = 'UTF-16BE';
2089 }
2090 // UTF-16 Little Endian Without BOM
2091 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
2092 {
2093 if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
2094 {
2095 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
2096 if ($parser->parse())
2097 {
2098 $encoding[] = $parser->encoding;
2099 }
2100 }
2101 $encoding[] = 'UTF-16LE';
2102 }
2103 // US-ASCII (or superset)
2104 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
2105 {
2106 if ($pos = strpos($data, "\x3F\x3E"))
2107 {
2108 $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
2109 if ($parser->parse())
2110 {
2111 $encoding[] = $parser->encoding;
2112 }
2113 }
2114 $encoding[] = 'UTF-8';
2115 }
2116 // Fallback to UTF-8
2117 else
2118 {
2119 $encoding[] = 'UTF-8';
2120 }
2121 return $encoding;
2122 }
2123
2124 public static function output_javascript()
2125 {
2126 if (function_exists('ob_gzhandler'))
2127 {
2128 ob_start('ob_gzhandler');
2129 }
2130 header('Content-type: text/javascript; charset: UTF-8');
2131 header('Cache-Control: must-revalidate');
2132 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
2133 ?>
2134function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
2135 if (placeholder != '') {
2136 document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
2137 }
2138 else {
2139 document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
2140 }
2141}
2142
2143function embed_flash(bgcolor, width, height, link, loop, type) {
2144 document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
2145}
2146
2147function embed_flv(width, height, link, placeholder, loop, player) {
2148 document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
2149}
2150
2151function embed_wmedia(width, height, link) {
2152 document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
2153}
2154 <?php
2155 }
2156
2157 /**
2158 * Get the SimplePie build timestamp
2159 *
2160 * Uses the git index if it exists, otherwise uses the modification time
2161 * of the newest file.
2162 */
2163 public static function get_build()
2164 {
2165 $root = dirname(dirname(__FILE__));
2166 if (file_exists($root . '/.git/index'))
2167 {
2168 return filemtime($root . '/.git/index');
2169 }
2170 elseif (file_exists($root . '/SimplePie'))
2171 {
2172 $time = 0;
2173 foreach (glob($root . '/SimplePie/*.php') as $file)
2174 {
2175 if (($mtime = filemtime($file)) > $time)
2176 {
2177 $time = $mtime;
2178 }
2179 }
2180 return $time;
2181 }
2182 elseif (file_exists(dirname(__FILE__) . '/Core.php'))
2183 {
2184 return filemtime(dirname(__FILE__) . '/Core.php');
2185 }
2186 else
2187 {
2188 return filemtime(__FILE__);
2189 }
2190 }
2191
2192 /**
2193 * Format debugging information
2194 */
2195 public static function debug(&$sp)
2196 {
2197 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
2198 $info .= 'PHP ' . PHP_VERSION . "\n";
2199 if ($sp->error() !== null)
2200 {
2201 $info .= 'Error occurred: ' . $sp->error() . "\n";
2202 }
2203 else
2204 {
2205 $info .= "No error found.\n";
2206 }
2207 $info .= "Extensions:\n";
2208 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
2209 foreach ($extensions as $ext)
2210 {
2211 if (extension_loaded($ext))
2212 {
2213 $info .= " $ext loaded\n";
2214 switch ($ext)
2215 {
2216 case 'pcre':
2217 $info .= ' Version ' . PCRE_VERSION . "\n";
2218 break;
2219 case 'curl':
2220 $version = curl_version();
2221 $info .= ' Version ' . $version['version'] . "\n";
2222 break;
2223 case 'mbstring':
2224 $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
2225 break;
2226 case 'iconv':
2227 $info .= ' Version ' . ICONV_VERSION . "\n";
2228 break;
2229 case 'xml':
2230 $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
2231 break;
2232 }
2233 }
2234 else
2235 {
2236 $info .= " $ext not loaded\n";
2237 }
2238 }
2239 return $info;
2240 }
2241
2242 public static function silence_errors($num, $str)
2243 {
2244 // No-op
2245 }
2246}
2247
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Net/IPv6.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Net/IPv6.php
new file mode 100644
index 00000000..da80d8ac
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Net/IPv6.php
@@ -0,0 +1,276 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Class to validate and to work with IPv6 addresses.
48 *
49 * @package SimplePie
50 * @subpackage HTTP
51 * @copyright 2003-2005 The PHP Group
52 * @license http://www.opensource.org/licenses/bsd-license.php
53 * @link http://pear.php.net/package/Net_IPv6
54 * @author Alexander Merz <alexander.merz@web.de>
55 * @author elfrink at introweb dot nl
56 * @author Josh Peck <jmp at joshpeck dot org>
57 * @author Geoffrey Sneddon <geoffers@gmail.com>
58 */
59class SimplePie_Net_IPv6
60{
61 /**
62 * Uncompresses an IPv6 address
63 *
64 * RFC 4291 allows you to compress concecutive zero pieces in an address to
65 * '::'. This method expects a valid IPv6 address and expands the '::' to
66 * the required number of zero pieces.
67 *
68 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
69 * ::1 -> 0:0:0:0:0:0:0:1
70 *
71 * @author Alexander Merz <alexander.merz@web.de>
72 * @author elfrink at introweb dot nl
73 * @author Josh Peck <jmp at joshpeck dot org>
74 * @copyright 2003-2005 The PHP Group
75 * @license http://www.opensource.org/licenses/bsd-license.php
76 * @param string $ip An IPv6 address
77 * @return string The uncompressed IPv6 address
78 */
79 public static function uncompress($ip)
80 {
81 $c1 = -1;
82 $c2 = -1;
83 if (substr_count($ip, '::') === 1)
84 {
85 list($ip1, $ip2) = explode('::', $ip);
86 if ($ip1 === '')
87 {
88 $c1 = -1;
89 }
90 else
91 {
92 $c1 = substr_count($ip1, ':');
93 }
94 if ($ip2 === '')
95 {
96 $c2 = -1;
97 }
98 else
99 {
100 $c2 = substr_count($ip2, ':');
101 }
102 if (strpos($ip2, '.') !== false)
103 {
104 $c2++;
105 }
106 // ::
107 if ($c1 === -1 && $c2 === -1)
108 {
109 $ip = '0:0:0:0:0:0:0:0';
110 }
111 // ::xxx
112 else if ($c1 === -1)
113 {
114 $fill = str_repeat('0:', 7 - $c2);
115 $ip = str_replace('::', $fill, $ip);
116 }
117 // xxx::
118 else if ($c2 === -1)
119 {
120 $fill = str_repeat(':0', 7 - $c1);
121 $ip = str_replace('::', $fill, $ip);
122 }
123 // xxx::xxx
124 else
125 {
126 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
127 $ip = str_replace('::', $fill, $ip);
128 }
129 }
130 return $ip;
131 }
132
133 /**
134 * Compresses an IPv6 address
135 *
136 * RFC 4291 allows you to compress concecutive zero pieces in an address to
137 * '::'. This method expects a valid IPv6 address and compresses consecutive
138 * zero pieces to '::'.
139 *
140 * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
141 * 0:0:0:0:0:0:0:1 -> ::1
142 *
143 * @see uncompress()
144 * @param string $ip An IPv6 address
145 * @return string The compressed IPv6 address
146 */
147 public static function compress($ip)
148 {
149 // Prepare the IP to be compressed
150 $ip = self::uncompress($ip);
151 $ip_parts = self::split_v6_v4($ip);
152
153 // Replace all leading zeros
154 $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
155
156 // Find bunches of zeros
157 if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
158 {
159 $max = 0;
160 $pos = null;
161 foreach ($matches[0] as $match)
162 {
163 if (strlen($match[0]) > $max)
164 {
165 $max = strlen($match[0]);
166 $pos = $match[1];
167 }
168 }
169
170 $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
171 }
172
173 if ($ip_parts[1] !== '')
174 {
175 return implode(':', $ip_parts);
176 }
177 else
178 {
179 return $ip_parts[0];
180 }
181 }
182
183 /**
184 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
185 *
186 * RFC 4291 allows you to represent the last two parts of an IPv6 address
187 * using the standard IPv4 representation
188 *
189 * Example: 0:0:0:0:0:0:13.1.68.3
190 * 0:0:0:0:0:FFFF:129.144.52.38
191 *
192 * @param string $ip An IPv6 address
193 * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
194 */
195 private static function split_v6_v4($ip)
196 {
197 if (strpos($ip, '.') !== false)
198 {
199 $pos = strrpos($ip, ':');
200 $ipv6_part = substr($ip, 0, $pos);
201 $ipv4_part = substr($ip, $pos + 1);
202 return array($ipv6_part, $ipv4_part);
203 }
204 else
205 {
206 return array($ip, '');
207 }
208 }
209
210 /**
211 * Checks an IPv6 address
212 *
213 * Checks if the given IP is a valid IPv6 address
214 *
215 * @param string $ip An IPv6 address
216 * @return bool true if $ip is a valid IPv6 address
217 */
218 public static function check_ipv6($ip)
219 {
220 $ip = self::uncompress($ip);
221 list($ipv6, $ipv4) = self::split_v6_v4($ip);
222 $ipv6 = explode(':', $ipv6);
223 $ipv4 = explode('.', $ipv4);
224 if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
225 {
226 foreach ($ipv6 as $ipv6_part)
227 {
228 // The section can't be empty
229 if ($ipv6_part === '')
230 return false;
231
232 // Nor can it be over four characters
233 if (strlen($ipv6_part) > 4)
234 return false;
235
236 // Remove leading zeros (this is safe because of the above)
237 $ipv6_part = ltrim($ipv6_part, '0');
238 if ($ipv6_part === '')
239 $ipv6_part = '0';
240
241 // Check the value is valid
242 $value = hexdec($ipv6_part);
243 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
244 return false;
245 }
246 if (count($ipv4) === 4)
247 {
248 foreach ($ipv4 as $ipv4_part)
249 {
250 $value = (int) $ipv4_part;
251 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
252 return false;
253 }
254 }
255 return true;
256 }
257 else
258 {
259 return false;
260 }
261 }
262
263 /**
264 * Checks if the given IP is a valid IPv6 address
265 *
266 * @codeCoverageIgnore
267 * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
268 * @see check_ipv6
269 * @param string $ip An IPv6 address
270 * @return bool true if $ip is a valid IPv6 address
271 */
272 public static function checkIPv6($ip)
273 {
274 return self::check_ipv6($ip);
275 }
276}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Parse/Date.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Parse/Date.php
new file mode 100644
index 00000000..d51f500d
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Parse/Date.php
@@ -0,0 +1,983 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Date Parser
48 *
49 * @package SimplePie
50 * @subpackage Parsing
51 */
52class SimplePie_Parse_Date
53{
54 /**
55 * Input data
56 *
57 * @access protected
58 * @var string
59 */
60 var $date;
61
62 /**
63 * List of days, calendar day name => ordinal day number in the week
64 *
65 * @access protected
66 * @var array
67 */
68 var $day = array(
69 // English
70 'mon' => 1,
71 'monday' => 1,
72 'tue' => 2,
73 'tuesday' => 2,
74 'wed' => 3,
75 'wednesday' => 3,
76 'thu' => 4,
77 'thursday' => 4,
78 'fri' => 5,
79 'friday' => 5,
80 'sat' => 6,
81 'saturday' => 6,
82 'sun' => 7,
83 'sunday' => 7,
84 // Dutch
85 'maandag' => 1,
86 'dinsdag' => 2,
87 'woensdag' => 3,
88 'donderdag' => 4,
89 'vrijdag' => 5,
90 'zaterdag' => 6,
91 'zondag' => 7,
92 // French
93 'lundi' => 1,
94 'mardi' => 2,
95 'mercredi' => 3,
96 'jeudi' => 4,
97 'vendredi' => 5,
98 'samedi' => 6,
99 'dimanche' => 7,
100 // German
101 'montag' => 1,
102 'dienstag' => 2,
103 'mittwoch' => 3,
104 'donnerstag' => 4,
105 'freitag' => 5,
106 'samstag' => 6,
107 'sonnabend' => 6,
108 'sonntag' => 7,
109 // Italian
110 'lunedì' => 1,
111 'martedì' => 2,
112 'mercoledì' => 3,
113 'giovedì' => 4,
114 'venerdì' => 5,
115 'sabato' => 6,
116 'domenica' => 7,
117 // Spanish
118 'lunes' => 1,
119 'martes' => 2,
120 'miércoles' => 3,
121 'jueves' => 4,
122 'viernes' => 5,
123 'sábado' => 6,
124 'domingo' => 7,
125 // Finnish
126 'maanantai' => 1,
127 'tiistai' => 2,
128 'keskiviikko' => 3,
129 'torstai' => 4,
130 'perjantai' => 5,
131 'lauantai' => 6,
132 'sunnuntai' => 7,
133 // Hungarian
134 'hétfő' => 1,
135 'kedd' => 2,
136 'szerda' => 3,
137 'csütörtok' => 4,
138 'péntek' => 5,
139 'szombat' => 6,
140 'vasárnap' => 7,
141 // Greek
142 'Δευ' => 1,
143 'Τρι' => 2,
144 'Τετ' => 3,
145 'Πεμ' => 4,
146 'Παρ' => 5,
147 'Σαβ' => 6,
148 'Κυρ' => 7,
149 );
150
151 /**
152 * List of months, calendar month name => calendar month number
153 *
154 * @access protected
155 * @var array
156 */
157 var $month = array(
158 // English
159 'jan' => 1,
160 'january' => 1,
161 'feb' => 2,
162 'february' => 2,
163 'mar' => 3,
164 'march' => 3,
165 'apr' => 4,
166 'april' => 4,
167 'may' => 5,
168 // No long form of May
169 'jun' => 6,
170 'june' => 6,
171 'jul' => 7,
172 'july' => 7,
173 'aug' => 8,
174 'august' => 8,
175 'sep' => 9,
176 'september' => 8,
177 'oct' => 10,
178 'october' => 10,
179 'nov' => 11,
180 'november' => 11,
181 'dec' => 12,
182 'december' => 12,
183 // Dutch
184 'januari' => 1,
185 'februari' => 2,
186 'maart' => 3,
187 'april' => 4,
188 'mei' => 5,
189 'juni' => 6,
190 'juli' => 7,
191 'augustus' => 8,
192 'september' => 9,
193 'oktober' => 10,
194 'november' => 11,
195 'december' => 12,
196 // French
197 'janvier' => 1,
198 'février' => 2,
199 'mars' => 3,
200 'avril' => 4,
201 'mai' => 5,
202 'juin' => 6,
203 'juillet' => 7,
204 'août' => 8,
205 'septembre' => 9,
206 'octobre' => 10,
207 'novembre' => 11,
208 'décembre' => 12,
209 // German
210 'januar' => 1,
211 'februar' => 2,
212 'märz' => 3,
213 'april' => 4,
214 'mai' => 5,
215 'juni' => 6,
216 'juli' => 7,
217 'august' => 8,
218 'september' => 9,
219 'oktober' => 10,
220 'november' => 11,
221 'dezember' => 12,
222 // Italian
223 'gennaio' => 1,
224 'febbraio' => 2,
225 'marzo' => 3,
226 'aprile' => 4,
227 'maggio' => 5,
228 'giugno' => 6,
229 'luglio' => 7,
230 'agosto' => 8,
231 'settembre' => 9,
232 'ottobre' => 10,
233 'novembre' => 11,
234 'dicembre' => 12,
235 // Spanish
236 'enero' => 1,
237 'febrero' => 2,
238 'marzo' => 3,
239 'abril' => 4,
240 'mayo' => 5,
241 'junio' => 6,
242 'julio' => 7,
243 'agosto' => 8,
244 'septiembre' => 9,
245 'setiembre' => 9,
246 'octubre' => 10,
247 'noviembre' => 11,
248 'diciembre' => 12,
249 // Finnish
250 'tammikuu' => 1,
251 'helmikuu' => 2,
252 'maaliskuu' => 3,
253 'huhtikuu' => 4,
254 'toukokuu' => 5,
255 'kesäkuu' => 6,
256 'heinäkuu' => 7,
257 'elokuu' => 8,
258 'suuskuu' => 9,
259 'lokakuu' => 10,
260 'marras' => 11,
261 'joulukuu' => 12,
262 // Hungarian
263 'január' => 1,
264 'február' => 2,
265 'március' => 3,
266 'április' => 4,
267 'május' => 5,
268 'június' => 6,
269 'július' => 7,
270 'augusztus' => 8,
271 'szeptember' => 9,
272 'október' => 10,
273 'november' => 11,
274 'december' => 12,
275 // Greek
276 'Ιαν' => 1,
277 'Φεβ' => 2,
278 'Μάώ' => 3,
279 'Μαώ' => 3,
280 'Απρ' => 4,
281 'Μάι' => 5,
282 'Μαϊ' => 5,
283 'Μαι' => 5,
284 'Ιούν' => 6,
285 'Ιον' => 6,
286 'Ιούλ' => 7,
287 'Ιολ' => 7,
288 'Αύγ' => 8,
289 'Αυγ' => 8,
290 'Σεπ' => 9,
291 'Οκτ' => 10,
292 'Νοέ' => 11,
293 'Δεκ' => 12,
294 );
295
296 /**
297 * List of timezones, abbreviation => offset from UTC
298 *
299 * @access protected
300 * @var array
301 */
302 var $timezone = array(
303 'ACDT' => 37800,
304 'ACIT' => 28800,
305 'ACST' => 34200,
306 'ACT' => -18000,
307 'ACWDT' => 35100,
308 'ACWST' => 31500,
309 'AEDT' => 39600,
310 'AEST' => 36000,
311 'AFT' => 16200,
312 'AKDT' => -28800,
313 'AKST' => -32400,
314 'AMDT' => 18000,
315 'AMT' => -14400,
316 'ANAST' => 46800,
317 'ANAT' => 43200,
318 'ART' => -10800,
319 'AZOST' => -3600,
320 'AZST' => 18000,
321 'AZT' => 14400,
322 'BIOT' => 21600,
323 'BIT' => -43200,
324 'BOT' => -14400,
325 'BRST' => -7200,
326 'BRT' => -10800,
327 'BST' => 3600,
328 'BTT' => 21600,
329 'CAST' => 18000,
330 'CAT' => 7200,
331 'CCT' => 23400,
332 'CDT' => -18000,
333 'CEDT' => 7200,
334 'CET' => 3600,
335 'CGST' => -7200,
336 'CGT' => -10800,
337 'CHADT' => 49500,
338 'CHAST' => 45900,
339 'CIST' => -28800,
340 'CKT' => -36000,
341 'CLDT' => -10800,
342 'CLST' => -14400,
343 'COT' => -18000,
344 'CST' => -21600,
345 'CVT' => -3600,
346 'CXT' => 25200,
347 'DAVT' => 25200,
348 'DTAT' => 36000,
349 'EADT' => -18000,
350 'EAST' => -21600,
351 'EAT' => 10800,
352 'ECT' => -18000,
353 'EDT' => -14400,
354 'EEST' => 10800,
355 'EET' => 7200,
356 'EGT' => -3600,
357 'EKST' => 21600,
358 'EST' => -18000,
359 'FJT' => 43200,
360 'FKDT' => -10800,
361 'FKST' => -14400,
362 'FNT' => -7200,
363 'GALT' => -21600,
364 'GEDT' => 14400,
365 'GEST' => 10800,
366 'GFT' => -10800,
367 'GILT' => 43200,
368 'GIT' => -32400,
369 'GST' => 14400,
370 'GST' => -7200,
371 'GYT' => -14400,
372 'HAA' => -10800,
373 'HAC' => -18000,
374 'HADT' => -32400,
375 'HAE' => -14400,
376 'HAP' => -25200,
377 'HAR' => -21600,
378 'HAST' => -36000,
379 'HAT' => -9000,
380 'HAY' => -28800,
381 'HKST' => 28800,
382 'HMT' => 18000,
383 'HNA' => -14400,
384 'HNC' => -21600,
385 'HNE' => -18000,
386 'HNP' => -28800,
387 'HNR' => -25200,
388 'HNT' => -12600,
389 'HNY' => -32400,
390 'IRDT' => 16200,
391 'IRKST' => 32400,
392 'IRKT' => 28800,
393 'IRST' => 12600,
394 'JFDT' => -10800,
395 'JFST' => -14400,
396 'JST' => 32400,
397 'KGST' => 21600,
398 'KGT' => 18000,
399 'KOST' => 39600,
400 'KOVST' => 28800,
401 'KOVT' => 25200,
402 'KRAST' => 28800,
403 'KRAT' => 25200,
404 'KST' => 32400,
405 'LHDT' => 39600,
406 'LHST' => 37800,
407 'LINT' => 50400,
408 'LKT' => 21600,
409 'MAGST' => 43200,
410 'MAGT' => 39600,
411 'MAWT' => 21600,
412 'MDT' => -21600,
413 'MESZ' => 7200,
414 'MEZ' => 3600,
415 'MHT' => 43200,
416 'MIT' => -34200,
417 'MNST' => 32400,
418 'MSDT' => 14400,
419 'MSST' => 10800,
420 'MST' => -25200,
421 'MUT' => 14400,
422 'MVT' => 18000,
423 'MYT' => 28800,
424 'NCT' => 39600,
425 'NDT' => -9000,
426 'NFT' => 41400,
427 'NMIT' => 36000,
428 'NOVST' => 25200,
429 'NOVT' => 21600,
430 'NPT' => 20700,
431 'NRT' => 43200,
432 'NST' => -12600,
433 'NUT' => -39600,
434 'NZDT' => 46800,
435 'NZST' => 43200,
436 'OMSST' => 25200,
437 'OMST' => 21600,
438 'PDT' => -25200,
439 'PET' => -18000,
440 'PETST' => 46800,
441 'PETT' => 43200,
442 'PGT' => 36000,
443 'PHOT' => 46800,
444 'PHT' => 28800,
445 'PKT' => 18000,
446 'PMDT' => -7200,
447 'PMST' => -10800,
448 'PONT' => 39600,
449 'PST' => -28800,
450 'PWT' => 32400,
451 'PYST' => -10800,
452 'PYT' => -14400,
453 'RET' => 14400,
454 'ROTT' => -10800,
455 'SAMST' => 18000,
456 'SAMT' => 14400,
457 'SAST' => 7200,
458 'SBT' => 39600,
459 'SCDT' => 46800,
460 'SCST' => 43200,
461 'SCT' => 14400,
462 'SEST' => 3600,
463 'SGT' => 28800,
464 'SIT' => 28800,
465 'SRT' => -10800,
466 'SST' => -39600,
467 'SYST' => 10800,
468 'SYT' => 7200,
469 'TFT' => 18000,
470 'THAT' => -36000,
471 'TJT' => 18000,
472 'TKT' => -36000,
473 'TMT' => 18000,
474 'TOT' => 46800,
475 'TPT' => 32400,
476 'TRUT' => 36000,
477 'TVT' => 43200,
478 'TWT' => 28800,
479 'UYST' => -7200,
480 'UYT' => -10800,
481 'UZT' => 18000,
482 'VET' => -14400,
483 'VLAST' => 39600,
484 'VLAT' => 36000,
485 'VOST' => 21600,
486 'VUT' => 39600,
487 'WAST' => 7200,
488 'WAT' => 3600,
489 'WDT' => 32400,
490 'WEST' => 3600,
491 'WFT' => 43200,
492 'WIB' => 25200,
493 'WIT' => 32400,
494 'WITA' => 28800,
495 'WKST' => 18000,
496 'WST' => 28800,
497 'YAKST' => 36000,
498 'YAKT' => 32400,
499 'YAPT' => 36000,
500 'YEKST' => 21600,
501 'YEKT' => 18000,
502 );
503
504 /**
505 * Cached PCRE for SimplePie_Parse_Date::$day
506 *
507 * @access protected
508 * @var string
509 */
510 var $day_pcre;
511
512 /**
513 * Cached PCRE for SimplePie_Parse_Date::$month
514 *
515 * @access protected
516 * @var string
517 */
518 var $month_pcre;
519
520 /**
521 * Array of user-added callback methods
522 *
523 * @access private
524 * @var array
525 */
526 var $built_in = array();
527
528 /**
529 * Array of user-added callback methods
530 *
531 * @access private
532 * @var array
533 */
534 var $user = array();
535
536 /**
537 * Create new SimplePie_Parse_Date object, and set self::day_pcre,
538 * self::month_pcre, and self::built_in
539 *
540 * @access private
541 */
542 public function __construct()
543 {
544 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
545 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
546
547 static $cache;
548 if (!isset($cache[get_class($this)]))
549 {
550 $all_methods = get_class_methods($this);
551
552 foreach ($all_methods as $method)
553 {
554 if (strtolower(substr($method, 0, 5)) === 'date_')
555 {
556 $cache[get_class($this)][] = $method;
557 }
558 }
559 }
560
561 foreach ($cache[get_class($this)] as $method)
562 {
563 $this->built_in[] = $method;
564 }
565 }
566
567 /**
568 * Get the object
569 *
570 * @access public
571 */
572 public static function get()
573 {
574 static $object;
575 if (!$object)
576 {
577 $object = new SimplePie_Parse_Date;
578 }
579 return $object;
580 }
581
582 /**
583 * Parse a date
584 *
585 * @final
586 * @access public
587 * @param string $date Date to parse
588 * @return int Timestamp corresponding to date string, or false on failure
589 */
590 public function parse($date)
591 {
592 foreach ($this->user as $method)
593 {
594 if (($returned = call_user_func($method, $date)) !== false)
595 {
596 return $returned;
597 }
598 }
599
600 foreach ($this->built_in as $method)
601 {
602 if (($returned = call_user_func(array($this, $method), $date)) !== false)
603 {
604 return $returned;
605 }
606 }
607
608 return false;
609 }
610
611 /**
612 * Add a callback method to parse a date
613 *
614 * @final
615 * @access public
616 * @param callback $callback
617 */
618 public function add_callback($callback)
619 {
620 if (is_callable($callback))
621 {
622 $this->user[] = $callback;
623 }
624 else
625 {
626 trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
627 }
628 }
629
630 /**
631 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
632 * well as allowing any of upper or lower case "T", horizontal tabs, or
633 * spaces to be used as the time seperator (including more than one))
634 *
635 * @access protected
636 * @return int Timestamp
637 */
638 public function date_w3cdtf($date)
639 {
640 static $pcre;
641 if (!$pcre)
642 {
643 $year = '([0-9]{4})';
644 $month = $day = $hour = $minute = $second = '([0-9]{2})';
645 $decimal = '([0-9]*)';
646 $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
647 $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
648 }
649 if (preg_match($pcre, $date, $match))
650 {
651 /*
652 Capturing subpatterns:
653 1: Year
654 2: Month
655 3: Day
656 4: Hour
657 5: Minute
658 6: Second
659 7: Decimal fraction of a second
660 8: Zulu
661 9: Timezone ±
662 10: Timezone hours
663 11: Timezone minutes
664 */
665
666 // Fill in empty matches
667 for ($i = count($match); $i <= 3; $i++)
668 {
669 $match[$i] = '1';
670 }
671
672 for ($i = count($match); $i <= 7; $i++)
673 {
674 $match[$i] = '0';
675 }
676
677 // Numeric timezone
678 if (isset($match[9]) && $match[9] !== '')
679 {
680 $timezone = $match[10] * 3600;
681 $timezone += $match[11] * 60;
682 if ($match[9] === '-')
683 {
684 $timezone = 0 - $timezone;
685 }
686 }
687 else
688 {
689 $timezone = 0;
690 }
691
692 // Convert the number of seconds to an integer, taking decimals into account
693 $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
694
695 return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
696 }
697 else
698 {
699 return false;
700 }
701 }
702
703 /**
704 * Remove RFC822 comments
705 *
706 * @access protected
707 * @param string $data Data to strip comments from
708 * @return string Comment stripped string
709 */
710 public function remove_rfc2822_comments($string)
711 {
712 $string = (string) $string;
713 $position = 0;
714 $length = strlen($string);
715 $depth = 0;
716
717 $output = '';
718
719 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
720 {
721 $output .= substr($string, $position, $pos - $position);
722 $position = $pos + 1;
723 if ($string[$pos - 1] !== '\\')
724 {
725 $depth++;
726 while ($depth && $position < $length)
727 {
728 $position += strcspn($string, '()', $position);
729 if ($string[$position - 1] === '\\')
730 {
731 $position++;
732 continue;
733 }
734 elseif (isset($string[$position]))
735 {
736 switch ($string[$position])
737 {
738 case '(':
739 $depth++;
740 break;
741
742 case ')':
743 $depth--;
744 break;
745 }
746 $position++;
747 }
748 else
749 {
750 break;
751 }
752 }
753 }
754 else
755 {
756 $output .= '(';
757 }
758 }
759 $output .= substr($string, $position);
760
761 return $output;
762 }
763
764 /**
765 * Parse RFC2822's date format
766 *
767 * @access protected
768 * @return int Timestamp
769 */
770 public function date_rfc2822($date)
771 {
772 static $pcre;
773 if (!$pcre)
774 {
775 $wsp = '[\x09\x20]';
776 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
777 $optional_fws = $fws . '?';
778 $day_name = $this->day_pcre;
779 $month = $this->month_pcre;
780 $day = '([0-9]{1,2})';
781 $hour = $minute = $second = '([0-9]{2})';
782 $year = '([0-9]{2,4})';
783 $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
784 $character_zone = '([A-Z]{1,5})';
785 $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
786 $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
787 }
788 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
789 {
790 /*
791 Capturing subpatterns:
792 1: Day name
793 2: Day
794 3: Month
795 4: Year
796 5: Hour
797 6: Minute
798 7: Second
799 8: Timezone ±
800 9: Timezone hours
801 10: Timezone minutes
802 11: Alphabetic timezone
803 */
804
805 // Find the month number
806 $month = $this->month[strtolower($match[3])];
807
808 // Numeric timezone
809 if ($match[8] !== '')
810 {
811 $timezone = $match[9] * 3600;
812 $timezone += $match[10] * 60;
813 if ($match[8] === '-')
814 {
815 $timezone = 0 - $timezone;
816 }
817 }
818 // Character timezone
819 elseif (isset($this->timezone[strtoupper($match[11])]))
820 {
821 $timezone = $this->timezone[strtoupper($match[11])];
822 }
823 // Assume everything else to be -0000
824 else
825 {
826 $timezone = 0;
827 }
828
829 // Deal with 2/3 digit years
830 if ($match[4] < 50)
831 {
832 $match[4] += 2000;
833 }
834 elseif ($match[4] < 1000)
835 {
836 $match[4] += 1900;
837 }
838
839 // Second is optional, if it is empty set it to zero
840 if ($match[7] !== '')
841 {
842 $second = $match[7];
843 }
844 else
845 {
846 $second = 0;
847 }
848
849 return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
850 }
851 else
852 {
853 return false;
854 }
855 }
856
857 /**
858 * Parse RFC850's date format
859 *
860 * @access protected
861 * @return int Timestamp
862 */
863 public function date_rfc850($date)
864 {
865 static $pcre;
866 if (!$pcre)
867 {
868 $space = '[\x09\x20]+';
869 $day_name = $this->day_pcre;
870 $month = $this->month_pcre;
871 $day = '([0-9]{1,2})';
872 $year = $hour = $minute = $second = '([0-9]{2})';
873 $zone = '([A-Z]{1,5})';
874 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
875 }
876 if (preg_match($pcre, $date, $match))
877 {
878 /*
879 Capturing subpatterns:
880 1: Day name
881 2: Day
882 3: Month
883 4: Year
884 5: Hour
885 6: Minute
886 7: Second
887 8: Timezone
888 */
889
890 // Month
891 $month = $this->month[strtolower($match[3])];
892
893 // Character timezone
894 if (isset($this->timezone[strtoupper($match[8])]))
895 {
896 $timezone = $this->timezone[strtoupper($match[8])];
897 }
898 // Assume everything else to be -0000
899 else
900 {
901 $timezone = 0;
902 }
903
904 // Deal with 2 digit year
905 if ($match[4] < 50)
906 {
907 $match[4] += 2000;
908 }
909 else
910 {
911 $match[4] += 1900;
912 }
913
914 return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
915 }
916 else
917 {
918 return false;
919 }
920 }
921
922 /**
923 * Parse C99's asctime()'s date format
924 *
925 * @access protected
926 * @return int Timestamp
927 */
928 public function date_asctime($date)
929 {
930 static $pcre;
931 if (!$pcre)
932 {
933 $space = '[\x09\x20]+';
934 $wday_name = $this->day_pcre;
935 $mon_name = $this->month_pcre;
936 $day = '([0-9]{1,2})';
937 $hour = $sec = $min = '([0-9]{2})';
938 $year = '([0-9]{4})';
939 $terminator = '\x0A?\x00?';
940 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
941 }
942 if (preg_match($pcre, $date, $match))
943 {
944 /*
945 Capturing subpatterns:
946 1: Day name
947 2: Month
948 3: Day
949 4: Hour
950 5: Minute
951 6: Second
952 7: Year
953 */
954
955 $month = $this->month[strtolower($match[2])];
956 return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
957 }
958 else
959 {
960 return false;
961 }
962 }
963
964 /**
965 * Parse dates using strtotime()
966 *
967 * @access protected
968 * @return int Timestamp
969 */
970 public function date_strtotime($date)
971 {
972 $strtotime = strtotime($date);
973 if ($strtotime === -1 || $strtotime === false)
974 {
975 return false;
976 }
977 else
978 {
979 return $strtotime;
980 }
981 }
982}
983
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Parser.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Parser.php
new file mode 100644
index 00000000..d698552c
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Parser.php
@@ -0,0 +1,407 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Parses XML into something sane
47 *
48 *
49 * This class can be overloaded with {@see SimplePie::set_parser_class()}
50 *
51 * @package SimplePie
52 * @subpackage Parsing
53 */
54class SimplePie_Parser
55{
56 var $error_code;
57 var $error_string;
58 var $current_line;
59 var $current_column;
60 var $current_byte;
61 var $separator = ' ';
62 var $namespace = array('');
63 var $element = array('');
64 var $xml_base = array('');
65 var $xml_base_explicit = array(false);
66 var $xml_lang = array('');
67 var $data = array();
68 var $datas = array(array());
69 var $current_xhtml_construct = -1;
70 var $encoding;
71 protected $registry;
72
73 public function set_registry(SimplePie_Registry $registry)
74 {
75 $this->registry = $registry;
76 }
77
78 public function parse(&$data, $encoding)
79 {
80 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
81 if (strtoupper($encoding) === 'US-ASCII')
82 {
83 $this->encoding = 'UTF-8';
84 }
85 else
86 {
87 $this->encoding = $encoding;
88 }
89
90 // Strip BOM:
91 // UTF-32 Big Endian BOM
92 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
93 {
94 $data = substr($data, 4);
95 }
96 // UTF-32 Little Endian BOM
97 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
98 {
99 $data = substr($data, 4);
100 }
101 // UTF-16 Big Endian BOM
102 elseif (substr($data, 0, 2) === "\xFE\xFF")
103 {
104 $data = substr($data, 2);
105 }
106 // UTF-16 Little Endian BOM
107 elseif (substr($data, 0, 2) === "\xFF\xFE")
108 {
109 $data = substr($data, 2);
110 }
111 // UTF-8 BOM
112 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
113 {
114 $data = substr($data, 3);
115 }
116
117 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
118 {
119 $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
120 if ($declaration->parse())
121 {
122 $data = substr($data, $pos + 2);
123 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
124 }
125 else
126 {
127 $this->error_string = 'SimplePie bug! Please report this!';
128 return false;
129 }
130 }
131
132 $return = true;
133
134 static $xml_is_sane = null;
135 if ($xml_is_sane === null)
136 {
137 $parser_check = xml_parser_create();
138 xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
139 xml_parser_free($parser_check);
140 $xml_is_sane = isset($values[0]['value']);
141 }
142
143 // Create the parser
144 if ($xml_is_sane)
145 {
146 $xml = xml_parser_create_ns($this->encoding, $this->separator);
147 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
148 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
149 xml_set_object($xml, $this);
150 xml_set_character_data_handler($xml, 'cdata');
151 xml_set_element_handler($xml, 'tag_open', 'tag_close');
152
153 // Parse!
154 if (!xml_parse($xml, $data, true))
155 {
156 $this->error_code = xml_get_error_code($xml);
157 $this->error_string = xml_error_string($this->error_code);
158 $return = false;
159 }
160 $this->current_line = xml_get_current_line_number($xml);
161 $this->current_column = xml_get_current_column_number($xml);
162 $this->current_byte = xml_get_current_byte_index($xml);
163 xml_parser_free($xml);
164 return $return;
165 }
166 else
167 {
168 libxml_clear_errors();
169 $xml = new XMLReader();
170 $xml->xml($data);
171 while (@$xml->read())
172 {
173 switch ($xml->nodeType)
174 {
175
176 case constant('XMLReader::END_ELEMENT'):
177 if ($xml->namespaceURI !== '')
178 {
179 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
180 }
181 else
182 {
183 $tagName = $xml->localName;
184 }
185 $this->tag_close(null, $tagName);
186 break;
187 case constant('XMLReader::ELEMENT'):
188 $empty = $xml->isEmptyElement;
189 if ($xml->namespaceURI !== '')
190 {
191 $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
192 }
193 else
194 {
195 $tagName = $xml->localName;
196 }
197 $attributes = array();
198 while ($xml->moveToNextAttribute())
199 {
200 if ($xml->namespaceURI !== '')
201 {
202 $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
203 }
204 else
205 {
206 $attrName = $xml->localName;
207 }
208 $attributes[$attrName] = $xml->value;
209 }
210 $this->tag_open(null, $tagName, $attributes);
211 if ($empty)
212 {
213 $this->tag_close(null, $tagName);
214 }
215 break;
216 case constant('XMLReader::TEXT'):
217
218 case constant('XMLReader::CDATA'):
219 $this->cdata(null, $xml->value);
220 break;
221 }
222 }
223 if ($error = libxml_get_last_error())
224 {
225 $this->error_code = $error->code;
226 $this->error_string = $error->message;
227 $this->current_line = $error->line;
228 $this->current_column = $error->column;
229 return false;
230 }
231 else
232 {
233 return true;
234 }
235 }
236 }
237
238 public function get_error_code()
239 {
240 return $this->error_code;
241 }
242
243 public function get_error_string()
244 {
245 return $this->error_string;
246 }
247
248 public function get_current_line()
249 {
250 return $this->current_line;
251 }
252
253 public function get_current_column()
254 {
255 return $this->current_column;
256 }
257
258 public function get_current_byte()
259 {
260 return $this->current_byte;
261 }
262
263 public function get_data()
264 {
265 return $this->data;
266 }
267
268 public function tag_open($parser, $tag, $attributes)
269 {
270 list($this->namespace[], $this->element[]) = $this->split_ns($tag);
271
272 $attribs = array();
273 foreach ($attributes as $name => $value)
274 {
275 list($attrib_namespace, $attribute) = $this->split_ns($name);
276 $attribs[$attrib_namespace][$attribute] = $value;
277 }
278
279 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
280 {
281 $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
282 if ($base !== false)
283 {
284 $this->xml_base[] = $base;
285 $this->xml_base_explicit[] = true;
286 }
287 }
288 else
289 {
290 $this->xml_base[] = end($this->xml_base);
291 $this->xml_base_explicit[] = end($this->xml_base_explicit);
292 }
293
294 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
295 {
296 $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
297 }
298 else
299 {
300 $this->xml_lang[] = end($this->xml_lang);
301 }
302
303 if ($this->current_xhtml_construct >= 0)
304 {
305 $this->current_xhtml_construct++;
306 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
307 {
308 $this->data['data'] .= '<' . end($this->element);
309 if (isset($attribs['']))
310 {
311 foreach ($attribs[''] as $name => $value)
312 {
313 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
314 }
315 }
316 $this->data['data'] .= '>';
317 }
318 }
319 else
320 {
321 $this->datas[] =& $this->data;
322 $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
323 $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
324 if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
325 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')
326 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
327 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
328 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
329 {
330 $this->current_xhtml_construct = 0;
331 }
332 }
333 }
334
335 public function cdata($parser, $cdata)
336 {
337 if ($this->current_xhtml_construct >= 0)
338 {
339 $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
340 }
341 else
342 {
343 $this->data['data'] .= $cdata;
344 }
345 }
346
347 public function tag_close($parser, $tag)
348 {
349 if ($this->current_xhtml_construct >= 0)
350 {
351 $this->current_xhtml_construct--;
352 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
353 {
354 $this->data['data'] .= '</' . end($this->element) . '>';
355 }
356 }
357 if ($this->current_xhtml_construct === -1)
358 {
359 $this->data =& $this->datas[count($this->datas) - 1];
360 array_pop($this->datas);
361 }
362
363 array_pop($this->element);
364 array_pop($this->namespace);
365 array_pop($this->xml_base);
366 array_pop($this->xml_base_explicit);
367 array_pop($this->xml_lang);
368 }
369
370 public function split_ns($string)
371 {
372 static $cache = array();
373 if (!isset($cache[$string]))
374 {
375 if ($pos = strpos($string, $this->separator))
376 {
377 static $separator_length;
378 if (!$separator_length)
379 {
380 $separator_length = strlen($this->separator);
381 }
382 $namespace = substr($string, 0, $pos);
383 $local_name = substr($string, $pos + $separator_length);
384 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
385 {
386 $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
387 }
388
389 // Normalize the Media RSS namespaces
390 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
391 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
392 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
393 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
394 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
395 {
396 $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
397 }
398 $cache[$string] = array($namespace, $local_name);
399 }
400 else
401 {
402 $cache[$string] = array('', $string);
403 }
404 }
405 return $cache[$string];
406 }
407}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Rating.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Rating.php
new file mode 100644
index 00000000..8689e5df
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Rating.php
@@ -0,0 +1,129 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
47 *
48 * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_rating_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Rating
56{
57 /**
58 * Rating scheme
59 *
60 * @var string
61 * @see get_scheme()
62 */
63 var $scheme;
64
65 /**
66 * Rating value
67 *
68 * @var string
69 * @see get_value()
70 */
71 var $value;
72
73 /**
74 * Constructor, used to input the data
75 *
76 * For documentation on all the parameters, see the corresponding
77 * properties and their accessors
78 */
79 public function __construct($scheme = null, $value = null)
80 {
81 $this->scheme = $scheme;
82 $this->value = $value;
83 }
84
85 /**
86 * String-ified version
87 *
88 * @return string
89 */
90 public function __toString()
91 {
92 // There is no $this->data here
93 return md5(serialize($this));
94 }
95
96 /**
97 * Get the organizational scheme for the rating
98 *
99 * @return string|null
100 */
101 public function get_scheme()
102 {
103 if ($this->scheme !== null)
104 {
105 return $this->scheme;
106 }
107 else
108 {
109 return null;
110 }
111 }
112
113 /**
114 * Get the value of the rating
115 *
116 * @return string|null
117 */
118 public function get_value()
119 {
120 if ($this->value !== null)
121 {
122 return $this->value;
123 }
124 else
125 {
126 return null;
127 }
128 }
129}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Registry.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Registry.php
new file mode 100644
index 00000000..1072cdeb
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Registry.php
@@ -0,0 +1,225 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Handles creating objects and calling methods
47 *
48 * Access this via {@see SimplePie::get_registry()}
49 *
50 * @package SimplePie
51 */
52class SimplePie_Registry
53{
54 /**
55 * Default class mapping
56 *
57 * Overriding classes *must* subclass these.
58 *
59 * @var array
60 */
61 protected $default = array(
62 'Cache' => 'SimplePie_Cache',
63 'Locator' => 'SimplePie_Locator',
64 'Parser' => 'SimplePie_Parser',
65 'File' => 'SimplePie_File',
66 'Sanitize' => 'SimplePie_Sanitize',
67 'Item' => 'SimplePie_Item',
68 'Author' => 'SimplePie_Author',
69 'Category' => 'SimplePie_Category',
70 'Enclosure' => 'SimplePie_Enclosure',
71 'Caption' => 'SimplePie_Caption',
72 'Copyright' => 'SimplePie_Copyright',
73 'Credit' => 'SimplePie_Credit',
74 'Rating' => 'SimplePie_Rating',
75 'Restriction' => 'SimplePie_Restriction',
76 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
77 'Source' => 'SimplePie_Source',
78 'Misc' => 'SimplePie_Misc',
79 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
80 'Parse_Date' => 'SimplePie_Parse_Date',
81 );
82
83 /**
84 * Class mapping
85 *
86 * @see register()
87 * @var array
88 */
89 protected $classes = array();
90
91 /**
92 * Legacy classes
93 *
94 * @see register()
95 * @var array
96 */
97 protected $legacy = array();
98
99 /**
100 * Constructor
101 *
102 * No-op
103 */
104 public function __construct() { }
105
106 /**
107 * Register a class
108 *
109 * @param string $type See {@see $default} for names
110 * @param string $class Class name, must subclass the corresponding default
111 * @param bool $legacy Whether to enable legacy support for this class
112 * @return bool Successfulness
113 */
114 public function register($type, $class, $legacy = false)
115 {
116 if (!is_subclass_of($class, $this->default[$type]))
117 {
118 return false;
119 }
120
121 $this->classes[$type] = $class;
122
123 if ($legacy)
124 {
125 $this->legacy[] = $class;
126 }
127
128 return true;
129 }
130
131 /**
132 * Get the class registered for a type
133 *
134 * Where possible, use {@see create()} or {@see call()} instead
135 *
136 * @param string $type
137 * @return string|null
138 */
139 public function get_class($type)
140 {
141 if (!empty($this->classes[$type]))
142 {
143 return $this->classes[$type];
144 }
145 if (!empty($this->default[$type]))
146 {
147 return $this->default[$type];
148 }
149
150 return null;
151 }
152
153 /**
154 * Create a new instance of a given type
155 *
156 * @param string $type
157 * @param array $parameters Parameters to pass to the constructor
158 * @return object Instance of class
159 */
160 public function &create($type, $parameters = array())
161 {
162 $class = $this->get_class($type);
163
164 if (in_array($class, $this->legacy))
165 {
166 switch ($type)
167 {
168 case 'locator':
169 // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
170 // Specified: file, timeout, useragent, max_checked_feeds
171 $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
172 array_splice($parameters, 3, 1, $replacement);
173 break;
174 }
175 }
176
177 if (!method_exists($class, '__construct'))
178 {
179 $instance = new $class;
180 }
181 else
182 {
183 $reflector = new ReflectionClass($class);
184 $instance = $reflector->newInstanceArgs($parameters);
185 }
186
187 if (method_exists($instance, 'set_registry'))
188 {
189 $instance->set_registry($this);
190 }
191 return $instance;
192 }
193
194 /**
195 * Call a static method for a type
196 *
197 * @param string $type
198 * @param string $method
199 * @param array $parameters
200 * @return mixed
201 */
202 public function &call($type, $method, $parameters = array())
203 {
204 $class = $this->get_class($type);
205
206 if (in_array($class, $this->legacy))
207 {
208 switch ($type)
209 {
210 case 'Cache':
211 // For backwards compatibility with old non-static
212 // Cache::create() methods
213 if ($method === 'get_handler')
214 {
215 $result = @call_user_func_array(array($class, 'create'), $parameters);
216 return $result;
217 }
218 break;
219 }
220 }
221
222 $result = call_user_func_array(array($class, $method), $parameters);
223 return $result;
224 }
225} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Restriction.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Restriction.php
new file mode 100644
index 00000000..4ba371bf
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Restriction.php
@@ -0,0 +1,155 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Handles `<media:restriction>` as defined in Media RSS
47 *
48 * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_restriction_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Restriction
56{
57 /**
58 * Relationship ('allow'/'deny')
59 *
60 * @var string
61 * @see get_relationship()
62 */
63 var $relationship;
64
65 /**
66 * Type of restriction
67 *
68 * @var string
69 * @see get_type()
70 */
71 var $type;
72
73 /**
74 * Restricted values
75 *
76 * @var string
77 * @see get_value()
78 */
79 var $value;
80
81 /**
82 * Constructor, used to input the data
83 *
84 * For documentation on all the parameters, see the corresponding
85 * properties and their accessors
86 */
87 public function __construct($relationship = null, $type = null, $value = null)
88 {
89 $this->relationship = $relationship;
90 $this->type = $type;
91 $this->value = $value;
92 }
93
94 /**
95 * String-ified version
96 *
97 * @return string
98 */
99 public function __toString()
100 {
101 // There is no $this->data here
102 return md5(serialize($this));
103 }
104
105 /**
106 * Get the relationship
107 *
108 * @return string|null Either 'allow' or 'deny'
109 */
110 public function get_relationship()
111 {
112 if ($this->relationship !== null)
113 {
114 return $this->relationship;
115 }
116 else
117 {
118 return null;
119 }
120 }
121
122 /**
123 * Get the type
124 *
125 * @return string|null
126 */
127 public function get_type()
128 {
129 if ($this->type !== null)
130 {
131 return $this->type;
132 }
133 else
134 {
135 return null;
136 }
137 }
138
139 /**
140 * Get the list of restricted things
141 *
142 * @return string|null
143 */
144 public function get_value()
145 {
146 if ($this->value !== null)
147 {
148 return $this->value;
149 }
150 else
151 {
152 return null;
153 }
154 }
155}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Sanitize.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Sanitize.php
new file mode 100644
index 00000000..6810cc49
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Sanitize.php
@@ -0,0 +1,549 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Used for data cleanup and post-processing
47 *
48 *
49 * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
50 *
51 * @package SimplePie
52 * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
53 */
54class SimplePie_Sanitize
55{
56 // Private vars
57 var $base;
58
59 // Options
60 var $remove_div = true;
61 var $image_handler = '';
62 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
63 var $encode_instead_of_strip = false;
64 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
65 var $strip_comments = false;
66 var $output_encoding = 'UTF-8';
67 var $enable_cache = true;
68 var $cache_location = './cache';
69 var $cache_name_function = 'md5';
70 var $timeout = 10;
71 var $useragent = '';
72 var $force_fsockopen = false;
73 var $replace_url_attributes = null;
74
75 public function __construct()
76 {
77 // Set defaults
78 $this->set_url_replacements(null);
79 }
80
81 public function remove_div($enable = true)
82 {
83 $this->remove_div = (bool) $enable;
84 }
85
86 public function set_image_handler($page = false)
87 {
88 if ($page)
89 {
90 $this->image_handler = (string) $page;
91 }
92 else
93 {
94 $this->image_handler = false;
95 }
96 }
97
98 public function set_registry(SimplePie_Registry $registry)
99 {
100 $this->registry = $registry;
101 }
102
103 public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
104 {
105 if (isset($enable_cache))
106 {
107 $this->enable_cache = (bool) $enable_cache;
108 }
109
110 if ($cache_location)
111 {
112 $this->cache_location = (string) $cache_location;
113 }
114
115 if ($cache_name_function)
116 {
117 $this->cache_name_function = (string) $cache_name_function;
118 }
119 }
120
121 public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
122 {
123 if ($timeout)
124 {
125 $this->timeout = (string) $timeout;
126 }
127
128 if ($useragent)
129 {
130 $this->useragent = (string) $useragent;
131 }
132
133 if ($force_fsockopen)
134 {
135 $this->force_fsockopen = (string) $force_fsockopen;
136 }
137 }
138
139 public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
140 {
141 if ($tags)
142 {
143 if (is_array($tags))
144 {
145 $this->strip_htmltags = $tags;
146 }
147 else
148 {
149 $this->strip_htmltags = explode(',', $tags);
150 }
151 }
152 else
153 {
154 $this->strip_htmltags = false;
155 }
156 }
157
158 public function encode_instead_of_strip($encode = false)
159 {
160 $this->encode_instead_of_strip = (bool) $encode;
161 }
162
163 public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
164 {
165 if ($attribs)
166 {
167 if (is_array($attribs))
168 {
169 $this->strip_attributes = $attribs;
170 }
171 else
172 {
173 $this->strip_attributes = explode(',', $attribs);
174 }
175 }
176 else
177 {
178 $this->strip_attributes = false;
179 }
180 }
181
182 public function strip_comments($strip = false)
183 {
184 $this->strip_comments = (bool) $strip;
185 }
186
187 public function set_output_encoding($encoding = 'UTF-8')
188 {
189 $this->output_encoding = (string) $encoding;
190 }
191
192 /**
193 * Set element/attribute key/value pairs of HTML attributes
194 * containing URLs that need to be resolved relative to the feed
195 *
196 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
197 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
198 * |q|@cite
199 *
200 * @since 1.0
201 * @param array|null $element_attribute Element/attribute key/value pairs, null for default
202 */
203 public function set_url_replacements($element_attribute = null)
204 {
205 if ($element_attribute === null)
206 {
207 $element_attribute = array(
208 'a' => 'href',
209 'area' => 'href',
210 'blockquote' => 'cite',
211 'del' => 'cite',
212 'form' => 'action',
213 'img' => array(
214 'longdesc',
215 'src'
216 ),
217 'input' => 'src',
218 'ins' => 'cite',
219 'q' => 'cite'
220 );
221 }
222 $this->replace_url_attributes = (array) $element_attribute;
223 }
224
225 public function sanitize($data, $type, $base = '')
226 {
227 $data = trim($data);
228 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
229 {
230 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
231 {
232 if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
233 {
234 $type |= SIMPLEPIE_CONSTRUCT_HTML;
235 }
236 else
237 {
238 $type |= SIMPLEPIE_CONSTRUCT_TEXT;
239 }
240 }
241
242 if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
243 {
244 $data = base64_decode($data);
245 }
246
247 if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
248 {
249
250 $document = new DOMDocument();
251 $document->encoding = 'UTF-8';
252 $data = $this->preprocess($data, $type);
253
254 set_error_handler(array('SimplePie_Misc', 'silence_errors'));
255 $document->loadHTML($data);
256 restore_error_handler();
257
258 // Strip comments
259 if ($this->strip_comments)
260 {
261 $xpath = new DOMXPath($document);
262 $comments = $xpath->query('//comment()');
263
264 foreach ($comments as $comment)
265 {
266 $comment->parentNode->removeChild($comment);
267 }
268 }
269
270 // Strip out HTML tags and attributes that might cause various security problems.
271 // Based on recommendations by Mark Pilgrim at:
272 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
273 if ($this->strip_htmltags)
274 {
275 foreach ($this->strip_htmltags as $tag)
276 {
277 $this->strip_tag($tag, $document, $type);
278 }
279 }
280
281 if ($this->strip_attributes)
282 {
283 foreach ($this->strip_attributes as $attrib)
284 {
285 $this->strip_attr($attrib, $document);
286 }
287 }
288
289 // Replace relative URLs
290 $this->base = $base;
291 foreach ($this->replace_url_attributes as $element => $attributes)
292 {
293 $this->replace_urls($document, $element, $attributes);
294 }
295
296 // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
297 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
298 {
299 $images = $document->getElementsByTagName('img');
300 foreach ($images as $img)
301 {
302 if ($img->hasAttribute('src'))
303 {
304 $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
305 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
306
307 if ($cache->load())
308 {
309 $img->setAttribute('src', $this->image_handler . $image_url);
310 }
311 else
312 {
313 $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
314 $headers = $file->headers;
315
316 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
317 {
318 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
319 {
320 $img->setAttribute('src', $this->image_handler . $image_url);
321 }
322 else
323 {
324 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
325 }
326 }
327 }
328 }
329 }
330 }
331
332 // Remove the DOCTYPE
333 // Seems to cause segfaulting if we don't do this
334 if ($document->firstChild instanceof DOMDocumentType)
335 {
336 $document->removeChild($document->firstChild);
337 }
338
339 // Move everything from the body to the root
340 $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
341 $document->replaceChild($real_body, $document->firstChild);
342
343 // Finally, convert to a HTML string
344 $data = trim($document->saveHTML());
345
346 if ($this->remove_div)
347 {
348 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
349 $data = preg_replace('/<\/div>$/', '', $data);
350 }
351 else
352 {
353 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
354 }
355 }
356
357 if ($type & SIMPLEPIE_CONSTRUCT_IRI)
358 {
359 $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
360 if ($absolute !== false)
361 {
362 $data = $absolute;
363 }
364 }
365
366 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
367 {
368 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
369 }
370
371 if ($this->output_encoding !== 'UTF-8')
372 {
373 $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
374 }
375 }
376 return $data;
377 }
378
379 protected function preprocess($html, $type)
380 {
381 $ret = '';
382 if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
383 {
384 // Atom XHTML constructs are wrapped with a div by default
385 // Note: No protection if $html contains a stray </div>!
386 $html = '<div>' . $html . '</div>';
387 $ret .= '<!DOCTYPE html>';
388 $content_type = 'text/html';
389 }
390 else
391 {
392 $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
393 $content_type = 'application/xhtml+xml';
394 }
395
396 $ret .= '<html><head>';
397 $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
398 $ret .= '</head><body>' . $html . '</body></html>';
399 return $ret;
400 }
401
402 public function replace_urls($document, $tag, $attributes)
403 {
404 if (!is_array($attributes))
405 {
406 $attributes = array($attributes);
407 }
408
409 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
410 {
411 $elements = $document->getElementsByTagName($tag);
412 foreach ($elements as $element)
413 {
414 foreach ($attributes as $attribute)
415 {
416 if ($element->hasAttribute($attribute))
417 {
418 $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
419 if ($value !== false)
420 {
421 $element->setAttribute($attribute, $value);
422 }
423 }
424 }
425 }
426 }
427 }
428
429 public function do_strip_htmltags($match)
430 {
431 if ($this->encode_instead_of_strip)
432 {
433 if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
434 {
435 $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
436 $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
437 return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
438 }
439 else
440 {
441 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
442 }
443 }
444 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
445 {
446 return $match[4];
447 }
448 else
449 {
450 return '';
451 }
452 }
453
454 protected function strip_tag($tag, $document, $type)
455 {
456 $xpath = new DOMXPath($document);
457 $elements = $xpath->query('body//' . $tag);
458 if ($this->encode_instead_of_strip)
459 {
460 foreach ($elements as $element)
461 {
462 $fragment = $document->createDocumentFragment();
463
464 // For elements which aren't script or style, include the tag itself
465 if (!in_array($tag, array('script', 'style')))
466 {
467 $text = '<' . $tag;
468 if ($element->hasAttributes())
469 {
470 $attrs = array();
471 foreach ($element->attributes as $name => $attr)
472 {
473 $value = $attr->value;
474
475 // In XHTML, empty values should never exist, so we repeat the value
476 if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
477 {
478 $value = $name;
479 }
480 // For HTML, empty is fine
481 elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
482 {
483 $attrs[] = $name;
484 continue;
485 }
486
487 // Standard attribute text
488 $attrs[] = $name . '="' . $attr->value . '"';
489 }
490 $text .= ' ' . implode(' ', $attrs);
491 }
492 $text .= '>';
493 $fragment->appendChild(new DOMText($text));
494 }
495
496 $number = $element->childNodes->length;
497 for ($i = $number; $i > 0; $i--)
498 {
499 $child = $element->childNodes->item(0);
500 $fragment->appendChild($child);
501 }
502
503 if (!in_array($tag, array('script', 'style')))
504 {
505 $fragment->appendChild(new DOMText('</' . $tag . '>'));
506 }
507
508 $element->parentNode->replaceChild($fragment, $element);
509 }
510
511 return;
512 }
513 elseif (in_array($tag, array('script', 'style')))
514 {
515 foreach ($elements as $element)
516 {
517 $element->parentNode->removeChild($element);
518 }
519
520 return;
521 }
522 else
523 {
524 foreach ($elements as $element)
525 {
526 $fragment = $document->createDocumentFragment();
527 $number = $element->childNodes->length;
528 for ($i = $number; $i > 0; $i--)
529 {
530 $child = $element->childNodes->item(0);
531 $fragment->appendChild($child);
532 }
533
534 $element->parentNode->replaceChild($fragment, $element);
535 }
536 }
537 }
538
539 protected function strip_attr($attrib, $document)
540 {
541 $xpath = new DOMXPath($document);
542 $elements = $xpath->query('//*[@' . $attrib . ']');
543
544 foreach ($elements as $element)
545 {
546 $element->removeAttribute($attrib);
547 }
548 }
549}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/Source.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/Source.php
new file mode 100644
index 00000000..51d8e6c2
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/Source.php
@@ -0,0 +1,611 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45/**
46 * Handles `<atom:source>`
47 *
48 * Used by {@see SimplePie_Item::get_source()}
49 *
50 * This class can be overloaded with {@see SimplePie::set_source_class()}
51 *
52 * @package SimplePie
53 * @subpackage API
54 */
55class SimplePie_Source
56{
57 var $item;
58 var $data = array();
59 protected $registry;
60
61 public function __construct($item, $data)
62 {
63 $this->item = $item;
64 $this->data = $data;
65 }
66
67 public function set_registry(SimplePie_Registry $registry)
68 {
69 $this->registry = $registry;
70 }
71
72 public function __toString()
73 {
74 return md5(serialize($this->data));
75 }
76
77 public function get_source_tags($namespace, $tag)
78 {
79 if (isset($this->data['child'][$namespace][$tag]))
80 {
81 return $this->data['child'][$namespace][$tag];
82 }
83 else
84 {
85 return null;
86 }
87 }
88
89 public function get_base($element = array())
90 {
91 return $this->item->get_base($element);
92 }
93
94 public function sanitize($data, $type, $base = '')
95 {
96 return $this->item->sanitize($data, $type, $base);
97 }
98
99 public function get_item()
100 {
101 return $this->item;
102 }
103
104 public function get_title()
105 {
106 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
107 {
108 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
109 }
110 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
111 {
112 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
113 }
114 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
115 {
116 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
117 }
118 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
119 {
120 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
121 }
122 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
123 {
124 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
125 }
126 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
127 {
128 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
129 }
130 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
131 {
132 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
133 }
134 else
135 {
136 return null;
137 }
138 }
139
140 public function get_category($key = 0)
141 {
142 $categories = $this->get_categories();
143 if (isset($categories[$key]))
144 {
145 return $categories[$key];
146 }
147 else
148 {
149 return null;
150 }
151 }
152
153 public function get_categories()
154 {
155 $categories = array();
156
157 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
158 {
159 $term = null;
160 $scheme = null;
161 $label = null;
162 if (isset($category['attribs']['']['term']))
163 {
164 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
165 }
166 if (isset($category['attribs']['']['scheme']))
167 {
168 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
169 }
170 if (isset($category['attribs']['']['label']))
171 {
172 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
173 }
174 $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
175 }
176 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
177 {
178 // This is really the label, but keep this as the term also for BC.
179 // Label will also work on retrieving because that falls back to term.
180 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
181 if (isset($category['attribs']['']['domain']))
182 {
183 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
184 }
185 else
186 {
187 $scheme = null;
188 }
189 $categories[] = $this->registry->create('Category', array($term, $scheme, null));
190 }
191 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
192 {
193 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
194 }
195 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
196 {
197 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
198 }
199
200 if (!empty($categories))
201 {
202 return array_unique($categories);
203 }
204 else
205 {
206 return null;
207 }
208 }
209
210 public function get_author($key = 0)
211 {
212 $authors = $this->get_authors();
213 if (isset($authors[$key]))
214 {
215 return $authors[$key];
216 }
217 else
218 {
219 return null;
220 }
221 }
222
223 public function get_authors()
224 {
225 $authors = array();
226 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
227 {
228 $name = null;
229 $uri = null;
230 $email = null;
231 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
232 {
233 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
234 }
235 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
236 {
237 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
238 }
239 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
240 {
241 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
242 }
243 if ($name !== null || $email !== null || $uri !== null)
244 {
245 $authors[] = $this->registry->create('Author', array($name, $uri, $email));
246 }
247 }
248 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
249 {
250 $name = null;
251 $url = null;
252 $email = null;
253 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
254 {
255 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
256 }
257 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
258 {
259 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
260 }
261 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
262 {
263 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
264 }
265 if ($name !== null || $email !== null || $url !== null)
266 {
267 $authors[] = $this->registry->create('Author', array($name, $url, $email));
268 }
269 }
270 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
271 {
272 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
273 }
274 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
275 {
276 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
277 }
278 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
279 {
280 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
281 }
282
283 if (!empty($authors))
284 {
285 return array_unique($authors);
286 }
287 else
288 {
289 return null;
290 }
291 }
292
293 public function get_contributor($key = 0)
294 {
295 $contributors = $this->get_contributors();
296 if (isset($contributors[$key]))
297 {
298 return $contributors[$key];
299 }
300 else
301 {
302 return null;
303 }
304 }
305
306 public function get_contributors()
307 {
308 $contributors = array();
309 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
310 {
311 $name = null;
312 $uri = null;
313 $email = null;
314 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
315 {
316 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
317 }
318 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
319 {
320 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
321 }
322 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
323 {
324 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
325 }
326 if ($name !== null || $email !== null || $uri !== null)
327 {
328 $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
329 }
330 }
331 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
332 {
333 $name = null;
334 $url = null;
335 $email = null;
336 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
337 {
338 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
339 }
340 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
341 {
342 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
343 }
344 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
345 {
346 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
347 }
348 if ($name !== null || $email !== null || $url !== null)
349 {
350 $contributors[] = $this->registry->create('Author', array($name, $url, $email));
351 }
352 }
353
354 if (!empty($contributors))
355 {
356 return array_unique($contributors);
357 }
358 else
359 {
360 return null;
361 }
362 }
363
364 public function get_link($key = 0, $rel = 'alternate')
365 {
366 $links = $this->get_links($rel);
367 if (isset($links[$key]))
368 {
369 return $links[$key];
370 }
371 else
372 {
373 return null;
374 }
375 }
376
377 /**
378 * Added for parity between the parent-level and the item/entry-level.
379 */
380 public function get_permalink()
381 {
382 return $this->get_link(0);
383 }
384
385 public function get_links($rel = 'alternate')
386 {
387 if (!isset($this->data['links']))
388 {
389 $this->data['links'] = array();
390 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
391 {
392 foreach ($links as $link)
393 {
394 if (isset($link['attribs']['']['href']))
395 {
396 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
397 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
398 }
399 }
400 }
401 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
402 {
403 foreach ($links as $link)
404 {
405 if (isset($link['attribs']['']['href']))
406 {
407 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
408 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
409
410 }
411 }
412 }
413 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
414 {
415 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
416 }
417 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
418 {
419 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
420 }
421 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
422 {
423 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
424 }
425
426 $keys = array_keys($this->data['links']);
427 foreach ($keys as $key)
428 {
429 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
430 {
431 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
432 {
433 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
434 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
435 }
436 else
437 {
438 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
439 }
440 }
441 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
442 {
443 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
444 }
445 $this->data['links'][$key] = array_unique($this->data['links'][$key]);
446 }
447 }
448
449 if (isset($this->data['links'][$rel]))
450 {
451 return $this->data['links'][$rel];
452 }
453 else
454 {
455 return null;
456 }
457 }
458
459 public function get_description()
460 {
461 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
462 {
463 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
464 }
465 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
466 {
467 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
468 }
469 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
470 {
471 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
472 }
473 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
474 {
475 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
476 }
477 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
478 {
479 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
480 }
481 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
482 {
483 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
484 }
485 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
486 {
487 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
488 }
489 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
490 {
491 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
492 }
493 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
494 {
495 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
496 }
497 else
498 {
499 return null;
500 }
501 }
502
503 public function get_copyright()
504 {
505 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
506 {
507 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
508 }
509 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
510 {
511 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
512 }
513 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
514 {
515 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
516 }
517 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
518 {
519 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
520 }
521 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
522 {
523 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
524 }
525 else
526 {
527 return null;
528 }
529 }
530
531 public function get_language()
532 {
533 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
534 {
535 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
536 }
537 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
538 {
539 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
540 }
541 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
542 {
543 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
544 }
545 elseif (isset($this->data['xml_lang']))
546 {
547 return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
548 }
549 else
550 {
551 return null;
552 }
553 }
554
555 public function get_latitude()
556 {
557 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
558 {
559 return (float) $return[0]['data'];
560 }
561 elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
562 {
563 return (float) $match[1];
564 }
565 else
566 {
567 return null;
568 }
569 }
570
571 public function get_longitude()
572 {
573 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
574 {
575 return (float) $return[0]['data'];
576 }
577 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
578 {
579 return (float) $return[0]['data'];
580 }
581 elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
582 {
583 return (float) $match[2];
584 }
585 else
586 {
587 return null;
588 }
589 }
590
591 public function get_image_url()
592 {
593 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
594 {
595 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
596 }
597 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
598 {
599 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
600 }
601 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
602 {
603 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
604 }
605 else
606 {
607 return null;
608 }
609 }
610}
611
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/XML/Declaration/Parser.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/XML/Declaration/Parser.php
new file mode 100644
index 00000000..aec19f10
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/XML/Declaration/Parser.php
@@ -0,0 +1,362 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Parses the XML Declaration
48 *
49 * @package SimplePie
50 * @subpackage Parsing
51 */
52class SimplePie_XML_Declaration_Parser
53{
54 /**
55 * XML Version
56 *
57 * @access public
58 * @var string
59 */
60 var $version = '1.0';
61
62 /**
63 * Encoding
64 *
65 * @access public
66 * @var string
67 */
68 var $encoding = 'UTF-8';
69
70 /**
71 * Standalone
72 *
73 * @access public
74 * @var bool
75 */
76 var $standalone = false;
77
78 /**
79 * Current state of the state machine
80 *
81 * @access private
82 * @var string
83 */
84 var $state = 'before_version_name';
85
86 /**
87 * Input data
88 *
89 * @access private
90 * @var string
91 */
92 var $data = '';
93
94 /**
95 * Input data length (to avoid calling strlen() everytime this is needed)
96 *
97 * @access private
98 * @var int
99 */
100 var $data_length = 0;
101
102 /**
103 * Current position of the pointer
104 *
105 * @var int
106 * @access private
107 */
108 var $position = 0;
109
110 /**
111 * Create an instance of the class with the input data
112 *
113 * @access public
114 * @param string $data Input data
115 */
116 public function __construct($data)
117 {
118 $this->data = $data;
119 $this->data_length = strlen($this->data);
120 }
121
122 /**
123 * Parse the input data
124 *
125 * @access public
126 * @return bool true on success, false on failure
127 */
128 public function parse()
129 {
130 while ($this->state && $this->state !== 'emit' && $this->has_data())
131 {
132 $state = $this->state;
133 $this->$state();
134 }
135 $this->data = '';
136 if ($this->state === 'emit')
137 {
138 return true;
139 }
140 else
141 {
142 $this->version = '';
143 $this->encoding = '';
144 $this->standalone = '';
145 return false;
146 }
147 }
148
149 /**
150 * Check whether there is data beyond the pointer
151 *
152 * @access private
153 * @return bool true if there is further data, false if not
154 */
155 public function has_data()
156 {
157 return (bool) ($this->position < $this->data_length);
158 }
159
160 /**
161 * Advance past any whitespace
162 *
163 * @return int Number of whitespace characters passed
164 */
165 public function skip_whitespace()
166 {
167 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
168 $this->position += $whitespace;
169 return $whitespace;
170 }
171
172 /**
173 * Read value
174 */
175 public function get_value()
176 {
177 $quote = substr($this->data, $this->position, 1);
178 if ($quote === '"' || $quote === "'")
179 {
180 $this->position++;
181 $len = strcspn($this->data, $quote, $this->position);
182 if ($this->has_data())
183 {
184 $value = substr($this->data, $this->position, $len);
185 $this->position += $len + 1;
186 return $value;
187 }
188 }
189 return false;
190 }
191
192 public function before_version_name()
193 {
194 if ($this->skip_whitespace())
195 {
196 $this->state = 'version_name';
197 }
198 else
199 {
200 $this->state = false;
201 }
202 }
203
204 public function version_name()
205 {
206 if (substr($this->data, $this->position, 7) === 'version')
207 {
208 $this->position += 7;
209 $this->skip_whitespace();
210 $this->state = 'version_equals';
211 }
212 else
213 {
214 $this->state = false;
215 }
216 }
217
218 public function version_equals()
219 {
220 if (substr($this->data, $this->position, 1) === '=')
221 {
222 $this->position++;
223 $this->skip_whitespace();
224 $this->state = 'version_value';
225 }
226 else
227 {
228 $this->state = false;
229 }
230 }
231
232 public function version_value()
233 {
234 if ($this->version = $this->get_value())
235 {
236 $this->skip_whitespace();
237 if ($this->has_data())
238 {
239 $this->state = 'encoding_name';
240 }
241 else
242 {
243 $this->state = 'emit';
244 }
245 }
246 else
247 {
248 $this->state = false;
249 }
250 }
251
252 public function encoding_name()
253 {
254 if (substr($this->data, $this->position, 8) === 'encoding')
255 {
256 $this->position += 8;
257 $this->skip_whitespace();
258 $this->state = 'encoding_equals';
259 }
260 else
261 {
262 $this->state = 'standalone_name';
263 }
264 }
265
266 public function encoding_equals()
267 {
268 if (substr($this->data, $this->position, 1) === '=')
269 {
270 $this->position++;
271 $this->skip_whitespace();
272 $this->state = 'encoding_value';
273 }
274 else
275 {
276 $this->state = false;
277 }
278 }
279
280 public function encoding_value()
281 {
282 if ($this->encoding = $this->get_value())
283 {
284 $this->skip_whitespace();
285 if ($this->has_data())
286 {
287 $this->state = 'standalone_name';
288 }
289 else
290 {
291 $this->state = 'emit';
292 }
293 }
294 else
295 {
296 $this->state = false;
297 }
298 }
299
300 public function standalone_name()
301 {
302 if (substr($this->data, $this->position, 10) === 'standalone')
303 {
304 $this->position += 10;
305 $this->skip_whitespace();
306 $this->state = 'standalone_equals';
307 }
308 else
309 {
310 $this->state = false;
311 }
312 }
313
314 public function standalone_equals()
315 {
316 if (substr($this->data, $this->position, 1) === '=')
317 {
318 $this->position++;
319 $this->skip_whitespace();
320 $this->state = 'standalone_value';
321 }
322 else
323 {
324 $this->state = false;
325 }
326 }
327
328 public function standalone_value()
329 {
330 if ($standalone = $this->get_value())
331 {
332 switch ($standalone)
333 {
334 case 'yes':
335 $this->standalone = true;
336 break;
337
338 case 'no':
339 $this->standalone = false;
340 break;
341
342 default:
343 $this->state = false;
344 return;
345 }
346
347 $this->skip_whitespace();
348 if ($this->has_data())
349 {
350 $this->state = false;
351 }
352 else
353 {
354 $this->state = 'emit';
355 }
356 }
357 else
358 {
359 $this->state = false;
360 }
361 }
362}
diff --git a/inc/3rdparty/libraries/simplepie/library/SimplePie/gzdecode.php b/inc/3rdparty/libraries/simplepie/library/SimplePie/gzdecode.php
new file mode 100644
index 00000000..52e024ea
--- /dev/null
+++ b/inc/3rdparty/libraries/simplepie/library/SimplePie/gzdecode.php
@@ -0,0 +1,371 @@
1<?php
2/**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3.1
37 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 */
44
45
46/**
47 * Decode 'gzip' encoded HTTP data
48 *
49 * @package SimplePie
50 * @subpackage HTTP
51 * @link http://www.gzip.org/format.txt
52 */
53class SimplePie_gzdecode
54{
55 /**
56 * Compressed data
57 *
58 * @access private
59 * @var string
60 * @see gzdecode::$data
61 */
62 var $compressed_data;
63
64 /**
65 * Size of compressed data
66 *
67 * @access private
68 * @var int
69 */
70 var $compressed_size;
71
72 /**
73 * Minimum size of a valid gzip string
74 *
75 * @access private
76 * @var int
77 */
78 var $min_compressed_size = 18;
79
80 /**
81 * Current position of pointer
82 *
83 * @access private
84 * @var int
85 */
86 var $position = 0;
87
88 /**
89 * Flags (FLG)
90 *
91 * @access private
92 * @var int
93 */
94 var $flags;
95
96 /**
97 * Uncompressed data
98 *
99 * @access public
100 * @see gzdecode::$compressed_data
101 * @var string
102 */
103 var $data;
104
105 /**
106 * Modified time
107 *
108 * @access public
109 * @var int
110 */
111 var $MTIME;
112
113 /**
114 * Extra Flags
115 *
116 * @access public
117 * @var int
118 */
119 var $XFL;
120
121 /**
122 * Operating System
123 *
124 * @access public
125 * @var int
126 */
127 var $OS;
128
129 /**
130 * Subfield ID 1
131 *
132 * @access public
133 * @see gzdecode::$extra_field
134 * @see gzdecode::$SI2
135 * @var string
136 */
137 var $SI1;
138
139 /**
140 * Subfield ID 2
141 *
142 * @access public
143 * @see gzdecode::$extra_field
144 * @see gzdecode::$SI1
145 * @var string
146 */
147 var $SI2;
148
149 /**
150 * Extra field content
151 *
152 * @access public
153 * @see gzdecode::$SI1
154 * @see gzdecode::$SI2
155 * @var string
156 */
157 var $extra_field;
158
159 /**
160 * Original filename
161 *
162 * @access public
163 * @var string
164 */
165 var $filename;
166
167 /**
168 * Human readable comment
169 *
170 * @access public
171 * @var string
172 */
173 var $comment;
174
175 /**
176 * Don't allow anything to be set
177 *
178 * @param string $name
179 * @param mixed $value
180 */
181 public function __set($name, $value)
182 {
183 trigger_error("Cannot write property $name", E_USER_ERROR);
184 }
185
186 /**
187 * Set the compressed string and related properties
188 *
189 * @param string $data
190 */
191 public function __construct($data)
192 {
193 $this->compressed_data = $data;
194 $this->compressed_size = strlen($data);
195 }
196
197 /**
198 * Decode the GZIP stream
199 *
200 * @return bool Successfulness
201 */
202 public function parse()
203 {
204 if ($this->compressed_size >= $this->min_compressed_size)
205 {
206 // Check ID1, ID2, and CM
207 if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
208 {
209 return false;
210 }
211
212 // Get the FLG (FLaGs)
213 $this->flags = ord($this->compressed_data[3]);
214
215 // FLG bits above (1 << 4) are reserved
216 if ($this->flags > 0x1F)
217 {
218 return false;
219 }
220
221 // Advance the pointer after the above
222 $this->position += 4;
223
224 // MTIME
225 $mtime = substr($this->compressed_data, $this->position, 4);
226 // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
227 if (current(unpack('S', "\x00\x01")) === 1)
228 {
229 $mtime = strrev($mtime);
230 }
231 $this->MTIME = current(unpack('l', $mtime));
232 $this->position += 4;
233
234 // Get the XFL (eXtra FLags)
235 $this->XFL = ord($this->compressed_data[$this->position++]);
236
237 // Get the OS (Operating System)
238 $this->OS = ord($this->compressed_data[$this->position++]);
239
240 // Parse the FEXTRA
241 if ($this->flags & 4)
242 {
243 // Read subfield IDs
244 $this->SI1 = $this->compressed_data[$this->position++];
245 $this->SI2 = $this->compressed_data[$this->position++];
246
247 // SI2 set to zero is reserved for future use
248 if ($this->SI2 === "\x00")
249 {
250 return false;
251 }
252
253 // Get the length of the extra field
254 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
255 $this->position += 2;
256
257 // Check the length of the string is still valid
258 $this->min_compressed_size += $len + 4;
259 if ($this->compressed_size >= $this->min_compressed_size)
260 {
261 // Set the extra field to the given data
262 $this->extra_field = substr($this->compressed_data, $this->position, $len);
263 $this->position += $len;
264 }
265 else
266 {
267 return false;
268 }
269 }
270
271 // Parse the FNAME
272 if ($this->flags & 8)
273 {
274 // Get the length of the filename
275 $len = strcspn($this->compressed_data, "\x00", $this->position);
276
277 // Check the length of the string is still valid
278 $this->min_compressed_size += $len + 1;
279 if ($this->compressed_size >= $this->min_compressed_size)
280 {
281 // Set the original filename to the given string
282 $this->filename = substr($this->compressed_data, $this->position, $len);
283 $this->position += $len + 1;
284 }
285 else
286 {
287 return false;
288 }
289 }
290
291 // Parse the FCOMMENT
292 if ($this->flags & 16)
293 {
294 // Get the length of the comment
295 $len = strcspn($this->compressed_data, "\x00", $this->position);
296
297 // Check the length of the string is still valid
298 $this->min_compressed_size += $len + 1;
299 if ($this->compressed_size >= $this->min_compressed_size)
300 {
301 // Set the original comment to the given string
302 $this->comment = substr($this->compressed_data, $this->position, $len);
303 $this->position += $len + 1;
304 }
305 else
306 {
307 return false;
308 }
309 }
310
311 // Parse the FHCRC
312 if ($this->flags & 2)
313 {
314 // Check the length of the string is still valid
315 $this->min_compressed_size += $len + 2;
316 if ($this->compressed_size >= $this->min_compressed_size)
317 {
318 // Read the CRC
319 $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
320
321 // Check the CRC matches
322 if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
323 {
324 $this->position += 2;
325 }
326 else
327 {
328 return false;
329 }
330 }
331 else
332 {
333 return false;
334 }
335 }
336
337 // Decompress the actual data
338 if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
339 {
340 return false;
341 }
342 else
343 {
344 $this->position = $this->compressed_size - 8;
345 }
346
347 // Check CRC of data
348 $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
349 $this->position += 4;
350 /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
351 {
352 return false;
353 }*/
354
355 // Check ISIZE of data
356 $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
357 $this->position += 4;
358 if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
359 {
360 return false;
361 }
362
363 // Wow, against all odds, we've actually got a valid gzip string
364 return true;
365 }
366 else
367 {
368 return false;
369 }
370 }
371}